I found a java.time bug recently. it is very easy to reproduce it;
I tested it on JDK 17.0.10 and JDK 21.0.4 on MacOS X and Centos Stream 9
Code as:
public class JakartaDateTime {
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy");
LocalDateTime now = LocalDateTime.now();
System.out.println(formatter.format(now));
}
This code will print a string
Fri Sept 06 23:10:23 2024
Sure,it is not I expected, the expected result should be:
Fri Sep 06 23:10:23 2024
I had report it as a bug to java bug report and Oracle bug database ID: 9077542. Im sure it will not be fixed soon. So I have to find out a work around to avoid it.
I’m trying to use gson to map a income json to our java class, json object key/value pair as:
{"date":"Fri Sep 06 23:10:23 2024"}
so, I have to code a deserialiser to pars that string to java.time.LocalDateTime. I did some thing like this:
public class EuDateTimeDeserializer implements JsonDeserializer<LocalDateTime> {
@Override
public LocalDateTime deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
String dateTimeStr =jsonElement.getAsString();
if(!ThssUtils.isValidString(dateTimeStr)){
return null;
}else {
return LocalDateTime.parse(dateTimeStr, DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy"));
}
}
}
But this deserialiser only works on other months than September.
throws error as:
java.time.format.DateTimeParseException: Text 'Fri Sep 6 15:42:12 2024' could not be parsed at index 4
That means, the deserialiser not recognise above string.
Does any one have this experience to find out a work around to avoid previous java.time bug?
Please advise!
>Solution :
tl;dr
Not a bug. Specify Locale.
DateTimeFormatter.ofPattern( … ).withLocale( locale )
Feature, not a bug
While you neglected to mention exactly what you consider to be a "bug", I presume you mean the missing t in Sept vs Sep.
Localization
The spelling, abbreviation, and punctuation in date-time formatting depends on a Locale. The human language and cultural norms contained in a Locale object control the process of [localization][1].
Specify a Locale
Here we specify English in United States. We get Sep.
LocalDateTime ldt = LocalDateTime.of( 2024 , Month.SEPTEMBER , 6 , 23 , 10 , 23 , 0 );
System.out.println( "ldt = " + ldt );
Locale locale = Locale.of( "en" , "US" );
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "EEE MMM dd HH:mm:ss yyyy" ).withLocale( locale );
String output = formatter.format( ldt );
System.out.println( "output = " + output );
ldt = 2024-09-06T23:10:23
output = Fri Sep 06 23:10:23 2024
Change that locale to English in Australia. We get Sept.
Locale locale = Locale.of( "en" , "AU" );
ldt = 2024-09-06T23:10:23
output = Fri Sept 06 23:10:23 2024
Please retract your faulty bug report.
Tip: Always suspect your own code, or your own misunderstanding, before doubting a library bundled with Java. Yes, a bug could creep into the the codebase of an implementation of Java. But bugs like your allegation here is rare. The [OpenJDK][2] code base used for most implementations of Java is some of the most thoroughly examined and tested code ever produced outside of specialties such as military & aerospace.
Avoid LocalDateTime.now
By the way, your code calls LocalDateTime.now. I cannot imagine a scenario where that is the smart thing to do.
A LocalDateTime object represens a date with a time-of-day but lacks the context of an offset-from-UTC or a time zone. Without that context, we have no way to know if you meant 11 PM in Toowoomba Australia, 11 PM in Toulouse France, 11 PM in Toledo Ohio US — three very different moments, several hours apart.
To capture the current moment, use one of the three classes that track a specific point on the timeline:
InstantOffsetDateTimeZonedDateTime
The first and third are most common for business purposes, while the second is used mainly for exchange with a SQL database.
Instant now = Instant.now() ; // Capture current moment as seen "in UTC", meaning an offset from UTC of zero hours-minutes-seconds.
See that same moment through the wall-clock/calendar of a particular time zone.
ZoneId z = ZoneId.of( "Australia/Brisbane" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
[1]: https://en.wikipedia.org/wiki/Internationalization_and_localization
[2]: https://en.wikipedia.org/wiki/OpenJDK