Как установить часовой пояс java.util.Date? - PullRequest
187 голосов
/ 23 мая 2010

Я проанализировал java.util.Date из String, но он устанавливает местный часовой пояс как часовой пояс объекта date.

Часовой пояс не указан в String, с которого анализируется Date. Я хочу установить определенный часовой пояс для объекта date.

Как я могу это сделать?

Ответы [ 9 ]

281 голосов
/ 23 мая 2010

Использовать DateFormat. Например,

SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = isoFormat.parse("2010-05-23T09:01:02");
157 голосов
/ 23 мая 2010

Имейте в виду, что java.util.Date объекты сами по себе не содержат никакой информации о часовом поясе - вы не можете установить часовой пояс для объекта Date.Единственное, что содержит объект Date, это количество миллисекунд, прошедших с «эпохи» - 1 января 1970 года, 00:00:00 UTC.

Как показывает ZZ Coder, вы устанавливаете часовой пояс на DateFormat объект, чтобы сообщить ему, в каком часовом поясе вы хотите отобразить дату и время.

71 голосов
/ 02 марта 2014

tl; dr

... проанализировано ... из строки ... часовой пояс не указан ... Я хочу установить определенный часовой пояс

LocalDateTime.parse( "2018-01-23T01:23:45.123456789" )  // Parse string, lacking an offset-from-UTC and lacking a time zone, as a `LocalDateTime`.
    .atZone( ZoneId.of( "Africa/Tunis" ) )              // Assign the time zone for which you are certain this date-time was intended. Instantiates a `ZonedDateTime` object.

Нет времениЗона в juDate

Как указано в других правильных ответах, java.util.Date не имеет часового пояса .Он представляет UTC / GMT (без смещения часового пояса).Очень запутанно, потому что его метод toString применяет часовой пояс JVM по умолчанию при генерации строкового представления.

Избегайте juDate

По этой и многим другим причинам вам следует избегать использования встроенного java.util.Date & .Calendar & java.text.SimpleDateFormat.Они общеизвестно хлопотно.

Вместо этого используйте java.time пакет в комплекте с Java 8 .

java.time

Классы java.time могут представлять момент на временной шкале тремя способами:

  • UTC (Instant)
  • со смещением (OffsetDateTime с ZoneOffset)
  • с часовым поясом (ZonedDateTime с ZoneId)

Instant

В java.time , базовым строительным блоком является Instant, момент на временной шкале в UTC.Используйте Instant объекты для большей части вашей бизнес-логики.

Instant instant = Instant.now();

OffsetDateTime

Примените offset-from-UTC , чтобы приспособиться к * 1061 некоторой местности* настенные часы .

Применить ZoneOffset, чтобы получить OffsetDateTime.

ZoneOffset zoneOffset = ZoneOffset.of( "-04:00" );
OffsetDateTime odt = OffsetDateTime.ofInstant( instant , zoneOffset );

ZonedDateTime

Лучшеприменить часовой пояс , смещение плюс правила обработки аномалий, такие как Летнее время (DST) .

Примените ZoneId к Instant, чтобы получить ZonedDateTime.Всегда указывайте правильное имя часового пояса .Никогда не используйте 3-4 сокращения, такие как EST или IST, которые не являются ни уникальными, ни стандартизированными.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

LocalDateTime

Если во входной строке отсутствовал какой-либо индикатор смещения илизона, анализируется как LocalDateTime.

Если вы уверены в предполагаемом часовом поясе, присвойте ZoneId, чтобы получить ZonedDateTime.См. Пример кода выше в разделе tl; dr вверху.

Форматированные строки

Вызовите метод toString в любом из этих трех классов, чтобы сгенерировать строку, представляющуюзначение даты и времени в стандартном формате ISO 8601 .Класс ZonedDateTime расширяет стандартный формат, добавляя имя часового пояса в скобках.

String outputInstant = instant.toString(); // Ex: 2011-12-03T10:15:30Z
String outputOdt = odt.toString(); // Ex: 2007-12-03T10:15:30+01:00
String outputZdt = zdt.toString(); // Ex: 2007-12-03T10:15:30+01:00[Europe/Paris]

Для других форматов используйте класс DateTimeFormatter.Обычно лучше, чтобы этот класс генерировал локализованные форматы, используя ожидаемый пользовательский язык и культурные нормы.Или вы можете указать конкретный формат.


О java.time

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

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

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

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

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

  • Java SE 8 , Java SE 9 , Java SE 10, Java SE 11 и более поздних версий - часть стандартного Java API с связанной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и JavaSE 7
    • Большинствофункциональность java.time перенесена в Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии реализаций комплекта Android java.time классов.
    • Для более ранних версий Android (<26)проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .

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


Joda-Time

Хотя Joda-Time все еще активно поддерживается, его создатели сказали нам перейти на java.time, как только это будет удобно.Я оставляю этот раздел нетронутым для справки, но вместо этого предлагаю использовать раздел java.time.

В Joda-Time , объект даты-времени (DateTime) действительно знает свой назначенный часовой пояс.Это означает смещение от UTC и правил и истории летнего времени (DST) этого часового пояса и других подобных аномалий.

String input = "2014-01-02T03:04:05";
DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" );
DateTime dateTimeIndia = new DateTime( input, timeZone );
DateTime dateTimeUtcGmt = dateTimeIndia.withZone( DateTimeZone.UTC );

Вызовите метод toString для генерацииСтрока в формате ISO 8601 .

String output = dateTimeIndia.toString();

Joda-Time также предлагает широкие возможности для генерации всех видов других форматов строк.

