ТЛ; др
Есть ли способ в коде или с аргументами JVM переопределить текущее время, представленное через System.currentTimeMillis, кроме ручного изменения системных часов на хост-машине?
Да.
Instant.now(
Clock.fixed(
Instant.parse( "2016-01-23T12:34:56Z"), ZoneOffset.UTC
)
)
Clock
В java.time
У нас есть новое решение проблемы замены сменных часов, чтобы облегчить тестирование с фиктивными значениями даты и времени. Пакет java.time в Java 8 включает абстрактный класс java.time.Clock
с явной целью:
чтобы можно было подключать альтернативные часы по мере необходимости
Вы можете подключить свою собственную реализацию Clock
, хотя, скорее всего, вы найдете такую, уже созданную для ваших нужд. Для вашего удобства java.time включает статические методы для получения специальных реализаций. Эти альтернативные реализации могут быть полезны во время тестирования.
Измененная каденция
Различные tick…
методы производят часы, которые увеличивают текущий момент с различной частотой.
По умолчанию Clock
время обновляется с такой частотой, как миллисекунды в Java 8 и в Java 9 с точностью до наносекунд (в зависимости от вашего оборудования). Вы можете запросить отчет об истинном текущем моменте с различной степенью детализации.
Ложные часы
Некоторые часы могут врать, производя результат, отличный от аппаратных часов ОС хоста.
fixed
- Сообщает один неизменный (не увеличивающийся) момент как текущий момент.
offset
- Сообщает текущий момент, но смещенный переданным Duration
аргументом.
Например, зафиксируйте первый момент самого раннего Рождества в этом году. другими словами, когда Санта и его олени делают свою первую остановку . Самый ранний часовой пояс в настоящее время, кажется, находится Pacific/Kiritimati
в +14:00
.
LocalDate ld = LocalDate.now( ZoneId.of( "America/Montreal" ) );
LocalDate xmasThisYear = MonthDay.of( Month.DECEMBER , 25 ).atYear( ld.getYear() );
ZoneId earliestXmasZone = ZoneId.of( "Pacific/Kiritimati" ) ;
ZonedDateTime zdtEarliestXmasThisYear = xmasThisYear.atStartOfDay( earliestXmasZone );
Instant instantEarliestXmasThisYear = zdtEarliestXmasThisYear.toInstant();
Clock clockEarliestXmasThisYear = Clock.fixed( instantEarliestXmasThisYear , earliestXmasZone );
Используйте эти специальные фиксированные часы, чтобы всегда возвращать один и тот же момент. Мы получаем первый момент Рождества в Киритимати , когда UTC показывает время на настенных часах на четырнадцать часов раньше, 10 часов утра предшествующей даты 24 декабря.
Instant instant = Instant.now( clockEarliestXmasThisYear );
ZonedDateTime zdt = ZonedDateTime.now( clockEarliestXmasThisYear );
Instant.toString (): 2016-12-24T10: 00: 00Z
zdt.toString (): 2016-12-25T00: 00 + 14: 00 [Тихоокеанский регион / Киритимати]
Смотрите живой код на IdeOne.com .
Истинное время, другой часовой пояс
Вы можете контролировать, какой часовой пояс назначается Clock
реализацией. Это может быть полезно при тестировании. Но я не рекомендую это в производственном коде, где вы всегда должны явно указывать необязательные аргументы ZoneId
или ZoneOffset
аргументы.
Вы можете указать, что UTC будет зоной по умолчанию.
ZonedDateTime zdtClockSystemUTC = ZonedDateTime.now ( Clock.systemUTC () );
Вы можете указать любой часовой пояс. Укажите правильное время имя зоны в формате continent/region
, например America/Montreal
, Africa/Casablanca
или Pacific/Auckland
. Никогда не используйте аббревиатуру из 3–4 букв, например EST
или, IST
поскольку они не являются истинными часовыми поясами, не стандартизированы и даже не уникальны (!).
ZonedDateTime zdtClockSystem = ZonedDateTime.now ( Clock.system ( ZoneId.of ( "America/Montreal" ) ) );
Вы можете указать, что текущий часовой пояс JVM по умолчанию должен быть по умолчанию для конкретного Clock
объекта.
ZonedDateTime zdtClockSystemDefaultZone = ZonedDateTime.now ( Clock.systemDefaultZone () );
Запустите этот код для сравнения. Обратите внимание, что все они сообщают об одном и том же моменте, об одной и той же точке на временной шкале. Они различаются только временем настенных часов ; Другими словами, три способа сказать одно и то же, три способа показать один и тот же момент.
System.out.println ( "zdtClockSystemUTC.toString(): " + zdtClockSystemUTC );
System.out.println ( "zdtClockSystem.toString(): " + zdtClockSystem );
System.out.println ( "zdtClockSystemDefaultZone.toString(): " + zdtClockSystemDefaultZone );
America/Los_Angeles
была текущей зоной JVM по умолчанию на компьютере, на котором выполнялся этот код.
zdtClockSystemUTC.toString (): 2016-12-31T20: 52: 39.688Z
zdtClockSystem.toString (): 2016-12-31T15: 52: 39.750-05: 00 [Америка / Монреаль]
zdtClockSystemDefaultZone.toString (): 2016-12-31T12: 52: 39.762-08: 00 [Америка / Лос-Анджелес]
По определению, Instant
класс всегда находится в формате UTC. Таким образом, эти три Clock
использования, связанные с зонами, имеют точно такой же эффект.
Instant instantClockSystemUTC = Instant.now ( Clock.systemUTC () );
Instant instantClockSystem = Instant.now ( Clock.system ( ZoneId.of ( "America/Montreal" ) ) );
Instant instantClockSystemDefaultZone = Instant.now ( Clock.systemDefaultZone () );
InstantClockSystemUTC.toString (): 2016-12-31T20: 52: 39.763Z
InstantClockSystem.toString (): 2016-12-31T20: 52: 39.763Z
InstantClockSystemDefaultZone.toString (): 2016-12-31T20: 52: 39.763Z
Часы по умолчанию
Реализация, используемая по умолчанию, Instant.now
- это та реализация, которую возвращает Clock.systemUTC()
. Эта реализация используется, когда вы не указываете Clock
. Убедитесь сами в исходном коде предварительной версии Java 9 дляInstant.now
.
public static Instant now() {
return Clock.systemUTC().instant();
}
По умолчанию Clock
для OffsetDateTime.now
и ZonedDateTime.now
установлено Clock.systemDefaultZone()
. Смотрите исходный код .
public static ZonedDateTime now() {
return now(Clock.systemDefaultZone());
}
Поведение реализаций по умолчанию изменилось между Java 8 и Java 9. В Java 8 текущий момент фиксируется с разрешением только в миллисекундах, несмотря на способность классов сохранять разрешение наносекунд . В Java 9 появилась новая реализация, способная фиксировать текущий момент с разрешением наносекунды - в зависимости, конечно, от возможностей аппаратных часов вашего компьютера.
О 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.*
занятиях. Hibernate 5 и JPA 2.2 поддерживают java.time .
Где взять классы java.time?