3
String s = 19.17.38.008000;
DateFormat f = new SimpleDateFormat("HH.mm.ss.SSSSSS");
Date d = f.parse(s);
system.out.println(d);

this is the code I am running it runs fine except when it prints it prints the time 19:17:46. Please someone explain this to me

As a side note:

String s = 19.17.38.008000;
DateFormat f = new SimpleDateFormat("HH.mm.ss");
Date d = f.parse(s);
system.out.println(d);

this code will print the same string correctly minus the milliseconds. Someone please tell me what I am missing here.

EDIT: Thanks for the answers I think the issue here is I was reading 38.008000 as .008 seconds but sdf is reading SSS as 8000 milliseconds which are not the same thing.

  • If I am understanding the answers correctly it is ignoring the leading 2 zeros and registering the trailing 3 as 8000 milliseconds and then adding it to the time. Is there a known work around that will display the milliseconds instead of adding them as I am comparing 2 times that will sometimes have up to 6 digits in the milliseconds – crimson_skier Apr 24 '14 at 21:05

3 Answers3

5

The SimpleDateFormat class is interpreting 008000 as 8000 milliseconds, or 8 seconds, and adding it to the 38 seconds already interpreted.

If we had this:

String s = "19.17.38.009000";

Then we would get this output, with 9 seconds added:

Thu Jan 01 19:17:47 PST 1970

Remove the 3 extra zeroes from the end of the string. If there are 6 digits, then they look like they should represent microseconds (millionths of a second), not milliseconds (thousandths of a second).

String s = "19.17.38.008";

Output:

Thu Jan 01 19:17:38 PST 1970
rgettman
  • 176,041
  • 30
  • 275
  • 357
  • I like this answer but I can not change the string itself I am receiving the string from a database and must compare it to another date for exact accuracy to 6 milliseconds. But this answer does explain to me what is happening I just have to figure a way around it. – crimson_skier Apr 24 '14 at 21:17
  • You don't have to change the source of the `String` coming from the database, but you can always remove the last 3 digits after it comes back from the DB -- something like `s = s.substring(0, s.length() - 3);`. – rgettman Apr 24 '14 at 21:20
  • I thought of that but unfortunately that will only work for this exact case I am doing thousands of these and there will be many of them that say .334887 or something without trailing or leading 0's and therefore can not be truncated the same way – crimson_skier Apr 24 '14 at 21:36
  • Then you'll need to determine how many digits there are, and remove the last `numDigits - 3` of them. – rgettman Apr 24 '14 at 21:39
3

SSSSSS is still milli-seconds even if you put 6 of them. 19:17:38 + 008000 ms is 19:17:46 so it correct, if surprising.

AFAIK The java.time library in Java 8 supports micro-second (and nano-second) timestamps.

Thank you @Meno for the corrections.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Thanks all for the help just for clarification on the issue from what everyone is saying. When I read 3.01 seconds I interpret that as 3 sec and 1% of a second. The 'S' in simpleDateFormat represents a full millisecond which is not the same. So 3.33455 interpreted by "s.SSSSS" is the same as saying 3 secons and 33455 milliseconds not 3 seconds and 33.455% of a second. – crimson_skier Apr 24 '14 at 21:26
  • Thanks for the additional info unfortuately this is on a Corporate framework that has not been updated to java 8 yet – crimson_skier Apr 24 '14 at 21:38
  • 1
    @user3570467 There is a backport for Java 7 https://github.com/ThreeTen/threetenbp – Peter Lawrey Apr 24 '14 at 21:44
  • 1
    Correction: The new time library in Java 8 (known as JSR-310) is not in java.util-package, but in java.time-package. And it supports nanosecond precision, not just microsecond precision. – Meno Hochschild Apr 25 '14 at 13:28
0

SimpleDateFormat does not parse beyond milliseconds precision. Also, look at the following description from the documentation (emphasis mine):

Parses text from the beginning of the given string to produce a date. The method may not use the entire text of the given string.

Thus, even though your pattern has six S's, SimpleDateFormat uses only the first three of them i.e.

HH.mm.ss.SSS

In other words, for your string, SimpleDateFormat will give you the same wrong result whether you use HH.mm.ss.SSS or HH.mm.ss.SSSSSS. SimpleDateFormat is full of many such surprises. In order to fix the problem while using SimpleDateFormat, you need to drop three 0s from the end of your string i.e. if you parse 19.17.38.008, SimpleDateFormat will give your the desired result.

Thus, the legacy date-time API (java.util date-time types and their formatting API, SimpleDateFormat) is not only outdated but also error-prone. It is recommended to stop using them completely and switch to java.time, the modern date-time API*.

Demo using modern date-time API:

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String args[]) {
        String s = "19.17.38.008000";
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("HH.mm.ss.SSSSSS", Locale.ENGLISH);
        LocalTime time = LocalTime.parse(s, dtf);
        System.out.println(time);
    }
}

Output:

19:17:38.008

Note that if you try using HH.mm.ss.SSS, for your string, with java.time API, it will throw an exception alerting you that there is something wrong whereas SimpleDateFormat silently parses your string giving you an undesirable result.

Learn more about the 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.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • 1
    To spell out what you said, `HH.mm.ss.SSS` with only three `S` does not help. The result is still Thu Jan 01 19:17:46. The solution is to give up on `SimpleDateFormat` completely. – Ole V.V. May 01 '21 at 16:00
  • @OleV.V. - Yes, the solution is to give up `SimpleDateFormat`. I have mentioned that with `SSS`, the correct result can be obtained only when you drop three `0`s from the end. – Arvind Kumar Avinash May 01 '21 at 16:09