MotoDave452
MotoDave452

Reputation: 406

Why does Java SimpleDateFormat work on some servers and not others?

Greetings Stack Overflow,

I am running into a strange issue with an application I am implementing for a foreign office located in Athens. When built, the application is a .war file that gets deployed on a Tomcat instance.

Just for some background information, this same application works successfully on several different OS (Ubuntu 12.04, Windows Server 2012 R2, etc.) both in the US and other countries with different Java/Tomcat configurations.

However the OS I am using to install the application for Athens is Windows Server 2008 R2. Installed on this server is Java JRE 1.8.0_111 which is utilized by Tomcat 8.5.4. This server is located in Athens.

Everything works fine with the application except for anywhere I am submitting a date field to my controller methods. When attempting to submit the date string to my controller throughout various different sections of the application, I get the following message:

Failed to convert the value of 'java.lang.String' to required type'java.util.Date'; 
nested exception is java.lang.illegalArgumentException:  Could not parse text 
[7/28/2017 7:00 AM] into any available date input formats.

Keep in mind that when I deploy this application to a Tomcat instance on another server, everything works fine and I do not receive this error message.

In an attempt to get around this error, I decided to change the type of one of my Request Parameters from:

@RequestParam("date") Date date

to

@RequestParam("date") String dateString

I then used Java SimpleDateFormat to convert the String to a Date:

SimpleDateFormat sdf_date = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
String startDate = dateString;
Date date = sdf_date.parse(startDate);

The date string being passed to the above function is:

11/25/2017 12:00 pm

I tested this on several test servers with different OS/Tomcat configurations and it worked like a charm. However when testing on the Windows 2008 R2 server located in Athens I still received an error. I no longer received the above error, but I did receive the following:

java.text.ParseException: Unparseable date: "11/25/2017 12:00 pm"

I am unsure why this same exact Java code would be able to parse the same date using the same SimpleDateFormat pattern on some servers but not others. This seems very strange to me.

Please let me know if you need any additional information and I will be happy to clarify.

Thank you!

EDIT: Screenshot of Server Side Debug on Server in Athens:

enter image description here

'dateString' that is being passed to the controller method

Upvotes: 2

Views: 1902

Answers (2)

Basil Bourque
Basil Bourque

Reputation: 338326

tl;dr

Instant.parse( "2017-11-25T12:00:00Z" ) 

Details

The Answer by Smith is correct.

In addition, three more issues. Addressing these will eliminate your problems of wrestling localized text formats.

Time zones

You are ignoring crucial issue of time zone. If not specified, you are relying implicitly on the JVM’s current default time zone. That default can vary, even during runtime(!), so better to specify explicitly you desired/expected time zone.

Generally best to use UTC unless you have a specific reason.

ISO 8601

The ISO 8601 standard defines practical unambiguous formats for text representing date-time values.

For a moment in the timeline in UTC, use YYYY-MM-DDTHH:MM:SS.SSSSSSSSSZ where the T separates the date portion from the time portion, the Z is short for Zulu and means UTC, and the time uses 24-hour clock (no AM/PM).

Use these standard formats when serializing date-time values to text.

java.time

You are using troublesome old date-time classes that are now legacy, supplanted by the modern java.time classes.

The Instant class represents a moment in the timeline in UTC, similar to java.time.Date except with a resolution of nanoseconds rather than milliseconds.

Instant instant = Instant.now() ;

The java.time classes use ISO 8601 formats by default when parsing/generating strings.

String output = instant.toString() ;

And…

Instant instant = Instant.parse( "2017-01-23T12:34:56Z" ) ;

Perhaps you meant noon on the 25th in a certain time zone rather than in UTC.

LocalDateTime.parse( "2017-11-25T12:00:00" )   // LocalDateTime has no concept of time zone or offset-from-UTC. Not on the timeline. Has no real meaning until assigned a time zone. 
             .atZone( ZoneId.of( "America/New_York" ) )   // Assign a time zone to determine a moment on the timeline, a ZonedDateTime.
             .toInstant()  // Extract a Instant, always in UTC by definition.
             .toString()  // Generate a string in standard ISO 8601 format. 

Upvotes: 1

J Smith
J Smith

Reputation: 147

Greece doesn't use the same am/pm designations as many other countries that speak Latin based languages. Greece instead uses π.µ. and µ.µ. Consequently, when the SimpleDateFormat doesn't receive a locale, it assumes it is the same as the computer running the program.

To fix this, try something such as the below:

SimpleDateFormat sdf_date = new SimpleDateFormat("MM/dd/yyyy hh:mm a",  new Locale("en", "US"));
String startDate = dateString;
Date date = sdf_date.parse(startDate);

This will use the English Language with US locale on this server. You'll still need to make sure this is the format being passed in the input in every scenario though.

Upvotes: 3

Related Questions