преобразование времени UTC в местный часовой пояс на Java - PullRequest
5 голосов
/ 10 июня 2010

Я знаю, что этот предмет был забит до смерти, но после нескольких часов поисков этой проблемы мне пришлось спросить.

Моя проблема: выполнять расчеты дат на сервере на основе текущего часового пояса клиентского приложения (iphone). Клиентское приложение в течение нескольких секунд сообщает серверу, как далеко его часовой пояс от GMT. Затем я хотел бы использовать эту информацию для вычисления дат на сервере. Все даты на сервере хранятся как время UTC. Так что я хотел бы получить ЧАС объекта UTC Date после того, как он был преобразован в этот местный часовой пояс. Моя текущая попытка:

int hours = (int) Math.floor(secondsFromGMT / (60.0 * 60.0));
int mins = (int) Math.floor((secondsFromGMT - (hours * 60.0 * 60.0)) / 60.0);
String sign = hours > 0 ? "+" : "-";

Calendar now = Calendar.getInstance();
TimeZone t = TimeZone.getTimeZone("GMT" + sign + hours + ":" + mins);
now.setTimeZone(t);

now.setTime(someDateTimeObject);

int hourOfDay = now.get(Calendar.HOUR_OF_DAY);

Переменные часы и минуты представляют часы и минуты, когда местный часовой пояс находится вне Гринвичского времени. После отладки этого кода переменные час, минуты и знак верны.

Проблема в том, что hourOfDay не возвращает правильный час - он возвращает час по времени UTC, а не по местному времени. Идеи?

Ответы [ 2 ]

3 голосов
/ 10 июня 2010

Строка вашего часового пояса сформулирована неправильно.Попробуйте это,

String sign = secondsFromGMT > 0 ? "+" : "-";
secondsFromGMT = Math.abs(secondsFromGMT);      
int hours = secondsFromGMT/3600;
int mins = (secondsFromGMT%3600)/60;
String zone = String.format("GMT%s%02d:%02d", sign, hours, mins);          
TimeZone t = TimeZone.getTimeZone(zone);
0 голосов
/ 22 января 2018

ТЛ; др

получить ЧАС объекта UTC Date после того, как он был преобразован в этот местный часовой пояс

Зона (предпочтительно)

ZonedDateTime.now(
    ZoneId.of( "Africa/Tunis" )  // Use a zone rather than a mere offset-from-UTC whenever possible.
).getHour()

23

Смещение

OffsetDateTime.now(
    ZoneOffset.ofTotalSeconds( secondsFromGMT )  // Use a mere offset-from-UTC only when the appropriate zone is unavailable AND you have been assured this particular offset is correct for your input data.
).getHour()

23

Избегайте устаревших классов даты и времени

Вы используете проблемные старые классы даты и времени, которые теперь унаследованы, заменены современными в отрасли классами java.time.

java.time

Получить текущий момент в UTC как Instant. Класс Instant представляет момент на временной шкале в UTC с разрешением наносекунд (до девяти (9) цифр десятичной дроби).

Instant instant = Instant.now() ;

Настройка на определенный часовой пояс.

Specify a [proper time zone name](https://en.wikipedia.org/wiki/List_of_tz_zones_by_name) in the format of `continent/region`, such as [`America/Montreal`](https://en.wikipedia.org/wiki/America/Montreal), [`Africa/Casablanca`](https://en.wikipedia.org/wiki/Africa/Casablanca), or `Pacific/Auckland`. Never use the 3-4 letter abbreviation such as `EST` or `IST` as they are *not* true time zones, not standardized, and not even unique(!). 

ZoneId z = ZoneId.of( "America/Montreal" );

Если во время выполнения вы хотите использовать текущий часовой пояс JVM по умолчанию, попросите его. Имейте в виду, это может изменить в любой момент . Поэтому, если критически, вы должны спросить или подтвердить с пользователем.

ZoneId z = ZoneId.systemDefault() ;

Применение часового пояса для создания объекта ZonedDateTime.

ZonedDateTime zdt = instant.atZone( z ) ;

Вы сказали, что хотите только час дня из этой зонированной даты-времени. Опрос определенным методом.

int hourOfDay = zdt.getHour() ;

Кстати, класс LocalTime может оказаться полезным.

LocalTime lt = zdt.toLocalTime() ;

смещение против зоны

Переменные часы и минуты представляют часы и минуты, по которым местный часовой пояс отличается от GMT

Нет, не часовой пояс. Вы сопоставили зону со смещением. Очень важно понять различие.

  • Смещение
    смещение от UTC - это количество часов, минут и секунд до / после UTC (GMT). Ни больше ни меньше.
  • Зона
    A часовой пояс - это история различных смещений, используемых народами определенного региана. Зона представляет все изменения смещения во времени , в прошлом, настоящем и ближайшем будущем. Политики во всем мире проявляют склонность к частым изменениям часового пояса.

Конкретное смещение может использоваться в нескольких местах по совпадению. Например, иногда Дублин, Лондон, Касабланка, Лагос и Браззавиль имеют одинаковое смещение +01:00, на один час впереди UTC. Но в других случаях это может быть не так, например, зимой этого года, когда Лагос остается на один час впереди UTC, а остальные три переключаются на ноль часов впереди UTC (то есть, самого UTC).

С зоной и моментом вы можете определить смещение. Но не так идет в другом направлении; только со смещением невозможно надежно определить зону.

То есть, ваше количество часов и минут - просто смещение. Это смещение может быть неправильным для вашей зоны для конкретной даты ввода. Поэтому всегда предпочитайте часовой пояс простому смещению.

OffsetDateTime

Если вы застряли по какой-то причине со смещением, которое, как вы уверены, является правильным для заданных вами входов, но вы не знаете часовой пояс, используйте ZoneOffset & OffsetDateTime , а не ZoneId & ZonedDateTime. Но если это вообще возможно, используйте зону вместо смещения, как описано выше.

ZoneOffset offset = ZoneOffset.ofTotalSeconds( secondsFromGMT ) ;
OffsetDateTime odt = OffsetDateTime.now( offset ) ;

О java.time

Фреймворк java.time встроен в Java 8 и более поздние версии. Эти классы заменяют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Проект Joda-Time , в настоящее время находящийся в режиме обслуживания , рекомендует перейти на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .

Где получить классы java.time?

  • Java SE 8 , Java SE 9 и выше
    • Встроенный.
    • Часть стандартного Java API с связанной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функций java.time перенесена на Java 6 и 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии Android связывают реализации классов java.time.
    • Для более ранних версий Android проект ThreeTenABP адаптируется ThreeTen-Backport (упоминалось выше). См. Как использовать ThreeTenABP… .

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти некоторые полезные классы, такие как Interval, YearWeek, YearQuarter и more .

...