25

erwartet, um funktioniert ein reproduzierbares Szenario zu zeigen, ich tue das folgendeJava Konvertieren GMT/UTC zu Ortszeit nicht als

  1. die aktuelle Systemzeit (Ortszeit) Holen

  2. Ortszeit in UTC umrechnen // Works Fine Bis hier

  3. Die UTC-Zeit umkehren, zurück zur Ortszeit. Es folgten 3 verschiedene Ansätze (siehe unten), aber alle 3 Ansätze behalten die Zeit nur in UTC.

    {

    long ts = System.currentTimeMillis(); 
    Date localTime = new Date(ts); 
    String format = "yyyy/MM/dd HH:mm:ss"; 
    SimpleDateFormat sdf = new SimpleDateFormat (format); 
    
    // Convert Local Time to UTC (Works Fine) 
    sdf.setTimeZone(TimeZone.getTimeZone("UTC")); 
    Date gmtTime = new Date(sdf.format(localTime)); 
    System.out.println("Local:" + localTime.toString() + "," + localTime.getTime() + " --> UTC time:" + gmtTime.toString() + "-" + gmtTime.getTime()); 
    
    // Reverse Convert UTC Time to Locale time (Doesn't work) Approach 1 
    sdf.setTimeZone(TimeZone.getDefault());   
    localTime = new Date(sdf.format(gmtTime)); 
    System.out.println("Local:" + localTime.toString() + "," + localTime.getTime() + " --> UTC time:" + gmtTime.toString() + "-" + gmtTime.getTime()); 
    
    // Reverse Convert UTC Time to Locale time (Doesn't work) Approach 2 using DateFormat 
    DateFormat df = new SimpleDateFormat (format); 
    df.setTimeZone(TimeZone.getDefault()); 
    localTime = df.parse((df.format(gmtTime))); 
    System.out.println("Local:" + localTime.toString() + "," + localTime.getTime() + " --> UTC time:" + gmtTime.toString() + "-" + gmtTime.getTime()); 
    
    // Approach 3 
    Calendar c = new GregorianCalendar(TimeZone.getDefault()); 
    c.setTimeInMillis(gmtTime.getTime()); 
    System.out.println("Local Time " + c.toString()); 
    

    }

Antwort

51

Ich empfehle auch Joda vor wie erwähnt werden.

Lösung Ihres Problems unter Verwendung von Standard JavaDate Objekte können nur wie folgt erfolgen:

// **** YOUR CODE **** BEGIN **** 
    long ts = System.currentTimeMillis(); 
    Date localTime = new Date(ts); 
    String format = "yyyy/MM/dd HH:mm:ss"; 
    SimpleDateFormat sdf = new SimpleDateFormat(format); 

    // Convert Local Time to UTC (Works Fine) 
    sdf.setTimeZone(TimeZone.getTimeZone("UTC")); 
    Date gmtTime = new Date(sdf.format(localTime)); 
    System.out.println("Local:" + localTime.toString() + "," + localTime.getTime() + " --> UTC time:" 
      + gmtTime.toString() + "," + gmtTime.getTime()); 

    // **** YOUR CODE **** END **** 

    // Convert UTC to Local Time 
    Date fromGmt = new Date(gmtTime.getTime() + TimeZone.getDefault().getOffset(localTime.getTime())); 
    System.out.println("UTC time:" + gmtTime.toString() + "," + gmtTime.getTime() + " --> Local:" 
      + fromGmt.toString() + "-" + fromGmt.getTime()); 

Ausgang:

Local:Tue Oct 15 12:19:40 CEST 2013,1381832380522 --> UTC time:Tue Oct 15 10:19:40 CEST 2013,1381825180000 
UTC time:Tue Oct 15 10:19:40 CEST 2013,1381825180000 --> Local:Tue Oct 15 12:19:40 CEST 2013-1381832380000 
+3

