24

I've been struggling for a while with this piece of code for an Android app and I can't get the hang of it. I've read and tried every solution I found on stackoverflow and other places, but still no luck.

What I want to do is have a function to convert a string like "17.08.2012 05:35:19:7600000" to a UTC date and a function that takes an UTC date and converts it to a string like that.

String value = "17.08.2012 05:35:19:7600000";
DateFormat df = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss:SSSSSSS");
try
{
  Date today = df.parse(value);
  System.out.println("Today = " + df.format(today) + " " + today.toGMTString());
} 
catch (ParseException e)
{
  e.printStackTrace();
}

This results in : Today = 17.08.2012 07:41:59:0000000 17 Aug 2012 04:41:59 GMT which are both wrong.

I tried setting SDF's timezone to UTC, no luck.
Another thing that I noticed: if I do df.setLenient(false);
It gives me : java.text.ParseException: Unparseable date: "17.08.2012 05:35:19:7600000" .

If anyone can provide me with some explanations / sample code, I would be very grateful. Thanks in advance

Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
Rhadoozooz
  • 243
  • 1
  • 2
  • 6

5 Answers5

25

The result you are getting is absolutely right.

Let's analyze this:

17.08.2012 05:35:19:7600000
  • 17: Day of month (17th)
  • 08: Month of year (August)
  • 2012: Year (2012)
  • 05: Hour of day (5am)
  • 35: Minute of hour (:35)
  • 19: Second of minute (:19)
  • 7600000: Milliseconds of second (7,600,000)

Now, the way the VM sees this is that you are declaring the time of day as 5:35:19am, then adding 7,600,000 milliseconds to it. 7,600,000 milliseconds = 7,600 seconds = 2 hours, 6 minutes, 40 seconds. 5:35:19am + 02:06:40 = 7:41:59am (and 0 milliseconds). This is the result you are getting. (It also appears that you are not setting the timezone properly, so the GMT string is 3 hours behind your result.)

If you want to retain the :7600000, to my knowledge this is not possible. As this can be simplified into seconds, the VM will automatically reduce it into the other time increments. The milliseconds (the SSSS) should be for storing values <1000.

I'd suggest you create a new SimpleDateFormat for your output; but remember that the milliseconds will be absorbed into the other times (since they are all stored as a single long in the Date object).

Cat
  • 66,919
  • 24
  • 133
  • 141
  • Thank you! After setTimeZone(TimeZone.getTimeZone("UTC")) all got ok. As about the milliseconds, I think I'll just reset them to 0. Don't think that it matters in my case. The example I gave was a response from a server, as a UTC now time, I'll have to see why does it return those milliseconds. – Rhadoozooz Aug 17 '12 at 06:42
  • Glad you've figured out the issue! Good luck! :) – Cat Aug 17 '12 at 06:43
6
    private String convertDate(String cdate)
{
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss:SSSSSSS");
    SimpleDateFormat postFormater = new SimpleDateFormat("yyyy-MM-dd");
    Date convertedDate;
    try
    {
        convertedDate = dateFormat.parse(cdate);
        cdate = postFormater.format(convertedDate);
    }
    catch (ParseException e)
    {
        Toast.makeText(getApplicationContext(),e.toString(),Toast.LENGTH_SHORT).show();
    }
    return cdate;
}

Try this.

Rajesh Rajaram
  • 3,271
  • 4
  • 29
  • 48
6

This is what you need (but it will loose millisecond information):

"dd.MM.yyyy HH:mm:ss.'000000'"

If you used "dd.MM.yyyy HH:mm:ss.SSSSSS", then would get three leading zeros for your milliseconds.

If you used "dd.MM.yyyy HH:mm:ss.SSS'000'", then you could format a date, but not parse any date.

Try it out:

public static void main(String[] args) throws ParseException {
    printDate("dd.MM.yyyy HH:mm:ss.SSS");//02.05.2010 21:45:58.073
    printDate("dd.MM.yyyy HH:mm:ss.SSSSSS");//02.05.2010 21:45:58.000073
    printDate("dd.MM.yyyy HH:mm:ss.SSS'000'");//02.05.2010 21:45:58.073000
    printDate("dd.MM.yyyy HH:mm:ss.'000000'");//02.05.2010 21:45:58.000000

    tryToParseDate("dd.MM.yyyy HH:mm:ss.SSS");//good
    tryToParseDate("dd.MM.yyyy HH:mm:ss.SSSSSS");//good
    tryToParseDate("dd.MM.yyyy HH:mm:ss.SSS'000'");//bad
    tryToParseDate("dd.MM.yyyy HH:mm:ss.'000000'");//good
}

private static void printDate(String formatString) {
    Date now = new Date();
    SimpleDateFormat format = new SimpleDateFormat(formatString);
    String formattedDate = format.format(now);

    // print that date
    System.out.println(formattedDate);
}

private static void tryToParseDate(String formatString) {
    Date now = new Date();
    SimpleDateFormat format = new SimpleDateFormat(formatString);
    String formattedDate = format.format(now);

    // try to parse it again
    try {
        format.parse(formattedDate);
        System.out.println("good");
    } catch (ParseException e) {
        System.out.println("bad");
    }
}
slartidan
  • 20,403
  • 15
  • 83
  • 131
1

To drop the nanoseconds, use:

new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.")
Henry
  • 2,870
  • 1
  • 25
  • 17
0

Update: java.time

The Question and other Answers use terrible date-time classes that are now legacy. These flawed classes were years ago supplanted by the modern java.time classes defined in JSR 310. Avoid Calendar, DateFormat, Date, etc.

Define a formatting pattern with DateTimeFormatter.

String input = "17.08.2012 05:35:19:7600000";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd.MM.uuuu HH:mm:ss:SSSSSSS" );

Parse.

LocalDateTime ldt = LocalDateTime.parse( input , f ) ;

A LocalDateTime object represents a date with a time of day, but lacks the context of a time zone or offset from UTC.

If you are certain the input text is intended to represent a moment as seen in UTC, having an offset of zero hours-minutes-seconds, then assign a ZoneOffset to produce an OffsetDateTime object.

OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;

See this code run live at Ideone.com.

ISO 8601

I suggest you educate the publisher of your data about the use of ISO 8601 standard formats when serializing date-time values to text.

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

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154