Мой вопрос может быть тривиальным, но я просто ищу разъяснения. Я где-то читал в SO, что Java Date() на самом деле всегда находится во времени UTC, почему, когда я создаю объект Date() и печатаю его с помощью toString(), он отображает местное время. Если это неправильный способ печати, что это должно быть, чтобы я получил время UTC?
Java Date() возвращает дату в формате UTC — что это на самом деле означает?
Ответы (3)
Для форматирования вам действительно следует использовать реализацию DateFormat
(например, SimpleDateFormat
). Это позволит вам указать часовой пояс (и формат вывода). Date
сам по себе не имеет понятия часовых поясов - он представляет момент времени, используя «миллисекунды с эпохи Unix» в качестве хранилища. Метод toString()
просто преобразует любой представленный момент в местное время, используя системный часовой пояс по умолчанию.
Лично я бы посоветовал полностью отказаться от встроенного API даты/времени и использовать Joda Time в качестве гораздо более разумная библиотека.
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?
- Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6 and Java SE 7
- Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.time classes.
- Для более ранних версий Android (‹26) ThreeTenABP a> проект адаптирует ThreeTen-Backport (упомянутое выше). См. Как использовать ThreeTenABP….
Проект ThreeTen-Extra расширяет java.time дополнительными классами. . Этот проект является испытательным полигоном для возможных дополнений к java.time в будущем. Здесь вы можете найти несколько полезных классов, таких как Interval
a>, YearWeek
, YearQuarter
и подробнее.
Объект 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.