【问题标题】:1 hour time difference daylight saving time issue1小时时差夏令时问题
【发布时间】: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 相关,但我无法弄清楚。感谢您的帮助?

【问题讨论】:

标签: java android datetime dst timezone-offset


【解决方案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 导入日期和时间类以及子包。

链接

【讨论】:

    【解决方案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;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-04-12
      • 2017-03-14
      • 2013-11-15
      • 2012-03-25
      • 2013-12-31
      • 2015-06-07
      • 2011-11-20
      • 2011-11-20
      • 2013-02-19
      相关资源
      最近更新 更多