2010-05-20 5 views
11

Я получаю datetime из веб-службы SOAP без информации о тимзоне. Следовательно, десериализатор оси принимает UTC. Тем не менее, дата-время действительно находится в Сиднее. Я решил эту проблему путем вычитания смещение часового пояса:Изменение часового пояса без изменения времени в Java

Calendar trade_date = trade.getTradeDateTime(); 
TimeZone est_tz = TimeZone.getTimeZone("Australia/Sydney"); 
long millis = trade_date.getTimeInMillis() - est_tz.getRawOffset(); 
trade_date.setTimeZone(est_tz); 
trade_date.setTimeInMillis(millis); 

Однако, я не уверен, если это решение также принимает летнее во внимание. Я думаю, что это нужно, потому что все операции выполняются в UTC. Любой опыт манипулирования временем в Java? Лучшие идеи о том, как решить эту проблему?

+1

Я всегда, когда-либо, и только манипулировать датой (на любом языке), используя только фиксированный блок. Этот блок является вторым (или миллисекундой). Есть минуты с 59 или 61 секундой, и есть дни с 23 или 25 часами. Есть часы с 60 * 60 +/- 1 секунд и т. Д. Все мои даты хранятся в виде (миллисекунд) секунд с эпохи. Вот как они находятся в БД, вот как они сортируются. Единственный раз, когда я делаю часовой пояс/yyyy-mm-dd любого преобразования, когда он должен отображаться пользователю (или при использовании сломанных API, которые не понимают, что дата выражается в секундах). – SyntaxT3rr0r

+0

@WizardOfOdds. Это звуковой совет, но OP четко сообщил, что он получает временную метку из веб-службы (возможно, стороннюю сторону) и использовал стороннюю библиотеку для обработки этого запроса. Ясно, что есть некоторые вещи из его прямого контроля, и переход от часового пояса к часовому поясу определенно не прямо с java.util.Calendar. –

+0

Спасибо за ваши комментарии. Я создаю заглушки веб-службы из файла WSDL с помощью Axis. Я использую сгенерированные классы для подключения к стороннему веб-сервису. На самом деле, они должны передавать поля datetime с информацией о часовом поясе или в UTC, что и ожидает Axis. Но это не мой выбор. – 2010-05-20 13:30:46

ответ

-1

Я принял решение reparse строка даты, полученная с заданным часовым поясом. Это также следует рассмотреть переход на летнее:

public class DateTest { 

    private static SimpleDateFormat soapdatetime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     TimeZone oztz = TimeZone.getTimeZone("Australia/Sydney"); 
     TimeZone gmtz = TimeZone.getTimeZone("GMT"); 
     Calendar datetime = Calendar.getInstance(gmtz); 

     soapdatetime.setTimeZone(gmtz); 
     String soap_datetime = soapdatetime.format(datetime.getTime()); 
     System.out.println(soap_datetime); 

     soapdatetime.setTimeZone(oztz); 
     datetime.setTimeZone(oztz); 
     try { 
      datetime.setTime(
        soapdatetime.parse(soap_datetime) 
      ); 
     } catch (ParseException e) { 
      e.printStackTrace(); 
     } 

     soapdatetime.setTimeZone(gmtz); 
     soap_datetime = soapdatetime.format(datetime.getTime()); 
     System.out.println(soap_datetime); 
    } 
} 
16

Жаль дура, который должен делать даты на Java.

То, что вы сделали, почти наверняка пойдет не так, как в переходные периоды перехода на летнее время. Лучший способ сделать это, вероятно, создать новый объект Calendar, установить на нем Timezone, а затем установить все поля отдельно, так что год, месяц, день, час, минута, секунда, получение значений из объекта Date ,

Edit:
Чтобы сохранить все счастливы, вы, вероятно, следует сделать это:

Calendar utcTime = Calendar.getInstance(TimeZone.getTimeZone("UTC")); 
Calendar sydneyTime = Calendar.getInstance(TimeZone.getTimeZone("Australia/Sydney"); 
utcTime.setTime(trade_date); 
for (int i = 0; i < Calendar.FIELD_COUNT; i++) { 
    sydneyTime.set(i, utcTime.get(i)); 
} 

Тогда вы не будете использовать какие-либо устаревшие методы.

+0

-1: Для предложения использования устаревших методов класса java.util.Date –

+0

возможно: 'newCalendar.set (oldCalendar.get (Calender.YEAR), oldCalendar.get (Calendar.MONTH), ..., oldCalendar.get (Calendar.SECOND)); ' – wds

+1

@ Александр Погребняк: Я обновил ответ, чтобы пользователи не привели к темной стороне ;-) –

