1小时时差夏令时问题

Posted

技术标签:

【中文标题】1小时时差夏令时问题【英文标题】:1 hour time difference daylight saving time issue 【发布时间】:2018-10-01 22:05:47 【问题描述】:

将服务器日期转换为设备本地时间的功能:

public static String convertIntoLocalTime(String strTime, String whichTimeZone, String dateFormat) 
    String strLocalTime = null;
    try 
        SimpleDateFormat sdf = getSimpleDateFormat(dateFormat, whichTimeZone);
        Date date = sdf.parse(strTime);

        AppLog.e(TAG,"Timezone = " + whichTimeZone);
        AppLog.e(TAG,"Date = " + strTime);
        AppLog.e(TAG,"Date in CET = " + date.toString());
        AppLog.e(TAG,"inDaylightTime = " + sdf.getTimeZone().inDaylightTime(date));
        AppLog.e(TAG,"DST savings = " + sdf.getTimeZone().getDSTSavings());

        if (sdf.getTimeZone().getDSTSavings() == 3600000) 
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            cal.add(Calendar.HOUR, 1);
            Date oneHourBack = cal.getTime();

            SimpleDateFormat local = getLocalSimpleDateFormat(dateFormat);
            strLocalTime = local.format(oneHourBack);
         else 
            SimpleDateFormat local = getLocalSimpleDateFormat(dateFormat);
            strLocalTime = local.format(date);
        
     catch (ParseException e) 
        AppLog.e(TAG, e.getMessage(), e);
    

    AppLog.e(TAG,"Local Time = " + strLocalTime);
    return strLocalTime;

获取简单日期格式的函数:

private static SimpleDateFormat getSimpleDateFormat(String format, String tz) 
        TimeZone timeZone = TimeZone.getTimeZone(tz);
        timeZone.useDaylightTime();

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format, Locale.getDefault());
        simpleDateFormat.setTimeZone(timeZone);
        return simpleDateFormat;
    

获取本地设备转换的简单日期格式的功能:

/**
     * @param format
     * @return
     */
    private static SimpleDateFormat getLocalSimpleDateFormat(String format) 
        TimeZone timeZone = TimeZone.getDefault();
        timeZone.useDaylightTime();

        SimpleDateFormat localSdf = new SimpleDateFormat(format, Locale.getDefault());
        localSdf.setTimeZone(timeZone);
        return localSdf;
    

输出:

日期 = 2018-04-22 14:30

CET 日期 = 2018 年 4 月 22 日星期日 13:30:00 GMT+01:00 2018

inDaylightTime = true

DST 节省 = 3600000

当地时间 = 2018-04-22 14:30

上面的代码之前运行得非常好,例如,我们在 4 月 1 日有 1 个事件正确显示时间,但从 4 月 21 日开始,它显示了额外的 1 小时时间。

我尝试使用 UTC 和 CET 转换来自服务器的日期,但在这两种情况下,当将其转换为设备本地时间时,它都会显示额外的一小时。

以上示例基于伦敦时区,而当我们在 IST 时区尝试时,它返回了正确的时间。

我们通过检查时区的inDaylightTime 函数处理了不同的 DST 时间,但它不起作用。

我确信有些东西与 DST 相关,但我无法弄清楚。感谢您的帮助?

【问题讨论】:

欢迎来到 SO。请查看此处了解如何改进您的问题(格式化、校对、提供代码等):***.com/help/how-to-ask 好的。谢谢会检查。 @JahanviKariya 我认为你需要使用github.com/dlew/joda-time-android 因为android Calendar 有一些错误 @VishalThakkar 这很奇怪,您对这些错误有任何了解吗?我的意思是任何参考链接来验证这一点,因为我在 ios Swift 3 上也遇到了同样的问题。 @JahanviKariya ***.com/questions/44346152/… 【参考方案1】:

首先,您使用的是旧的和过时的日期和时间类:SimpleDateFormatDateCalendarTimeZone。这些以设计不佳而闻名,有时使用起来很麻烦。我的第一个建议是您使用现代 Java 日期和时间 API java.time 重写您的代码。它的错误要少得多,我希望您能更轻松地开发出正确的代码。

也就是说,无论您使用老式课程还是现代课程,都不要自己处理暑期课程。图书馆课程将为您完成。你的工作是让时区正确。不要增加或减少一个小时来补偿夏季时间。看看其他关于从一个时区转换到另一个时区的问题,有很多。

不要使用三个和四个字母的时区缩写。 CET 不是时区。 IST 是模棱两可的,它可能表示爱尔兰夏令时间、以色列标准时间或印度标准时间。冬季使用 CET 的欧洲国家自 2018 年 3 月 26 日起使用 CEST(中欧夏令时)。

