如何从ISO 8601格式字符串中选择时区到日历实例中 [英] How to Pick Timezone from ISO 8601 format String into a Calendar instace

查看:545
本文介绍了如何从ISO 8601格式字符串中选择时区到日历实例中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

As an input I have a string which is a String in ISO 8601 to represent date. For example:


2017-04-04T09:00:00-08:00

"2017-04-04T09:00:00-08:00"

String 的最后一部分, - 08:00表示TimeZone Offset 。我将此字符串转换为日历实例,如下所示:

The last part of String, which is "-08:00" denotes TimeZone Offset. I convert this string into a Calendar instance as shown below:

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字符串中获取时间戳。我通过日历实例检查时区为:

But this does not pick timezone and if I get timezone from Calendar instance, it gives currently set instance of the laptop and does not pick up timestamp from ISO 8601 String. I check for timezone via calendar instance as:

calendar.getTimeZone().getDisplayName()

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

Can someone show how to pick timezone also in the Calendar instance?

推荐答案

当您创建日历时,它将采用JVM的默认时区。当你将 String 解析为 Date 时,它只设置一个值:自纪元以来的毫秒数( 1970-01-01T00:00Z )。 A 日期 没有任何时区信息,只有这个毫秒值。因此,您需要在日历中设置时区。

When you create a Calendar, it takes the JVM's default timezone. And when you parse a String to a Date, it just sets one value: the number of milliseconds since epoch (1970-01-01T00:00Z). A Date doesn't have any timezone information, just this milliseconds value. So you need to set the timezone in the calendar.

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

In your formatter, you're treating Z as a literal, because it's inside quotes ('Z'). This ignores the offset and gets the date in the JVM default timezone (which will have a different value if the corresponding offset is not -08:00).

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

In JDK >= 7, you can use the X pattern to parse the offset:

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

但是这不会在日历中设置时区(它仍将使用JVM的默认值)。因此,更好的方法是从输入中去除偏移并单独处理:

But this doesn't set the timezone in the calendar (it will still use the JVM's default). So, a "better" way is to strip the offset from the input and handle it separately:

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的回答所述, -08:00 是偏移量,而不是时区 TimeZone 类对待偏移量就像它们是时区,这是一种解决方法/糟糕的设计选择。)

With this, the calendar will have the offset -08:00 set. As @BasilBourque's answer already said, -08:00 is an offset, not a timezone (the TimeZone class treats offsets just like they were timezones, which is a workaround/bad design choice).

旧班级(日期日历 SimpleDateFormat 许多问题设计问题,它们将被新的API取代。

The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.

在Android中你可以使用 ThreeTen Backport ,是Java 8新日期/时间类的绝佳后端。您还需要 ThreeTenABP 才能使其正常运行(更多关于如何使用它在其他地方

In Android you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. You'll also need the ThreeTenABP to make it work (more on how to use it here).

@ BasilBourque的答案已经告诉你 OffsetDateTime 。但要转换为日历,您可以使用 org.threeten.bp.ZonedDateTime 并使用<转换它code> org.threeten.bp.DateTimeUtils class:

@BasilBourque's answer already tells you about OffsetDateTime. But to convert to a Calendar, you can use a org.threeten.bp.ZonedDateTime and convert it using the org.threeten.bp.DateTimeUtils class:

String iso8601Date = "2017-04-04T09:00:00-08:00";
ZonedDateTime zdt = ZonedDateTime.parse(iso8601Date);
Calendar cal = DateTimeUtils.toGregorianCalendar(zdt);

日历将设置为 -08:00 偏移。

如果你想从偏移量中获取时区,恐怕不是那样的简单。 多个时区可以使用相同的偏移量,因此您无法确定哪个时区使用(你可以做的最好的事情是获得可能的候选人名单)。

If you want to get the timezone from the offset, I'm afraid it's not that simple. More than one timezone can use the same offset, so you can't know for sure which timezone to use (the best you can do is to get a list of possible candidates).

关于 java.util.Date 的更详细说明。 此链接解释了很多相关信息,所以我真的建议你阅读它。

Just a more detailed note about java.util.Date. This link explains a lot about it, so I really recommend you to read it.

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

As already said above, a Date has no timezone information. It just keeps the number of milliseconds since epoch (which is 1970-01-01T00:00Z, or January 1st 1970 at midnight in UTC).

这个值在世界各地都是一样的。示例:在我写这篇文章时,当前时间的millis值为 1504632865935 。对于世界上任何人来说,无论他们使用的是什么时区,这个数字都是相同的。

This value is the same everywhere in the world. Example: at the moment I'm writing this, the millis value for the current time is 1504632865935. This number is the same for anyone in the world who gets the current time at the same instant I did, regardless of what timezone they're using.

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

What is different is the local date and time that corresponds to this millis value. In UTC, it corresponds to 2017-09-05T17:34:25.935Z, in New York, the date is the same (September 5th 2017) but the time is different (13:34), and in Tokyo is September 6th 2017 at 02:34 AM.

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

Although the Date object is the same (because its millis value is 1504632865935 for everyone), the corresponding date and time changes according to the timezone used.

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

People tend to think that a Date has a timezone because when printing it (with System.out.println or by loggging) or when inspecting in a debugger, it implicity uses the toString() method, and this converts the date to the JVM's default timezone (and it also prints the zone name). This gives the impression that a Date has a format and a timezone set to it, but it doesn't.

这篇关于如何从ISO 8601格式字符串中选择时区到日历实例中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