创建时
Calendar,它将采用JVM的默认时区。而且,当您
String将a
解析为a时
Date,它只会设置一个值:自历元(
1970-01-01T00:00Z)以来的毫秒数。A
Date
没有任何时区信息,仅此毫秒值。因此,您需要在日历中设置时区。
在格式化程序中,您将其
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 formattersdf.setTimeZone(tz);// parse just date and time (without the offset)Date date = sdf.parse(iso8601Date.substring(0, 19));// set the offset in the calendarcalendar.setTimeZone(tz);calendar.setTime(date);这样,日历将
-08:00设置偏移量。正如@BasilBourque的回答已经说的那样,它
-08:00是一个偏移量,而不是时区(
TimeZone该类将偏移量视为时区一样对待偏移量,这是一种解决方法/错误的设计选择)。
Java新的日期/时间API
老班(
Date,
Calendar和
SimpleDateFormat)有很多问题和设计问题,他们正在被新的API取代。
在Android中,您可以使用ThreeTen Backport,这是Java
8的新日期/时间类的绝佳反向端口。您还需要ThreeTenABP使其起作用(更多有关如何在此处使用的信息)。
@BasilBourque的答案已经告诉您有关的信息
OffsetDateTime。但是要转换为a
Calendar,您可以使用a
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偏移量。
如果要从偏移量获取时区,恐怕不是那么简单。多个时区可以使用相同的offset,因此您无法确定要使用哪个时区(最好的方法是获取可能的候选者列表)。
java.util.Date
只是有关的更详细的说明
java.util.Date。该链接对此有很多解释,所以我真的建议您阅读它。
如上所述,a
Date没有时区信息。它只是让纪元以来的毫秒数(是
1970-01-01T00:00Z或 年1月1 日
1970年,在午夜UTC)。
这个值在世界各地都一样。示例:目前,我正在编写此代码,当前时间的Millis值为
1504632865935。对于世界上任何人,无论我使用的是哪个时区,在与我相同的时间获取当前时间的人,此数字都是相同的。
与该毫秒值相对应的 当地日期和时间 有所不同。在UTC,它对应于
2017-09-05T17:34:25.935Z在纽约,日期是相同的(9月5 日
2017年),但时间是不同的(13:34),并在东京为九月 6 日 2017年在上午2时34分。
尽管
Date对象是相同的(因为对象的Millis值适用
1504632865935于每个人),但是 相应的 日期和时间会根据使用的时区而变化。
人们倾向于认为a
Date具有时区,因为在打印时(通过
System.out.println或通过日志记录)或在调试器中进行检查时,它隐式使用该
toString()方法,并将日期转换为JVM的默认时区(并且还会打印时区名称)
)。这样给人的印象是,a
Date设置了格式和时区,但没有。



