[英]Is DateTimeFormatter more strict than SimpleDateFormat? Parsing date with milliseconds
[英]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秒。 也許您可以截斷6739
到673
(或者如果您願意,將其四舍五入到674
),這樣它就可以正確解析為毫秒。
似乎不可能使用SimpleDateFormat來表示比毫秒更精細的粒度。 發生的事情是,當你輸入6739時,Java將其理解為6739毫秒,即6秒和739毫秒,因此觀察到6秒的差異。
檢查這些,它解釋得很好: 字符串日期轉換納秒秒 Java日期解析微秒或納秒精度
LocalDateTime.parse(
"2016-03-16 01:14:21.6739".replace( " " , "T" ) // Comply with ISO 8601 standard format.
)
正如其他人所說, java.util.Date
具有毫秒級的分辨率。 這意味着最多3位小數秒。
輸入字符串中有4位數字,一個數字太多。 您的輸入值需要更精細的分辨率,例如微秒或納秒。
不要使用有缺陷,令人困惑和麻煩的java.util.Date/.Calendar類,而是繼續使用它們:Java 8及更高版本中內置的java.time框架。
java.time類的分辨率為納秒級 ,最高可達一位小數的九位數。 例如:
2016-03-17T05:19:24.123456789Z
在解析/生成日期時間值的文本表示時,您的字符串輸入幾乎是標准的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
(一個寬松的 (請參閱此處 )選項)的一個非常可疑的特性。 默認情況下, SimpleDateFormat
將setLenient
設置為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.