【问题标题】:Convert UTC to EST doesn't work with day light saving on Android将 UTC 转换为 EST 不适用于 Android 上的夏令时
【发布时间】:2020-06-22 17:29:26
【问题描述】:

我一直在尝试将本地时间 (EST) 转换为 UTC,反之亦然。因此,我提出了一个时间选择器,用户选择时间,我将其转换为 UTC 并发送到服务器。代码如下:

        val cal = Calendar.getInstance()
        cal.set(Calendar.HOUR_OF_DAY, mHour) //mHour = 15
        cal.set(Calendar.MINUTE, mMinute)    //mMinute = 00
        cal.set(Calendar.SECOND, 0)
        val formatter = SimpleDateFormat("HH:mm:ss")
        formatter.timeZone = TimeZone.getTimeZone("UTC")
        val cutOffTime = formatter.format(cal.time)  //this gives 19:00:00 which is correct

上面的 cutOffTime 输出是正确的,因为 15:00 EST 在考虑夏令时后是 19:00 UTC。

现在,我从服务器获取相同的 cutOffTime,将其转换为本地 (EST) 并显示。代码如下:

        val cutOffTime = jsonObject.get("cutOffTime").getAsString())  //value is 19:00:00
        var cutoffTime: Time? = null
        val format = SimpleDateFormat("hh:mm:ss")
        format.timeZone = TimeZone.getTimeZone("UTC")
        cutoffTime = Time(format.parse(cutOffTime).time)

        //cutoffTime has value 14:00 which is strange, it should be 15:00

所以,上面代码中的 cutoffTime 的值是 14:00,这很奇怪,应该是 15:00。 请注意,此代码在 2020 年 3 月 8 日夏令时之前有效。知道我做错了什么吗?

【问题讨论】:

    标签: java android kotlin dst


    【解决方案1】:

    请不要使用旧的和设计糟糕的 java api 来获取日期和时间。使用新的java.time api。它更健壮,更易于使用。

    这是一个关于如何使用java.time 编写代码的示例:

    int mHour = 15;
    int mMinute = 0;
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
    
    ZonedDateTime toFormat = LocalDateTime
        .now() // Current date and time.
        .withHour(mHour).withMinute(mMinute).withSecond(0) // Change hour, minute and second like in your example.
        .truncatedTo(ChronoUnit.SECONDS) // Throw away milliseconds and nanoseconds.
        .atZone(ZoneOffset.UTC); // Say that the time is located at UTC+0.
    
    String formatted = formatter
        .withZone(ZoneId.of("America/New_York")) // Create a new formatter that formats toFormat to the local time America/New_York.
        .format(toFormat);
    
    System.out.println(formatted); // Gives 11:00:00 on my machine now. America/New_York is either UTC-5 or UTC-4.
    
    ZonedDateTime parsed = LocalTime
        .parse(formatted, formatter) // Parse the String. The result is an instance of LocalTime.
        .atDate(LocalDate.now(ZoneId.of("America/New_York"))) // Add the date values which are those of the current local date at America/New_York.
        .atZone(ZoneId.of("America/New_York")); // Create a ZonedDateTime of the LocalDateTime to explicitly define the zone.
    
    Instant pointInTimeA = parsed.toInstant();
    Instant pointInTimeB = toFormat.toInstant();
    
    System.out.println(pointInTimeA.equals(pointInTimeB)); // Gives true because both describe the same point in time as they should.
    

    最大的好处是该 api 将为您处理有关夏季和冬季的所有事情。已阅读 here 了解有关 EST 以及为什么不应该使用它的信息。

    您面临的问题可能是由于您在一种格式化程序中使用了HH,而在另一种格式化程序中使用了hh。这些是相同的。已阅读 here 关于格式化和解析模式

    【讨论】:

    • 感谢回复,我试试这个。我尝试在两种格式化程序中使用 HH。问题仍然存在。另外,API 级别 26 中添加了 java.time。我的最低 API 级别是 21。还有其他解决方案吗?
    • 看看here,这看起来和我有关。无论如何,我强烈建议您使用新的 api。正是这样的问题是旧 api 的弱点。您应该仔细阅读旧 api 关于夏令时的文档。问题很可能是因为这个。
    【解决方案2】:

    我最终得到了以下解决方案。我从服务器知道字符串的格式,所以我将其拆分。我不想使用新的时间 API,因为它从 API 级别 26 开始可用。

                    val cutOffString = jsonObject.get("cutOffTime").getAsString() //UTC date 19:00:00 from server
    
                    val cal = Calendar.getInstance()
                    cal.set(Calendar.HOUR_OF_DAY, cutOffString.split(":")[0].toInt())
                    cal.set(Calendar.MINUTE, cutOffString.split(":")[1].toInt())
                    cal.set(Calendar.SECOND, 0)
                    cal.timeZone = TimeZone.getTimeZone("UTC")
    
                    val cutoffTime: Time = Time(cal.time.time) //15:00:00
    
    

    【讨论】:

      猜你喜欢
      • 2021-11-04
      • 2018-07-03
      • 2015-08-04
      • 1970-01-01
      • 2014-06-01
      • 2017-09-10
      • 2021-03-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多