3

Однако, я не уверен, если это решение также принимает в летнее счет. Я думаю, это должно быть, потому что все операции находятся в UTC.

Да, вы должны учитывать летнее время, поскольку оно влияет на смещение по UTC.

Любые впечатления от манипуляции временем на Java? Лучшие идеи о том, как решить эту проблему?

Joda-Time - API лучшего времени. Может быть, следующий фрагмент может быть полезен:

DateTimeZone zone; // TODO : get zone 
DateTime fixedTimestamp = new DateTime(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, zone); 

типы JodaTime неизменны, который также является преимуществом.

+0

Спасибо за ссылку на JodaTime. Однако я не буду вводить новую стороннюю библиотеку для этого проекта. Но я буду рассматривать JodaTime в неактивном времени. – 2010-05-20 15:47:38

+0

Joda-Time стоит того, чтобы добавить стороннюю библиотеку. Хорошо изношенный и проверенный. Классы java.util.Date & Calendar, как известно, хлопотны. –

2

я обычно делаю это таким образом

Calendar trade_date_utc = trade.getTradeDateTime(); 
TimeZone est_tz = TimeZone.getTimeZone("Australia/Sydney"); 
Calendar trade_date = Calendar.GetInstance(est_tz); 
trade_date.setTimeInMillis(millis); 
4

Я хочу поблагодарить человека за Быстродействие 6. Это был отличный старт для меня, и подход, который я не сделал рассматривать. Для приведения его в уровень производственного кода необходимы некоторые дополнительные шаги. В частности, обратите внимание на шаги, необходимые для DST_OFFSET и ZONE_OFFSET. Я хочу поделиться решением, которое я придумал.

Это занимает время от входного объекта Calendar, копирует его на выходное время, устанавливает новый часовой пояс на выход. Это используется, когда время буквально поступает из базы данных и настраивает часовой пояс без изменения времени.

public static Calendar setNewTimeZoneCopyOldTime(Calendar inputTime, 
     TimeZone timeZone) { 
    if((inputTime == null) || (timeZone == null)) { return(null); } 

    Calendar outputTime = Calendar.getInstance(timeZone); 
    for(int i = 0; i < Calendar.FIELD_COUNT; i++) { 
     if((i != Calendar.ZONE_OFFSET) && (i != Calendar.DST_OFFSET)) { 
      outputTime.set(i, inputTime.get(i)); 
     } 
    } 

    return((Calendar) outputTime.clone()); 
} 
0

Вы получаете строку стиля ISO 8601 из этой испорченной веб-службы? Если это так, библиотека Joda-Time 2.3 делает это очень просто.

Если вы получаете строку ISO 8601 без какого-либо смещения часового пояса, вы передаете объект часового пояса конструктору DateTime.

DateTimeZone timeZone = DateTimeZone.forID("Australia/Sydney"); 
String input = "2014-01-02T03:00:00"; // Note the lack of time zone offset at end. 
DateTime dateTime = new DateTime(input, timeZone); 

самосвала утешать ...

System.out.println("dateTime: " + dateTime); 

При запуске ...

dateTime: 2014-01-02T03:00:00.000+11:00 
0
@Test 
public void tzTest() { 
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS Z"); 
    TimeZone tz1 = TimeZone.getTimeZone("Europe/Moscow"); 
    Calendar cal1 = Calendar.getInstance(tz1); 
    long l1 = cal1.getTimeInMillis(); 
    df.setTimeZone(tz1); 
    System.out.println(df.format(cal1.getTime())); 
    System.out.println(l1); 
    TimeZone tz2 = TimeZone.getTimeZone("Africa/Douala"); 
    Calendar cal2 = Calendar.getInstance(tz2); 
    long l2 = l1 + tz1.getRawOffset() - tz2.getRawOffset(); 
    cal2.setTimeInMillis(l2); 
    df.setTimeZone(tz2); 
    System.out.println(df.format(cal2.getTime())); 
    System.out.println(l2); 
    assertNotEquals(l2, l1); 
} 


Запуск CalendarTest
2016-06-30 19: 09: 16,522 +0300
2016-06-30 19: 09: 16,522 +0100
Тесты запуска: 1, Отказы: 0, ошибки: 0, пропущено: 0, Время, прошедшее: 0,137 сек

Смежные вопросы