9

In various Android projects, I use the following static function to parse dates such as 1900-12-31. Of course, this function should be deterministic - but it turns out it is not. Why?

Normally, it parses the date 2010-10-30, for example, to the correct Date instance holding that value. But I have noticed that when I have an IntentService running at the same time and parsing some dates, this function parses the same date as above to 1983-01-20, which is one of the dates parsed in the IntentService. How can this happen?

public static Date dateFromString(String dateStr) {
    SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
    SimpleDateFormat mDateTimeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault());
    Date dateOut = null;
    try {
        if (dateStr != null) {
            if (dateStr.length() == 7) {
                if (dateStr.startsWith("--")) {
                    dateStr = "0000"+dateStr.substring(1);
                }
            }
            else if (dateStr.length() == 6) {
                if (dateStr.startsWith("-")) {
                    dateStr = "0000"+dateStr;
                }
            }
            else if (dateStr.length() == 5) {
                dateStr = "0000-"+dateStr;
            }
            else if (dateStr.matches("[0-9]{2}\\.[0-9]{2}\\.[0-9]{4}")) {
                dateStr = dateStr.substring(6, 10)+"-"+dateStr.substring(3, 5)+"-"+dateStr.substring(0, 2);
            }
            else if (dateStr.matches("[0-9]{2}\\/[0-9]{2}\\/[0-9]{4}")) {
                dateStr = dateStr.substring(6, 10)+"-"+dateStr.substring(3, 5)+"-"+dateStr.substring(0, 2);
            }
            else if (dateStr.matches("[0-9]{8}")) {
                dateStr = dateStr.substring(0, 4)+"-"+dateStr.substring(4, 6)+"-"+dateStr.substring(6, 8);
            }
            if (dateStr.length() >= 20) {
                String dateTimeStr = dateStr.trim();
                if (dateTimeStr.endsWith("Z")) {
                    dateTimeStr = dateStr.substring(0, dateTimeStr.length()-1)+"+0000";
                }
                if (dateStr.charAt(10) == ' ') {
                    dateTimeStr = dateStr.substring(0, 10)+"T"+dateStr.substring(11);
                }
                try {
                    dateOut = mDateTimeFormat.parse(dateTimeStr);
                }
                catch (Exception e2) {
                    dateOut = mDateFormat.parse(dateStr);
                }
            }
            else {
                dateOut = mDateFormat.parse(dateStr);
            }
        }
    }
    catch (Exception e) {
        dateOut = null;
    }
    return dateOut;
}

Edit: I do the parsing in my Activity's onCreate() where I start an AsyncTask that does the job. In the Activity's onStop(), a background service is started which does the same job. When I close the app (onStop()) and quickly restart it (onCreate()), both seem to be running simultaneously and the error occurrs.

7
  • Just as an experiment, what happens if you make dateFromString synchronized? Commented Jan 14, 2013 at 0:08
  • Firstly, why is the method static and secondly which class is it in? Commented Jan 14, 2013 at 0:10
  • @DiegoBasch Thanks, I will try! But actually, synchronized should by no means be necessary, as it only prevents interference on objects - which are not used here (static). Commented Jan 14, 2013 at 0:44
  • @Squonk Actually, it used to be non-static before. But as it does not operate on any objects, I made it static. The problem also occurred for the non-static method. It is located in MyApp.java which extends Application. Commented Jan 14, 2013 at 0:47
  • @MarcoW. : I think the answer from Dheeraj V.S. probably explains it. The fact SimpleDateFormat is not thread safe is most likely to be the cause of the problem. Commented Jan 14, 2013 at 3:44

1 Answer 1

7

The documentation of SimpleDateFormat says:

SimpleDateFormat is not thread-safe. Users should create a separate instance for each thread.

There you go. Just create the SimpleDateFormat object separately in each thread and pass it to the method.

Sign up to request clarification or add additional context in comments.

2 Comments

He does create a separate instance in each thread, in fact he creates two new instances in every call.
Thank you! I didn't expect the parse() method to have side effects and change some of the class's fields - but in fact the parse() method (which is inherited from the Date class) writes to Date's field calendar. Thus, it's logical that concurrent use of parse() causes problems.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.