25

,以顯示可再現的情況下不工作,我做了以下的Java轉換GMT/UTC到當地時間預期

  1. 獲取當前系統時間(本地時間)

  2. 將當地時間轉換爲UTC //工作成功直到此處

  3. 將UTC時間反​​轉回當地時間。遵循3種不同的方法(下面列出),但所有3種方法僅保留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()); 
    

    }

回答

51

我還建議使用喬達如前所述。

解決在使用標準的Java您的問題Date對象只可以做如下:

// **** 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()); 

輸出:

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

一個很好的答案!但是,應該有TimeZone.getDefault()。getOffset(gmtTime.getTimeInMillis()))而不是TimeZone.getDefault()。getOffset(localTime.getTime())。否則,如果您的UTC時間爲冬季,但夏令時爲夏令時,則可能會遇到DaylightSaving的問題。 – Dime

+3

'新的日期(字符串字符串)'已棄用:( –

+0

你是一個救生員T_T這是唯一的方法來解決衝突java.util.date(@temporal)和timestamp(postgresql)的GMT與UTC – Sarief

1

我強烈建議使用約達時間http://joda-time.sourceforge.net/faq.html

+0

你能否提供一個使用#joda實現相同的例子? –

+0

我不介意使用joda,但想了解爲什麼代碼沒有按預期運行。 –

5

通常情況下,我們認爲這是壞的形式通過StackOverflow.com建議的替代回答具體問題技術。但是對於與Java 7及更早版本捆綁的日期,時間和日曆類,這些類在設計和執行方面都非常糟糕,以至於我不得不建議使用第三方庫:Joda-Time

Joda-Time的作品創建immutable objects。因此,我們只是實例化一個具有不同時區的新日期時間,而不是更改DateTime對象的時區。

在Joda-Time中,使用本地和UTC時間的中心問題非常簡單,僅需3行代碼。當北美西海岸運行可能是

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

輸出:

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

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

下面是幾個例子和進一步的評論一類。使用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

你有一個已知的時區(這裏Europe/Madrid)的日期,和目標時區(UTC

你只需要兩個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()); 

所以以後看到它的工作,你可以將這個方法添加到您的utils的:

 
    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

我加入了合唱團,建議您跳過現在早已過時的類DateCalendarSimpleDateFormat和朋友。特別是我會警告不要使用Date類的不推薦使用的方法和構造函數,例如您使用的Date(String)構造函數。他們被棄用,因爲它們不能跨時區可靠地工作,所以不要使用它們。是的,該類的大多數構造函數和方法都被棄用。

當你問這個問題的時候,Joda-Time是(我所知道的)一個明顯更好的選擇,時間又一次移動了。今天,Joda-Time是一個基本完成的項目,開發人員建議您使用java.time,即現代Java日期和時間API。我會告訴你如何。

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

對於初學者,請注意,不僅是代碼只長及你的一半,也更加清晰易讀。

在我的電腦代碼打印:

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] 

我從時代冷落的毫秒。您可以隨時從System.currentTimeMillis();中獲取它們,並且它們與時區無關,所以我沒有在這裏找到它們。

我猶豫地保留了你的變量名稱localTime。我認爲這是個好名字。現代的API有一個名爲LocalTime的類,所以使用該名稱,只有大寫,沒有類型LocalTime的對象可能會混淆一些(一個LocalTime不包含時區信息,我們需要保留在這裏能夠進行正確的轉換;它也只能保持時間,而不是日期)。

你從本地時間到UTC是不正確的,也是不可能的轉換

過時Date類不持有任何時區信息(你可能會說,在內部它總是使用UTC),所以沒有這樣的將Date從一個時區轉換爲另一個時區。當我剛跑我的電腦,它打印的第一行代碼,是:

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是正確的,當然。正確的UTC時間應該是05:25:45 UTC,但它又說CEST,這是不正確的。

現在你再也不需要Date這個類了:-)但是如果你打算去的話,Jon Skeet的編碼博客上的必讀內容是All about java.util.Date

問題:我可以在我的Java版本中使用現代API嗎?

如果至少使用Java ,您可以。