我正在尝试以Date
+时区转换我的String
。 我从DateTime
变量(这里:xyz)中获取字符串。 我的代码:
String abc = xyz.toString("yyyy-MM-ddZZ");
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-ddXXX");
java.util.Date date = sdf.parse(abc);
System.out.println("Date: " + sdf.format(date));
错误:
格式无效:"2017-01-03+01:00"在"+01:00"格式不正确
如果我尝试SimpleDateFormat("yyyy-MM-dd");
它可以工作,但没有时区("+01:00")
输入有一个日期 - 年,月,日 - 和一个偏移量 - 与UTC的差异 - 但要构建一个java.util.Date
,您还需要时间:小时,分钟,秒,秒的小数部分。
SimpleDateFormat
很糟糕,因为它做了一些"魔术",将缺少的字段设置为默认值。另一个问题是X
模式不适用于所有Java版本,而且文档很糟糕。
如前所述,您可以使用新的 Java 8 类。使用它们,您可以解析输入,选择要用于时间字段的默认值并转换为java.util.Date
,如果需要的话:
DateTimeFormatter fmt = new DateTimeFormatterBuilder().append(DateTimeFormatter.ISO_OFFSET_DATE)
// set hour to midnight
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0).toFormatter();
OffsetDateTime odt = OffsetDateTime.parse("2017-01-03+01:00", fmt); // 2017-01-03T00:00+01:00
OffsetDateTime
会将时间设置为午夜,但您可以将其更改为所需的任何值,而使用SimpleDateFormat
则不可能,因为它使用内部默认值并且您无法控制它。
并且日期和偏移量已正确设置为输入字符串中的值。然后,如果需要,可以转换为java.util.Date
:
Date date = Date.from(odt.toInstant());
如果需要,您还可以获取日期的各个"碎片":
// get just the date
LocalDate localDate = odt.toLocalDate(); // 2017-01-03
// get just the offset
ZoneOffset offset = odt.getOffset(); // +01:00
PS:偏移量+01:00
与时区不同。在这里查看差异
String abc = "2017-01-03+01:00";
TemporalAccessor parsed = DateTimeFormatter.ISO_OFFSET_DATE.parse(abc);
LocalDate date = LocalDate.from(parsed);
ZoneOffset offset = ZoneOffset.from(parsed);
System.out.println("Date: " + date + "; offset: " + offset + '.');
这将打印:
Date: 2017-01-03; offset: +01:00.
我正在使用java.time
,现代Java日期和时间API,并建议您也这样做。Date
类早已过时(对不起,没有双关语),而且SimpleDateFormat
特别麻烦。不要使用它们。现代 API 使用起来要好得多。仅当您需要无法更改的旧 API 的java.util.Date
和/或java.util.TimeZone
时,才可以像这样转换:
Date oldfashionedDate = Date.from(date.atStartOfDay(offset).toInstant());
TimeZone oldfashionedTimeZone = TimeZone.getTimeZone(offset);
System.out.println("Old-fashioned date: " + oldfashionedDate
+ "; old-fashioned time-zone: " + oldfashionedTimeZone.getDisplayName() + '.');
在我的电脑上,这打印:
Old-fashioned date: Tue Jan 03 00:00:00 CET 2017; old-fashioned time-zone: GMT+01:00.
我碰巧在一个与您与 UTC 的偏移量一致的时区,因此很明显转换给出了正确的结果。在其他时区,输出会更加混乱,因为Date.toString()
使用 JVM 的时区设置来生成字符串,但Date
仍然是正确的。
有时区的日期?LocalDate
和Date
都不能在其中保存时区,因此您需要单独拥有偏移量信息。有趣的是,您的字符串似乎遵循偏移日期的"类似 ISO-8601"格式,该格式甚至由名称中包含 ISO 的内置格式化程序表示。如果 Java 包含一个OffsetDate
或一个ZonedDate
类,我希望这样的类将你的字符串解析为一个对象,即使没有显式格式化程序。不幸的是,据我一目了然,不存在这样的类,即使在 ThreeTen-Extra 项目中也是如此。
链接
- Oracle 教程:日期时间,说明如何使用
java.time
。 - ThreeTen Extra,随着
java.time
开发的更多类。 - 编辑:看到我更新的代码在ideone上实时运行。
"2017-01-03+01:00">
我认为它是类似的ISO 8601格式日期字符串,但实际上不是ISO 8601。感谢@Meno霍克希尔德和@Basil布尔克的指示。
幸运的是,此方法适用于这种格式的字符串:javax.xml.bind.DatatypeConverter.parseDateTime
,它将返回一个Calendar
:
System.out.println(DatatypeConverter.parseDate("2017-01-03+01:00").getTime());
输出:
星期二 1月 03 07:00:00 CST 2017
从方法javadoc:
公共静态日历分析日期(字符串词法 XSDDate)将
字符串参数转换为日历值。
参数:词法XSDDate - 包含词法的字符串 xsd:日期的表示形式。
返回:日历值,表示如下 字符串参数。
抛出:非法参数异常 - if 字符串 参数不符合 XML 中定义的词法值空间 架构第 2 部分:xsd:Date 的数据类型。