Tar*_*run 5 java android date datetime-parsing java.util.calendar
作为输入,我有一个字符串,它是 ISO 8601 中的字符串,用于表示日期。例如:
“2017-04-04T09:00:00-08:00”
String的最后一部分“-08:00”表示时区偏移。我将此字符串转换为Calendar实例,如下所示:
Calendar calendar = GregorianCalendar.getInstance();
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).parse(iso8601Date);
calendar.setTime(date);
Run Code Online (Sandbox Code Playgroud)
iso8601日期为“2017-04-04T09:00:00-08:00”
但这不会选择时区,如果我从Calendar实例获取时区,它会给出笔记本电脑当前设置的实例,并且不会从 ISO 8601 字符串中获取时间戳。我通过日历实例检查时区:
calendar.getTimeZone().getDisplayName()
Run Code Online (Sandbox Code Playgroud)
有人可以展示如何在Calendar实例中选择时区吗?
小智 3
当您创建 时Calendar,它采用 JVM 的默认时区。当您将 a 解析String为 a时Date,它只设置一个值:自纪元 ( ) 以来的毫秒数1970-01-01T00:00Z。ADate 没有任何时区信息,只有这个毫秒值。所以你需要在日历中设置时区。
在格式化程序中,您将其视为Z文字,因为它位于引号 ( 'Z') 内。这会忽略偏移量并获取 JVM 默认时区中的日期(如果相应的偏移量不是 -08:00,则将具有不同的值)。
在 JDK >= 7 中,可以使用X模式来解析偏移量:
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX", Locale.US).parse(iso8601Date);
Run Code Online (Sandbox Code Playgroud)
但这不会在日历中设置时区(它仍将使用 JVM 的默认值)。因此,“更好”的方法是从输入中去除偏移量并单独处理:
Calendar calendar = GregorianCalendar.getInstance();
String iso8601Date = "2017-04-04T09:00:00-08:00";
// get the offset (-08:00)
String offset = iso8601Date.substring(19);
TimeZone tz = TimeZone.getTimeZone("GMT" + offset);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
// set the offset in the formatter
sdf.setTimeZone(tz);
// parse just date and time (without the offset)
Date date = sdf.parse(iso8601Date.substring(0, 19));
// set the offset in the calendar
calendar.setTimeZone(tz);
calendar.setTime(date);
Run Code Online (Sandbox Code Playgroud)
这样,日历就会设置偏移量-08:00。正如@BasilBourque 的回答已经说过的那样,-08:00是一个偏移量,而不是一个时区(该类TimeZone将偏移量视为时区,这是一种解决方法/糟糕的设计选择)。
旧的类(Date、Calendar和SimpleDateFormat)有很多问题和设计问题,它们正在被新的 API 所取代。
在 Android 中,您可以使用ThreeTen Backport,它是 Java 8 新日期/时间类的一个很好的向后移植。您还需要ThreeTenABP才能使其工作(更多关于如何使用它的信息,请参见此处)。
@BasilBourque 的答案已经告诉你了OffsetDateTime。但要转换为 a Calendar,您可以使用 aorg.threeten.bp.ZonedDateTime并使用类转换它org.threeten.bp.DateTimeUtils:
String iso8601Date = "2017-04-04T09:00:00-08:00";
ZonedDateTime zdt = ZonedDateTime.parse(iso8601Date);
Calendar cal = DateTimeUtils.toGregorianCalendar(zdt);
Run Code Online (Sandbox Code Playgroud)
日历将已经设置好偏移量-08:00。
如果你想从偏移量中获取时区,恐怕没那么简单。多个时区可以使用相同的 offset,因此您无法确定要使用哪个时区(您能做的最好的事情就是获取可能的候选时区列表)。
只是关于 的更详细说明java.util.Date。这个链接解释了很多相关内容,所以我强烈建议您阅读它。
如上所述,aDate没有时区信息。1970-01-01T00:00Z它只保留自纪元(即,或UTC 时间 1970 年1 月 1日午夜)以来的毫秒数)以来的毫秒数。
这个值在世界各地都是一样的。示例:在我写这篇文章时,当前时间的毫秒值为1504632865935。对于世界上与我同时获得当前时间的任何人来说,这个数字都是相同的,无论他们使用哪个时区。
不同之处在于与该毫秒值对应的本地日期和时间。在 UTC 中,它对应于2017-09-05T17:34:25.935Z,在纽约,日期相同(2017 年 9 月 5日)但时间不同(13:34),在东京为 2017 年 9 月6日凌晨 02:34。
虽然Date对象是相同的(因为它的 millis 值是1504632865935针对每个人的),但是相应的日期和时间根据所使用的时区而变化。
人们倾向于认为 aDate具有时区,因为当打印它(使用System.out.println或通过日志记录)或在调试器中检查时,它隐式使用该toString()方法,并且这会将日期转换为 JVM 的默认时区(并且它还打印区域名称)。这给人的印象是 aDate设置了格式和时区,但事实并非如此。
| 归档时间: |
|
| 查看次数: |
3432 次 |
| 最近记录: |