При необходимости вы можете преобразовать изJoda-Time DateTime для java.util.Date.

Java.util.Date date = dateTimeIndia.toDate();

Поиск StackOverflow по "joda date", чтобы найти еще много примеров, некоторые довольно подробные.


На самом деле - это часовой пояс, встроенный в java.util.Date, используемый для некоторых внутренних функций (см. Комментарии к этому ответу).Но этот внутренний часовой пояс не отображается как свойство и не может быть установлен.Этот внутренний часовой пояс не тот, который используется методом toString при создании строкового представления значения даты и времени;вместо этого текущий часовой пояс JVM по умолчанию применяется на лету.Таким образом, как сокращение, мы часто говорим: «У juDate нет часового пояса».Смешение?Да.Еще одна причина избегать этих усталых старых классов.

68 голосов
/ 05 сентября 2013

Вы также можете установить часовой пояс на уровне JVM

Date date1 = new Date();
System.out.println(date1);

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
// or pass in a command line arg: -Duser.timezone="UTC"

Date date2 = new Date();
System.out.println(date2);

выход:

Thu Sep 05 10:11:12 EDT 2013
Thu Sep 05 14:11:12 UTC 2013
7 голосов
/ 22 мая 2015

Если вам нужно работать только со стандартными классами JDK, вы можете использовать это:

/**
 * Converts the given <code>date</code> from the <code>fromTimeZone</code> to the
 * <code>toTimeZone</code>.  Since java.util.Date has does not really store time zome
 * information, this actually converts the date to the date that it would be in the
 * other time zone.
 * @param date
 * @param fromTimeZone
 * @param toTimeZone
 * @return
 */
public static Date convertTimeZone(Date date, TimeZone fromTimeZone, TimeZone toTimeZone)
{
    long fromTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, fromTimeZone);
    long toTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, toTimeZone);

    return new Date(date.getTime() + (toTimeZoneOffset - fromTimeZoneOffset));
}

/**
 * Calculates the offset of the <code>timeZone</code> from UTC, factoring in any
 * additional offset due to the time zone being in daylight savings time as of
 * the given <code>date</code>.
 * @param date
 * @param timeZone
 * @return
 */
private static long getTimeZoneUTCAndDSTOffset(Date date, TimeZone timeZone)
{
    long timeZoneDSTOffset = 0;
    if(timeZone.inDaylightTime(date))
    {
        timeZoneDSTOffset = timeZone.getDSTSavings();
    }

    return timeZone.getRawOffset() + timeZoneDSTOffset;
}

Кредит переходит на этот пост .

6 голосов
/ 23 мая 2010

java.util.Calendar - это обычный способ обработки часовых поясов с использованием только классов JDK. Apache Commons имеет некоторые дополнительные альтернативы / утилиты, которые могут быть полезны. Редактировать Заметка Спонга напомнила мне, что я слышал действительно хорошие вещи о Joda-Time (хотя я сам не использовал его).

0 голосов
/ 17 января 2019

Этот код был полезен в приложении, над которым я работаю:

    Instant date = null;
    Date sdf = null;
    String formatTemplate = "EEE MMM dd yyyy HH:mm:ss";
    try {
        SimpleDateFormat isoFormat = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss");
        isoFormat.setTimeZone(TimeZone.getTimeZone(ZoneId.of("US/Pacific")));
        sdf = isoFormat.parse(timeAtWhichToMakeAvailable);
        date = sdf.toInstant();

    } catch (Exception e) {
        System.out.println("did not parse: " + timeAtWhichToMakeAvailable);
    }

    LOGGER.info("timeAtWhichToMakeAvailable: " + timeAtWhichToMakeAvailable);
    LOGGER.info("sdf: " + sdf);
    LOGGER.info("parsed to: " + date);
0 голосов
/ 17 января 2018

Преобразуйте дату в строку и сделайте это с SimpleDateFormat.

    SimpleDateFormat readFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    readFormat.setTimeZone(TimeZone.getTimeZone("GMT" + timezoneOffset));
    String dateStr = readFormat.format(date);
    SimpleDateFormat writeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    Date date = writeFormat.parse(dateStr);
0 голосов
/ 26 августа 2015

Если кому-то это понадобится, если вам нужно преобразовать часовой пояс XMLGregorianCalendar в ваш текущий часовой пояс из UTC, тогда все, что вам нужно сделать, это установить часовой пояс на 0, затем позвонить toGregorianCalendar() - он останется тот же часовой пояс, но Date знает, как преобразовать его в ваш, так что вы можете получить данные оттуда.

XMLGregorianCalendar xmlStartTime = DatatypeFactory.newInstance()
    .newXMLGregorianCalendar(
        ((GregorianCalendar)GregorianCalendar.getInstance());
xmlStartTime.setTimezone(0);
GregorianCalendar startCalendar = xmlStartTime.toGregorianCalendar();
Date startDate = startCalendar.getTime();
XMLGregorianCalendar xmlStartTime = DatatypeFactory.newInstance()
    .newXMLGregorianCalendar(startCalendar);
xmlStartTime.setHour(startDate.getHours());
xmlStartTime.setDay(startDate.getDate());
xmlStartTime.setMinute(startDate.getMinutes());
xmlStartTime.setMonth(startDate.getMonth()+1);
xmlStartTime.setTimezone(-startDate.getTimezoneOffset());
xmlStartTime.setSecond(startDate.getSeconds());
xmlStartTime.setYear(startDate.getYear() + 1900);
System.out.println(xmlStartTime.toString());

Результат:

2015-08-26T12:02:27.183Z
2015-08-26T14:02:27.183+02:00
...