java.util.Date format SSSSSS: 如果不是微秒,最后的三位数字代表什么?

63

我刚在我的Windows(8)工作站和一台AIX上测试了这段代码:

    public static void main(String[] args) {
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS").format(new Date()));
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS").format(new Date()));
    }

然后得到了类似这样的结果:

2013-10-07 12:53:26.000905
2013-10-07 12:53:26.000906

有人能解释一下什么是最后几位数字吗?如果不是微秒?

注意:我与一个使用带有6个数字AFTER秒即微秒(IMO)的TIMESTAMP作为时间列存储时间数据的DB2数据库进行交互。但所有这些“时间戳”都是通过请求以下查询创建的:

SELECT current timestamp as currenttimestamp FROM Table ( values (1)) temp

考虑到上述结果,我想知道是否可以在我的代码中使用 new Date() 替代从数据库中选择 current timestamp

谢谢。

PS:我搜索了一下,但没有找到相关的(已回答)问题,例如: Java 中微秒级别的当前时间 或者 获取时、分、秒、毫秒和微秒时间


2
请注意,像 java.util.Datejava.util.Calendarjava.text.SimpleDateFormat 等旧的日期时间类现在已成为遗留系统,被内置于 Java 8 & Java 9 的 java.time 类所替代。请参阅 Oracle 的教程 - Basil Bourque
4
继@BasilBourque的评论后,进一步解释:虽然老式的SimpleDateFormat会混淆大写格式字母S,无论使用多少个字母,都被视为毫秒。而现代化的工具类DateTimeFormatter则将S解释为秒的小数部分。因此,使用DateTimeFormatter.ofPattern可以有意义地指定1到9个S,并获得您期望的结果。 - Ole V.V.
新的java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS").parse("2019-01-01 00:00:00.001000")返回00:00:01.000! - Hafthor
5个回答

126

来自SimpleDateFormat文档

Letter     Date or Time Component     Presentation     Examples  
S          Millisecond                Number           978 

所以它是毫秒,即1秒的1/1000。您只需将其格式化为6位数字,并添加3个额外的前导零...

您可以通过以下方式检查:

    Date d =new Date();
    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S").format(d));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS").format(d));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(d));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS").format(d));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSS").format(d));
    System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS").format(d));

输出:

2013-10-07 12:13:27.132
2013-10-07 12:13:27.132
2013-10-07 12:13:27.132
2013-10-07 12:13:27.0132
2013-10-07 12:13:27.00132
2013-10-07 12:13:27.000132

(Ideone示例)


1
好的,谢谢你,我没有想到这么简单的解决方案...感到非常糟糕!:( - maxxyme
21
@maxxyme 不用感到难过,我们都会犯错误。有时候长时间盯着一个问题看反而会让人对问题本身视而不见...(我也经历过这种情况)。有时候需要的只是另一双眼睛。 - ppeterka
2
警告:除非您可以保证毫秒数小于等于999且正确,否则不要使用SimpleDateFormat.parse处理带有小数秒的时间。实际上,最好不要使用SimpleDateFormat。 - Hafthor
我们如何获取微秒? - CMCDragonkai
public static void main(String[] args) throws ParseException { System.out.println(new SimpleDateFormat("yyy-MM-dd hh:mm:ss.SSSSSS").parse("2020-10-02 17:17:27.149320")); System.out.println(new SimpleDateFormat("yyy-MM-dd hh:mm:ss.SSSSSS").parse("2020-10-02 17:14:58.986670")); }会输出Fri Oct 02 17:19:56 AEST 2020 Fri Oct 02 17:31:24 AEST 2020这是错误的... - HoaPhan

16

太长不看

Instant.now()
       .toString() 

2018-02-02T00:28:02.487114Z

Instant.parse(
    "2018-02-02T00:28:02.487114Z"
)

java.time

ppeterka的被接受的答案是正确的。您对格式模式的滥用导致数据显示错误,而内部值始终限于毫秒。

您正在使用的麻烦的SimpleDateFormatDate类现在已过时,被java.time类取代。 java.time类处理纳秒分辨率,比旧类的毫秒限制更精细。

java.util.Date的等效物是java.time.Instant。您甚至可以使用添加到旧类的新方法之间进行转换。

Instant instant = myJavaUtilDate.toInstant() ;

Instant类表示时间轴上以UTC为参考的瞬间,精度高达nanoseconds纳秒(小数点后最多九位)。

捕获当前的UTC时间。Java 8以毫秒为单位捕获当前时刻,而Java 9中的新Clock实现以更细的粒度捕获时刻,通常为微秒,但这取决于您计算机硬件时钟、操作系统和JVM实现的能力。

Instant instant = Instant.now() ;

生成一个符合ISO 8601标准格式的字符串。

String output = instant.toString() ;

2018-02-02T00:28:02.487114Z

如果需要生成其他格式的字符串,请在Stack Overflow上搜索DateTimeFormatter,这个已经有很多次讨论了。

如果需要调整到其他时区而不是UTC,请使用ZonedDateTime

ZonedDateTime zdt = instant.atZone( ZoneId.of( "Pacific/Auckland" ) ) ;

关于java.time

java.time框架内置于Java 8及更高版本。这些类替代了旧的legacy日期时间类,如java.util.DateCalendarSimpleDateFormat

Joda-Time项目现在处于maintenance mode,建议迁移到java.time类。

想要了解更多,请参阅Oracle Tutorial。此外,您可以在Stack Overflow上搜索许多示例和解释。规范为JSR 310

如何获取java.time类?

ThreeTen-Extra项目通过添加额外的类扩展了java.time。该项目是java.time可能未来添加内容的试验场。您可能会在这里找到一些有用的类,例如Interval, YearWeek, YearQuarter以及more


1
@maxxyme 这里的问题不会过时。实际上,这个网站会为回答老问题的新答案颁发“徽章”,以表彰其突出贡献。Stack Overflow旨在更像维基百科,而不是无休止的讨论板或论坛。 - Basil Bourque
注意:SimpleDateFormat的Android实现与Oracle版本不同。在Android中,“S”格式实际上是十进制秒,而Oracle是毫秒数。因此,以048结尾的毫秒时间将在Android上以“0”的格式显示为“S”,而在常规Oracle实现中显示为“48”。我认为Android文档在技术上是错误的。 - Dave Hubbard

4

我使用了另一个技巧来格式化日期,精确到6位数字(微秒):

System.out.println(
    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.").format(microseconds/1000)
    +String.format("%06d", microseconds%1000000));

这项技术可以进一步扩展到纳秒及以上。


7
java.util.Date 对象仅支持毫秒级别的精度,不支持微秒级别或纳秒级别的精度。 - Basil Bourque

0

如果您想要获取文本表示中的小数秒,请使用java.sql.Timestamp.toString。 DB时间戳和Java日期之间的差异是DB精度为纳秒,而Java日期精度为毫秒。


-4

SSSSSS 是微秒。假设时间是 10:30:22(第 22 秒),10:30:22.1 就是 22 秒和 1/10 秒。按照同样的逻辑,10:32.22.000132 就是 22 秒和 132/1,000,000 秒,也就是微秒。


7
但是 java.util.Date 对象不包含微秒,只有毫秒。 - Basil Bourque
虽然在现实世界中是正确的,但对于“SimpleDateFormat”来说并不正确。这个类确实令人困惑。它太好了,以至于已经过时了很久。 - Ole V.V.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接