将 UTC 转换为 EST 不适用于 Android 上的夏令时
Posted
技术标签:
【中文标题】将 UTC 转换为 EST 不适用于 Android 上的夏令时【英文标题】:Convert UTC to EST doesn't work with day light saving on 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 日夏令时之前有效。知道我做错了什么吗?
【问题讨论】:
【参考方案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
【讨论】:
以上是关于将 UTC 转换为 EST 不适用于 Android 上的夏令时的主要内容,如果未能解决你的问题,请参考以下文章