考虑夏令时,将本地时间转换为UTC时间,反之亦然

时间:2011-05-14 11:15:55

标签: java datetime calendar dst

我知道如何将本地时间转换为UTC时间,反之亦然。 但是,在执行此操作时,我对夏令时(DST)处理非常困惑。

所以任何人都可以回答以下问题:
 1.在时区之间转换时,java内部处理DST吗?  2.在时区之间转换时我需要做些什么?  3.任何能够更清楚地解释这个问题的好文章?

提前致谢。

3 个答案:

答案 0 :(得分:15)

您确定知道如何将日期转换为UTC并返回吗?正确?
我很害怕,我对此表示怀疑。

  1. 您无需转换,只需指定正确的TimeZone。
  2. 您需要什么文章?好的,我正在研究这个问题,但现在让我在这里给出答案。
  3. 首先是第一件事。您的程序应在内部以UTC TimeZone存储日期(或日历)。嗯,实际上在GMT中,因为Java中没有闰秒,但这是另一个故事 您应该需要“转换”的唯一地方是您要向用户显示时间。这也涉及发送电子邮件。在这两种情况下,您都需要 格式 日期才能获得其文字表示。为此,您可以使用DateFormat并指定正确的TimeZone:

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

答案 1 :(得分:8)

这是我找到的最佳解决方案。我在这里复制它,但解决方案来自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");
    }
}

答案 2 :(得分: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);
    }
}