Преобразовать объект календаря Java из местного времени в UTC - PullRequest
0 голосов
/ 30 июня 2018

Как преобразовать объект Java Calendar из местного времени в UTC? Вот что я попробовал:

    Calendar calendar = Calendar.getInstance();
    calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
    calendar.setTime(localDateTime.getTime());
    SimpleDateFormat outputFmt = new SimpleDateFormat("MMM dd, yyy h:mm a zz");
    String dateAsString = outputFmt.format(calendar.getTime());
    System.out.println(dateAsString)

Время всегда отображается в MT, а не в GMT. Я хочу сохранить календарь в формате UTC в базе данных (меня не интересует форматирование или отображение времени).

Ответы [ 3 ]

0 голосов
/ 30 июня 2018

Вот как я конвертирую обычную дату в UTC. Поэтому сначала преобразуйте ваш объект Calendar в объект Date:

public static String convertToUTC(Date date) {
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    return dateFormat.format(date);
}
0 голосов
/ 30 июня 2018

Не конвертируйте дату и время в строку для хранения в базе данных SQL. Используйте объект даты и времени.

Я предполагаю, что вы сохраняете в столбце базы данных тип данных datetime или timestamp без часового пояса, и этот столбец должен содержать значения UTC (рекомендуется). В этом случае, при условии, что вы используете хотя бы Java 8 и хотя бы JDBC 4.2, сохраните LocalDateTime в формате UTC в базе данных.

    ZonedDateTime dateTime = ZonedDateTime.of(
            2018, 7, 1, 9, 0, 0, 0, ZoneId.of("America/Denver"));
    LocalDateTime dateTimeInUtc = dateTime.withZoneSameInstant(ZoneOffset.UTC)
            .toLocalDateTime();
    System.out.println("UTC: " + dateTimeInUtc);

    PreparedStatement ps = yourDatabaseConnection.prepareStatement(
            "insert into your_table(date_time) values (?)");
    ps.setObject(1, dateTimeInUtc);
    ps.executeUpdate();

Пример кода берет 1 июля в 9 часов утра в Денвере, преобразует его и печатает:

UTC: 2018-07-01T15: 00

Затем он сохраняет распечатанное время UTC в базе данных. Обратите внимание на использование метода setObject.

Используемый вами класс Calendar давно устарел и всегда был плохо спроектирован. Если вы получили объект Calendar от устаревшего API, который вы не можете изменить или не хотите изменять прямо сейчас, сначала преобразуйте его в Instant, а затем выполните дальнейшее преобразование оттуда:

    Calendar localDateTime = // …;
    LocalDateTime dateTimeInUtc = localDateTime.toInstant()
            .atOffset(ZoneOffset.UTC)
            .toLocalDateTime();

Должен ли я использовать LocalDateTime здесь?

РЕДАКТИРОВАТЬ: Это зависит от типа данных, который вы используете в вашей базе данных и требований вашего драйвера JDBC. Как я уже сказал, я предполагал, что вы знаете, что значения в базе данных указаны в формате UTC и что используемый вами тип данных не имеет часового пояса, поэтому база данных не знает . Если это так, то нет смысла использовать тип Java с информацией о часовом поясе или смещении, так как это будет в любом случае потеряно при его сохранении.

Некоторые скажут, что в этом случае вы уже используете неверный тип в базе данных, и порекомендуют вам использовать столбец timestamp with timezone, чтобы база данных знала, что время указано в UTC. В этом случае вы, конечно, должны включить информацию о смещении в значение, которое вы храните. Например, для драйвера JDBC PostgreSQL в этом случае требуется OffsetDateTime, что логично (поскольку в нем хранится смещение UTC, а не реальный часовой пояс).

В зависимости от возможностей вашей СУБД, возможны и другие варианты. Я включил еще несколько ссылок внизу, и вы можете искать больше.

Что пошло не так в вашем коде?

Ваше преобразование в Calendar работает правильно и дает вам тот же момент времени в UTC. Проблема началась только тогда, когда вы попытались отформатировать ее в String: когда вы берете calendar.getTime(), вы получаете Date объект, который содержит тот же момент времени (все еще правильный), но Date не может содержать информацию о часовом поясе, поэтому вы потеряли информацию о UTC. Затем вы отформатировали Date, используя SimpleDateFormat. У SimpleDateFormat есть часовой пояс, и если вы не устанавливаете его самостоятельно, он использует настройку часового пояса вашей JVM, которая, вероятно, была некоторым вариантом Mountain Time. Поэтому ваше время было напечатано в МТ.

Ссылки

0 голосов
/ 30 июня 2018

Вам нужно позвонить setTimeZone на SimpleDateFormat, а не на Calendar:

//getting local time 
Calendar calendar = Calendar.getInstance(Locale.getDefault());

SimpleDateFormat outputFmt = new SimpleDateFormat("MMM dd, yyy h:mm a zz");
outputFmt.setTimeZone(TimeZone.getTimeZone("GMT")); //set timezone here

//shows calendar time correctly set    
System.out.println(outputFmt.format(calendar.getTime()));
...