将长字符串解析为 LocalDate 变量

Parsing a long string to a LocalDate variable

我最近需要获取一个字符串并将其转换为 Java 中的 LocalDate 变量;我知道这是可能且容易的,但这是我没有看到的:

上下文: 我正在使用 exiftool 通过 Java 运行时执行从图像中提取元数据。 问题是 exiftool 提供了下一个字符串:

2019:02:28 11:37:47-06:00

这不是您的标准 ISO 格式(或者至少我认为不是)。我不知道这是否使用任何已经实施的格式标准。 因此,为了解决我的问题,我创建了下一个用于手动解析的代码:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ssZ", Locale.ENGLISH);
LocalDate date = LocalDate.parse(VAR_WITH_STR_TO_CONVERT, formatter);

我认为这是手动转换的一个很好的实现,但是这段代码会产生下一个异常:

> Text '2019:02:28 11:37:47-06:00' could not be parsed at index 19
at java.time.format.DateTimeFormatter.parseResolved0(Unknown Source)
at java.time.format.DateTimeFormatter.parse(Unknown Source)
at java.time.LocalDate.parse(Unknown Source)

我认为问题出在我提供的用于转换的格式字符串,但在检查 DateTimeFormatter 文档后,我认为我的字符串是正确的。

yyyy:MM:dd HH:mm:ssZ

我没主意了,有人知道这里的问题吗?

2019:02:28 11:37:47-06:00

This isn't your normal Standard ISO Format

类似于 ISO 8601:

  • 将中间的SPACE字符替换为T字符。
  • 用连字符替换前两个 COLON 字符。

字符串操作

您可以通过拆分 SPACE 上的字符串,替换第一部分中的前两个冒号,然后重新拼接起来。

String input = "2019:02:28 11:37:47-06:00";
String[] parts = input.split(" ");
String inputModified = parts[0].replace( ":" , "-" ) + "T" + parts[1] ;

格式化代码:xxxxx

或者您可以使用 DateTimeFormatter 对象定义自定义格式化模式。使用五个 x 代码字符作为小时-分钟的偏移量和带有冒号字符定界符的可选秒。

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu:MM:dd HH:mm:ssxxxxx") ;

code running live at IdeOne.com 中查看此格式化程序。

OffsetDateTime

LocalDate.parse

不,首先解析所有内容,而不仅仅是日期部分,以防万一您可能会发现它在某些时候很有价值。解析为 OffsetDateTime,因为您的输入指示与 UTC 的偏移量(小时-分钟-秒)但不是完整时区 (Continent/Region)。

OffsetDateTime odt = OffsetDateTime.parse( input ) ;

显然您想要只有日期的部分,没有一天中的时间,也没有与 UTC 的偏移量。假设您想要在该偏移量中看到的日期,只需调用 toLocalDate.

LocalDate ld = odt.toLocalDate() ;

ld.toString(): 2019-02-28

或者您可能想要在其他地方看到的日期。请记住,对于任何给定时刻,全球各地的日期和时间因时区而异。在 Asia/Japan 中可能是“明天”,而在 America/Edmonton 中可能是“昨天”。

UTC

如果您想要 UTC 显示的日期:

OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC ) ;
LocalDate ld = odtUTc.toLocalDate() ;

ZonedDateTime

或者您可能想要在特定时区看到的日期。

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
LocalDate ld = zdt.toLocalDate() ;

提示:如果您可以确定日期部分中冒号的来源,请向他们介绍 ISO 8601 标准。

TL;DR 对于时区,使用 XXX,而不是 Z 来解析像 -06:00.[=20 这样的值=]


文档,即 DateTimeFormatter 的 javadoc,指定:

Offset X and x: This formats the offset based on the number of pattern letters.

  • One letter outputs just the hour, such as '+01', unless the minute is non-zero in which case the minute is also output, such as '+0130'.
  • Two letters outputs the hour and minute, without a colon, such as '+0130'.
  • Three letters outputs the hour and minute, with a colon, such as '+01:30'.
  • Four letters outputs the hour and minute and optional second, without a colon, such as '+013015'.
  • Five letters outputs the hour and minute and optional second, with a colon, such as '+01:30:15'.
  • Six or more letters throws IllegalArgumentException.

Pattern letter 'X' (upper case) will output 'Z' when the offset to be output would be zero, whereas pattern letter 'x' (lower case) will output '+00', '+0000', or '+00:00'.

Offset Z: This formats the offset based on the number of pattern letters.

  • One, two or three letters outputs the hour and minute, without a colon, such as '+0130'. The output will be '+0000' when the offset is zero.
  • Four letters outputs the full form of localized offset, equivalent to four letters of Offset-O. The output will be the corresponding localized offset text if the offset is zero.
  • Five letters outputs the hour, minute, with optional second if non-zero, with colon. It outputs 'Z' if the offset is zero.
  • Six or more letters throws IllegalArgumentException.

可以看到,你用了1个Z,也就是-0600.

要使用小时和分钟(可选秒)解析时区,使用 冒号,您需要突出显示的模式之一:

XXX      UTC is `Z`.
XXXXX    UTC is `Z`. Optional seconds.
xxx      UTC is `+00:00`
xxxxx    UTC is `+00:00`. Optional seconds.
ZZZZZ    UTC is `Z`. Optional seconds.