Java日期解析具有微秒或纳秒精度

根据SimpleDateFormat class documentation,Java在其日期模式中不支持超过毫秒的时间粒度.

所以,日期字符串就像

> 2015-05-09 00:10:23.999750900 //最后9位数字表示纳秒

通过模式解析时

> yyyy-MM-dd HH:mm:ss.SSSSSSSSS // 9’S’符号

实际上解释了之后的整数.符号为(近10亿!)毫秒而不是纳秒,导致日期

> 2015-05-20 21:52:53 UTC

即提前11天.令人惊讶的是,使用较少数量的S符号仍会导致所有9个数字被解析(而不是,例如,对于.SSS最左边的3个数字).

有两种方法可以正确处理此问题:

>使用字符串预处理
>使用自定义SimpleDateFormat实现

是否有任何其他方法可以通过向标准SimpleDateFormat实现提供模式来获得正确的解决方案,而无需任何其他代码修改或字符串操作?

解决方法:

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.

不,你不能使用SimpleDateFormat来处理nanoseconds.

但你的前提是……

Java does not support time granularity above 07001 in its date patterns

…从Java 8,9,10及更高版本开始,内置java.time类不再是真的.并不像Java 6和Java 7那样真实,因为大多数java.time functionality is back-ported.

java.time

SimpleDateFormat和相关的java.util.Date/.Calendar类现在已经过时了Java 8(Tutorial)中的新java.time软件包.

新的java.time类支持nanosecond分辨率.该支持包括解析和生成九位数的小数秒.例如,当您使用java.time.format DateTimeFormatter API时,S模式字母表示“秒的一小部分”而不是“毫秒”,它可以处理纳秒值.

瞬间

例如,Instant类表示UTC中的一个时刻.其toString方法使用标准ISO 8601格式生成String对象.最后的Z表示UTC,发音为“Zulu”.

instant.toString()  // Generate a `String` representing this moment, using standard ISO 8601 format.

2013-08-20T12:34:56.123456789Z

请注意,捕获Java 8中的当前时刻仅限于毫秒级分辨率. java.time类可以保存以纳秒为单位的值,但只能以毫秒为单位确定当前时间.这种限制是由于Clock的实现.在Java 9及更高版本中,新的Clock实现可以以更精细的分辨率获取当前时刻,具体取决于主机硬件和操作系统的限制,根据我的经验,通常为microseconds.

Instant instant = Instant.now() ;  // Capture the current moment. May be in milliseconds or microseconds rather than the maximum resolution of nanoseconds.

LocalDateTime

您的示例输入字符串2015-05-09 00:10:23.999750900缺少时区指示符或UTC的偏移量.这意味着它不代表片刻,不是时间轴上的一个点.相反,它代表了全球约26-27小时范围内的潜在时刻.

将此类输入视为LocalDateTime对象.首先,用T替换中间的SPACE以符合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类也处理纳秒分辨率,但是处于一种尴尬的方式.通常最好在java.time类中完成你的工作.从JDBC 4.2及更高版本开始,无需再次使用Timestamp.

myPreparedStatement.setObject( … , instant ) ;

并检索.

Instant instant = myResultSet.getObject( … , Instant.class ) ;

OffsetDateTime

JDBC规范并未强制支持Instant,但OffsetDateTime是.因此,如果上述代码因JDBC驱动程序而失败,请使用以下代码.

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ; 
myPreparedStatement.setObject( … , odt ) ;

并检索.

Instant instant = myResultSet.getObject( … , OffsetDateTime.class ).toInstant() ;

如果使用较早的4.2之前的JDBC驱动程序,则可以使用toInstantfrom方法在java.sql.Timestamp和java.time之间来回切换.这些新的转换方法已添加到旧的遗留类中.

Java日期解析具有微秒或纳秒精度

关于java.time

java.time框架内置于Java 8及更高版本中.这些课程取代了麻烦的旧legacy日期时间课程,如java.util.Date,Calendar和& SimpleDateFormat.

Joda-Time项目现在是maintenance mode,建议迁移到java.time课程.

要了解更多信息,请参阅Oracle Tutorial.并搜索Stack Overflow以获取许多示例和说明.规格是JSR 310.

您可以直接与数据库交换java.time对象.使用符合JDBC 4.2或更高版本的JDBC driver.不需要字符串,不需要java.sql.*类.

从哪里获取java.time类?

> Java SE 8,Java SE 9,Java SE 10及更高版本

>内置.
>部分标准Java API,带有捆绑实现.
> Java 9增加了一些小功能和修复.

> Java SE 6Java SE 7

>大部分java.time功能都被反向移植到Java 6& 7月在ThreeTen-Backport.

> Android

>更新版本的Android捆绑java.time类的实现.
>对于早期的Android(< 26),ThreeTenABP项目适应ThreeTen-Backport(如上所述).见How to use ThreeTenABP….

ThreeTen-Extra项目使用其他类扩展了java.time.该项目是未来可能添加到java.time的试验场.您可以在这里找到一些有用的类,例如Interval,YearWeek,YearQuartermore.

上一篇:在Java中将带有毫秒的字符串转换为日期格式[复制]


下一篇:block的数据结构