Eine gute Antwort! Jedoch sollte statt TimeZone.getDefault(). GetOffset (localTime.getTime()) TimeZone.getDefault() sein. GetOffset (gmtTime.getTimeInMillis()). Andernfalls können Sie Probleme mit DaylightSaving haben, wenn Ihre UTC-Zeit im Winter ist, die Ortszeit jedoch im Sommer ist. – Dime

+3

'neues Datum (Zeichenkette)' veraltet :( –

+0

du bist ein Lebensretter T_T das ist die einzige Möglichkeit, den Konflikt von java.util.date (@temporal) und Zeitstempel (postgresql) von GMT vs UTC zu lösen – Sarief

1

ich stark Joda Zeit mit empfehlen http://joda-time.sourceforge.net/faq.html

+0

Können Sie ein Beispiel angeben, um dasselbe mit #joda zu erreichen? –

+0

Es macht mir nichts aus, joda zu benutzen, würde aber gerne verstehen, warum sich der Code nicht wie erwartet verhält. –

5

Normalerweise halten wir es für schlechte Form auf StackOverflow.com eine bestimmte Frage zu beantworten, indem ein alternatives was darauf hindeutet, Technologie. Aber im Fall der Datums-, Zeit- und Kalenderklassen, die mit Java 7 und früher gebündelt sind, sind diese Klassen sowohl im Design als auch in der Ausführung so notorisch schlecht, dass ich stattdessen die Verwendung einer 3rd-Party-Bibliothek vorschlagen muss: Joda-Time.

Joda-Time funktioniert durch Erstellen immutable objects. Anstatt also die Zeitzone eines DateTime-Objekts zu ändern, instanziieren wir einfach eine neue DateTime mit einer anderen zugewiesenen Zeitzone.

Ihr zentrales Anliegen, sowohl lokale als auch UTC-Zeit zu verwenden, ist in Joda-Time so einfach und benötigt nur 3 Codezeilen.

org.joda.time.DateTime now = new org.joda.time.DateTime(); 
    System.out.println("Local time in ISO 8601 format: " + now + " in zone: " + now.getZone()); 
    System.out.println("UTC (Zulu) time zone: " + now.toDateTime(org.joda.time.DateTimeZone.UTC)); 

Ausgang schaltet, wenn an der Westküste von Nordamerika laufen könnte:

Local time in ISO 8601 format: 2013-10-15T02:45:30.801-07:00

UTC (Zulu) time zone: 2013-10-15T09:45:30.801Z

Hier ist eine Klasse mit mehreren Beispielen und weitere Kommentare. Verwenden von Joda-Time 2.5.

/** 
* Created by Basil Bourque on 2013-10-15. 
* © Basil Bourque 2013 
* This source code may be used freely forever by anyone taking full responsibility for doing so. 
*/ 
public class TimeExample { 
    public static void main(String[] args) { 
     // Joda-Time - The popular alternative to Sun/Oracle's notoriously bad date, time, and calendar classes bundled with Java 8 and earlier. 
     // http://www.joda.org/joda-time/ 

     // Joda-Time will become outmoded by the JSR 310 Date and Time API introduced in Java 8. 
     // JSR 310 was inspired by Joda-Time but is not directly based on it. 
     // http://jcp.org/en/jsr/detail?id=310 

     // By default, Joda-Time produces strings in the standard ISO 8601 format. 
     // https://en.wikipedia.org/wiki/ISO_8601 
     // You may output to strings in other formats. 

     // Capture one moment in time, to be used in all the examples to follow. 
     org.joda.time.DateTime now = new org.joda.time.DateTime(); 

     System.out.println("Local time in ISO 8601 format: " + now + " in zone: " + now.getZone()); 
     System.out.println("UTC (Zulu) time zone: " + now.toDateTime(org.joda.time.DateTimeZone.UTC)); 

     // You may specify a time zone in either of two ways: 
     // • Using identifiers bundled with Joda-Time 
     // • Using identifiers bundled with Java via its TimeZone class 

     // ----| Joda-Time Zones |--------------------------------- 

     // Time zone identifiers defined by Joda-Time… 
     System.out.println("Time zones defined in Joda-Time : " + java.util.Arrays.toString(org.joda.time.DateTimeZone.getAvailableIDs().toArray())); 

     // Specify a time zone using DateTimeZone objects from Joda-Time. 
     // http://joda-time.sourceforge.net/apidocs/org/joda/time/DateTimeZone.html 
     org.joda.time.DateTimeZone parisDateTimeZone = org.joda.time.DateTimeZone.forID("Europe/Paris"); 
     System.out.println("Paris France (Joda-Time zone): " + now.toDateTime(parisDateTimeZone)); 

     // ----| Java Zones |--------------------------------- 

     // Time zone identifiers defined by Java… 
     System.out.println("Time zones defined within Java : " + java.util.Arrays.toString(java.util.TimeZone.getAvailableIDs())); 

     // Specify a time zone using TimeZone objects built into Java. 
     // http://docs.oracle.com/javase/8/docs/api/java/util/TimeZone.html 
     java.util.TimeZone parisTimeZone = java.util.TimeZone.getTimeZone("Europe/Paris"); 
     System.out.println("Paris France (Java zone): " + now.toDateTime(org.joda.time.DateTimeZone.forTimeZone(parisTimeZone))); 

    } 
} 
1

Sie haben mit einer bekannten Zeitzone (hier Europe/Madrid), ein Datum und eine Zielzeitzone (UTC)

Sie brauchen nur zwei SimpleDateFormats:

 
     long ts = System.currentTimeMillis(); 
     Date localTime = new Date(ts); 

     SimpleDateFormat sdfLocal = new SimpleDateFormat ("yyyy/MM/dd HH:mm:ss"); 
     sdfLocal.setTimeZone(TimeZone.getTimeZone("Europe/Madrid")); 

     SimpleDateFormat sdfUTC = new SimpleDateFormat ("yyyy/MM/dd HH:mm:ss"); 
     sdfUTC.setTimeZone(TimeZone.getTimeZone("UTC")); 

     // Convert Local Time to UTC 
     Date utcTime = sdfLocal.parse(sdfUTC.format(localTime)); 
     System.out.println("Local:" + localTime.toString() + "," + localTime.getTime() + " --> UTC time:" + utcTime.toString() + "-" + utcTime.getTime()); 

     // Reverse Convert UTC Time to Locale time 
     localTime = sdfUTC.parse(sdfLocal.format(utcTime)); 
     System.out.println("UTC:" + utcTime.toString() + "," + utcTime.getTime() + " --> Local time:" + localTime.toString() + "-" + localTime.getTime()); 

es also nach der Arbeit sehen Sie diese Methode, um Ihre utils hinzufügen:

 
    public Date convertDate(Date dateFrom, String fromTimeZone, String toTimeZone) throws ParseException { 
     String pattern = "yyyy/MM/dd HH:mm:ss"; 
     SimpleDateFormat sdfFrom = new SimpleDateFormat (pattern); 
     sdfFrom.setTimeZone(TimeZone.getTimeZone(fromTimeZone)); 

     SimpleDateFormat sdfTo = new SimpleDateFormat (pattern); 
     sdfTo.setTimeZone(TimeZone.getTimeZone(toTimeZone)); 

     Date dateTo = sdfFrom.parse(sdfTo.format(dateFrom)); 
     return dateTo; 
    } 
2

Ich trete empfehlen Chor, dass Sie die jetzt lange veraltete Klassen Date, Calendar, überspringen SimpleDateFormat und Freunde. Insbesondere würde ich davor warnen, die veralteten Methoden und Konstruktoren der Klasse Date wie den von Ihnen verwendeten Konstruktor Date(String) zu verwenden. Sie wurden missbilligt, da sie nicht zuverlässig über Zeitzonen hinweg funktionieren. Verwenden Sie sie daher nicht. Und ja, die meisten Konstruktoren und Methoden dieser Klasse sind veraltet.

Während Sie die Frage gestellt haben, war Joda-Time (von allem was ich weiß) eine deutlich bessere Alternative, die Zeit hat sich wieder verschoben. Heute ist Joda-Time ein weitgehend abgeschlossenes Projekt, und seine Entwickler empfehlen stattdessen die Verwendung der modernen Java-API für Datum und Uhrzeit, java.time. Ich werde dir zeigen, wie.

ZonedDateTime localTime = ZonedDateTime.now(ZoneId.systemDefault()); 

    // Convert Local Time to UTC 
    OffsetDateTime gmtTime 
      = localTime.toOffsetDateTime().withOffsetSameInstant(ZoneOffset.UTC); 
    System.out.println("Local:" + localTime.toString() 
      + " --> UTC time:" + gmtTime.toString()); 

    // Reverse Convert UTC Time to Local time 
    localTime = gmtTime.atZoneSameInstant(ZoneId.systemDefault()); 
    System.out.println("Local Time " + localTime.toString()); 

Für den Anfang, beachten Sie, dass nicht nur der Code ist nur halb so lang wie bei Ihnen, es habe auch gelesen, klarer zu.

Auf meinem Computer der Code druckt:

Local:2017-09-02T07:25:46.211+02:00[Europe/Berlin] --> UTC time:2017-09-02T05:25:46.211Z 
Local Time 2017-09-02T07:25:46.211+02:00[Europe/Berlin] 

verließ ich die Millisekunden seit Beginn der Epoche aus. Sie können sie immer von System.currentTimeMillis(); wie in Ihrer Frage erhalten, und sie sind unabhängig von der Zeitzone, so dass ich sie hier nicht interessant fand.

Ich zögerte zögernd Ihren Variablennamen localTime. Ich denke, es ist ein guter Name. Die moderne API hat eine Klasse namens LocalTime, daher kann die Verwendung dieses Namens, der nur nicht großgeschrieben wird, für ein Objekt, das nicht den Typ LocalTime hat, einige verwirren (ein LocalTime enthält keine Zeitzoneninformationen, die wir hier behalten müssen) in der Lage, die richtige Umwandlung zu machen, es hält auch nur die Uhrzeit, nicht das Datum).

