Jak mogę uzyskać aktualną datę i godzinę w UTC lub GMT w Javie?


479

Kiedy tworzę nowy Dateobiekt, jest on inicjowany na bieżący czas, ale w lokalnej strefie czasowej. Jak mogę uzyskać aktualną datę i godzinę w GMT?


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.


5
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:

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…

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 );

Zrzut do konsoli…

System.out.println( "now.toString(): " + now );

Po uruchomieniu…

now.toString(): 2014-01-21T23:42:03.522Z

Tabela typów daty i godziny w Javie, zarówno nowoczesnych, jak i starszych.


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, i SimpleDateFormat.

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?

Tabela, z której biblioteki java.time należy korzystać, w której wersji Java lub Android

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.

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ł.

DateTimeZone zoneDefault = DateTimeZone.getDefault();

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 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.


2
DateTime.now().toDateTime(DateTimeZone.UTC)właśnie tego szukałem! Dzięki!
Managarm

1
@Managarm Możesz to skrócić do: DateTime nowUtc = DateTime.now ( DateTimeZone.UTC ) ;
Basil Bourque,

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 = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));

//Local time zone   
SimpleDateFormat dateFormatLocal = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");

//Time in GMT
return dateFormatLocal.parse( dateFormatGmt.format(new Date()) );

11
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!

static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

public static Date getUTCdatetimeAsDate() {
    // note: doesn't check for null
    return stringDateToDate(getUTCdatetimeAsString());
}

public static String getUTCdatetimeAsString() {
    final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
    final String utcTime = sdf.format(new Date());

    return utcTime;
}

public static Date stringDateToDate(String StrDate) {
    Date dateToReturn = null;
    SimpleDateFormat dateFormat = new SimpleDateFormat(DATEFORMAT);

    try {
        dateToReturn = (Date)dateFormat.parse(StrDate);
    }
    catch (ParseException e) {
        e.printStackTrace();
    }

    return dateToReturn;
}

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.
Brian rozpoczął

65
    Calendar c = Calendar.getInstance();
    System.out.println("current: "+c.getTime());

    TimeZone z = c.getTimeZone();
    int offset = z.getRawOffset();
    if(z.inDaylightTime(new Date())){
        offset = offset + z.getDSTSavings();
    }
    int offsetHrs = offset / 1000 / 60 / 60;
    int offsetMins = offset / 1000 / 60 % 60;

    System.out.println("offset: " + offsetHrs);
    System.out.println("offset: " + offsetMins);

    c.add(Calendar.HOUR_OF_DAY, (-offsetHrs));
    c.add(Calendar.MINUTE, (-offsetMins));

    System.out.println("GMT Time: "+c.getTime());

52

Właściwie nie czas, ale jego reprezentację można zmienić.

SimpleDateFormat f = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
f.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(f.format(new Date()));

Czas jest taki sam w dowolnym punkcie Ziemi, ale nasze postrzeganie czasu może być różne w zależności od lokalizacji.


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ęć

Źle!

Calendar aGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
aGMTCalendar.getTime(); //or getTimeInMillis()

i

Calendar aNotGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT-2"));aNotGMTCalendar.getTime();

wróci w tym samym czasie. Idem do

new Date(); //it's not GMT.

17

Ten kod drukuje aktualny czas UTC.

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;


public class Test
{
    public static void main(final String[] args) throws ParseException
    {
        final SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
        f.setTimeZone(TimeZone.getTimeZone("UTC"));
        System.out.println(f.format(new Date()));
    }
}

Wynik

2013-10-26 14:37:48 UTC

14

Działa to w celu uzyskania milisekund UTC w Androidzie.

Calendar c = Calendar.getInstance();
int utcOffset = c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET);  
Long utcMilliseconds = c.getTimeInMillis() + utcOffset;

7
tylko musisz odjąć przesunięcie?
tevch

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.

Jednak kod:

System.out.println(new java.util.Date().getHours() + " hours");

podaje godziny lokalne, a nie GMT (godziny UTC), bez Calendari wcale SimpleDateFormat.

Dlatego wydaje się, że coś jest nie tak.

Łącząc odpowiedzi, kod:

System.out.println(Calendar.getInstance(TimeZone.getTimeZone("GMT"))
                           .get(Calendar.HOUR_OF_DAY) + " Hours");

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.


6
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 = new Date();
System.out.println("Local: " + local);
DateTimeZone zone = DateTimeZone.getDefault();
long utc = zone.convertLocalToUTC(local.getTime(), false);
System.out.println("UTC: " + new Date(utc));

1
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)
Maciej Miklas

6

Możesz użyć:

Calendar aGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

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ą.


6
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(dateFormatGmt.format(date));

Dodaj wyjaśnienie do swojej odpowiedzi. Czym różni się od tylu innych odpowiedzi?
akjoshi,

czy ta metoda dostaje czas zależy od kalendarza urządzenia?
Arnold Brown

6

Możesz bezpośrednio z tego skorzystać

SimpleDateFormat dateFormatGmt = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(dateFormatGmt.format(new Date())+"");

5

Z:

Calendar cal = Calendar.getInstance();

Następnie calpodaj aktualną datę i godzinę.
Możesz również uzyskać bieżącą datę i godzinę dla strefy czasowej, korzystając z:

Calendar cal2 = Calendar.getInstance(TimeZone.getTimeZone("GMT-2"));

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.


6
Niektóre metody i konstruktory Date i Timestamp są przestarzałe, ale same klasy nie są.
Powerlord,

5

Oto kolejna sugestia, aby uzyskać obiekt znacznika czasu GMT:

