ТЛ; др
Есть ли способ, либо в коде, либо с аргументами JVM, переопределить текущее время, представленное через System.currentTimeMillis, кроме ручного изменения системных часов на хост-компьютере?
Да.
Instant.now(
Clock.fixed(
Instant.parse( "2016-01-23T12:34:56Z"), ZoneOffset.UTC
)
)
Clock
В java.time
У нас есть новое решение проблемы замены сменных часов, чтобы упростить тестирование со значениями faux date-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 );
Используйте эти специальные фиксированные часы, чтобы всегда возвращать один и тот же момент. Первый момент Рождества мы получаем в Kiritimati , когда 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 [Pacific / Kiritimati]
См. живой код в 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 [America / Los_Angeles]
Класс 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
.
Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на классы java.time .
Чтобы узнать больше, см. Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .
Вы можете обмениваться java.time объектами непосредственно с вашей базой данных. Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.*
классах.
Где получить классы java.time?
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval
, YearWeek
, YearQuarter
и more .