String-Date conversion with nanoseconds
Asked Answered
A

5

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

Atilt answered 17/8, 2012 at 6:16 Comment(0)
D
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).

Dielectric answered 17/8, 2012 at 6:25 Comment(2)
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.Atilt
Glad you've figured out the issue! Good luck! :)Dielectric
U
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.

Uncial answered 17/8, 2012 at 6:22 Comment(0)
D
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");
    }
}
Directorate answered 12/5, 2015 at 15:56 Comment(0)
D
1

To drop the nanoseconds, use:

new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.")
Delinquent answered 10/3, 2020 at 17:46 Comment(1)
is it possible to ignore the nanoseconds but to include the timezone in a string like this: 2020-12-15T15:40:15.000000ZUnmeant
P
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.

Popovich answered 30/8, 2022 at 15:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.