0
0

Joda-Timeとjava.timeでは書式文字列が同じでもパース結果が異なる場合がある

Last updated at Posted at 2023-09-25

この挙動でバグらせてしまったので、供養のために書いておきます。

Joda-Timeは書式文字列で指定した桁数以下でもパースできる

yyyy/MM/dd HH:mmという書式文字列で解析するとします。java.timeでは2023/9/1 8:1みたいな文字列は解析できません。MHなどの文字数は最低桁数として解釈されます。

@ import java.time._, java.time.format._ 
import java.time._, java.time.format._

@ LocalDateTime.parse("2023/09/01 08:01", DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm")) 
res6: LocalDateTime = 2023-09-01T08:01

@ LocalDateTime.parse("2023/9/1 8:1", DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm")) 
java.time.format.DateTimeParseException: Text '2023/9/1 8:1' could not be parsed at index 5
  java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2052)
  java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1954)
  java.time.LocalDateTime.parse(LocalDateTime.java:494)
  ammonite.$sess.cmd7$.<clinit>(cmd7.sc:1)

一方、Joda-Timeでは解析できます。

@ import $ivy.`joda-time:joda-time:2.12.5`  
import $ivy.$                            

@ import org.joda.time._, org.joda.time.format._ 
import org.joda.time._, org.joda.time.format._

@ DateTime.parse("2023/09/01 09:07", DateTimeFormat.forPattern("yyyy/MM/dd HH:mm")) 
res3: DateTime = 2023-09-01T09:07:00.000+09:00

@ DateTime.parse("2023/9/1 9:7", DateTimeFormat.forPattern("yyyy/MM/dd HH:mm")) 
res4: DateTime = 2023-09-01T09:07:00.000+09:00

JavaDocを読む

比較しやすい様に英語で比べてみます。

java.time

Number: If the count of letters is one, then the value is output using the minimum number of digits and without padding. Otherwise, the count of digits is used as the width of the output field, with the value zero-padded as necessary. The following pattern letters have constraints on the count of letters. Only one letter of 'c' and 'F' can be specified. Up to two letters of 'd', 'H', 'h', 'K', 'k', 'm', and 's' can be specified. Up to three letters of 'D' can be specified.

文字の数は最小桁数になる、と書いてあります。

Joda-Time

Number: The minimum number of digits. Shorter numbers are zero-padded to this amount. When parsing, any number of digits are accepted.

解析する場合は、どんな数字でも受け付けると書いてあります。つまり、解析の際は文字の数は関係ないみたいですね。

まとめ

JavaDocをよく読むと

  • java.timeは、文字数は最小桁数として解釈
  • Joda-Timeは、文字数は関係なく数字として解釈

することがわかります。これらを考慮して、Joda-Timeにてyyyy/MM/dd HH:mmとして受け取っていた文字列をjava.timeで受け取る様にするためにはy/M/d H:mという書式文字列にする必要があります。

@ import java.time._, java.time.format._ 
import java.time._, java.time.format._

@ LocalDateTime.parse("2023/09/01 08:01", DateTimeFormatter.ofPattern("y/M/d H:m")) 
res12: LocalDateTime = 2023-09-01T08:01

@ LocalDateTime.parse("2023/9/1 8:1", DateTimeFormatter.ofPattern("y/M/d H:m")) 
res13: LocalDateTime = 2023-09-01T08:01

ちなみに、この文字列であれば、Joda-Timeでも同様に解析できます。

@ import $ivy.`joda-time:joda-time:2.12.5`  
import $ivy.$                            

@ import org.joda.time._, org.joda.time.format._ 
import org.joda.time._, org.joda.time.format._

@ DateTime.parse("2023/9/01 9:7", DateTimeFormat.forPattern("y/M/d H:m")) 
res14: DateTime = 2023-09-01T09:07:00.000+09:00

@ DateTime.parse("2023/09/01 09:07", DateTimeFormat.forPattern("y/M/d H:m")) 
res15: DateTime = 2023-09-01T09:07:00.000+09:00
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0