How to convert String to Date Example in Java Multithreading

Data type conversion is one of the most common tasks in programming and a good programmer must know how to convert one type to another type. There are many times when you will be required to convert a String to java.util.Date object mostly in different format e.g. dd-MM-yy or yyyy-MM-dd or simply yyyy MM dd. For example, client pass dates as String to Server or sometimes we read Date related data from CSV file. Java provides API for parsing String to date using DateFormat class, though Java's Date and Time API is severely criticized, it is also the most used Date and Time format solution. Though Joda Date and Time API is always there and now Java 8 also got new date and time API, many of us don't have the luxury to use it in production. Many enterprise application is still running on Java 5 and Java 6, forget about JDK 7 or 8.

It may take another 5 year before you start using lambda expressions and Stream API. Apart from several design mistake of Date class e.g. mutability, not intuitive, most obvious problem with formatting date in Java is SimpleDateFormat not being thread-safe.

That's why I wrote this post to show how to convert String to Date correctly in Java multi-threading environment. There are mainly two ways to use SimpleDateFormat properly in concurrent application, either synchronize the access to DateFormat object or use ThreadLocal variable.

Earlier we have see how to make SimpleDateFormat thread-safe, and in this tutorial, we will learn how to use synchronized keyword for making DateFormat thread-safe.





String to Date Example in Java Multithreading

Date to String conversion in Java Multi-threading
Here is complete example of converting String to Date on a Multi-threading Java Program. In this program, I have created a nested static class DateUtils, which holds a static final DateFormat object. Here we have created a method called toDate() which return a date object when we pass String to it. This DateFormat object is created with pattern "dd/MM/yyy", you can choose any format as you like, please refer to cheat sheet given in this blog post to see various date formatting options.

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
* String to Date Example in Java Multi-threading. In single threaded environment
 * converting String to date is easy because you can use SimpleDateFormat
* class without worrying. * * @author Javin Paul */ public class DateToStringDemo{ public static class DateUtils { private static final DateFormat format = new SimpleDateFormat("dd/MM/yyyy"); public static synchronized Date toDate(String date) throws ParseException { return format.parse(date); } } public static void main(String args[]) { // One example, long dates String string = "February 6, 2014"; Date date; try { date = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH).parse(string); System.out.println(date); // Thu Feb 06 00:00:00 IST 2014 } catch (ParseException e) { e.printStackTrace(); } // Another example, date in MM/dd/yyyy format String source = "01/09/2014"; try { date = new SimpleDateFormat("MM/dd/yyyy").parse(source); System.out.println(date); // Thu Jan 09 00:00:00 IST 2014 } catch (ParseException e) { e.printStackTrace(); } // One more String to Date Example in 04 JAN 2014 20:30 String birthday = "04 JAN 2014 20:30"; try { date = new SimpleDateFormat("dd MMM yyyy HH:mm").parse(birthday); System.out.println(date); // Sat Jan 04 20:30:00 IST 2014 } catch (ParseException e) { e.printStackTrace(); } // Remember "m" and "M" are different String weddingday = "30-01-2011"; try { date = new SimpleDateFormat("dd-mm-yyyy").parse(weddingday); System.out.println(date); //Sun Jan 30 00:01:00 IST 2011 } catch (ParseException e) { e.printStackTrace(); } // calling synchronized method to convert String to date try { Date mydate = DateUtils.toDate("04/02/2014"); System.out.println(mydate); //Tue Feb 04 00:00:00 IST 2014 } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } Output: Thu Feb 06 00:00:00 IST 2014 Thu Jan 09 00:00:00 IST 2014 Sat Jan 04 20:30:00 IST 2014 Sun Jan 30 00:01:00 IST 2011 Tue Feb 04 00:00:00 IST 2014


As I said, In multithreading, your String to date conversion logic must be thread-safe. You have two options, you can either synchronize it or use SimpleDateFormat as threadlocal variable. Here is what  we have done by using synchronized keyword:

public static class DateUtils {

        private static final DateFormat format = new SimpleDateFormat("dd/MM/yyyy");

        public static synchronized Date toDate(String date) throws ParseException {
            return format.parse(date);
        }
 }

When you pass an incorrect date to this toDate() method, you will see following Exception in your console.

// spelling mistake, should be February instead of Febrauary, see additional 'a'
java.text.ParseException: Unparseable date: "Febrauary 6, 2014"
   at java.text.DateFormat.parse(DateFormat.java:357)
   at Testing.main(Testing.java:19)



Here is another common example of passing incorrect date String which is not in expected format and cannot be converted to date.

// the date passed was "02/06/2014", which was not in expected format 
// e.g. dd MMM yyyy HH:mm, should
// be 04 JAN 2014 20:30
java.text.ParseException: Unparseable date: "02/06/2014"
               at java.text.DateFormat.parse(DateFormat.java:357)
               at Testing.main(Testing.java:39)


Date to String - Things to remember :


1) Long time ago, one developer asked me, instead of compromising performance by using synchronized block, why not just use DateFormat as local variable. Important point to note is that creating DateFormat every time is  very expensive, it will be overkill for an application which need to convert millions of String to Date e.g. an Order processing engine, which receives millions of orders.


2) Sharing same DateFormat object between multiple thread can also result in unexpected result. For example, you may end up a completely different date then the expected value, or you will be greeted by java.lang.ArrayIndexOutOfBoundsException or java.lang.NumberFormatException.


