2011-05-14 55 views
9

我知道如何將本地時間轉換爲UTC時間,反之亦然。 但我在做這件事的時候非常困惑夏令時(DST)的處理。考慮夏時制時間將本地時間轉換爲UTC時間或反之亦然

所以任何人都可以回答下面的問題:
1.當在時區之間轉換時,java是否內部處理DST?
2.在時區之間轉換時我需要做什麼?
3.什麼好的文章更清楚地解釋這一點?

在此先感謝。

+0

要時區之間進行轉換時,需要指定時區你有你想要的時區轉換。日期使用UTC,所以getDate()方法將是UTC。夏令時的時區將處理夏令時。 – 2011-05-14 11:29:51

+0

我正在使用日曆對象。另外,我的問題是,我必須在做轉換時處理與DST相關的任何事情嗎? – Newbie 2011-05-14 11:50:20

回答

15

您確定您知道如何將日期轉換爲UTC並返回?正確?
恐怕我懷疑。

  1. 是的。
  2. 你不需要轉換,你只需要分配正確的TimeZone。
  3. 您需要什麼文章?好的,我正在研究這個問題,但現在讓我在這裏回答一個問題。

首先是第一件事。您的程序應在內部以UTC時區存儲日期(或日曆)。那麼,事實上在格林尼治標準時間,因爲在Java中沒有閏秒,但這是另一回事。
當你需要「轉換」時,唯一的地方是當你要顯示給用戶的時間。這也涉及發送電子郵件。在這兩種情況下,您需要格式日期以獲取其文本表示形式。爲了您將使用DateFormat並指定正確的時區:

// that's for desktop application 
    // for web application one needs to detect Locale 
    Locale locale = Locale.getDefault(); 
    // again, this one works for desktop application 
    // for web application it is more complicated 
    TimeZone currentTimeZone = TimeZone.getDefault(); 
    // in fact I could skip this line and get just DateTime instance, 
    // but I wanted to show how to do that correctly for 
    // any time zone and locale 
    DateFormat formatter = DateFormat.getDateTimeInstance(
      DateFormat.DEFAULT, 
      DateFormat.DEFAULT, 
      locale); 
    formatter.setTimeZone(currentTimeZone); 

    // Dates "conversion" 
    Date currentDate = new Date(); 
    long sixMonths = 180L * 24 * 3600 * 1000; 
    Date inSixMonths = new Date(currentDate.getTime() + sixMonths); 

    System.out.println(formatter.format(currentDate)); 
    System.out.println(formatter.format(inSixMonths)); 
    // for me it prints 
    // 2011-05-14 16:11:29 
    // 2011-11-10 15:11:29 

    // now for "UTC" 
    formatter.setTimeZone(TimeZone.getTimeZone("UTC")); 
    System.out.println(formatter.format(currentDate)); 
    System.out.println(formatter.format(inSixMonths)); 
    // 2011-05-14 14:13:50 
    // 2011-11-10 14:13:50 

正如你所看到的,Java的關心處理DST。你當然可以手動處理它,只需閱讀TimeZone related JavaDoc

+0

「六個月內」應該是「六個月左右」,但這並不重要。小時部分是重要的。 – 2011-05-14 14:20:56

7

這是我找到的最佳解決方案。我在這裏複製它,但解決方案來自http://biese.wordpress.com/2014/02/28/the-easy-way-to-convert-local-time-to-utc-time/

package com.test.timezone; 

import java.util.TimeZone; 

public final class Utility { 
    public static final TimeZone utcTZ = TimeZone.getTimeZone("UTC"); 

    public static long toLocalTime(long time, TimeZone to) { 
     return convertTime(time, utcTZ, to); 
    } 

    public static long toUTC(long time, TimeZone from) { 
     return convertTime(time, from, utcTZ); 
    } 

    public static long convertTime(long time, TimeZone from, TimeZone to) { 
     return time + getTimeZoneOffset(time, from, to); 
    } 

