Установить часовой пояс Java как GMT / UTC


97

Мне нужно принудительно установить любые операции, связанные со временем, в GMT / UTC, независимо от часового пояса, установленного на машине. Любой удобный способ сделать это в коде?

Чтобы уточнить, я использую время сервера БД для всех операций, но оно форматируется в соответствии с местным часовым поясом.

Спасибо!


На самом деле его проблема - это моя подгруппа, но я нашел решение.
SyBer

Посмотрите на повторяющийся вопрос и найдите «Joda» и «DateTimeZone».
Basil Bourque

Ответы:


126

OP ответил на этот вопрос, чтобы изменить часовой пояс по умолчанию для одного экземпляра запущенной JVM, установить user.timezoneсистемное свойство:

java -Duser.timezone=GMT ... <main-class>

Если вам нужно установить определенные часовые пояса при извлечении объектов Date / Time / Timestamp из базы данных ResultSet, используйте вторую форму getXXXметодов, которые принимают Calendarобъект:

Calendar tzCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
ResultSet rs = ...;
while (rs.next()) {
    Date dateValue = rs.getDate("DateColumn", tzCal);
    // Other fields and calculations
}

Или, установив дату в PreparedStatement:

Calendar tzCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
PreparedStatement ps = conn.createPreparedStatement("update ...");
ps.setDate("DateColumn", dateValue, tzCal);
// Other assignments
ps.executeUpdate();

Это обеспечит согласованность значения, хранящегося в базе данных, когда столбец базы данных не хранит информацию о часовом поясе.

java.util.DateИ java.sql.Dateклассы хранить фактическое время (миллисекунды) в формате UTC. Чтобы отформатировать их при выводе в другой часовой пояс, используйте SimpleDateFormat. Вы также можете связать часовой пояс со значением с помощью объекта Calendar:

TimeZone tz = TimeZone.getTimeZone("<local-time-zone>");
//...
Date dateValue = rs.getDate("DateColumn");
Calendar calValue = Calendar.getInstance(tz);
calValue.setTime(dateValue);

Полезная ссылка

https://docs.oracle.com/javase/9/troubleshoot/time-zone-settings-jre.htm#JSTGD377

https://confluence.atlassian.com/kb/setting-the-timezone-for-the-java-environment-841187402.html


Следует отметить, что установка часового пояса для всей JVM влияет на все, включая такие вещи, как ведение журнала. Просто помните, если это желаемый эффект.
Герман Ганс

Ага, это нормально. Стоит упомянуть лишь одно: я фактически устанавливаю user.timezone непосредственно в коде, а не через параметр -D.
SyBer

6
@SyBer: это работает, но вы должны убедиться, что вы установили это до того, как какой-либо метод вызовет метод TimeZone.getDefault (). В противном случае у вас будет некоторая путаница, поскольку значение по умолчанию кешируется после первого выполнения. Это также означает, что это может быть проблемой, если вы делаете это внутри API / библиотеки (скрытой от обычного просмотра) - обязательно тщательно документируйте, что вы делаете.
Кевин Брок,

23

Также, если вы можете установить часовой пояс JVM таким образом

System.setProperty("user.timezone", "EST");

или -Duser.timezone=GMTв аргументах JVM.


System.setProperty("user.timezone" ...)не работает.
Wilmol

13

Мне пришлось установить часовой пояс JVM для Windows 2003 Server, потому что он всегда возвращал GMT для новой даты ();

-Duser.timezone=America/Los_Angeles

Или подходящий часовой пояс. Найти список часовых поясов тоже оказалось непросто ...

Вот два списка;

http://wrapper.tanukisoftware.com/doc/english/prop-timezone.html

http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzatz%2F51%2Fadmin%2Freftz.htm


10

Вы можете изменить часовой пояс с помощью TimeZone.setDefault () :

TimeZone.setDefault(TimeZone.getTimeZone("GMT"))

Без обид, но временное изменение глобального статического состояния звучит как очень плохая идея ...
Г. Демеки

Вы могли бы, но не должны. Это чрезвычайно плохой совет. У всей JVM изменен часовой пояс.
scot

1
Иногда это именно то, чего вы хотите достичь. Например. Я видел микросервисы на основе Java, всегда работающие с UTC, чтобы избежать проблем с часовыми поясами. В этих системах серверная часть базы данных также работает с UTC, поэтому естественно "принудительно" использовать JVM в UTC. Что важно: вы должны знать, что делаете и каковы последствия ...
snorbi

точно нет. Если вы хотите, чтобы вся ваша система была в формате UTC (очень хорошая идея), установите системный часовой пояс на UTC и оставьте часовой пояс Java в покое.
scot

3
За исключением случаев, когда у вас несколько JVM с разными требованиями. Мы можем спорить бесконечно, но каждый случай уникален: иногда вам нужно установить часовой пояс всей системы, иногда вы устанавливаете только одну JVM. Давайте будем счастливы, что сегодняшние системы настолько гибкие, что мы можем делать и то, и другое 😉
snorbi

8

для меня просто быстрый SimpleDateFormat,

  private static final SimpleDateFormat GMT = new SimpleDateFormat("yyyy-MM-dd");
  private static final SimpleDateFormat SYD = new SimpleDateFormat("yyyy-MM-dd");
  static {
      GMT.setTimeZone(TimeZone.getTimeZone("GMT"));
    SYD.setTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
  }