3) There are multiple way to correctly use DateFormat in multi-threading Java applications, which includes using SimpleDateFormat as ThreadLocal or properly synchronizing excess to DateFormat object. I suggest to use ThreadLocal approach for core Java application, which is not running on managed environment like Web server or application Server. Since managed environment manages essential service on behalf of application e.g. Thread pools, their is a chance that their thread outlived application itself, which can create ThreadLocal memory leaks in Java.


4) Another mistake to avoid while using DateFormat in multithreading environment is, storing them in static variable. When programmer comes to know that creating DateFormat locally, every time you need to convert String to Date is very time and memory consuming, they usually create a global DateFormat object and store them as static variable. Though that solves their memory and performance issue, by only using one instance of DateFormat object, it introduce more subtle concurrency bugs in application, due to shared  and unprotected access of a non-thread object. Remember, DateFormat is not threadsafe in Java.

5) Apart from thread-safety issue, String to date conversion process also faces subtle mistakes on formatting options, mainly  due to lack of good knowledge of formatting characters explained in Javadoc. Remember even same character in different case result in totally different meaning, which may result in "java.text.ParseException: Unparseable date" error. One of those is using "m" as Month, which is actually stands for minuets. For example following date format "dd-mm-yyyy" is incorrect and will result in different meaning, when passed a date like 30-01-2011 e.g. 01 will be minutes.

6) Have various Date format options handy, a cheat sheet image is not bad at all.
G   Era designator       Text               AD
y   Year                 Year               1996; 96
M   Month in year        Month              July; Jul; 07
w   Week in year         Number             27
W   Week in month        Number             2
D   Day in year          Number             189
d   Day in month         Number             10
F   Day of week in month Number             2
E   Day in week          Text               Tuesday; Tue
u   Day number of week   Number             1
a   Am/pm marker         Text               PM
H   Hour in day (0-23)   Number             0
k   Hour in day (1-24)   Number             24
K   Hour in am/pm (0-11) Number             0
h   Hour in am/pm (1-12) Number             12
m   Minute in hour       Number             30
s   Second in minute     Number             55
S   Millisecond          Number             978
z   Time zone            General time zone  Pacific Standard Time; PST; GMT-08:00
Z   Time zone            RFC 822 time zone  -0800
X   Time zone            ISO 8601 time zone -08; -0800; -08:00


That's all on how to convert String to Date in Java. As I said parsing String to Date in Java is very simple in single threaded program,  but you have to be careful while doing this in multi-threaded Java program because SimpleDateFormat is not thread-safe. You can use any of synchronization mechanism we have discussed in this article, but prefer ThreadLocal variable over synchronized keyword because of performance reason. Cost of synchronization is much higher than maintaining separate copy for each thread. Another thing you should remember while creating Date from String is to remember various Date format options e.g. many people make mistake between 'm' and 'M', where m is for minute of hour while M is for month of year. By the if you are using Java 8, consider using new Date and Time API for converting String to Date. There is no point using old date API if you already moved to JDK 8.

7 comments:

  1. just like d is for date and D is for Day, Similaryl m is for "minute in a hour" and M is for "month in a year", good source of silly mistakes

    ReplyDelete
  2. Interresting usage of the synchronised keyword but you are bottlenecked in the case of severall threads.

    Have you ever consider using the DateTimeFormat adhoc replacement in org.joda.time library ?

    ReplyDelete
    Replies
    1. I think that's a very good option if you don't mind an additional step from converting to joda time LocalDate to java.util.Date. It's thread-safe and easy to use.

      Delete
  3. > How to convert String to Date Example in Java Multithreading ?
    pre java 8 : the safer, simpler option is joda time.

    ReplyDelete
    Replies
    1. In fact for all your date needs one should use joda time, not just formatting e.g. their LocalDate class is better than Date and Joda also has useful Instant, Duration classes to calcualte differnece between two dates e.g. how many days to Christmas, or New Year. On Java 8, yes, you can use java Date and time API but before that, go for Joda.

      Delete
  4. ThreadLocal for your SimpleDateFormat is a better solution.

    ReplyDelete
    Replies
    1. Indeed, and I think that is the most legitimate and natural use of ThreadLocal variable in Java. SimpleDateFormat + ThreadLocal rocks!!

      Delete