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 Clockpodaje 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 Durationargument.
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/Kiritimatiw +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 Clockimplementację. 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 ZoneIdlub ZoneOffsetargumenty.
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/Casablancalub Pacific/Auckland. Nigdy nie używaj 3-4-literowego skrótu, takiego jak ESTlub, ISTponieważ 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 Clockobiektu.
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]
InstantKlasa jest zawsze w UTC definicji. Więc te trzy Clockzastosowania 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.nowjest 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 Clockdla OffsetDateTime.nowi ZonedDateTime.nowto 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?