Java Date() возвращает дату в формате UTC — что это на самом деле означает?

Мой вопрос может быть тривиальным, но я просто ищу разъяснения. Я где-то читал в SO, что Java Date() на самом деле всегда находится во времени UTC, почему, когда я создаю объект Date() и печатаю его с помощью toString(), он отображает местное время. Если это неправильный способ печати, что это должно быть, чтобы я получил время UTC?


person jasonline    schedule 10.05.2011    source источник


Ответы (3)


Для форматирования вам действительно следует использовать реализацию DateFormat (например, SimpleDateFormat). Это позволит вам указать часовой пояс (и формат вывода). Date сам по себе не имеет понятия часовых поясов - он представляет момент времени, используя «миллисекунды с эпохи Unix» в качестве хранилища. Метод toString() просто преобразует любой представленный момент в местное время, используя системный часовой пояс по умолчанию.

Лично я бы посоветовал полностью отказаться от встроенного API даты/времени и использовать Joda Time в качестве гораздо более разумная библиотека.

person Jon Skeet    schedule 10.05.2011
comment
да, именно из вашего поста я придумал этот вопрос. Для печати да, я использую DateFormat. Но как UTC связано с Date()? Я не мог найти связь и почему всегда отображается местное время, хотя я думал, что это время UTC (GMT+0)? Ну, я знаю, что Date() просто представляет время, прошедшее с 1 января 1970 года... - person jasonline; 10.05.2011
comment
@jasonline: эпоха Unix определяется как полночь 1 января 1970 года в UTC. - person Jon Skeet; 10.05.2011
comment
Так что я предполагаю, что именно так появилось соединение, и я не должен ожидать, что время UTC будет отображаться, если я где-то живу, например, по Гринвичу +8. - person jasonline; 10.05.2011
comment
@jasonline: Не от Date.toString, нет. Как я уже сказал, используйте Joda вместо этого :) - person Jon Skeet; 10.05.2011

«Java Date() возвращает дату в формате UTC» — что это на самом деле означает?

UTC — это базовая линия, относительно которой мы корректируем время суток по всему миру.

Со дней пещерного человека полдень или 12:00 — это когда солнце находится прямо над головой. Конечно, это означает разные моменты в разных местах. Полдень в Японии наступает на несколько часов раньше, чем в Европе, а в Америке полдень наступает даже позже.

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

Какой базовый уровень? Эта исходная линия была произвольно выбрана судьбой истории как широта, проходящая через Королевскую обсерваторию в Гринвиче. в Лондоне, Англия, Великобритания. Часовые пояса к востоку от UTC на определенное количество часов-минут-секунд отстают от UTC, а к западу - на определенное количество отстают от UTC. Например, Индия опережает UTC на пять с половиной часов, а Мартиника в Карибском бассейне отстает на четыре часа.

Если смещение равно нулю часов-минут-секунд, то мы говорим, что находимся «в UTC» или «в UTC».

Java Date() на самом деле всегда во времени UTC

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

Между прочим, класс Date устарел. Класс java.time.Instant теперь используется как замена для представления момента в формате UTC. Instant имеет разрешение наносекунды, что меньше, чем миллисекунд из Date.

когда я создаю объект Date() и печатаю его с помощью toString(), он отображает местное время

С устаревшими классами даты и времени возникает много проблем. Во-первых, это плохое наименование, как упоминалось выше. Другим является благонамеренное неудачное дизайнерское решение, принятое, что Date::toString должен динамически применять текущий часовой пояс JVM по умолчанию для корректировки относительно UTC при генерации текста. Это плохое решение вызвало бесконечное замешательство и боль у Java-программистов, поскольку оно создает иллюзию того, что java.util.Date назначен часовой пояс.

Кстати… Хуже того, java.util.Date имеет часовой пояс, но спрятан глубоко в исходном коде без методов получения/установки доступа. Но эта зона влияет на некоторое поведение, например на определение равенства между объектами этого класса. Сбивает с толку? Да. Как я уже сказал, эти устаревшие классы даты и времени пронизаны плохими дизайнерскими решениями.

