具有微秒或纳秒精度的 Java 日期解析
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30135025/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java date parsing with microsecond or nanosecond accuracy
提问by PNS
According to the SimpleDateFormat class documentation, Java
does not support time granularity above milliseconds in its date patterns.
根据SimpleDateFormat 类文档,Java
其日期模式不支持超过毫秒的时间粒度。
So, a date string like
所以,像这样的日期字符串
- 2015-05-09 00:10:23.999750900 // The last 9 digits denote nanoseconds
- 2015-05-09 00:10:23.999750900 // 最后 9 位数字表示纳秒
when parsed via the pattern
当通过模式解析时
- yyyy-MM-dd HH:mm:ss.SSSSSSSSS // 9 'S' symbols
- yyyy-MM-dd HH:mm:ss.SSSSSSSS // 9 个“S”符号
actually interprets the whole number after the .
symbol as (nearly 1 billion!) milliseconds and not as nanoseconds, resulting in the date
实际上将.
符号后面的整数解释为(近 10 亿!)毫秒而不是纳秒,从而得到日期
- 2015-05-20 21:52:53 UTC
- 2015-05-20 21:52:53 UTC
i.e. over 11 days ahead. Surprisingly, using a smaller number of S
symbols still results in all 9 digits being parsed (instead of, say, the leftmost 3 for .SSS
).
即提前 11 天。令人惊讶的是,使用较少数量的S
符号仍然会导致所有 9 位数字都被解析(而不是最左边的 3 个.SSS
)。
There are 2 ways to handle this issue correctly:
有两种方法可以正确处理此问题:
- Use string preprocessing
- Use a custom SimpleDateFormat implementation
- 使用字符串预处理
- 使用自定义 SimpleDateFormat 实现
Would there be any other way for getting a correct solution by just supplying a pattern to the standard SimpleDateFormat
implementation, without any other code modifications or string manipulation?
是否有任何其他方法可以通过向标准SimpleDateFormat
实现提供模式来获得正确的解决方案,而无需任何其他代码修改或字符串操作?
采纳答案by Basil Bourque
tl;dr
tl;博士
LocalDateTime.parse( // With resolution of nanoseconds, represent the idea of a date and time somewhere, unspecified. Does *not* represent a moment, is *not* a point on the timeline. To determine an actual moment, place this date+time into context of a time zone (apply a `ZoneId` to get a `ZonedDateTime`).
"2015-05-09 00:10:23.999750900" // A `String` nearly in standard ISO 8601 format.
.replace( " " , "T" ) // Replace SPACE in middle with `T` to comply with ISO 8601 standard format.
) // Returns a `LocalDateTime` object.
Nope
不
No, you cannot use SimpleDateFormat to handle nanoseconds.
不,您不能使用 SimpleDateFormat 来处理nanoseconds。
But your premise that…
但你的前提是……
Java does not support time granularity above millisecondsin its date patterns
Java在其日期模式中不支持超过毫秒的时间粒度
…is no longer true as of Java 8, 9, 10 and later with java.timeclasses built-in. And not really true of Java 6 and Java 7 either, as most of the java.timefunctionality is back-ported.
...从Java 8、 9 、 10 及更高版本开始,内置java.time类不再如此。Java 6 和 Java 7 也并非如此,因为大多数java.time功能都是向后移植的。
java.time
时间
SimpleDateFormat
, and the related java.util.Date
/.Calendar
classes are now outmoded by the new java.timepackage found in Java 8 (Tutorial).
SimpleDateFormat
,而相关的java.util.Date
/.Calendar
类现在已被Java 8(教程)中的新java.time包所取代。
The new java.time classes support nanosecondresolution. That support includes parsing and generating nine digits of fractional second. For example, when you use the java.time.format
DateTimeFormatter
API, the S
pattern letter denotes a "fraction of the second" rather than "milliseconds", and it can cope with nanosecond values.
新的 java.time 类支持纳秒分辨率。该支持包括解析和生成九位小数秒。例如,当您使用java.time.format
DateTimeFormatter
API 时,S
模式字母表示“秒的分数”而不是“毫秒”,它可以处理纳秒值。
Instant
Instant
As an example, the Instant
class represents a moment in UTC. Its toString
method generates a String
object using the standard ISO 8601format. The Z
on the end means UTC, pronounced “Zulu”.
例如,Instant
该类表示UTC 中的一个时刻。它的toString
方法String
使用标准ISO 8601格式生成一个对象。在Z
上月底手段UTC,发音为“祖鲁”。
instant.toString() // Generate a `String` representing this moment, using standard ISO 8601 format.
2013-08-20T12:34:56.123456789Z
2013-08-20T12:34:56.123456789Z
Note that capturing the current moment in Java 8 is limited to millisecond resolution. The java.timeclasses can holda value in nanoseconds, but can only determine the current time with milliseconds. This limitation is due to the implementation of Clock
. In Java 9 and later, a new Clock
implementation can grab the current moment in finer resolution, depending on the limits of your host hardware and operating system, usually microsecondsin my experience.
请注意,在 Java 8 中捕获当前时刻仅限于毫秒分辨率。该java.time类可以保持在纳秒的值,但只能确定当前时间毫秒。此限制是由于Clock
. 在 Java 9 及更高版本中,新的Clock
实现可以更精细地捕捉当前时刻,具体取决于主机硬件和操作系统的限制,根据我的经验,通常为微秒。
Instant instant = Instant.now() ; // Capture the current moment. May be in milliseconds or microseconds rather than the maximum resolution of nanoseconds.
LocalDateTime
LocalDateTime
Your example input string of 2015-05-09 00:10:23.999750900
lacks an indicator of time zone or offset-from-UTC. That means it does notrepresent a moment, is nota point on the timeline. Instead, it represents potentialmoments along a range of about 26-27 hours, the range of time zones around the globe.
您的示例输入字符串2015-05-09 00:10:23.999750900
缺少时区或UTC 偏移量的指示符。这意味着它不能代表一个时刻,是不是在时间轴上的一个点。相反,它代表了大约 26-27 小时范围内的潜在时刻,即全球时区的范围。
Pares such an input as a LocalDateTime
object. First, replace the SPACE in the middle with a T
to comply with ISO 8601 format, used by default when parsing/generating strings. So no need to specify a formatting pattern.
将此类输入解析为LocalDateTime
对象。首先,将中间的空格替换为 aT
以符合 ISO 8601 格式,解析/生成字符串时默认使用。所以不需要指定格式模式。
LocalDateTime ldt =
LocalDateTime.parse(
"2015-05-09 00:10:23.999750900".replace( " " , "T" ) // Replace SPACE in middle with `T` to comply with ISO 8601 standard format.
)
;
java.sql.Timestamp
java.sql.Timestamp
The java.sql.Timestamp
class also handles nanosecond resolution, but in an awkward way. Generally best to do your work inside java.time classes. No need to ever use Timestamp
again as of JDBC 4.2 and later.
该java.sql.Timestamp
班也处理纳秒级的分辨率,但在一个尴尬的方式。通常最好在 java.time 类中完成您的工作。Timestamp
从 JDBC 4.2 及更高版本开始,无需再次使用。
myPreparedStatement.setObject( … , instant ) ;
And retrieval.
和检索。
Instant instant = myResultSet.getObject( … , Instant.class ) ;
OffsetDateTime
OffsetDateTime
Support for Instant
is not mandated by the JDBC specification, but OffsetDateTime
is. So if the above code fails with your JDBC driver, use the following.
Instant
JDBC 规范并未强制要求支持,但OffsetDateTime
确实如此。因此,如果上述代码与您的 JDBC 驱动程序失败,请使用以下代码。
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;
And retrieval.
和检索。
Instant instant = myResultSet.getObject( … , OffsetDateTime.class ).toInstant() ;
If using an older pre-4.2 JDBC driver, you can use toInstant
and from
methods to go back and forth between java.sql.Timestamp
and java.time. These new conversion methods were added to the oldlegacy classes.
如果使用旧的 4.2 之前的 JDBC 驱动程序,您可以使用toInstant
和from
方法在java.sql.Timestamp
java.time之间来回切换。这些新的转换方法被添加到旧的遗留类中。
About java.time
关于java.time
The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
该java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date
, Calendar
, & SimpleDateFormat
。
The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310。
You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*
classes.
您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*
Where to obtain the java.time classes?
从哪里获得 java.time 类?
- Java SE 8, Java SE 9, Java SE 10, and later
- Built-in.
- Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6and Java SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.timeclasses.
- For earlier Android (<26), the ThreeTenABPproject adapts ThreeTen-Backport(mentioned above). See How to use ThreeTenABP….
- Java SE 8、Java SE 9、Java SE 10及更高版本
- 内置。
- 具有捆绑实现的标准 Java API 的一部分。
- Java 9 添加了一些小功能和修复。
- Java SE 6和Java SE 7
- 多的java.time功能后移植到Java 6和7在ThreeTen-反向移植。
- 安卓
- java.time类的更高版本的 Android 捆绑实现。
- 对于早期的 Android(<26),ThreeTenABP项目采用了ThreeTen-Backport(上面提到过)。请参阅如何使用ThreeTenABP ...。
The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
该ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如Interval
,YearWeek
,YearQuarter
,和更多。
回答by flowgrad
I found the it wonderful to cover multiple variants of date time format like this:
我发现像这样涵盖日期时间格式的多种变体真是太好了:
final DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder();
dtfb.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SS"))
.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S"))
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0);