Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Date object SimpleDateFormat not parsing timestamp string correctly in Java (Android) environment

I'm using the SimpleDateFormat object with the Date object as shown below. The problem lis that the Date object shows the wrong date, which is a few minutes off from the original string. The Date object appears to store the time in total milliseconds in the debugger.

Any ideas on the problem?

import java.text.SimpleDateFormat;

import java.util.Date;

Date played_at_local; 

dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSSSSZ");

played_at_local = dateFormat.parse("2011-04-11T22:27:18.491726-05:00"); 

//played_at_local shows "Mon Apr 11 22:35:29 America/Chicago 2011" in debugger
like image 571
Chirag Patel Avatar asked Apr 12 '11 14:04

Chirag Patel


People also ask

How do I change date format in SimpleDateFormat?

String date_s = " 2011-01-18 00:00:00.0"; SimpleDateFormat dt = new SimpleDateFormat("yyyyy-mm-dd hh:mm:ss"); Date date = dt. parse(date_s); SimpleDateFormat dt1 = new SimpleDateFormat("yyyyy-mm-dd"); System. out. println(dt1.

How do you change date format to MM DD YYYY in Java?

String pattern = "MM-dd-yyyy"; SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern); String date = simpleDateFormat. format(new Date()); System. out. println(date);

Is SimpleDateFormat deprecated?

Class SimpleDateFormat. Deprecated. A class for parsing and formatting dates with a given pattern, compatible with the Java 6 API.

What can I use instead of SimpleDateFormat?

DateTimeFormatter is a replacement for the old SimpleDateFormat that is thread-safe and provides additional functionality.


3 Answers

Try this, working for me Z should be useed in date, or rmove from Format String

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSSSS'Z'");

played_at_local = dateFormat.parse("2011-04-11T22:27:18.491726Z-05:00");
like image 36
Imran Avatar answered Oct 08 '22 22:10

Imran


Try removing the fractional seconds from the format string. I just ran into the same issue, but with a slightly different format. My input format wasn't in ISO format (no "T", and no "Z"), but the symptom was the same -- time was off by some random number of minutes and seconds, but everything else was fine. This is what my log results looked like:

When using the fractional second format:

SimpleDateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");

# Parsed date: 2011-05-27 17:11:15.271816 => Fri May 27 17:15:46 EDT 2011
# Parsed date: 2011-05-27 17:09:37.750343 => Fri May 27 17:22:07 EDT 2011
# Parsed date: 2011-05-27 17:05:55.182921 => Fri May 27 17:08:57 EDT 2011
# Parsed date: 2011-05-27 16:55:05.69092 => Fri May 27 16:56:14 EDT 2011
# Parsed date: 2011-05-27 16:38:35.50348 => Fri May 27 16:39:25 EDT 2011

I fixed it by removing the fractional seconds from the format.

SimpleDateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

# Parsed date: 2011-05-27 17:11:15.271816 => Fri May 27 17:11:15 EDT 2011
# Parsed date: 2011-05-27 17:09:37.750343 => Fri May 27 17:09:37 EDT 2011
# Parsed date: 2011-05-27 17:05:55.182921 => Fri May 27 17:05:55 EDT 2011
# Parsed date: 2011-05-27 16:55:05.69092 => Fri May 27 16:55:05 EDT 2011
# Parsed date: 2011-05-27 16:38:35.50348 => Fri May 27 16:38:35 EDT 2011

What I think is happening is that my "fractional seconds" part of the input string is too long (the same is true in the OP example). It appears to be expecting only three decimal places. If you do the math (take the first example):

  • fractional seconds = 0.271816 seconds
  • What DateFormat sees is 271816 / 1000 of a second
  • 271816 / 1000 == 271 seconds
  • 271 / 60 = 4 minutes
  • 271 % 60 = 31 seconds
  • 17:11:15 to 17:15:46 is exactly 4 minutes, 31 seconds off
like image 110
Joe Avatar answered Oct 08 '22 22:10

Joe


There are three major problems in your code:

  1. You have used .SSSSSS for the fraction of a second whereas the SimpleDateFormat does not support a precision beyond milliseconds (.SSS). It also means that you need to limit the digits in the fraction of a second to three.
  2. You have used Z to parse the timezone offset, -05:00 whereas the correct pattern for this is XXX.
  3. You have used hh for a time in 24-Hour format whereas the correct pattern for this is HH. The symbol, hh is used for a time in 12-Hour (i.e. with am/pm) format.

Apart from this, I recommend you always use Locale with a date parsing/formatting API because parts of a date-time string are represented in different ways in different Locales.

Demo:

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

public class Main {
    public static void main(String[] args) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
        Date date = sdf.parse("2011-04-11T22:27:18.491-05:00");

        // Print the default string i.e. Date#toString
        System.out.println(date);

        // Print the date-time in a custom format
        sdf.setTimeZone(TimeZone.getTimeZone("GMT-05:00"));
        System.out.println(sdf.format(date));
    }
}

Output:

Tue Apr 12 04:27:18 BST 2011
2011-04-11T22:27:18.491-05:00

Some facts about legacy date-time API:

  1. The java.util.Date object is not a real date-time object like the modern date-time types; rather, it represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). When you print an object of java.util.Date, its toString method returns the date-time in the JVM's timezone, calculated from this milliseconds value. If you need to print the date-time in a different timezone, you will need to set the timezone to SimpleDateFormat and obtain the formatted string from it.
  2. The java.util date-time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API* .

Using modern date-time API:

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        OffsetDateTime odt = OffsetDateTime.parse("2011-04-11T22:27:18.491726-05:00");

        // Print the default string i.e. OffsetDateTime#toString
        System.out.println(odt);

        // Print the date-time in a custom format. Note: OffsetDateTime#toString drops
        // seconds if it is zero
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSSSSXXX");
        System.out.println(dtf.format(odt));
    }
}

Output:

2011-04-11T22:27:18.491726-05:00
2011-04-11T22:27:18.491726-05:00

Note: For DateTimeFormatter, the symbol, u means year whereas the symbol, y means year-of-era. It doesn't make any difference for a year in the [AD][2] era, but it matters for a year in the BC era. Check this answer to learn more about it.

Learn more about the modern date-time API from Trail: Date Time.


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

like image 37
Arvind Kumar Avinash Avatar answered Oct 08 '22 20:10

Arvind Kumar Avinash