    private static long getTimeZoneOffset(long time, TimeZone from, TimeZone to) { 
     int fromOffset = from.getOffset(time); 
     int toOffset = to.getOffset(time); 
     int diff = 0; 

     if (fromOffset >= 0){ 
      if (toOffset > 0){ 
       toOffset = -1*toOffset; 
      } else { 
       toOffset = Math.abs(toOffset); 
      } 
      diff = (fromOffset+toOffset)*-1; 
     } else { 
      if (toOffset <= 0){ 
       toOffset = -1*Math.abs(toOffset); 
      } 
      diff = (Math.abs(fromOffset)+toOffset); 
     } 
     return diff; 
    } 
} 

package com.test.timezone; 

import java.text.SimpleDateFormat; 
import java.util.Calendar; 
import java.util.GregorianCalendar; 
import java.util.TimeZone; 

public class TestTimezone { 

    public static void main(String[] args) { 
     SimpleDateFormat sdf = new SimpleDateFormat("yyyy MMM dd HH:mm:ss zzzz"); 
     Calendar date1 = new GregorianCalendar(2014,0,15,10,0,0); 
     System.out.println(sdf.format(date1.getTime())+"\n"); 
     long utcTimeStamp = Utility.toUTC(date1.getTimeInMillis(), date1.getTimeZone()); 
     Calendar utcCal = Calendar.getInstance(); 
     utcCal.setTimeInMillis(utcTimeStamp); 
     System.out.println("toUTC: "+sdf.format(utcCal.getTime())+"\n"); 

     System.out.println("---------------------------------------"); 
     Calendar date2 = new GregorianCalendar(2014,2,15,10,0,0); 
     System.out.println(sdf.format(date2.getTime())+"\n"); 
     utcTimeStamp = Utility.toUTC(date2.getTimeInMillis(), date2.getTimeZone()); 
     utcCal.setTimeInMillis(utcTimeStamp); 
     System.out.println("toUTC: "+sdf.format(utcCal.getTime())+"\n"); 

     System.out.println("---------------------------------------"); 
     Calendar date3 = new GregorianCalendar(2014,11,25,9,0,0); 
     System.out.println(sdf.format(date3.getTime())+"\n"); 
     long uTime = Utility.toUTC(date3.getTimeInMillis(), date3.getTimeZone()); 
     System.out.println("utcTimeStamp: "+uTime+"\n"); 
     long lTime = Utility.toLocalTime(uTime, TimeZone.getTimeZone("EST")); 
     Calendar locCal = Calendar.getInstance(); 
     locCal.setTimeInMillis(lTime); 
     System.out.println("toLocal: "+sdf.format(locCal.getTime())+"\n"); 

     System.out.println("---------------------------------------"); 
     Calendar date4 = new GregorianCalendar(2014,6,4,9,0,0); 
     System.out.println(sdf.format(date4.getTime())+"\n"); 
     uTime = Utility.toUTC(date4.getTimeInMillis(), date4.getTimeZone()); 
     System.out.println("utcTimeStamp: "+uTime+"\n"); 
     lTime = Utility.toLocalTime(uTime, TimeZone.getTimeZone("EST")); 
     locCal = Calendar.getInstance(); 
     locCal.setTimeInMillis(lTime); 
     System.out.println("toLocal: "+sdf.format(locCal.getTime())+"\n"); 
    } 
} 
+0

由於您將時間基準(Unix Epoch)轉換爲本地化存儲時間,因此這是不好的做法。日期實際上處理這些「轉換」實際上代表你。如果您使用您描述的方法並將時間用作= in = new Date(time)中的日期,則Date對象將假定時間爲GMT,並且該對象被錯誤地實例化。這些函數的唯一有效用途是將時間從外部系統轉換爲不在GMT時間戳中操作的外部系統,因此不符合UNIX時間戳約定。 – 2016-11-09 12:42:25

4

在TALE的答案的代碼可以簡化爲:

public final class Utility { 
    public static long toLocalTime(long time, TimeZone to) { 
     return time + to.getOffset(time); 
    } 

    public static long toUTC(long time, TimeZone from) { 
     return time - from.getOffset(time); 
    } 
} 
相關問題