SimpleDateFormat cannot parse milliseconds with more than 4 digits

前端 未结 7 695
花落未央
花落未央 2020-12-06 13:20

I want to parse a timestamp, like this - \"2016-03-16 01:14:21.6739\". But when I use the SimpleDateFormat to parse it, I find that it outputs an i

相关标签:
7条回答
  • 2020-12-06 13:34

    If you have to get string as final output why not use format instead of parse

            final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ");
            sf.setTimeZone(TimeZone.getTimeZone("UTC")); 
            Date curDate = new Date();
    
            String outputdate = sf.format(curDate);
            // 2016-03-17 09:45:28.658+0000
            System.out.println(outputdate);
    
            Date strToDate = new Date();
            try {
                strToDate = sf.parse(outputdate);
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            //Thu Mar 17 17:11:30 MYT 2016
            System.out.println(strToDate);
    

    and instead of "yyyy-MM-dd HH:mm:ss.SSSS" use "yyyy-MM-dd HH:mm:ss.SSSZ" check it here https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

    "yyyy-MM-dd'T'HH:mm:ss.SSSZ"    2001-07-04T12:08:56.235-0700
    
    0 讨论(0)
  • 2020-12-06 13:35

    It seems that is not possible to use SimpleDateFormat to express times with a finer grain than the millisecond. What is happening is that as you put 6739, Java understands it as 6739 milliseconds i.e. 6 seconds and 739 milliseconds hence the 6 seconds difference observed.

    Check these ones, it is explained quite well: String-Date conversion with nanoseconds Java date parsing with microsecond or nanosecond accuracy

    0 讨论(0)
  • 2020-12-06 13:35

    As mentioned in the comments above your question already contains the answer: milliseconds must not have more than 3 digits otherwise it represents at least one full second already.

    That your code is working is simply due to a very questionable feature of java.text.SimpleDateFormat, the lenient (see here) option. By default a SimpleDateFormat has setLenient set to true wich means that the parser will try to interpret strings that do not match the pattern 100% and will convert them to date objects by means of some heuristics. For example it will accept a date 31.04.2016 and convert it to 01.05.2016. This feature may be nice in some situations but produces questionable results in most of the cases.

    If you set lenient to false in your code, the date string won't be parsed anymore. Making the error in the pattern more obvious:

    final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS");
    sf.setLenient(false);
    String parsedate="2016-03-16 01:14:21.6739";
    ...
    

    As java.util.Date is not able to represent any precision lower than milliseconds, I think the best option for you to parse your date would be to simply strip of the last digits of your input date, if the part after the dot has more than four digits. Your code might look something like this:

    final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    sf.setLenient(false);
    String parsedate="2016-03-16 01:14:21.6739";
    try {
        // 23 is the length of the date pattern
        if (parsedate.length() > 23) {
            parsedate = parsedate.substring(0, 23);
        }
        Date outputdate = sf.parse(parsedate);
        String newdate = sf.format(outputdate);  //==output date is: 2016-03-16 01:14:21.673
        System.out.println(newdate);
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    

    You could try to add some rounding logic as well in order to not loose all the information of the 4th digit...

    0 讨论(0)
  • 2020-12-06 13:41

    You can use String newdate = sf.format(outputdate); in place of String newdate = outputdate.toString();

    0 讨论(0)
  • 2020-12-06 13:47

    tl;dr

    LocalDateTime.parse(
        "2016-03-16 01:14:21.6739".replace( " " , "T" )  // Comply with ISO 8601 standard format.
    )
    

    Milliseconds versus Microseconds

    As others noted, java.util.Date has millisecond resolution. That means up to 3 digits of a decimal fraction of second.

    You have 4 digits in your input string, one too many. Your input value demands finer resolution such as microseconds or nanoseconds.

    java.time

    Instead of using the flawed, confusing, and troublesome java.util.Date/.Calendar classes, move on to their replacement: the java.time framework built into Java 8 and later.

    The java.time classes have a resolution of nanosecond, up to nine digits of decimal fraction of a second. For example:

    2016-03-17T05:19:24.123456789Z

    ISO 8601

    Your string input is almost in standard ISO 8601 format used by default in java.time when parsing/generating textual representations of date-time values. Replace that space in the middle with a T to comply with ISO 8601.

    String input = "2016-03-16 01:14:21.6739".replace( " " , "T" );
    

    Unzoned

    A LocalDateTime is an approximation of a date-time, without any time zone context. Not a moment on the timeline.

    LocalDateTime ldt = LocalDateTime.parse( input );
    

    UTC

    Make that LocalDateTime an actual moment on the timeline by applying the intended time zone. If meant for UTC, make an Instant.

    Instant instant = ldt.toInstant( ZoneOffset.UTC );
    

    Zoned

    If meant for a particular time zone, specify a ZoneId to get a ZoneDateTime.

    ZoneId zoneId = ZoneId.of( "America/Montreal" );
    ZonedDateTime zdt = ldt.atZone( zoneId );
    
    0 讨论(0)
  • 2020-12-06 13:53

    A little off-topic but SimpleDateFormat class is not thread safe - not only on parsing which is somewhat understandable but also on formatting. there are a lot of info on this on the net, here is one example: http://javarevisited.blogspot.co.il/2012/03/simpledateformat-in-java-is-not-thread.html. This problem will not be fixed. In Java 8 there is a whole new package java.time with wonderful new features allowing to work with full or partial dates and times. Also there is a new class DateTimeFormatter that provides vastly improved formatting and parsing features. However, if you use java older then java 8 then the recommendation would be to use Joda time library or Apache FastDateFormat

    0 讨论(0)
提交回复
热议问题