Jak uzyskać datę UTC + 0 w Javie 8?


108

Mam problemy z klasą Date w Javie. Klasa Date zwraca lokalną datę maszyny, ale potrzebuję UTC-0.

Wyszukałem w Google i znalazłem świetne rozwiązanie dla JavaScript, ale dla Javy nic przydatnego.

Jak uzyskać datę UTC + 0 w Javie 8?


12
java.util.Datenigdy nie jest datą maszyny lokalnej. Jest zawsze definiowany jako upływające milisekundy od 1970-01-01 względem UTC + 00: 00. Być może zachowanie tej metody wprowadza w błąd toString(), ponieważ rzeczywiście używasz reprezentacji w lokalnej strefie czasowej.
Meno Hochschild

Jedną prawdopodobną odpowiedź można znaleźć w pytaniu: stackoverflow.com/questions/45350095/…
Priya Jain

Odpowiedzi:


146

W Javie 8 możesz pisać:

OffsetDateTime utc = OffsetDateTime.now(ZoneOffset.UTC);

Aby odpowiedzieć na swój komentarz, możesz następnie przekonwertować go na datę (chyba że polegasz na starszym kodzie, nie widzę żadnego powodu) lub na milis od epok:

Date date = Date.from(utc.toInstant());
long epochMillis = utc.toEpochSecond() * 1000;

1
dzięki. czy można przekonwertować ZonedDateTime na Date lub long (ms)?
Mark

7
Chociaż kod tej odpowiedzi technicznie działa, czy nie byłoby bardziej odpowiednie użycie OffsetDateTime, niż ZonedDateTimebiorąc pod uwagę, że pracujemy z przesunięciem względem UTC, a nie z pełną strefą czasową?
Basil Bourque

179

tl; dr

Instant.now()

java.time

Kłopotliwe stare klasy daty i godziny dołączone do najwcześniejszych wersji Javy zostały zastąpione przez klasy java.time wbudowane w Javę 8 i nowsze. Zobacz samouczek Oracle . Wiele funkcji zostało przeniesionych do Java 6 i 7 w ThreeTen-Backport i dodatkowo dostosowanych do systemu Android w ThreeTenABP .

Instant

Symbol Instantreprezentuje moment na osi czasu w UTC z rozdzielczością do nanosekund .

Instant instant = Instant.now();

toStringMetoda generuje obiekt String z tekstem reprezentującego wartość data-czas, korzystając z jednego ze standardowych ISO 8601 formatach.

String output = instant.toString();  

2016-06-27T19: 15: 25.864Z

InstantKlasa podstawowa klasa budynku blok w java.time. Powinna to być klasa, na którą powinieneś przejść podczas obsługi daty i godziny, ponieważ ogólnie najlepszą praktyką jest śledzenie, przechowywanie i wymiana wartości daty i czasu w UTC.

OffsetDateTime

Ale Instantma ograniczenia, takie jak brak opcji formatowania do generowania ciągów w alternatywnych formatach. Aby uzyskać większą elastyczność, przekonwertuj z Instantna OffsetDateTime. Określ przesunięcie od czasu UTC . W java.time oznacza to ZoneOffsetobiekt. Tutaj chcemy trzymać się UTC (+00), abyśmy mogli użyć wygodnej stałej ZoneOffset.UTC.

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC );

2016-06-27T19: 15: 25.864Z

Lub pomiń Instantzajęcia.

OffsetDateTime.now( ZoneOffset.UTC )

Teraz, mając OffsetDateTimeobiekt w dłoni, możesz użyć go DateTimeFormatterdo tworzenia obiektów typu String z tekstem w alternatywnych formatach. Wyszukaj przepełnienie stosu dla wielu przykładów użycia DateTimeFormatter.

ZonedDateTime

Jeśli chcesz wyświetlić zegar ścienny dla określonej strefy czasowej, zastosuj ZoneIdznak ZonedDateTime.

W tym przykładzie stosujemy strefę czasową Montréal. Latem, pod nonsensem czasu letniego (DST) , strefa ma przesunięcie -04:00. Zwróć więc uwagę, że pora dnia jest o cztery godziny wcześniejsza 15niż 19godziny. Instanta ZonedDateTimeoba przedstawiają ten sam jednoczesny moment, oglądany tylko przez dwie różne soczewki.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );

2016-06-27T15: 15: 25.864-04: 00 [Ameryka / Montreal]

Konwersja

Chociaż powinieneś unikać starych klas daty i godziny, jeśli musisz, możesz konwertować przy użyciu nowych metod dodanych do starych klas. Tutaj używamy java.util.Date.from( Instant )i java.util.Date::toInstant.

java.util.Date utilDate = java.util.Date.from( instant );

I idzie w innym kierunku.

Instant instant= utilDate.toInstant();

Podobnie poszukaj nowych metod dodanych do GregorianCalendar(podklasy Calendar) w celu konwersji na i z java.time.ZonedDateTime.

Tabela typów klas daty i czasu we współczesnym java.time i starszej wersji.

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?


3
Doceniam stwierdzenie, że czas letni to
bezsens

więc gdyby czas letni nie istniał ZonedDateTime, nie byłby potrzebny, ponieważ wszystko ZoneIdbyłoby mapowane na taki, ZoneOffsetktórego moglibyśmy po prostu użyć OffsetDateTime?
wilmol

1
@wilmol Nie. Czas letni (DST) to tylko jeden z wielu powodów, dla których politycy decydują się na przedefiniowanie granic stref czasowych i przesunięć w tych strefach. Niedawno Korea Północna zmieniła swój zegar o pół godziny, aby zsynchronizować się z Koreą Południową z powodów dyplomatycznych. Podczas wojny najeźdźcy / okupanci mogą zmienić przesunięcie, aby dopasować je do kraju ojczystego. Obecnie pojawia się nowa moda, w której rządy decydują się zatrzymać zmiany czasu letniego, ale na stałe pozostają na nim, zamiast powracać do poprzedniego standardowego czasu. Zawsze planuj przesunięcie każdej zmiany strefy lub Twoja aplikacja w końcu się zepsuje.
Basil Bourque,

1
Fantastyczna odpowiedź! Naprawdę doceniam czas, jaki w to włożyłeś. :)
drognisep

ZoneId.of („Ameryka / Montreal”); po co ktoś miałby wymyślać coś takiego w jdk? jest brzydki, obrzydliwy, nie mówi, czy coś jest nie tak przed uruchomieniem, kto pamięta cały ten twardy kod? dlaczego nie umieścić tego w klasie ENUM?
workplaylifecycle

4

W java8 użyłbym Instantklasy, która jest już w UTC i jest wygodna w obsłudze .

import java.time.Instant;

Instant ins = Instant.now();
long ts = ins.toEpochMilli();

Instant ins2 = Instant.ofEpochMilli(ts)

Alternatywnie możesz skorzystać z:

import java.time.*;

Instant ins = Instant.now(); 

OffsetDateTime odt = ins.atOffset(ZoneOffset.UTC);
ZonedDateTime zdt = ins.atZone(ZoneId.of("UTC"));

Wrócić do Instant

Instant ins4 = Instant.from(odt);

3
Nie, nieInstant jest to czas lokalny. Z Instantdefinicji jest to UTC. Więc nie ma potrzeby, aby machinacje widoczne w tej odpowiedzi próbowały dostać się do UTC; Instantjuż jest w UTC. Zobacz moją odpowiedź, aby uzyskać więcej informacji i znacznie prostszy kod.
Basil Bourque

Dziękuję za komentarz.
Abel Terefe


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.