затем отформатируйте дату с другим часовым поясом.


6

Я бы получил время из БД в необработанном виде (длинная временная метка или дата Java), а затем использовал бы SimpleDateFormat для его форматирования или Calendar для управления им. В обоих случаях вы должны установить часовой пояс объектов перед его использованием.

Смотрите SimpleDateFormat.setTimeZone(..)и Calendar.setTimeZone(..)подробности


6

tl; dr

String sql = "SELECT CURRENT_TIMESTAMP ;

OffsetDateTime odt = myResultSet.getObject( 1 , OffsetDateTime.class ) ;

Избегайте зависимости от ОС хоста или JVM для часового пояса по умолчанию

Я рекомендую вам написать весь свой код, чтобы явно указать желаемый / ожидаемый часовой пояс. Вам не нужно зависеть от текущего часового пояса JVM по умолчанию. И имейте в виду, что текущий часовой пояс JVM по умолчанию может измениться в любой момент во время выполнения с любым кодом в любом потоке любого вызываемого приложения TimeZone.setDefault. Такой вызов немедленно влияет на все приложения в этой JVM.

java.time

Некоторые другие ответы были правильными, но теперь устарели. Ужасные классы времени и даты, связанные с самыми ранними версиями Java, были ошибочными, написанными людьми, которые не понимали сложности и тонкости обработки даты и времени.

Унаследованные классы даты и времени были заменены классами java.time, определенными в JSR 310.

Чтобы представить часовой пояс, используйте ZoneId. Чтобы представить смещение от UTC, используйте ZoneOffset. Смещение - это просто количество часов, минут и секунд вперед или назад от нулевого меридиана. Часовой пояс - это гораздо больше. Часовой пояс - это история прошлых, настоящих и будущих изменений смещения, используемого людьми определенного региона.

Мне нужно принудительно установить любые операции, связанные со временем, в GMT / UTC

Для смещения нуля часов-минут-секунд используйте константу ZoneOffset.UTC.

Instant

Чтобы зафиксировать текущий момент в формате UTC, используйте расширение Instant. Этот класс представляет момент в формате UTC, всегда по определению в формате UTC.

Instant instant = Instant.now() ;  // Capture current moment in UTC.

ZonedDateTime

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

ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

База данных

Вы упоминаете базу данных.

Чтобы получить момент из базы данных, ваш столбец должен иметь тип данных, близкий к стандарту SQL TIMESTAMP WITH TIME ZONE. Получите объект, а не строку. В JDBC 4.2 и новее мы можем обмениваться объектами java.time с базой данных. OffsetDateTimeТребуется JDBC, в то время как Instantи не ZonedDateTimeявляются обязательными.

OffsetDateTime odt = myResultSet.getObject(  , OffsetDateTime.class ) ;

Я предполагаю, что в большинстве баз данных и драйверов вы получите момент, который отображается в формате UTC. Но если нет, вы можете настроить любой из двух способов:

  • Извлеките Instant: odt.toInstant()
  • Отрегулируйте от заданного смещения до смещения нуля: OffsetDateTime odtUtc = odt.withOffsetSameInstant (ZoneOffset.UTC); `.

Таблица типов даты и времени в Java (как устаревшей, так и современной) и в стандартном SQL


О java.time

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

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

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

Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте драйвер JDBC, совместимый с JDBC 4.2 или новее. Нет необходимости в строках, нет необходимости в java.sql.*занятиях.

Где взять классы java.time?


1

создать пару клиент / сервер, чтобы после выполнения клиент-сервер отправлял правильное время и дату. Затем клиент запрашивает у сервера pm GMT, и сервер возвращает правильный ответ.


1

Использовать системное свойство:

-Duser.timezone=UTC

5
Зачем нужно это использовать? Пожалуйста, добавьте пояснения к своему ответу, чтобы другие могли извлечь из него уроки
Нико Хаасе,

1

Выполните эту строку в MySQL, чтобы сбросить часовой пояс:

SET @@global.time_zone = '+00:00';

0

Вот это да. Я знаю, что это древний поток, но все, что я могу сказать, это не вызывать TimeZone.setDefault () в любом коде пользовательского уровня. Это всегда устанавливает часовой пояс для всей JVM и почти всегда является очень плохой идеей. Научитесь использовать библиотеку joda.time или новый класс DateTime в Java 8, который очень похож на библиотеку joda.time.


-6

Если вы хотите получить время по Гринвичу только с помощью intiger: var currentTime = new Date (); var currentYear = '2010' var currentMonth = 10; var currentDay = '30 'var currentHours = '20' var currentMinutes = '20 'var currentSeconds = '00' var currentMilliseconds = '00 '

currentTime.setFullYear(currentYear);
currentTime.setMonth((currentMonth-1)); //0is January
currentTime.setDate(currentDay);  
currentTime.setHours(currentHours);
currentTime.setMinutes(currentMinutes);
currentTime.setSeconds(currentSeconds);
currentTime.setMilliseconds(currentMilliseconds);

var currentTimezone = currentTime.getTimezoneOffset();
currentTimezone = (currentTimezone/60) * -1;
var gmt ="";
if (currentTimezone !== 0) {
  gmt += currentTimezone > 0 ? ' +' : ' ';
  gmt += currentTimezone;
}
alert(gmt)

5
для меня это похоже на JavaScript (! = Java).
Фил
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.