Ihre Konvertierung von Ortszeit in UTC falsch und unmöglich war

Die veraltete Date Klasse keine Zeitzoneninformationen nicht halten (man kann sagen, dass es intern UTC verwendet immer), so gibt es keine solche Ding wie ein Date von einer Zeitzone in eine andere umwandeln. Wenn ich den Code auf meinem Computer gerade lief, die erste Zeile es gedruckt war:

Local:Sat Sep 02 07:25:45 CEST 2017,1504329945967 --> UTC time:Sat Sep 02 05:25:45 CEST 2017-1504322745000 

07:25:45 CEST korrekt ist, natürlich.Die korrekte UTC-Zeit wäre gewesen, aber es heißt wieder CEST, was falsch ist.

Jetzt brauchen Sie nie wieder die Date Klasse, aber wenn Sie jemals gehen würden, wäre das Lesen All about java.util.Date auf Jon Skeet Coding Blog.

Frage: Kann ich die moderne API mit meiner Java-Version verwenden?

Wenn Sie mindestens Java verwenden, können Sie.

  • In Java 8 und höher ist die neue API integriert.
  • In Java 6 und 7 erhalten the ThreeTen Backport, die Backport der neuen Klassen (das ist ThreeTen für JSR-310, wo die moderne API zuerst definiert wurde).
  • Verwenden Sie auf Android die Android-Edition von ThreeTen Backport. Es heißt ThreeTenABP, und ich denke, dass es eine wunderbare Erklärung in this question: How to use ThreeTenABP in Android Project gibt.