如果这是服务器时区,请将服务器时区指定为 continent/city,例如 Europe/London。这是明确的。

还要确保将您的设备时区设置为真实时区。似乎您已将其设置为 GMT+01:00,这是 GMT 偏移量,而不是时区。它与欧洲/伦敦时区和冬季的 CET 一致,但不是在 3 月 26 日之后。

最后,您将 添加 1 小时到您的 Calendar,将其向前 1 小时,然后调用您从它获得的 Date oneHourBack。这看起来不对。你的意思是减去 1 小时,还是说变量应该是 oneHourForward

编辑:我可能不知道哪些时区对您来说是正确的,因此不知道什么是您的代码的正确输出。因此,仅将以下内容作为您尝试完成的猜测。请填写正确的时区。

public static String convertIntoLocalTime(
        String strTime, String serverTimeZone, String dateFormat) 
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat);
    ZonedDateTime serverDateTime = LocalDateTime.parse(strTime, formatter)
            .atZone(ZoneId.of(serverTimeZone));

    AppLog.e(TAG, "Server timezone = " + serverTimeZone);
    AppLog.e(TAG, "Date = " + strTime);
    AppLog.e(TAG, "Date in server timezone = " + serverDateTime.toString());

    ZonedDateTime deviceTime = serverDateTime
            .withZoneSameInstant(ZoneId.systemDefault());
    String strLocalTime = deviceTime.format(formatter);

    AppLog.e(TAG, "Device Time = " + deviceTime);
    AppLog.e(TAG, "Local Time = " + strLocalTime);

    return strLocalTime;

我尝试将我的时区设置为欧洲/伦敦并发出以下调用:

    convertIntoLocalTime("2018-04-22 14:30", "Europe/Berlin", "yyyy-MM-dd HH:mm")

我得到的输出是:

Server timezone = Europe/Berlin
Date = 2018-04-22 14:30
Date in server timezone = 2018-04-22T14:30+02:00[Europe/Berlin]
Device Time = 2018-04-22T13:30+01:00[Europe/London]
Local Time = 2018-04-22 13:30

问题:我可以在 Android 上使用 java.time 吗?

是的,java.time 在较旧和较新的 Android 设备上都能很好地工作。它只需要至少 Java 6

在 Java 8 及更高版本以及更新的 Android 设备上(据我所知,从 API 级别 26 开始),现代 API 是内置的。 在 Java 6 和 7 中,获取 ThreeTen Backport,即新类的后向端口(对于 JSR 310,ThreeTen;请参阅底部的链接)。 在(较旧的)Android 上使用 ThreeTen Backport 的 Android 版本。它被称为 ThreeTenABP。并确保从 org.threeten.bp 导入日期和时间类以及子包。

链接

List of tz database time zones Oracle tutorial: Date Time 解释如何使用java.time。 Java Specification Request (JSR) 310,其中首次描述了 java.time。 ThreeTen Backport project,java.time 到 Java 6 和 7(JSR-310 的 ThreeTen)的反向移植。 ThreeTenABP,Android 版 ThreeTen Backport Question: How to use ThreeTenABP in Android Project,解释得很透彻。

【讨论】:

【参考方案2】:

我没有经过测试,所以先试试吧。

 public  String convertIntoLocalTime(String strTime, String whichTimeZone, String dateFormat) 
    String strLocalTime = null;
    strLocalTime=convertDateToUserTimeZone(strTime,whichTimeZone,dateFormat);


    return strLocalTime;




public String convertDateToUserTimeZone(String strTime, String whichTimeZone, String dateFormat) 
    String ourdate;
    try 
        SimpleDateFormat formatter = new SimpleDateFormat(dateFormat, Locale.UK);
        formatter.setTimeZone(TimeZone.getTimeZone(whichTimeZone));
        Date value = formatter.parse(strTime);
        TimeZone timeZone = TimeZone.getTimeZone("Asia/Kolkata");
        SimpleDateFormat dateFormatter = new SimpleDateFormat(dateFormat, Locale.UK); //this format changeable
        dateFormatter.setTimeZone(timeZone);
        ourdate = dateFormatter.format(value);

        //Log.d("OurDate", OurDate);
     catch (Exception e) 
        ourdate = "00-00-0000 00:00";
    
    return ourdate;

【讨论】:

以上是关于1小时时差夏令时问题的主要内容,如果未能解决你的问题,请参考以下文章

美国和中国的时差是多少?

请问美国与中国时间时差多少?

请问美国太平洋时间和北京时间时差几个小时?

中国与美国的时差怎么算?

时差问题

美国现在时间是几点几分几秒?