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

标签 java simpledateformat milliseconds

根据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 位数字(而不是最左边的 3 位 .SSS)。

    有两种方法可以正确处理此问题:
  • 使用字符串预处理
  • 使用自定义 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 milliseconds in its date patterns



    Java 8 、 9 、 10 及更高版本开始,内置 java.time 类不再如此。 Java 6 和 Java 7 也不是真的,因为大多数 java.time functionality is back-ported

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

    新的 java.time 类支持 nanosecond 解析。该支持包括解析和生成九位小数秒。例如,当您使用 java.time.format DateTimeFormatter API 时,S 模式字母表示“秒的分数”而不是“毫秒”,它可以处理纳秒值。
    Instant
    例如, 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 对象。首先,将中间的 SPACE 替换为 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.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 驱动程序,您可以使用 toInstant from 方法在 java.sql.Timestamp 和 java.time 之间来回切换。这些新的转换方法被添加到旧的遗留类中。

    Table of date-time types in Java (both legacy and modern) and in standard SQL

    关于 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 driver 或更高版本的 JDBC 4.2。不需要字符串,不需要 java.sql.* 类。

    从哪里获得 java.time 类?
  • Java SE 8Java SE 9Java SE 10 和更高版本
  • 内置。
  • 具有捆绑实现的标准 Java API 的一部分。
  • Java 9 添加了一些小功能和修复。
  • Java SE 6Java SE 7
  • java.time 的大部分功能在 ThreeTen-Backport 中向后移植到 Java 6 和 7。
  • Android
  • java.time 类的 Android 捆绑实现的更高版本。
  • 对于更早的Android(<26),ThreeTenABP 项目适配了ThreeTen-Backport(上面提到过)。见 How to use ThreeTenABP…

  • ThreeTen-Extra 项目使用附加类扩展了 java.time。该项目是 future 可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如 Interval YearWeek YearQuarter more

    关于具有微秒或纳秒精度的 Java 日期解析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30135025/

    相关文章:

    java - 在java中显示两个日期之间的小时数

    c - 在 Windows、Linux、Solaris、HP-UX、IBM AIX、Vxworks、Wind River Linux 上休眠几毫秒?

    java - SimpleDateFormat 将字符串转换为日期

    stm32中的Arduino millis()

    java - 了解 Intellij 中 Maven 的正确工作流程

    java - 这种类型的初始化称为什么以及为什么使用它?

    java - 如何从HTTP请求中获取正确的数据

    java - JDBC:如何使用属性文件中的详细信息从 Jdbc 连接到 RAC 数据库?

    sql - 使用 Apache Derby 转换日期

    java - android 将字符串解析为日期 - 错误的日期