import java.sql.Timestamp;
import java.util.Calendar;

...

private static Timestamp getGMT() {
   Calendar cal = Calendar.getInstance();
   return new Timestamp(cal.getTimeInMillis()
                       -cal.get(Calendar.ZONE_OFFSET)
                       -cal.get(Calendar.DST_OFFSET));
}

5

Oto inny sposób na uzyskanie czasu GMT w formacie String

String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss z" ;
final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String dateTimeString =  sdf.format(new Date());

5

Oto moja implementacja toUTC:

    public static Date toUTC(Date date){
    long datems = date.getTime();
    long timezoneoffset = TimeZone.getDefault().getOffset(datems);
    datems -= timezoneoffset;
    return new Date(datems);
}

Prawdopodobnie istnieje kilka sposobów, aby to poprawić, ale to działa dla mnie.


3

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;

public class TimZoneTest {
    public static void 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") );


    }

    public static String 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 = new SimpleDateFormat(format);
        date_format_gmt.setTimeZone(tz);
        return date_format_gmt.format(date);
    }

}

Wynik

10/08/2011 21: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

3

Aby to uprościć, aby utworzyć Datew UTC, możesz użyć Calendar:

Calendar.getInstance(TimeZone.getTimeZone("UTC"));

Który skonstruuje nową instancję do Calendarużywania „UTC” TimeZone.

Jeśli potrzebujesz Dateobiektu z tego kalendarza, możesz go po prostu użyć getTime().


5
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 Zone

DateTime currDateTime = new DateTime(); //Current DateTime

long 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

1
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!

    Date currDate;
    SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
    dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
    SimpleDateFormat dateFormatLocal = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");

    long currTime = 0;
    try {

        currDate = dateFormatLocal.parse( dateFormatGmt.format(new Date()) );
        currTime = currDate.getTime();
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

2

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
{
private static final String TAG = "SntpClient";

private static final int RECEIVE_TIME_OFFSET = 32;
private static final int TRANSMIT_TIME_OFFSET = 40;
private static final int NTP_PACKET_SIZE = 48;

private static final int NTP_PORT = 123;
private static final int NTP_MODE_CLIENT = 3;
private static final int NTP_VERSION = 3;

// Number of seconds between Jan 1, 1900 and Jan 1, 1970
// 70 years plus 17 leap days
private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;

private long mNtpTime;

public boolean requestTime(String host, int timeout) {
    try {
        DatagramSocket socket = new DatagramSocket();
        socket.setSoTimeout(timeout);
        InetAddress address = InetAddress.getByName(host);
        byte[] buffer = new byte[NTP_PACKET_SIZE];
        DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT);

        buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);

        writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET);

        socket.send(request);

        // read the response
        DatagramPacket response = new DatagramPacket(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);
        return false;
    }

    return true;
}


public long getNtpTime() {
    return mNtpTime;
}


/**
 * Reads an unsigned 32 bit big endian number from the given offset in the buffer.
 */
private long 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 values
    int 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).
 */    
private long 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
 */    
private void 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:

private String get_UTC_Datetime_from_timestamp(long timeStamp){

    try{

        Calendar cal = Calendar.getInstance();
        TimeZone tz = cal.getTimeZone();

        int tzt = tz.getOffset(System.currentTimeMillis());

        timeStamp -= tzt;

        // DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.getDefault());
        DateFormat sdf = new SimpleDateFormat();
        Date netDate = (new Date(timeStamp));
        return sdf.format(netDate);
    }
    catch(Exception ex){
        return "";
     }
    } 

i używaj go z:

String UTC_DateTime = get_UTC_Datetime_from_timestamp(now);

W jednym wierszu <br/> <pre> <code> Calendar utcTime = Calendar.getInstance (). Add (Calendar.MILLISECOND, -time.getTimeZone (). GetOffset (time.getTimeInMillis ())); </pre> < / code>
Harun

1
Tak, ale wywołuje to lokalny czas urządzenia, który może zostać zmieniony ręcznie z użytkownika na fałszywy parametr Data i godzina
Ingo,

2
public static void main(String args[]){
    LocalDate date=LocalDate.now();  
    System.out.println("Current date = "+date);
}

1

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 ...


1

to moja realizacja:

public static String GetCurrentTimeStamp()
{
    Calendar cal=Calendar.getInstance();
    long offset = cal.getTimeZone().getOffset(System.currentTimeMillis());//if you want in UTC else remove it .
    return new java.sql.Timestamp(System.currentTimeMillis()+offset).toString();    
}

1

Jeśli chcesz uniknąć analizowania daty i po prostu chcesz mieć znacznik czasu w GMT, możesz użyć:

final Date gmt = new Timestamp(System.currentTimeMillis()
            - Calendar.getInstance().getTimeZone()
                    .getOffset(System.currentTimeMillis()));

0

Jeśli używasz czasu Joda i chcesz mieć bieżący czas w milisekundach bez lokalnego przesunięcia , możesz użyć tego:

long instant = DateTimeZone.UTC.getMillisKeepLocal(DateTimeZone.getDefault(), System.currentTimeMillis());

0
public class CurrentUtcDate 
{
    public static void main(String[] args) {
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
        dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
        System.out.println("UTC Time is: " + dateFormat.format(date));
    }
}

Wynik:

UTC Time is: 22-01-2018 13:14:35

W razie potrzeby możesz zmienić format daty.


1
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 );

lub

LocalDateTime now2 = LocalDateTime.now( ZoneOffset.UTC );

w zależności od potrzeb aplikacji.


(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.
Basil Bourque,
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.