(In Java syntax, not Kotlin)
tl;dr
To reject such inputs, specify a strict resolver style.
DateTimeFormatter
.ofPattern( "uuuuMMddHHmm" )
.withResolverStyle( ResolverStyle.STRICT )
LocalDateTime accepts input when time part of input is 24:00, converting it to next day
Yes, it should do that. What you see is a feature, not a bug.
Using 24:00 on a 00-23 clock means “end of today” which is also “beginning of tomorrow”. So logically:
( 202308102400 = 202308110000 ) -> true
This specific behavior is documented.
24:00 does mean the next day
24:00
means the first moment of the next day. In contrast, 00:00 means the first moment of the specified day.
Conceptually, every day has two midnights, one at the beginning of the day, and one at the end of the day. To avoid this ambiguity, notice that the java.time classes avoid both the term and the concept of “midnight”. Instead the java.time classes focus on the first moment of the day.
Some industries differentiate between the two midnights by using 00:00
& 24:00
. They use the 24:00
notation as a way of saying “at the end of the day today”.
So we see that 202308102400
is the same as 202308110000
. The end of the day today is also the beginning of the day tomorrow.
So the behavior of LocalDateTime
is semantically correct, returning to you the date of the next day along with the time-of-day of 00:00.
See the following code run at Ideone.com
final DateTimeFormatter BASIC_ISO_LOCAL_DATE_TIME = DateTimeFormatter.ofPattern( "uuuuMMddHHmm" ) ;
String input = "202308102400" ;
try {
LocalDateTime ldt = LocalDateTime.parse ( input , BASIC_ISO_LOCAL_DATE_TIME ) ;
System.out.println( "ldt.toString() = " + ldt ) ;
} catch ( DateTimeParseException e ) {
System.out.println( "Yuck. Your input is distasteful. " ) ;
}
ldt.toString() = 2023-08-11T00:00
Check input with String#endsWith
If in your case you are certain the time 24:00
should be rejected, you could simply check tho string input for the presence of 2400
at the end.
if ( input.endsWith( "2400" ) { … }
else { LocalDateTime ldt = LocalDateTime.parse( input ) ; }
Resolver.STRICT
As you eventually found, to make the DateTimeFormatter
object reject inputs with a time of 24:00, set the ResolverStyle
to the enum object STRICT
. Strict mode will tolerate only hours of 00-23.
final DateTimeFormatter STRICT_BASIC_ISO_LOCAL_DATE_TIME =
DateTimeFormatter
.ofPattern( "uuuuMMddHHmm" )
.withResolverStyle( ResolverStyle.STRICT ) ; // <— Reject 2400 as time of day.
Catch DateTimeParseException
to handle such unwelcome inputs.
String input = "202308102400" ;
try {
LocalDateTime ldt = LocalDateTime.parse ( input , STRICT_BASIC_ISO_LOCAL_DATE_TIME ) ;
System.out.println( "ldt.toString() = " + ldt ) ;
} catch ( DateTimeParseException e ) {
System.out.println( "Yuck. Your input is distasteful. " ) ;
}