Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

When Parsing/Formatting Dates in Java, Make Sure You Don't Rely on the Default Behavior

4.68/5 (8 votes)
5 Jun 2017CPOL4 min read 16.8K  
If you have a string of date/time without time zone information, you can have unexpected results due to Java default time zone.

Introduction

Java is very complacent. It often tries to save a developer from extra key presses by providing default values. Sometimes, it leads to undesired behavior.

Problem

Imagine in your application you have the "1970-01-01 00:00:00" time string received in a JSON response from a service. The time is a time of a certain event, let's say this is a time of registration for a certain user. The thing is that given only the above string, you can say nothing about when the event actually happened. This is easy to check with the next code snippet:

Java
import java.text.ParseException;
import java.text.SimpleDateFormat;

public class Main {
    
    public static void main(final String[] args) throws ParseException {
        final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(format.parse("1970-01-01 00:00:00").getTime());
    }
}

Expected output is 0 as the user in our example registered exactly at the epoch time and getTime() returns the number of milliseconds since the epoch. However on my PC (which is currently in Riga), the output is -7200000 (i.e., 2 hours before epoch). And if you live in Los Angeles, the output will be 28800000 (i.e., 8 hours after epoch). What does it mean? Does the time of an event really depend on where we read it? Fortunately, no.

Cause

The problem is that when you have the "1970-01-01 00:00:00" string, you have only partial information about the time of the event, namely you don't know in which time zone the time of the event was recorded. And Java doesn't know either. So it "kindly" treats the event time in the default time zone. The default time zone for a Java application is the time zone of the platform the JVM is running on. For my PC it is "Europe/Helsinki" so I see one result. For the PC in Los Angeles, time zone will be likely "America/Los_Angeles", so there another output will be observed.

Solution

Whenever you parse a time string, you should always take into consideration the time zone for which this time string is specified. Sometimes, the string already contains the time zone information. But if no, it is quite a bad idea to let Java make the assumption. Better to find in the documentation of a service from where you received the string in which time zone the service provides dates and then specify this time zone explicitly every time parsing is performed. In the ideal world, every service which provides dates should default to UTC, but unfortunately some developers don't implement this best practice.

For the above case with the user, the next code will print the same result for every location, as expected:

Java
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
    
public class Main {
    
    public static void main(final String[] args) throws ParseException {
        final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        format.setTimeZone(TimeZone.getTimeZone("UTC"));
        System.out.println(format.parse("1970-01-01 00:00:00").getTime());
    }
}

Strictly speaking, UTC is not a time zone, but a time standard. It may be convenient to think about UTC as about a huge clock somewhere in the middle of the Universe, so for anyone in any place of the Universe (including our Earth), they show the same time which, obviously, stays the same also at summer/winter. Why UTC is considered as a timezone in Java (and not only there) — it's a different question and a reason for another article. For now to be more accurate, we can assume that whenever we speak about UTC as a time zone, we assume that "UTC" in this context means "any time zone which always has the same time as that huge UTC clock in the middle of the Universe".

Summary

To summarize, whenever you deal with strings which contain date/time information:

  1. Try to avoid parsing/formatting in your application. In case of JSON, you can request date as a number of milliseconds. In this case, parsing is not needed at all. Although the disadvantage of this approach is that it's not human-readable.
  2. If the parsing is needed, make sure the string contains the time zone information and you consider it during parsing, e.g., the string you receive is like "1970-01-01 00:00:00 UTC" and the pattern you use for parsing is "yyyy-MM-dd HH:mm:ss Z".
  3. If the parsing is needed and no time zone information is contained in the string, check the documentation (or implementation) of the service which provides the time string and find in which time zone one is provided. Make sure every time you deal with parsing/formatting, you specify the time zone explicitly (like in the example above).
  4. Alternatively, instead of specifying explicitly, you can run JVM with the parameter which overrides the time zone with the required one, e.g. -Duser.timezone=UTC, or even set default timezone globally for your application: 
    Java
    TimeZone.setDefault(TimeZone.getTimeZone("UTC"))
    Of course, you can change your platform time zone to one which the service uses, but that's far not the best solution: if this is a local PC, then why not to use the proper time zone of the city you're living in; if it is a server, it's recommended to use UTC timezone always. Moreover, there is a possibility that one day your application will be running on another platform where there's another time zone.
  5. If nothing is specified in the documentation of a service, assume the time strings are provided in UTC time zone. Here, it would be useful to contact the developers of the service and make sure they follow the best practice to provide times in UTC.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)