Если это неправильный способ печати, что это должно быть, чтобы я получил время UTC?

Правильный путь — полностью избегать класса Date. Вместо этого используйте только классы java.time.

➥ Чтобы получить текущий момент в формате UTC, используйте Instant.now.

Instant instant = Instant.now() ;

Совет. Если вы хотите изменить время для искусственного тестирования, передайте альтернативный Clock на Instant.now( Clock ).

Чтобы сгенерировать String с текстом, представляющим значение этого Instant в стандартном формате ISO 8601, просто вызовите toString. К счастью, этот класс не вводит часовой пояс, как это делает Date. Метод Instant::toString сообщает простая истина, текст момента в UTC.

String output = instant.toString() ;

2019-12-03T10:15:30.032163Z

Учтите, что объекты даты и времени, такие как Instant, не имеют «формата». Только текст, представляющий значение этих объектов, имеет формат. Текст и объект даты и времени различны и отделены друг от друга. Объект даты и времени может генерировать такой текст и может анализировать такой текст, но на самом деле текстом не является.

Если вам нужна гибкость при создании текста в других форматах, примените ZoneOffset, чтобы получить объект OffsetDateTime, или примените ZoneId, чтобы получить объект ZonedDateTime. Примените объект DateTimeFormatter для создания текста.


О java.time

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

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

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

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

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

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

person Basil Bourque    schedule 17.01.2019

Объект java.util.Date просто представляет количество миллисекунд со стандартного базового времени, известного как эпоха, а именно 1 января 1970 года, 00:00:00 по Гринвичу (или UTC). Поскольку он не содержит никакой информации о часовом поясе, его toString применяет часовой пояс JVM для возврата String в формате EEE MMM dd HH:mm:ss zzz yyyy, полученном из этого значения миллисекунды. Чтобы получить String представление объекта java.util.Date в другом формате и часовом поясе, вам нужно использовать SimpleDateFormat с желаемым форматом и применимым часовым поясом, например.

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) {
        Date date = new Date();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);

        sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
        String strDateNewYork = sdf.format(date);
        System.out.println(strDateNewYork);

        sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
        String strDateUtc = sdf.format(date);
        System.out.println(strDateUtc);
    }
}

Вывод:

2021-06-20T09:43:39.517-04:00
2021-06-20T13:43:39.517Z

ОНЛАЙН-ДЕМО

java.время

API даты и времени java.util и их API форматирования SimpleDateFormat устарели и подвержены ошибкам. Рекомендуется полностью прекратить их использование и перейти на современный API даты и времени*.

Кроме того, ниже приводится уведомление с главной страницы Joda-Time< /а>:

Обратите внимание, что начиная с Java SE 8 пользователям предлагается перейти на java.time (JSR-310) — основную часть JDK, которая заменяет этот проект.

Решение с использованием java.time, современного API даты и времени:

import java.time.Instant;

public class Main {
    public static void main(String[] args) {
        Instant now = Instant.now();
        System.out.println(now);
    }
}

Вывод:

2021-06-20T13:37:42.174352Z

ОНЛАЙН-ДЕМО

Instant представляет мгновенную точку на временная шкала в UTC. Z в выходных данных — это обозначение часового пояса для нулевого смещения часового пояса. Он означает Zulu и указывает часовой пояс Etc/UTC (который имеет смещение часового пояса +00:00 часов).

Узнайте больше о современном API Date-Time на странице Trail: Date Time< /а>.


* По какой-либо причине, если вам нужно придерживаться Java 6 или Java 7, вы можете использовать ThreeTen-Backport, который переносит большую часть функций java.time на Java 6 и 7. Если вы работаете над проектом Android и ваш уровень Android API по-прежнему не соответствует Java-8, проверьте Java 8+ API доступно через дешугаринг и Как использовать ThreeTenABP в Android Project.

person Arvind Kumar Avinash    schedule 20.06.2021