Wiem, że tego rodzaju tematy są całkowicie omówione, ale okazało się, że pakiet commons-lang naprawdę dobrze radzi sobie z typowymi problemami Java. commons.apache.org/lang/api-2.5/org/apache/commons/lang/time Sprawdź różne pakiety, które mają.
Który czas lokalny chcesz i do jakiej precyzji. Większość stref czasowych jest zdefiniowanych w odniesieniu do UTC ze stałym przesunięciem mierzonym w sekundach SI , ale związek GMT, który jest oparty na obserwacji Słońca i (nieznacznie) zmiennej długości sekundy jest bardziej złożony. Oba różnią się o maksymalnie 0,9 sekundy.
mc0e
1
A Datenie ma strefy czasowej, więc „ale w lokalnej strefie czasowej” jest niepoprawne (lub w najlepszym razie niedokładne). Zobacz wszystko o java.util.Date .
Ole VV
Odpowiedzi:
409
java.util.Datenie ma określonej strefy czasowej, chociaż o jej wartości najczęściej myśli się w odniesieniu do UTC. Co sprawia, że myślisz, że to czas lokalny?
Mówiąc dokładniej: wartość w a java.util.Datejest liczbą milisekund od epoki Uniksa, która miała miejsce o północy 1 stycznia 1970 r., UTC. Tę samą epokę można również opisać w innych strefach czasowych, ale tradycyjny opis dotyczy UTC. Ponieważ jest to kilka milisekund od ustalonej epoki, wartość wewnątrz java.util.Datejest taka sama na całym świecie w dowolnym momencie, niezależnie od lokalnej strefy czasowej.
Podejrzewam, że problem polega na tym, że wyświetlasz go za pomocą instancji Kalendarza, która korzysta z lokalnej strefy czasowej, lub ewentualnie za pomocą, Date.toString()która również korzysta z lokalnej strefy czasowej, lub SimpleDateFormatinstancji, która domyślnie korzysta również z lokalnej strefy czasowej.
Jeśli to nie jest problem, proszę opublikować przykładowy kod.
Polecam jednak korzystanie z Joda-Time , która oferuje znacznie bardziej przejrzysty interfejs API.
To prawdopodobnie problem ze sterownikiem. Może być konieczne ustawienie połączenia na UTC lub coś w tym rodzaju. Widziałem już takie problemy, ale problem nie dotyczy java.util.Date.
Jon Skeet
13
Behrang, zgodnie z stackoverflow.com/questions/4123534/... , sterownik JDBC MySQL konwertuje dane java.util.Timestamp(lub java.util.Date) strefy czasowe serwera.
Derek Mahar,
5
@Pan. Kot: Jak to określasz? Czy to przez pisanie System.out.println(new Date())? Jeśli tak, powinieneś mieć świadomość, że jest to toString()metoda, która stosuje tam strefę czasową ... jeśli to nie to, podaj więcej szczegółów.
Jon Skeet,
8
@KanagaveluSugumar: toString()zawsze używa domyślnej strefy czasowej. date.getTime()zdecydowanie zwraca milisekundy od epoki Uniksa, w UTC. Najdokładniej jest powiedzieć, że Datesama nie ma żadnej strefy czasowej - to tylko chwila w czasie, którą można rozpatrywać w wielu strefach czasowych. Ale gdy tworzysz instancję, nie zależy ona od Twojej strefy czasowej.
Jon Skeet
6
@Jemenake: Właściwie tak się nie stało, kiedy w Greenwich była północ, ponieważ Wielka Brytania była wtedy na UTC + 1. To tylko jeden z dziwnych fragmentów historii. Ale rozumiem twój punkt widzenia - lepiej powiedzieć „new Date (). GetTime () zwraca milisekundy od epoki Uniksa, która miała miejsce o północy na początku 1 stycznia 1970 roku, UTC”. Tak więc UTC jest częścią przypisywania epoki do określonego momentu w czasie, a nie częścią wyniku.
Jon Skeet
323
tl; dr
Instant.now()// Capture the current moment in UTC.
Wygeneruj ciąg reprezentujący tę wartość:
Instant.now().toString()
2016-09-13T23: 30: 52.123Z
Detale
Jak podała poprawna odpowiedź Jona Skeeta , obiekt java.util.Date nie ma strefy czasowej † . Ale jego toStringimplementacja stosuje domyślną strefę czasową maszyny JVM podczas generowania ciągu reprezentującego tę wartość daty i godziny. Mylące dla naiwnego programisty data wydaje się mieć strefę czasową, ale jej nie ma.
Te java.util.Date, j.u.Calendaroraz java.text.SimpleDateFormatzajęcia wiązane z Java są notorycznie kłopotliwe. Unikaj ich. Zamiast tego użyj jednej z tych kompetentnych bibliotek daty i godziny:
Uzyskiwanie aktualnego czasu w UTC / GMT jest prostym linkiem…
Instant instant =Instant.now();
Ta Instantklasa jest podstawowym elementem składowym java.time, reprezentującym moment na osi czasu w UTC z rozdzielczością nanosekund .
W Javie 8 bieżący moment jest rejestrowany z rozdzielczością do milisekund. Java 9 przynosi świeży realizacji ma wśród Clockoddaje obecną chwilę w górę do pełnej zdolności nanosekundy tej klasy, w zależności od możliwości sprzętu zegara komputera hosta.
Ta toStringmetoda generuje ciąg reprezentujący jego wartość przy użyciu jednego określonego formatu ISO 8601 . Ten format generuje cyfry zero, trzy, sześć lub dziewięć cyfr ( milisekund , mikrosekund lub nanosekund ), jeśli jest to konieczne do przedstawienia ułamka sekundy.
Jeśli chcesz bardziej elastycznego formatowania lub innych dodatkowych funkcji, zastosuj przesunięcie względem UTC równe zero, aby sam UTC ( ZoneOffset.UTCstały ) uzyskał wartość OffsetDateTime.
OffsetDateTime now =OffsetDateTime.now(ZoneOffset.UTC );
Możesz wymieniać obiekty java.time bezpośrednio ze swoją bazą danych. Użyj sterownika JDBC zgodnego z JDBC 4.2 lub nowszym. Nie potrzeba ciągów, nie ma potrzeby java.sql.*klas.
Projekt ThreeTen-Extra rozszerza java.time o dodatkowe klasy. Ten projekt jest poligonem doświadczalnym dla ewentualnych przyszłych dodatków do java.time. Można znaleźć kilka przydatnych klas tutaj takie jak Interval, YearWeek, YearQuarter, i więcej .
Korzystając z darmowej biblioteki open source firmy Joda-Time innej firmy, możesz uzyskać bieżącą datę i godzinę w jednym wierszu kodu.
Joda-Time zainspirował nowe klasy java.time. * W Javie 8, ale ma inną architekturę. Możesz używać Joda-Time w starszych wersjach Javy. Joda-Time nadal działa w Javie 8 i jest aktywnie utrzymywany (od 2014). Jednak zespół Joda-Time zaleca migrację do java.time.
System.out.println("UTC/GMT date-time in ISO 8601 format: "+new org.joda.time.DateTime( org.joda.time.DateTimeZone.UTC ));
Bardziej szczegółowy przykładowy kod (Joda-Time 2.3)…
org.joda.time.DateTime now =new org.joda.time.DateTime();// Default time zone.
org.joda.time.DateTime zulu = now.toDateTime( org.joda.time.DateTimeZone.UTC );
Zrzut do konsoli…
System.out.println("Local time in ISO 8601 format: "+ now );System.out.println("Same moment in UTC (Zulu): "+ zulu );
Po uruchomieniu…
Local time in ISO 8601 format: 2014-01-21T15:34:29.933-08:00
Same moment in UTC (Zulu): 2014-01-21T23:34:29.933Z
Aby zobaczyć więcej przykładowego kodu wykonującego pracę w strefie czasowej, zobacz moją odpowiedź na podobne pytanie.
Strefa czasowa
Zalecam, aby zawsze określać strefę czasową, zamiast domyślnie polegać na bieżącej domyślnej strefie czasowej JVM (która może ulec zmianie w dowolnym momencie!). Takie poleganie wydaje się być częstą przyczyną zamieszania i błędów w pracy z datą.
Podczas dzwonienia now()należy podać żądaną / oczekiwaną strefę czasową do przypisania. Skorzystaj z DateTimeZoneklasy.
DateTimeZone zoneMontréal =DateTimeZone.forID("America/Montreal");DateTime now =DateTime.now( zoneMontréal );
Klasa ta utrzymuje stałą dla strefy czasowej UTC .
DateTime now =DateTime.now(DateTimeZone.UTC );
Jeśli naprawdę chcesz użyć bieżącej domyślnej strefy czasowej maszyny JVM, wykonaj jawne wywołanie, aby kod sam się dokumentował.
Przeczytaj o formatach ISO 8601 . Zarówno java.time, jak i Joda-Time używają rozsądnych formatów tego standardu jako domyślnych dla parsowania i generowania ciągów.
† Właściwie tak, java.util.Date tak posiada strefę czasową, zakopane głęboko pod warstwami kodu źródłowego. Dla większości praktycznych celów ta strefa czasowa jest ignorowana. Tak więc, jak stenografia, mówimy java.util.Date nie ma strefy czasowej. Co więcej, ta zakopana strefa czasowa nie jest tą, którą stosuje toStringmetoda Date ; ta metoda używa bieżącej domyślnej strefy czasowej maszyny JVM. Tym bardziej należy unikać tej mylącej klasy i trzymać się Joda-Time i java.time.
Jak to zrobić za pomocą Pure Java 8 2014-01-21T15:34:29.933-08:00w przykładzie, którego użyłeśnew org.joda.time.DateTime()
GOXR3PLUS
1
@ GOXR3PLUS ZonedDateTime.now( ZoneId.of( "America/Los_Angeles" ) ).truncatedTo( ChronoUnit.MILLIS ).toOffsetDateTime().toString() Otrzymujemy bieżący moment dla określonej strefy czasowej. Następnie odetnij wszelkie mikrosfery / nanosy. Następnie przechodzimy do posiadania jedynie zwykłego przesunięcia względem UTC (liczba godzin-minut-sekund) zamiast pełnej strefy czasowej (historia przeszłych, obecnych i przyszłych zmian w przesunięciu stosowanym przez ludzi konkretny region). Na koniec generujemy tekst reprezentujący wartość OffsetDateTimezgodną ze standardowym formatem ISO 8601 używanym domyślnie w tej toStringmetodzie.
Basil Bourque,
Dzięki za udzielenie tego szczegółowego wyjaśnienia, również +1 dla Androida obsługuje :) @BasilBourque
mochadwi
271
SimpleDateFormat dateFormatGmt =newSimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));//Local time zone SimpleDateFormat dateFormatLocal =newSimpleDateFormat("yyyy-MMM-dd HH:mm:ss");//Time in GMTreturn dateFormatLocal.parse( dateFormatGmt.format(newDate()));
Dlaczego parsujesz dateFormatLocal po użyciu formatu dateFormatGmt ... nie ma sensu, czytając go. Jestem pewien, że to działa, ale zastanawiam się?
MindWire,
2
setTimeZone to zrobił (myślę, że możesz także użyć getTimeZone („UTC”) tak samo jak GMT?)
rogerdpack
6
ale czas zależy od ustawionego czasu urządzenia. Jeśli użytkownik ustawił zły czas na swoim urządzeniu, to popełnisz błąd UTC. Popraw mnie, jeśli się mylę
Basavaraj Hampali
@BasavarajHampali, ale w dzisiejszym świecie większość urządzeń jest podłączona do Internetu, co koryguje niepoprawny czas
Akshat Agarwal
3
Nie ma różnicy czasu między uniwersalnym czasem koordynowanym (UTC) a średnim czasem Greenwich (GMT)
slott,
86
To zdecydowanie zwraca czas UTC: jako obiekty String i Date!
W mojej odpowiedzi zapomniałem pokazać, jak zdefiniowano DATEFORMAT:static final String DATEFORMAT = "yyyy-MM-dd HH:mm:ss";
Someone Somewhere
21
Unikaj rozpoczynania nazw metod wielkimi literami w Javie. Zobacz konwencje kodowania Java dla nazw metod.
Florian Schrofner
2
Przekierowanie do tej odpowiedzi new Date()powoduje, że funkcja Połączenia nigdy nie zwróci prawidłowego czasu UTC, jeśli czas urządzenia jest nieprawidłowy.
Sanoop
czy ta metoda dostaje czas zależy od kalendarza urządzenia?
Arnold Brown,
Jedną rzecz do zapamiętania. Każde rozwiązanie, które musi uzyskać datę lub znacznik czasu w UTC, wygląda na to, że kluczem jest nie używać ponownie SimpleDateFormat, ale raczej użyć jednego, aby uzyskać UTC w ciągu, a następnie utworzyć inny UTC podczas konwersji ciągu na dowolną datę lub Obiekt znacznika czasu. Zauważyłem, że jeśli spróbujesz ponownie użyć tego samego SimpleDateFormat, wynikowy obiekt Date / Timestamp powróci do lokalnej strefy czasowej zamiast UTC.
Tak, ładne i czyste rozwiązanie. Martwi mnie to, czy nieefektywne jest utworzenie nowego obiektu Date zamiast tylko uzyskania instancji kalendarza?
Beemo,
Zostanie zoptymalizowany przez JVM, a HotSpot wykona najbardziej efektywny możliwy kod x86
Antonio
17
Kalendarz aGMTCalendar = Calendar.getInstance (TimeZone.getTimeZone („GMT”)); Następnie wszystkie operacje wykonane przy użyciu obiektu aGMTCalendar zostaną wykonane w strefie czasowej GMT i nie będą miały zastosowania czasu letniego ani stałych przesunięć
c.add(Calendar.MILLISECOND, (-utcOffset))uzyskać Kalendarz z strefą czasową
utc
10
Oto, co wydaje się nieprawidłowe w odpowiedzi Jona Skeeta . Powiedział:
java.util.Datejest zawsze w UTC. Co sprawia, że myślisz, że to czas lokalny? Podejrzewam, że problem polega na tym, że wyświetlasz go za pomocą instancji Kalendarza, która korzysta z lokalnej strefy czasowej, lub ewentualnie używa,
Date.toString()która również korzysta z lokalnej strefy czasowej.
pokazuje godziny GMT zamiast godzin lokalnych - zauważ, że getTime.getHours()brakuje, ponieważ stworzyłoby to Date()obiekt, który teoretycznie przechowuje datę w GMT, ale zwraca godziny w lokalnej strefie czasowej.
Nie widziałem tej odpowiedzi wcześniej, ale jeśli przeczytasz dokumentację przestarzałej Date.getHours()metody, to jest bardzo jasne: „Zwrócona wartość to liczba (od 0 do 23) reprezentująca godzinę w ciągu dnia, który zawiera lub zaczyna się od natychmiastowe w czasie reprezentowane przez ten obiekt Date, zgodnie z interpretacją w lokalnej strefie czasowej . ” (Podkreśl mój.) Jest to getHours()metoda, która interpretuje wartość w lokalnej strefie czasowej - nie jest to część stanu Datesamego obiektu.
Jon Skeet
2
Jak słusznie stwierdził Jon Skeet, obiekt java.util.Date nie ma strefy czasowej . Ale myląco metody toStringi getHourszastosowanie domyślnej strefy czasowej do ich wyniku. Tak więc naiwni programiści łatwo dają się zwieść, ponieważ wydaje się, że Data ma strefę czasową, ale w rzeczywistości nie.
Basil Bourque,
7
Jeśli chcesz obiekt Date z polami dostosowanymi do UTC, możesz to zrobić w następujący sposób: Joda Time :
import org.joda.time.DateTimeZone;import java.util.Date;...Date local =newDate();System.out.println("Local: "+ local);DateTimeZone zone =DateTimeZone.getDefault();long utc = zone.convertLocalToUTC(local.getTime(),false);System.out.println("UTC: "+newDate(utc));
Pracujesz zbyt ciężko. Joda-Time może to zrobić w jednym wierszu kodu. Zobacz własną odpowiedź na to pytanie. Wywołaj .toDateTimemetodę i przekaż stałą dla strefy czasowej UTC.
Basil Bourque,
1
DateTime utcDate = new DateTime (). ToDateTime (DateTimeZone.UTC)
Następnie wszystkie operacje wykonywane przy użyciu obiektu aGMTCalendar będą wykonywane w strefie czasowej GMT i nie będą miały zastosowania czasu letniego ani stałych przesunięć. Myślę, że poprzedni plakat ma rację, że obiekt Date () zawsze zwraca GMT, dopóki nie zrobisz czegoś z obiektem daty, który zostanie przekonwertowany na lokalną strefę czasową.
Możesz zapytać cal.get(Calendar.DATE);lub inną stałą kalendarza o inne szczegóły.
Data i znacznik czasu są przestarzałe w Javie. Nie jest to klasa kalendarza.
Przykładowy kod do renderowania czasu systemowego w określonej strefie czasowej i określonym formacie.
import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;import java.util.TimeZone;publicclassTimZoneTest{publicstaticvoid main (String[] args){//<GMT><+/-><hour>:<minutes>// Any screw up in this format, timezone defaults to GMT QUIETLY. So test your format a few times.System.out.println(my_time_in("GMT-5:00","MM/dd/yyyy HH:mm:ss"));System.out.println(my_time_in("GMT+5:30","'at' HH:mm a z 'on' MM/dd/yyyy"));System.out.println("---------------------------------------------");// Alternate format System.out.println(my_time_in("America/Los_Angeles","'at' HH:mm a z 'on' MM/dd/yyyy"));System.out.println(my_time_in("America/Buenos_Aires","'at' HH:mm a z 'on' MM/dd/yyyy"));}publicstaticString my_time_in(String target_time_zone,String format){TimeZone tz =TimeZone.getTimeZone(target_time_zone);Date date =Calendar.getInstance().getTime();SimpleDateFormat date_format_gmt =newSimpleDateFormat(format);
date_format_gmt.setTimeZone(tz);return date_format_gmt.format(date);}}
Wynik
10/08/201121:07:21
at 07:37 AM GMT+05:30 on 10/09/2011
at 19:07 PM PDT on 10/08/2011
at 23:07 PM ART on 10/08/2011
Wywołanie getTime () powoduje utratę informacji o strefie czasowej i zwrócenie czasu lokalnego.
RealCasually
3
Przeliczanie bieżącej daty i godziny w UTC:
DateTimeFormatter formatter =DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");DateTimeZone dateTimeZone =DateTimeZone.getDefault();//Default Time ZoneDateTime currDateTime =newDateTime();//Current DateTimelong utcTime = dateTimeZone.convertLocalToUTC(currDateTime .getMillis(),false);String currTime = formatter.print(utcTime);//UTC time converted to string from long in format of formatter
currDateTime = formatter.parseDateTime(currTime);//Converted to DateTime in UTC
Wykonujesz tutaj zbyt dużo pracy. (a) Wzorzec formatera, który zdefiniujesz, jest już domyślnie wbudowany w DateTime; wystarczy zadzwonić toStringna DateTime, aby uzyskać ten ciąg znaków ISO 8601 . (b) Zbyt dużo kodu do konwersji między strefami czasowymi. Wystarczy wywołać „toDateTime” i przekazać obiekt strefy czasowej. Tak: myDateTime.toDateTime( DateTimeZone.UTC ). W przypadku określonej strefy czasowej utwórz i przekaż obiekt strefy czasowej na podstawie prawidłowej nazwy , wywołanie myDateTime.toDateTime( DateTimeZone.forID( "Asia/Tehran" ) ).
Basil Bourque,
2
To zadziałało dla mnie, zwraca znacznik czasu w GMT!
Użyj tej klasy, aby uzyskać właściwy czas UTC z internetowego serwera NTP:
import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;class NTP_UTC_Time
{privatestaticfinalString TAG ="SntpClient";privatestaticfinalint RECEIVE_TIME_OFFSET =32;privatestaticfinalint TRANSMIT_TIME_OFFSET =40;privatestaticfinalint NTP_PACKET_SIZE =48;privatestaticfinalint NTP_PORT =123;privatestaticfinalint NTP_MODE_CLIENT =3;privatestaticfinalint NTP_VERSION =3;// Number of seconds between Jan 1, 1900 and Jan 1, 1970// 70 years plus 17 leap daysprivatestaticfinallong OFFSET_1900_TO_1970 =((365L*70L)+17L)*24L*60L*60L;privatelong mNtpTime;publicboolean requestTime(String host,int timeout){try{DatagramSocket socket =newDatagramSocket();
socket.setSoTimeout(timeout);InetAddress address =InetAddress.getByName(host);byte[] buffer =newbyte[NTP_PACKET_SIZE];DatagramPacket request =newDatagramPacket(buffer, buffer.length, address, NTP_PORT);
buffer[0]= NTP_MODE_CLIENT |(NTP_VERSION <<3);
writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
socket.send(request);// read the responseDatagramPacket response =newDatagramPacket(buffer, buffer.length);
socket.receive(response);
socket.close();
mNtpTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);}catch(Exception e){// if (Config.LOGD) Log.d(TAG, "request time failed: " + e);returnfalse;}returntrue;}publiclong getNtpTime(){return mNtpTime;}/**
* Reads an unsigned 32 bit big endian number from the given offset in the buffer.
*/privatelong read32(byte[] buffer,int offset){byte b0 = buffer[offset];byte b1 = buffer[offset+1];byte b2 = buffer[offset+2];byte b3 = buffer[offset+3];// convert signed bytes to unsigned valuesint i0 =((b0 &0x80)==0x80?(b0 &0x7F)+0x80: b0);int i1 =((b1 &0x80)==0x80?(b1 &0x7F)+0x80: b1);int i2 =((b2 &0x80)==0x80?(b2 &0x7F)+0x80: b2);int i3 =((b3 &0x80)==0x80?(b3 &0x7F)+0x80: b3);return((long)i0 <<24)+((long)i1 <<16)+((long)i2 <<8)+(long)i3;}/**
* Reads the NTP time stamp at the given offset in the buffer and returns
* it as a system time (milliseconds since January 1, 1970).
*/privatelong readTimeStamp(byte[] buffer,int offset){long seconds = read32(buffer, offset);long fraction = read32(buffer, offset +4);return((seconds - OFFSET_1900_TO_1970)*1000)+((fraction *1000L)/0x100000000L);}/**
* Writes 0 as NTP starttime stamp in the buffer. --> Then NTP returns Time OFFSET since 1900
*/privatevoid writeTimeStamp(byte[] buffer,int offset){int ofs = offset++;for(int i=ofs;i<(ofs+8);i++)
buffer[i]=(byte)(0);}}
I używaj go z:
long now =0;
NTP_UTC_Time client =new NTP_UTC_Time();if(client.requestTime("pool.ntp.org",2000)){
now = client.getNtpTime();}
Jeśli potrzebujesz czasu UTC „teraz” jako funkcji użycia DateTimeString:
Mówiąc najprościej. Obiekt kalendarza przechowuje informacje o strefie czasowej, ale po wykonaniu cal.getTime () informacje o strefie czasowej zostaną utracone. Dlatego w przypadku konwersji stref czasowych radzę korzystać z klas DateFormat ...
publicstaticStringGetCurrentTimeStamp(){Calendar cal=Calendar.getInstance();long offset = cal.getTimeZone().getOffset(System.currentTimeMillis());//if you want in UTC else remove it .returnnew java.sql.Timestamp(System.currentTimeMillis()+offset).toString();}
publicclassCurrentUtcDate{publicstaticvoid main(String[] args){Date date =newDate();SimpleDateFormat dateFormat =newSimpleDateFormat("dd-MM-yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));System.out.println("UTC Time is: "+ dateFormat.format(date));}}
Proszę, nie uczcie młodych, jak używać dawno przestarzałych i notorycznie kłopotliwych SimpleDateFormat. Dzisiaj mamy o wiele lepsze java.time, nowoczesne API daty i godziny Java . Co również zapewniasz, czego nie ma jeszcze w odpowiedziach Dana, Antonio i innych?
Ole VV
2
(a) W jaki sposób ta odpowiedź dodaje wartość dziesiątkom istniejących odpowiedzi? (b) Stosowane tu kłopotliwe klasy zostały wyparte lata temu przez współczesne klasy java.time . Sugerowanie ich użycia w 2018 r. To kiepska rada.
Basil Bourque,
0
Użyj pakietu java.time i dołącz poniżej kodu-
ZonedDateTime now = ZonedDateTime.now( ZoneOffset.UTC );
(A) Jeśli używasz offsetu ( ZoneOffset) zamiast strefy czasowej ( ZoneId), OffsetDateTimebardziej odpowiednie jest niż ZonedDateTime. (B) LocalDateTimenie należy używać do uchwycenia bieżącego momentu, ponieważ nie ma on pojęcia strefy czasowej ani przesunięcia względem UTC. (C) Inne istniejące odpowiedzi obejmowały ten materiał i wykonały lepszą pracę. Nie rozumiem, jak ta odpowiedź dodaje wartości.
Date
nie ma strefy czasowej, więc „ale w lokalnej strefie czasowej” jest niepoprawne (lub w najlepszym razie niedokładne). Zobacz wszystko o java.util.Date .Odpowiedzi:
java.util.Date
nie ma określonej strefy czasowej, chociaż o jej wartości najczęściej myśli się w odniesieniu do UTC. Co sprawia, że myślisz, że to czas lokalny?Mówiąc dokładniej: wartość w a
java.util.Date
jest liczbą milisekund od epoki Uniksa, która miała miejsce o północy 1 stycznia 1970 r., UTC. Tę samą epokę można również opisać w innych strefach czasowych, ale tradycyjny opis dotyczy UTC. Ponieważ jest to kilka milisekund od ustalonej epoki, wartość wewnątrzjava.util.Date
jest taka sama na całym świecie w dowolnym momencie, niezależnie od lokalnej strefy czasowej.Podejrzewam, że problem polega na tym, że wyświetlasz go za pomocą instancji Kalendarza, która korzysta z lokalnej strefy czasowej, lub ewentualnie za pomocą,
Date.toString()
która również korzysta z lokalnej strefy czasowej, lubSimpleDateFormat
instancji, która domyślnie korzysta również z lokalnej strefy czasowej.Jeśli to nie jest problem, proszę opublikować przykładowy kod.
Polecam jednak korzystanie z Joda-Time , która oferuje znacznie bardziej przejrzysty interfejs API.
źródło
java.util.Timestamp
(lubjava.util.Date
) strefy czasowe serwera.System.out.println(new Date())
? Jeśli tak, powinieneś mieć świadomość, że jest totoString()
metoda, która stosuje tam strefę czasową ... jeśli to nie to, podaj więcej szczegółów.toString()
zawsze używa domyślnej strefy czasowej.date.getTime()
zdecydowanie zwraca milisekundy od epoki Uniksa, w UTC. Najdokładniej jest powiedzieć, żeDate
sama nie ma żadnej strefy czasowej - to tylko chwila w czasie, którą można rozpatrywać w wielu strefach czasowych. Ale gdy tworzysz instancję, nie zależy ona od Twojej strefy czasowej.tl; dr
Wygeneruj ciąg reprezentujący tę wartość:
Detale
Jak podała poprawna odpowiedź Jona Skeeta , obiekt java.util.Date nie ma strefy czasowej † . Ale jego
toString
implementacja stosuje domyślną strefę czasową maszyny JVM podczas generowania ciągu reprezentującego tę wartość daty i godziny. Mylące dla naiwnego programisty data wydaje się mieć strefę czasową, ale jej nie ma.Te
java.util.Date
,j.u.Calendar
orazjava.text.SimpleDateFormat
zajęcia wiązane z Java są notorycznie kłopotliwe. Unikaj ich. Zamiast tego użyj jednej z tych kompetentnych bibliotek daty i godziny:java.time (Java 8)
Java 8 oferuje doskonały nowy pakiet java.time. *, Który zastępuje stare klasy java.util.Date/Calendar.
Uzyskiwanie aktualnego czasu w UTC / GMT jest prostym linkiem…
Ta
Instant
klasa jest podstawowym elementem składowym java.time, reprezentującym moment na osi czasu w UTC z rozdzielczością nanosekund .W Javie 8 bieżący moment jest rejestrowany z rozdzielczością do milisekund. Java 9 przynosi świeży realizacji ma wśród
Clock
oddaje obecną chwilę w górę do pełnej zdolności nanosekundy tej klasy, w zależności od możliwości sprzętu zegara komputera hosta.Ta
toString
metoda generuje ciąg reprezentujący jego wartość przy użyciu jednego określonego formatu ISO 8601 . Ten format generuje cyfry zero, trzy, sześć lub dziewięć cyfr ( milisekund , mikrosekund lub nanosekund ), jeśli jest to konieczne do przedstawienia ułamka sekundy.Jeśli chcesz bardziej elastycznego formatowania lub innych dodatkowych funkcji, zastosuj przesunięcie względem UTC równe zero, aby sam UTC (
ZoneOffset.UTC
stały ) uzyskał wartośćOffsetDateTime
.Zrzut do konsoli…
Po uruchomieniu…
O java.time
Środowisko java.time jest wbudowane w Javę 8 i nowsze wersje . Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak
java.util.Date
,Calendar
, iSimpleDateFormat
.Aby dowiedzieć się więcej, zobacz samouczek Oracle . I przeszukaj stos przepełnienia dla wielu przykładów i wyjaśnień. Specyfikacja to JSR 310 .
Projekt Joda-Time , teraz 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 potrzeba ciągów, nie ma potrzeby
java.sql.*
klas.Gdzie można uzyskać klasy java.time?
Projekt ThreeTen-Extra rozszerza java.time o dodatkowe klasy. Ten projekt jest poligonem doświadczalnym dla ewentualnych przyszłych dodatków do java.time. Można znaleźć kilka przydatnych klas tutaj takie jak
Interval
,YearWeek
,YearQuarter
, i więcej .Joda-Time
AKTUALIZACJA: Projekt Joda-Time , teraz w trybie konserwacji , zaleca migrację do klas java.time .
Korzystając z darmowej biblioteki open source firmy Joda-Time innej firmy, możesz uzyskać bieżącą datę i godzinę w jednym wierszu kodu.
Joda-Time zainspirował nowe klasy java.time. * W Javie 8, ale ma inną architekturę. Możesz używać Joda-Time w starszych wersjach Javy. Joda-Time nadal działa w Javie 8 i jest aktywnie utrzymywany (od 2014). Jednak zespół Joda-Time zaleca migrację do java.time.
Bardziej szczegółowy przykładowy kod (Joda-Time 2.3)…
Zrzut do konsoli…
Po uruchomieniu…
Aby zobaczyć więcej przykładowego kodu wykonującego pracę w strefie czasowej, zobacz moją odpowiedź na podobne pytanie.
Strefa czasowa
Zalecam, aby zawsze określać strefę czasową, zamiast domyślnie polegać na bieżącej domyślnej strefie czasowej JVM (która może ulec zmianie w dowolnym momencie!). Takie poleganie wydaje się być częstą przyczyną zamieszania i błędów w pracy z datą.
Podczas dzwonienia
now()
należy podać żądaną / oczekiwaną strefę czasową do przypisania. Skorzystaj zDateTimeZone
klasy.Klasa ta utrzymuje stałą dla strefy czasowej UTC .
Jeśli naprawdę chcesz użyć bieżącej domyślnej strefy czasowej maszyny JVM, wykonaj jawne wywołanie, aby kod sam się dokumentował.
ISO 8601
Przeczytaj o formatach ISO 8601 . Zarówno java.time, jak i Joda-Time używają rozsądnych formatów tego standardu jako domyślnych dla parsowania i generowania ciągów.
† Właściwie tak, java.util.Date tak posiada strefę czasową, zakopane głęboko pod warstwami kodu źródłowego. Dla większości praktycznych celów ta strefa czasowa jest ignorowana. Tak więc, jak stenografia, mówimy java.util.Date nie ma strefy czasowej. Co więcej, ta zakopana strefa czasowa nie jest tą, którą stosuje
toString
metoda Date ; ta metoda używa bieżącej domyślnej strefy czasowej maszyny JVM. Tym bardziej należy unikać tej mylącej klasy i trzymać się Joda-Time i java.time.źródło
DateTime.now().toDateTime(DateTimeZone.UTC)
właśnie tego szukałem! Dzięki!DateTime nowUtc = DateTime.now ( DateTimeZone.UTC ) ;
2014-01-21T15:34:29.933-08:00
w przykładzie, którego użyłeśnew org.joda.time.DateTime()
ZonedDateTime.now( ZoneId.of( "America/Los_Angeles" ) ).truncatedTo( ChronoUnit.MILLIS ).toOffsetDateTime().toString()
Otrzymujemy bieżący moment dla określonej strefy czasowej. Następnie odetnij wszelkie mikrosfery / nanosy. Następnie przechodzimy do posiadania jedynie zwykłego przesunięcia względem UTC (liczba godzin-minut-sekund) zamiast pełnej strefy czasowej (historia przeszłych, obecnych i przyszłych zmian w przesunięciu stosowanym przez ludzi konkretny region). Na koniec generujemy tekst reprezentujący wartośćOffsetDateTime
zgodną ze standardowym formatem ISO 8601 używanym domyślnie w tejtoString
metodzie.źródło
To zdecydowanie zwraca czas UTC: jako obiekty String i Date!
źródło
static final String DATEFORMAT = "yyyy-MM-dd HH:mm:ss";
new Date()
powoduje, że funkcja Połączenia nigdy nie zwróci prawidłowego czasu UTC, jeśli czas urządzenia jest nieprawidłowy.źródło
Właściwie nie czas, ale jego reprezentację można zmienić.
Czas jest taki sam w dowolnym punkcie Ziemi, ale nasze postrzeganie czasu może być różne w zależności od lokalizacji.
źródło
Źle!
i
wróci w tym samym czasie. Idem do
źródło
Ten kod drukuje aktualny czas UTC.
Wynik
źródło
Działa to w celu uzyskania milisekund UTC w Androidzie.
źródło
c.add(Calendar.MILLISECOND, (-utcOffset))
uzyskać Kalendarz z strefą czasowąOto, co wydaje się nieprawidłowe w odpowiedzi Jona Skeeta . Powiedział:
Jednak kod:
podaje godziny lokalne, a nie GMT (godziny UTC), bez
Calendar
i wcaleSimpleDateFormat
.Dlatego wydaje się, że coś jest nie tak.
Łącząc odpowiedzi, kod:
pokazuje godziny GMT zamiast godzin lokalnych - zauważ, że
getTime.getHours()
brakuje, ponieważ stworzyłoby toDate()
obiekt, który teoretycznie przechowuje datę w GMT, ale zwraca godziny w lokalnej strefie czasowej.źródło
Date.getHours()
metody, to jest bardzo jasne: „Zwrócona wartość to liczba (od 0 do 23) reprezentująca godzinę w ciągu dnia, który zawiera lub zaczyna się od natychmiastowe w czasie reprezentowane przez ten obiekt Date, zgodnie z interpretacją w lokalnej strefie czasowej . ” (Podkreśl mój.) Jest togetHours()
metoda, która interpretuje wartość w lokalnej strefie czasowej - nie jest to część stanuDate
samego obiektu.toString
igetHours
zastosowanie domyślnej strefy czasowej do ich wyniku. Tak więc naiwni programiści łatwo dają się zwieść, ponieważ wydaje się, że Data ma strefę czasową, ale w rzeczywistości nie.Jeśli chcesz obiekt Date z polami dostosowanymi do UTC, możesz to zrobić w następujący sposób: Joda Time :
źródło
.toDateTime
metodę i przekaż stałą dla strefy czasowej UTC.Możesz użyć:
Następnie wszystkie operacje wykonywane przy użyciu obiektu aGMTCalendar będą wykonywane w strefie czasowej GMT i nie będą miały zastosowania czasu letniego ani stałych przesunięć. Myślę, że poprzedni plakat ma rację, że obiekt Date () zawsze zwraca GMT, dopóki nie zrobisz czegoś z obiektem daty, który zostanie przekonwertowany na lokalną strefę czasową.
źródło
źródło
Możesz bezpośrednio z tego skorzystać
źródło
Z:
Następnie
cal
podaj aktualną datę i godzinę.Możesz również uzyskać bieżącą datę i godzinę dla strefy czasowej, korzystając z:
Możesz zapytać
cal.get(Calendar.DATE);
lub inną stałą kalendarza o inne szczegóły.Data i znacznik czasu są przestarzałe w Javie. Nie jest to klasa kalendarza.
źródło
Oto kolejna sugestia, aby uzyskać obiekt znacznika czasu GMT:
źródło
Oto inny sposób na uzyskanie czasu GMT w formacie String
źródło
Oto moja implementacja toUTC:
Prawdopodobnie istnieje kilka sposobów, aby to poprawić, ale to działa dla mnie.
źródło
Przykładowy kod do renderowania czasu systemowego w określonej strefie czasowej i określonym formacie.
Wynik
źródło
Aby to uprościć, aby utworzyć
Date
wUTC
, możesz użyćCalendar
:Który skonstruuje nową instancję do
Calendar
używania „UTC”TimeZone
.Jeśli potrzebujesz
Date
obiektu z tego kalendarza, możesz go po prostu użyćgetTime()
.źródło
Przeliczanie bieżącej daty i godziny w UTC:
źródło
toString
na DateTime, aby uzyskać ten ciąg znaków ISO 8601 . (b) Zbyt dużo kodu do konwersji między strefami czasowymi. Wystarczy wywołać „toDateTime” i przekazać obiekt strefy czasowej. Tak:myDateTime.toDateTime( DateTimeZone.UTC )
. W przypadku określonej strefy czasowej utwórz i przekaż obiekt strefy czasowej na podstawie prawidłowej nazwy , wywołaniemyDateTime.toDateTime( DateTimeZone.forID( "Asia/Tehran" ) )
.To zadziałało dla mnie, zwraca znacznik czasu w GMT!
źródło
Użyj tej klasy, aby uzyskać właściwy czas UTC z internetowego serwera NTP:
I używaj go z:
Jeśli potrzebujesz czasu UTC „teraz” jako funkcji użycia DateTimeString:
i używaj go z:
źródło
źródło
Mówiąc najprościej. Obiekt kalendarza przechowuje informacje o strefie czasowej, ale po wykonaniu cal.getTime () informacje o strefie czasowej zostaną utracone. Dlatego w przypadku konwersji stref czasowych radzę korzystać z klas DateFormat ...
źródło
to moja realizacja:
źródło
Jeśli chcesz uniknąć analizowania daty i po prostu chcesz mieć znacznik czasu w GMT, możesz użyć:
źródło
Jeśli używasz czasu Joda i chcesz mieć bieżący czas w milisekundach bez lokalnego przesunięcia , możesz użyć tego:
źródło
Wynik:
W razie potrzeby możesz zmienić format daty.
źródło
SimpleDateFormat
. Dzisiaj mamy o wiele lepszejava.time
, nowoczesne API daty i godziny Java . Co również zapewniasz, czego nie ma jeszcze w odpowiedziach Dana, Antonio i innych?Użyj pakietu java.time i dołącz poniżej kodu-
ZonedDateTime now = ZonedDateTime.now( ZoneOffset.UTC );
lub
LocalDateTime now2 = LocalDateTime.now( ZoneOffset.UTC );
w zależności od potrzeb aplikacji.
źródło
ZoneOffset
) zamiast strefy czasowej (ZoneId
),OffsetDateTime
bardziej odpowiednie jest niżZonedDateTime
. (B)LocalDateTime
nie należy używać do uchwycenia bieżącego momentu, ponieważ nie ma on pojęcia strefy czasowej ani przesunięcia względem UTC. (C) Inne istniejące odpowiedzi obejmowały ten materiał i wykonały lepszą pracę. Nie rozumiem, jak ta odpowiedź dodaje wartości.