簡體   English   中英

SimpleDateFormat無法解析超過4位數的毫秒數

[英]SimpleDateFormat cannot parse milliseconds with more than 4 digits

我想解析時間戳,像這樣 - "2016-03-16 01:14:21.6739" 但是當我使用SimpleDateFormat來解析它時,我發現它輸出了一個不正確的解析值。 它將隱藏6739毫秒到6秒,剩下739毫秒。 它將日期轉換為此格式 - Wed Mar 16 01:14:27 PDT 2016 為什么秒部分從21秒變為27秒(增加6秒?)。 以下是我的代碼片段:

final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS");
String parsedate="2016-03-16 01:14:21.6739";
try {
    Date outputdate = sf.parse(parsedate);
    String newdate = outputdate.toString();  //==output date is: Wed Mar 16 01:14:27 PDT 2016 
    System.out.println(newdate);
} catch (ParseException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

SimpleDateFormat SS是毫秒。 你有6739毫秒,這意味着你額外增加了6.7秒。 也許您可以截斷6739673 (或者如果您願意,將其四舍五入到674 ),這樣它就可以正確解析為毫秒。

似乎不可能使用SimpleDateFormat來表示比毫秒更精細的粒度。 發生的事情是,當你輸入6739時,Java將其理解為6739毫秒,即6秒和739毫秒,因此觀察到6秒的差異。

檢查這些,它解釋得很好: 字符串日期轉換納秒秒 Java日期解析微秒或納秒精度

TL;博士

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

毫秒與微秒

正如其他人所說, java.util.Date具有毫秒級的分辨率。 這意味着最多3位小數秒。

輸入字符串中有4位數字,一個數字太多。 您的輸入值需要更精細的分辨率,例如微秒或納秒。

java.time

不要使用有缺陷,令人困惑和麻煩的java.util.Date/.Calendar類,而是繼續使用它們:Java 8及更高版本中內置的java.time框架。

java.time類的分辨率為納秒級 ,最高可達一位小數的位數。 例如:

2016-03-17T05:19:24.123456789Z

ISO 8601

在解析/生成日期時間值的文本表示時,您的字符串輸入幾乎是標准的ISO 8601格式,在java.time中默認使用。 T替換中間的空間以符合ISO 8601。

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

不分區

LocalDateTime是日期時間的近似值,沒有任何時區上下文。 時間軸上沒有片刻。

LocalDateTime ldt = LocalDateTime.parse( input );

世界標准時間

通過應用預期的時區,使LocalDateTime成為時間軸上的實際時刻。 如果用於UTC,請Instant

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

如果用於特定時區,請指定ZoneId以獲取ZoneDateTime

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ldt.atZone( zoneId );

您可以使用String newdate = sf.format(outputdate); 代替String newdate = outputdate.toString();

如果必須將字符串作為最終輸出,為什么不使用format而不是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);

而不是"yyyy-MM-dd HH:mm:ss.SSSS"使用"yyyy-MM-dd HH:mm:ss.SSSZ"在這里查看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

一點偏離主題,但SimpleDateFormat類不是線程安全的 - 不僅在解析上有些可理解,而且在格式化方面。 網上有很多關於此的信息,這里有一個例子: http//javarevisited.blogspot.co.il/2012/03/simpledateformat-in-java-is-not-thread.html 這個問題不會得到解決。 在Java 8中,有一個全新的java.time包, java.time具有很棒的新功能,可以處理完整或部分日期和時間。 還有一個新類DateTimeFormatter ,它提供了大大改進的格式和解析功能。 但是,如果你使用舊的Java然后java 8,那么建議使用Joda時間庫或Apache FastDateFormat

正如上面的評論中提到的,你的問題已經包含了答案:毫秒不得超過3位,否則它至少代表一整秒。

您的代碼工作正是由於java.text.SimpleDateFormat (一個寬松的 (請參閱此處 )選項)的一個非常可疑的特性。 默認情況下, SimpleDateFormatsetLenient設置為true這意味着解析器將嘗試解釋與100%模式不匹配的字符串,並通過一些啟發式方法將它們轉換為日期對象。 例如,它將接受日期31.04.2016並將其轉換為01.05.2016 在某些情況下,此功能可能很好,但在大多數情況下會產生可疑的結果。

如果在代碼中將lenient設置為false ,則不再解析日期字符串。 使模式中的錯誤更明顯:

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

由於java.util.Date無法表示低於毫秒的任何精度,我認為解析日期的最佳選擇是簡單地刪除輸入日期的最后數字,如果點后面的部分有更多超過四位數。 您的代碼可能如下所示:

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();
}

您可以嘗試添加一些舍入邏輯,以便不會丟失第4位的所有信息......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM