我想解析一个时间戳,就像这样 - "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();
}
答案 0 :(得分:5)
SimpleDateFormat
中的 SS
是毫秒。你有6739毫秒,这意味着你额外增加了6.7秒。也许您可以将6739
截断为673
(或者如果您愿意,将其四舍五入为674
),以便可以正确解析为毫秒。
答案 1 :(得分:4)
似乎不可能使用SimpleDateFormat来表示比毫秒更精细的粒度。 发生的事情是,当你输入6739时,Java将其理解为6739毫秒,即6秒和739毫秒,因此观察到6秒的差异。
检查这些,解释得很好: String-Date conversion with nanoseconds Java date parsing with microsecond or nanosecond accuracy
答案 2 :(得分:3)
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类的分辨率为nanosecond ,最多为 9 位小数的秒数。例如:
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 );
答案 3 :(得分:0)
您可以使用字符串newdate = sf.format(outputdate); 代替字符串newdate = outputdate.toString();
答案 4 :(得分:0)
如果您必须将字符串作为最终输出,为什么不使用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
答案 5 :(得分:0)
有点偏离主题,但SimpleDateFormat
类不是线程安全的 - 不仅在解析上有些可理解,而且在格式化方面。网上有很多关于此的信息,这里有一个例子:http://javarevisited.blogspot.co.il/2012/03/simpledateformat-in-java-is-not-thread.html。这个问题不会得到解决。在Java 8中,有一个全新的包java.time
具有很棒的新功能,可以处理完整或部分日期和时间。还有一个新类DateTimeFormatter,它提供了大大改进的格式和解析功能。但是,如果您使用Java旧版本然后使用java 8,那么建议使用Joda time library或Apache FastDateFormat
答案 6 :(得分:0)
正如上面评论中提到的,你的问题已经包含了答案:毫秒不得超过3位,否则它至少代表一整秒。
您的代码正常运行只是由于java.text.SimpleDateFormat
,宽松(请参阅here)选项的一个非常可疑的功能。默认情况下,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
无法表示任何低于毫秒的精度,我认为解析日期的最佳选择是简单地删除输入日期的最后一位数字,如果后面的部分是dot有四位数以上。您的代码可能如下所示:
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位的所有信息......