其他分享
首页 > 其他分享> > 如何从ISO 8601格式字符串中选择时区到日历实例中

如何从ISO 8601格式字符串中选择时区到日历实例中

作者:互联网

作为输入,我有一个字符串,它是ISO 8601中表示日期的字符串.例如:

“2017-04-04T09:00:00-08:00”

String的最后一部分,即“-08:00”表示TimeZone Offset.我将此字符串转换为Calendar实例,如下所示:

Calendar calendar = GregorianCalendar.getInstance();
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US).parse(iso8601Date);
calendar.setTime(date);

iso8601Date是“2017-04-04T09:00:00-08:00”

但这并没有选择时区,如果我从Calendar实例获取时区,它会提供笔记本电脑的当前设置实例,而不会从ISO 8601字符串中获取时间戳.我通过日历实例检查时区为:

calendar.getTimeZone().getDisplayName()

有人可以在Calendar实例中显示如何选择时区吗?

解决方法:

创建日历时,它采用JVM的默认时区.当你将一个字符串解析为一个日期时,它只设置一个值:自纪元以来的毫秒数(1970-01-01T00:00Z).日期doesn’t have any timezone information,只有这个毫秒值.因此,您需要在日历中设置时区.

在格式化程序中,您将Z视为文字,因为它在引号内(‘Z’).这会忽略偏移量并在JVM默认时区中获取日期(如果相应的偏移量不是-08:00,则会有不同的值).

在JDK> = 7中,您可以使用X模式来解析偏移量:

Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX", Locale.US).parse(iso8601Date);

但是这并没有在日历中设置时区(它仍将使用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);

这样,日历将设置偏移-08:00.正如@BasilBourque’s answer已经说过的那样,-08:00 is an offset, not a timezone(TimeZone类将偏移视为时区,这是一种解决方法/糟糕的设计选择).

Java新的日期/时间API

旧类(Date,Calendar和SimpleDateFormat)有lots of problemsdesign issues,它们将被新API替换.

在Android中,您可以使用ThreeTen Backport,这是Java 8新日期/时间类的优秀后端.你还需要ThreeTenABP来使它工作(更多关于如何使用它here).

@BasilBourque’s answer已经告诉你有关OffsetDateTime的信息.但要转换为Calendar,您可以使用org.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);

日历将已使用-08:00偏移设置.

如果你想从偏移量中获取时区,我恐怕不是那么简单.不止一个时区can use the same offset,所以你无法确定使用哪个时区(你能做的最好的事情就是获得可能的候选人名单).

java.util.Date

关于java.util.Date的更详细说明. This link解释了很多,所以我真的建议你阅读它.

如上所述,Date没有时区信息.它只保留自纪元以来的毫秒数(即1970-01-01T00:00Z,或1970年1月1日在UTC的午夜).

这个价值在世界各地都是一样的.示例:在我写这篇文章时,当前时间的毫秒值是1504632865935.这个数字对于世界上任何人来说都是一样的,他们在我做的同一时刻得到当前时间,无论他们是什么时区使用.

不同的是与此millis值对应的本地日期和时间.在UTC中,它对应于2017-09-05T17:34:25.935Z,在纽约,日期相同(2017年9月5日)但时间不同(13:34),东京时间是2017年9月6日02:34 AM

虽然Date对象是相同的(因为每个人的millis值为1504632865935),但相应的日期和时间会根据使用的时区而变化.

人们倾向于认为Date有一个时区,因为在打印它时(使用System.out.println或通过loggging)或在调试器中检查时,它隐含使用toString()方法,这会将日期转换为JVM的默认值时区(还会打印区域名称).这给人的印象是Date有一个格式和时区设置,但它没有.

标签:datetime-parsing,java-util-calendar,android,java,date
来源: https://codeday.me/bug/20190823/1699166.html