tl; dr
Czy istnieje sposób, w kodzie lub z argumentami JVM, aby zastąpić bieżący czas, przedstawiony w System.currentTimeMillis, inny niż ręczna zmiana zegara systemowego na komputerze głównym?
Tak.
Instant.now(
Clock.fixed(
Instant.parse( "2016-01-23T12:34:56Z"), ZoneOffset.UTC
)
)
Clock
W java.time
Mamy nowe rozwiązanie problemu wymiany wtykowego zegara, aby ułatwić testowanie z fałszywymi wartościami daty i czasu. Pakiet java.time w Java 8 zawiera klasę abstrakcyjną java.time.Clock
, z wyraźnym celu:
aby umożliwić podłączanie alternatywnych zegarów w razie potrzeby
Możesz podłączyć własną implementację Clock
, ale prawdopodobnie znajdziesz taką, która już spełnia Twoje potrzeby. Dla Twojej wygody java.time zawiera statyczne metody, aby zapewnić specjalne implementacje. Te alternatywne implementacje mogą być przydatne podczas testowania.
Zmieniona kadencja
Różne tick…
metody produkują zegary, które zwiększają bieżący moment z inną kadencją.
Domyślnie Clock
podaje czas aktualizowany tak często, jak milisekundy w Javie 8, a w Javie 9, nawet w nanosekundach (w zależności od sprzętu). Możesz poprosić o raportowanie rzeczywistego aktualnego momentu z inną szczegółowością.
Fałszywe zegary
Niektóre zegary mogą kłamać, dając wynik inny niż zegar sprzętowy systemu operacyjnego hosta.
fixed
- Zgłasza pojedynczy niezmienny (bez inkrementacji) moment jako moment bieżący.
offset
- Podaje bieżący moment, ale przesunięty o przekazany Duration
argument.
Na przykład zamknij w pierwszej chwili najwcześniejszych świąt Bożego Narodzenia w tym roku. innymi słowy, gdy Święty Mikołaj i jego renifery robią pierwszy przystanek . Najwcześniejszym strefa czasowa w dzisiejszych czasach wydaje się być Pacific/Kiritimati
w +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 );
Użyj tego specjalnego zegara, aby zawsze powracać w tej samej chwili. Otrzymujemy pierwszy moment Bożego Narodzenia w Kiritimati , w którym UTC pokazuje zegar ścienny czternaście godzin wcześniej, 10 rano w dniu poprzedzającym 24 grudnia.
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]
Zobacz kod na żywo w IdeOne.com .
Prawdziwy czas, inna strefa czasowa
Możesz kontrolować, która strefa czasowa jest przypisywana przez Clock
implementację. Może to być przydatne w niektórych testach. Ale nie polecam tego w kodzie produkcyjnym, w którym zawsze należy wyraźnie określać opcjonalne ZoneId
lub ZoneOffset
argumenty.
Możesz określić, że UTC będzie strefą domyślną.
ZonedDateTime zdtClockSystemUTC = ZonedDateTime.now ( Clock.systemUTC () );
Możesz określić dowolną strefę czasową. Określ prawidłową nazwę strefy czasowej w formacie continent/region
, takie jak America/Montreal
, Africa/Casablanca
lub Pacific/Auckland
. Nigdy nie używaj 3-4-literowego skrótu, takiego jak EST
lub, IST
ponieważ nie są one prawdziwymi strefami czasowymi, nie znormalizowane, a nawet nie są unikalne (!).
ZonedDateTime zdtClockSystem = ZonedDateTime.now ( Clock.system ( ZoneId.of ( "America/Montreal" ) ) );
Można określić, że bieżąca domyślna strefa czasowa maszyny JVM powinna być domyślna dla określonego Clock
obiektu.
ZonedDateTime zdtClockSystemDefaultZone = ZonedDateTime.now ( Clock.systemDefaultZone () );
Uruchom ten kod, aby porównać. Zwróć uwagę, że wszystkie przedstawiają ten sam moment, ten sam punkt na osi czasu. Różnią się tylko czasem zegarowym ; innymi słowy, trzy sposoby powiedzenia tego samego, trzy sposoby pokazania tej samej chwili.
System.out.println ( "zdtClockSystemUTC.toString(): " + zdtClockSystemUTC );
System.out.println ( "zdtClockSystem.toString(): " + zdtClockSystem );
System.out.println ( "zdtClockSystemDefaultZone.toString(): " + zdtClockSystemDefaultZone );
America/Los_Angeles
była bieżącą domyślną strefą maszyny JVM na komputerze, na którym uruchomiono ten kod.
zdtClockSystemUTC.toString (): 2016-12-31T20: 52: 39.688Z
zdtClockSystem.toString (): 2016-12-31T15: 52: 39.750-05: 00 [Ameryka / Montreal]
zdtClockSystemDefaultZone.toString (): 2016-12-31T12: 52: 39.762-08: 00 [America / Los_Angeles]
Instant
Klasa jest zawsze w UTC definicji. Więc te trzy Clock
zastosowania związane ze strefami mają dokładnie ten sam efekt.
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
Domyślny zegar
Implementacja używana domyślnie dla Instant.now
jest zwracana przez Clock.systemUTC()
. Jest to implementacja używana, gdy nie określono pliku Clock
. Przekonaj się sam w przedpremierowym kodzie źródłowym Java 9 dlaInstant.now
.
public static Instant now() {
return Clock.systemUTC().instant();
}
Wartość domyślna Clock
dla OffsetDateTime.now
i ZonedDateTime.now
to Clock.systemDefaultZone()
. Zobacz kod źródłowy .
public static ZonedDateTime now() {
return now(Clock.systemDefaultZone());
}
Zachowanie domyślnych implementacji zmieniło się między Java 8 i Java 9. W Javie 8 bieżący moment jest rejestrowany z rozdzielczością tylko w milisekundach, pomimo zdolności klas do przechowywania rozdzielczości nanosekund . Java 9 przynosi nową implementację, która potrafi uchwycić bieżący moment z rozdzielczością nanosekund - oczywiście w zależności od możliwości zegara sprzętowego komputera.
Informacje o java.time
Struktura java.time jest wbudowana w Javę 8 i nowsze. Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak java.util.Date
, Calendar
, i SimpleDateFormat
.
Aby dowiedzieć się więcej, zobacz samouczek Oracle . I przeszukaj Stack Overflow, aby znaleźć wiele przykładów i wyjaśnień. Specyfikacja to JSR 310 .
Projekt Joda-Time , obecnie w trybie konserwacji , zaleca migrację do klas java.time .
Możesz wymieniać obiekty java.time bezpośrednio ze swoją bazą danych. Użyj sterownika JDBC zgodnego z JDBC 4.2 lub nowszym. Nie ma potrzeby stosowania ciągów ani java.sql.*
klas. Hibernate 5 i JPA 2.2 obsługują java.time .
Skąd wziąć klasy java.time?