具有微秒或纳秒精度的Java数据解析

具有微秒或纳秒精度的Java数据解析,java,simpledateformat,milliseconds,Java,Simpledateformat,Milliseconds,根据,Java在其日期模式中不支持超过毫秒的时间粒度 所以,像这样的日期字符串 2015-05-09 00:10:23.99975000//最后9位数字表示纳秒 当通过模式解析时 yyyy MM dd HH:MM:ss.SSSSS//9’S’符号 实际上,将符号后的整数解释为(近10亿!)毫秒,而不是纳秒,从而生成日期 2015-05-20 21:52:53 UTC i、 e.提前11天以上。令人惊讶的是,使用较少数量的S符号仍然会导致解析所有9位数字(而不是,比如说,.SSS的最左

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

所以,像这样的日期字符串

  • 2015-05-09 00:10:23.99975000//最后9位数字表示纳秒
当通过模式解析时

  • yyyy MM dd HH:MM:ss.SSSSS//9’S’符号
实际上,将
符号后的整数解释为(近10亿!)毫秒,而不是纳秒,从而生成日期

  • 2015-05-20 21:52:53 UTC
i、 e.提前11天以上。令人惊讶的是,使用较少数量的
S
符号仍然会导致解析所有9位数字(而不是,比如说,
.SSS
的最左边3位)

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

  • 使用字符串预处理
  • 使用自定义SimpleDataFormat实现
如果只向标准的
SimpleDateFormat
实现提供一个模式,而不进行任何其他代码修改或字符串操作,是否还有其他方法可以获得正确的解决方案?

tl;博士 不 不,不能使用SimpleDataFormat来处理

但是你的前提是

Java在其日期模式中不支持上述时间粒度

…对于内置的java.time类,在9、10及更高版本中不再适用。对于Java6和Java7也不是这样,因为大多数Java.time都是这样

java.time
SimpleDataFormat
,以及相关的
java.util.Date
/
.Calendar
类现在已经被java 8()中的新包过时了

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

Instant
作为一个例子,这个类代表了一个时刻。它的
toString
方法使用标准格式生成
String
对象。末尾的
Z
表示UTC,发音为“Zulu”

instant.toString()  // Generate a `String` representing this moment, using standard ISO 8601 format.
2013-08-20T12:34:56.123456789Z

请注意,在Java8中捕获当前时刻的分辨率仅限于毫秒。time类可以以纳秒为单位保存值,但只能以毫秒为单位确定当前时间。此限制是由于实现了
时钟
。在Java 9和更高版本中,一个新的
时钟
实现可以以更高的分辨率抓住当前时刻,这取决于主机硬件和操作系统的限制,通常是我的经验

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>代码>替换中间的空间,以符合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.time类中完成工作。从JDBC 4.2及更高版本开始,不再需要再次使用时间戳

myPreparedStatement.setObject( … , instant ) ;
和检索

Instant instant = myResultSet.getObject( … , Instant.class ) ;
OffsetDateTime
JDBC规范没有强制要求支持
即时
,但是
OffsetDateTime
是。因此,如果上述代码在JDBC驱动程序中失败,请使用以下代码

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

Instant instant = myResultSet.getObject( … , OffsetDateTime.class ).toInstant() ;
如果使用较旧的4.2版本之前的JDBC驱动程序,则可以使用和方法在
java.sql.Timestamp
和java.time之间来回切换。这些新的转换方法被添加到旧的遗留类中


关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

该项目现已启动,建议迁移到类

要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

您可以直接与数据库交换java.time对象。使用兼容的或更高版本。不需要字符串,也不需要
java.sql.*

从哪里获得java.time类

  • 然后
    • 内置的
    • 标准JavaAPI的一部分,带有捆绑实现
    • Java9添加了一些次要功能和修复
    • 大部分java.time功能都在中向后移植到Java6和Java7
    • 更高版本的Android捆绑包实现了java.time类

    • 对于早期的Android(我发现覆盖多种日期-时间格式非常好,如下所示:

      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);
      

      …只向标准的
      SimpleDataFormat
      实现提供一个模式,而不进行任何其他代码修改或字符串操作?显然不是。是的,尽管由于相应的用例,要求使用
      SimpleDataFormat
      解决方案。@OleV.V.完成。谢谢你的建议。有人想解析dat吗有时区的时间字符串,可以使用instant.Parse(“datetimestring”)@PrashantSaraswat不,对于时区,可以使用
      ZonedDateTime
      ,而不是
      instant
      。请参见我回答中的表格图形。@BasilBourque感谢您指出这一点。这两种方法都有效。我使用instant是因为javadoc for LocalDateTime建议使用instant。
      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);