军事时区使用JSR 310(DateTime API)

har*_*ldK 11 java timezone datetime java-time

我在我的应用程序中使用JSR 310 DateTime API*,我需要解析和格式化军事日期时间(称为DTG或"日期时间组").

我正在解析的格式如下(使用DateTimeFormatter):

"ddHHmm'Z' MMM yy" // (ie. "312359Z DEC 14", for new years eve 2014)
Run Code Online (Sandbox Code Playgroud)

如上所述,这种格式很容易解析.当日期包含与'Z'不同的时区(祖鲁时区,与UTC/GMT相同)时出现问题,例如'A'(Alpha,UTC + 1:00)或'B'(Bravo,UTC + 2:00).有关完整列表,请参阅军事时区.

我该如何解析这些时区?或者换句话说,除了文字"Z"之外,我还可以使用上面的格式来正确解析所有区域?我已经尝试使用"ddHHmmX MMM yy","ddHHmmZ MMM yy""ddHHmmVV MMM yy",但他们没有工作(一切都会抛出DateTimeParseException: Text '312359A DEC 14' could not be parsed at index 6了上面的例子中,在解析时).V不允许在格式中使用单个(IllegalArgumentException尝试实例化时DateTimeFormatter).

编辑:z如果不是下面的问题,似乎符号可能有效.

我还要提一下,我已经创建了一个ZoneRulesProvider包含所有命名区域和正确的偏移量.我已经验证使用SPI机制正确注册了这些,并且我的provideZoneIds()方法按预期调用.仍然不会解析.作为一个副问题(编辑:现在这似乎是主要问题),API不允许使用"Z"以外的单字符时区ID(或"区域").

例如:

ZoneId alpha = ZoneId.of("A"); // boom
Run Code Online (Sandbox Code Playgroud)

将抛出DateTimeException: Invalid zone: A(甚至没有访问我的规则提供程序,看它是否存在).

这是API的疏忽吗?或者我做错了什么?


*)实际上,我使用的是Java 7和ThreeTen Backport,但我认为这对于这个问题并不重要.

PS:我目前的解决办法是使用25个不同DateTimeFormatters的文字区域ID(即"ddHHmm'A' MMM yy","ddHHmm'B' MMM yy"等),使用RegExp提取区域ID,并委托给基于区域的正确格式.提供程序中的区域ID命名为"Alpha","Bravo"等,以便ZoneId.of(...)查找区域.有用.但它不是很优雅,我希望有更好的解决方案.

Jod*_*hen 8

In java.time, the ZoneId is limited to be 2 characters or more. Ironically, this was to reserve space to allow the military IDs to be added in a future JDK release if it proved to be heavily in demand. As such, sadly your provider will not work, and there is no way to create the ZoneId instances you desire with those names.

一旦你考虑使用ZoneOffset而不是ZoneId(并且鉴于军事区域是固定的偏移,这是查看问题的好方法),解析问题是可溶的.

关键是DateTimeFormatterBuilder.appendText(TemporalField, Map)允许使用您选择的文本格式化数字字段并将其解析为文本的方法.并且ZoneOffset是一个数字字段(值是偏移中的总秒数).

我这个例子中,我设置的映射Z,A以及B,但你需要添加他们.否则,代码非常简单,设置一个格式化程序,可以打印和解析军事时间(OffsetDateTime用于日期和时间).

Map<Long, String> map = ImmutableMap.of(0L, "Z", 3600L, "A", 7200L, "B");
DateTimeFormatter f = new DateTimeFormatterBuilder()
    .appendPattern("HH:mm")
    .appendText(ChronoField.OFFSET_SECONDS, map)
    .toFormatter();
System.out.println(OffsetTime.now().format(f));
System.out.println(OffsetTime.parse("11:30A", f));
Run Code Online (Sandbox Code Playgroud)

  • ODT更简单,没有DST问题.它也是标准网络ISO08601格式.否则这些类非常相似.使用最适合你的方法. (2认同)