Java 将符合ISO 8601的字符串转换为ZoneDateTime
我正在解析来自不同来源的日志,我正在从日志中提取datetime字符串。现在我想把它转换成java ZoneDateTime 这里的问题是,我不知道确切的日期时间格式,我只知道,字符串将符合ISO-8601。所以我想编写如下函数:Java 将符合ISO 8601的字符串转换为ZoneDateTime,java,java-time,Java,Java Time,我正在解析来自不同来源的日志,我正在从日志中提取datetime字符串。现在我想把它转换成java ZoneDateTime 这里的问题是,我不知道确切的日期时间格式,我只知道,字符串将符合ISO-8601。所以我想编写如下函数: /** * @param _dateTime : any ISO 8601 format , e.g 1. %Y-%m-%dT%H:%M:%s%z => 2014-05-25T08:20:03.123456Z , *
/**
* @param _dateTime : any ISO 8601 format , e.g 1. %Y-%m-%dT%H:%M:%s%z => 2014-05-25T08:20:03.123456Z ,
* e.g 2. %Y-%m-%dT%H:%M:%s => 2014-05-25T08:20:03.123456, e.g 3. %Y-%m-%d %H:%M:%s%z => 2014-11-08 15:55:55.123456Z,
* e.g 4. %Y-%m-%d %H:%M:%s => 2014-11-08 15:55:55
* @return Instance of ZonedDateTime if conversion successful
* @throws DateTimeParseException
*/
private ZonedDateTime parse (String _dateTime) throws DateTimeParseException {
// Magic here.
}
用java做这件事的最佳方法是什么?这很重要。大部分神奇之处在于以下格式化程序:
private static final DateTimeFormatter formatter
= new DateTimeFormatterBuilder().append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendPattern("['T'][' ']")
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendPattern("[XX]")
.toFormatter();
此格式化程序接受
- 类似于
的日期2014-05-25
- 要么是一个
要么是一个空格(要么两者都有,要么两者都没有,但我只知道字符串中有一个空格)。方括号表示格式的可选部分。单引号表示文字部分,并导致T
不被解释为模式字母T
- 一天中的某个时间<代码>ISO_本地时间接受带小数点和不带小数点的秒数
- 可选的UTC偏移量,如
(零)或Z
-0600
private static final ZoneId defaultZone = ZoneId.of("America/Curacao");
您的方法仍然需要做的是区分有UTC偏移和没有UTC偏移的情况。带有偏移量的表单可以直接解析为ZonedDateTime
。没有的不能,因此我们需要将其解析为LocalDateTime
并进行转换
/**
* @param dateTime : any ISO 8601 format , e.g 1. %Y-%m-%dT%H:%M:%s%z => 2014-05-25T08:20:03.123456Z ,
* e.g 2. %Y-%m-%dT%H:%M:%s => 2014-05-25T08:20:03.123456,
* e.g 3. %Y-%m-%d %H:%M:%s%z => 2014-11-08 15:55:55.123456Z,
* e.g 4. %Y-%m-%d %H:%M:%s => 2014-11-08 15:55:55
* @return Instance of ZonedDateTime if conversion successful
* @throws DateTimeParseException
*/
private static ZonedDateTime parse(String dateTime) {
// Little magic here.
TemporalAccessor parsed = formatter.parseBest(dateTime,
ZonedDateTime::from, LocalDateTime::from);
if (parsed instanceof ZonedDateTime) {
return (ZonedDateTime) parsed;
} else {
return ((LocalDateTime) parsed).atZone(defaultZone);
}
}
让我们试试看。我已经用了你的四个例子,加上我在第一个和第二个之间添加的一个
System.out.println(parse("2014-05-25T08:20:03.123456Z"));
System.out.println(parse("2014-05-25T10:20:03.123456+0200"));
System.out.println(parse("2014-05-25T08:20:03.123456"));
System.out.println(parse("2014-11-08 15:55:55.123456Z"));
System.out.println(parse("2014-11-08 15:55:55"));
输出:
另外,对于UTC偏移量的字符串,您更喜欢OffsetDateTime
而不是zoneDateTime
。代码将是相同的,除非您需要在atZone(defaultZone)
之后进一步转换.toOffsetDateTime()
,如果您没有直接从解析中获得OffsetDateTime
。ZonedDateTime
表示时区为欧洲/布拉格的日期和时间。OffsetDateTime
表示具有UTC偏移的日期和时间。正如我提到的,Z
是UTC的0偏移量
编辑:Arvind Kumar Avinash在评论中的注释非常有用,非常重要,值得正确回答:给未来访客的一些注释:
[XX]
替换为[XX][XXX]
也将满足+02:00等偏移量.toFormatter(Locale.ENGLISH)
而不是.toFormatter()
ZoneId
,可以使用ZoneId.systemDefault()
这不是小事。大部分神奇之处在于以下格式化程序:
private static final DateTimeFormatter formatter
= new DateTimeFormatterBuilder().append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendPattern("['T'][' ']")
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendPattern("[XX]")
.toFormatter();
此格式化程序接受
- 类似于
的日期2014-05-25
- 要么是一个
要么是一个空格(要么两者都有,要么两者都没有,但我只知道字符串中有一个空格)。方括号表示格式的可选部分。单引号表示文字部分,并导致T
不被解释为模式字母T
- 一天中的某个时间<代码>ISO_本地时间接受带小数点和不带小数点的秒数
- 可选的UTC偏移量,如
(零)或Z
-0600
private static final ZoneId defaultZone = ZoneId.of("America/Curacao");
您的方法仍然需要做的是区分有UTC偏移和没有UTC偏移的情况。带有偏移量的表单可以直接解析为ZonedDateTime
。没有的不能,因此我们需要将其解析为LocalDateTime
并进行转换
/**
* @param dateTime : any ISO 8601 format , e.g 1. %Y-%m-%dT%H:%M:%s%z => 2014-05-25T08:20:03.123456Z ,
* e.g 2. %Y-%m-%dT%H:%M:%s => 2014-05-25T08:20:03.123456,
* e.g 3. %Y-%m-%d %H:%M:%s%z => 2014-11-08 15:55:55.123456Z,
* e.g 4. %Y-%m-%d %H:%M:%s => 2014-11-08 15:55:55
* @return Instance of ZonedDateTime if conversion successful
* @throws DateTimeParseException
*/
private static ZonedDateTime parse(String dateTime) {
// Little magic here.
TemporalAccessor parsed = formatter.parseBest(dateTime,
ZonedDateTime::from, LocalDateTime::from);
if (parsed instanceof ZonedDateTime) {
return (ZonedDateTime) parsed;
} else {
return ((LocalDateTime) parsed).atZone(defaultZone);
}
}
让我们试试看。我已经用了你的四个例子,加上我在第一个和第二个之间添加的一个
System.out.println(parse("2014-05-25T08:20:03.123456Z"));
System.out.println(parse("2014-05-25T10:20:03.123456+0200"));
System.out.println(parse("2014-05-25T08:20:03.123456"));
System.out.println(parse("2014-11-08 15:55:55.123456Z"));
System.out.println(parse("2014-11-08 15:55:55"));
输出:
另外,对于UTC偏移量的字符串,您更喜欢OffsetDateTime
而不是zoneDateTime
。代码将是相同的,除非您需要在atZone(defaultZone)
之后进一步转换.toOffsetDateTime()
,如果您没有直接从解析中获得OffsetDateTime
。ZonedDateTime
表示时区为欧洲/布拉格的日期和时间。OffsetDateTime
表示具有UTC偏移的日期和时间。正如我提到的,Z
是UTC的0偏移量
编辑:Arvind Kumar Avinash在评论中的注释非常有用,非常重要,值得正确回答:给未来访客的一些注释:
[XX]
替换为[XX][XXX]
也将满足+02:00等偏移量.toFormatter(Locale.ENGLISH)
而不是.toFormatter()
ZoneId
,可以使用ZoneId.systemDefault()
你不知道格式是什么意思?ISO 8601 datetime是一种格式。您的javadoc似乎建议在日期和时间之间使用空格可以替代字母T。这不是ISO 8601。ISO 8601始终使用T作为分隔符。正如我在方法描述中提到的,它可能类似于2014-05-25T08:20:03.123456或2014-11-08 15:55:55.123456Z或2014-11-08 15:55:55等等……您的第四个示例,
2014-11-08 15:55:55
,不符合ISO 8601。ISO 8601要求使用T
来表示时间部分的开始,如第一个和第二个示例所示。第三个示例也存在同样的问题。当字符串以UTC的Z
结尾时,显然应该在UTC中获得ZonedDateTime
。如果没有,你想要哪个时区?它需要一个时区来构造ZonedDateTim