【问题标题】:Grouping Long UTC dates by Day按天分组长 UTC 日期
【发布时间】:2009-03-24 12:46:42
【问题描述】:

有没有一种合理的方法可以按天对长 UTC 日期进行分组?

我会将它们修改为 86400,但这不考虑闰秒。

有没有人有其他想法,我正在使用 java,所以我可以将它们解析为日期对象,但我有点担心使用日期类的性能开销。

还有比比较 Date 对象的年月日部分更有效的方法吗?

【问题讨论】:

    标签: java utc


    【解决方案1】:

    您的源数据一定是否包含闰秒?有些 API 可以,有些则不可以 - 例如,Joda Time(我建议使用内置日期/时间 API)doesn't use leap seconds。 Java 日期和时间 API“有时”会这样做——它们支持 60 和 61 作为“分钟秒数”的值,但支持取决于操作系统(见下文)。如果你有一些好的样本值,如果我是你,我会先检查一下。显然,只是划分比其他任何事情都简单。

    如果您确实需要创建 Date 对象(或 Joda 中的 DateTime),我会在做任何其他事情之前对其进行基准测试。您可能会发现性能实际上是完全足够的。浪费时间优化适合您的数据的东西是没有意义的。当然,您需要确定需要支持的数据大小,以及首先需要多快 :)

    即使java.util.Date 对闰秒的支持也有些不确定。来自the docs:

    虽然 Date 类旨在 反映协调世界时 (UTC),它可能不完全这样做, 取决于主机环境 Java 虚拟机。差不多全部 现代操作系统假设 1 天 = 24 × 60 × 60 = 86400 秒 所有情况。然而,在 UTC 中,大约有一次 每一两年都有一个额外的 第二,称为“闰秒”。这 闰秒总是添加为 一天的最后一秒,并且始终开启 12 月 31 日或 6 月 30 日。例如, 1995 年的最后一分钟是 61 秒长,多亏了 闰秒。大多数计算机时钟是 不够准确,无法 反映闰秒的区别。

    有一个 rather good blog post 关于 Java 和闰秒的混乱,您可能也想阅读。

    【讨论】:

      【解决方案2】:

      我会将它们修改为 86400,但这不考虑闰秒......

      我很确定那会很好。 Date 的 API 文档实际上不应该包含任何关于闰秒的内容,因为事实上它模拟了一个标准的 Unix 时间记录器,其值中不包含闰秒。 相反,它的作用是通过在闰秒开始时将代码值向后设置 1 秒(如上一篇文章中的链接所述),使第 59 秒持续两秒。

      因此,您可以假设您从Date.getTime() 获得的值仅由 86400 秒组成。如果您真的需要知道特定日是否有闰秒,互联网上有几张表格(自 1972 年以来只有 23-24 日,而在此之前的计算机日期很少将它们纳入帐户)。

      嗨

      温斯顿

      【讨论】:

        【解决方案3】:

        tl;博士

        Instant.ofEpochSecond( 1_493_367_302L )            // Convert a count of whole seconds from epoch of 1970 into a date-time value in UTC.
               .atZone( ZoneId.of( "Pacific/Auckland" ) )  // Adjust into the time zone as a context for determining a date.
               .toLocalDate()                              // Extract a date-only value by which we can sort/collect/organize our date-time values.
        

        时区

        java.util.Date 类代表 UTC 时间线上的一个时刻。因此,向它询问日期会为您提供一个仅在 UTC 中有意义的日期。同一时刻可能是更早的魁北克或新西兰奥克兰的更晚日期。

        时区对于确定日期至关重要,您的问题忽略了这个问题。

        使用 java.time

        java.util.Date 类是麻烦的旧日期时间类的一部分,现在已被 java.time 类取代。

        至于闰秒,正如其他答案所建议的那样,大多数从纪元计数的来源不计算闰秒。因此,请验证您的来源。

        如果您从1970-01-01T00:00:00 的纪元开始计算整秒,则使用静态方法创建Instant 对象。

        Instant instant = Instant.ofEpochSecond( 1_493_367_302L ) ;
        

        instant.toString(): 2017-04-28T08:15:02Z

        分配一个时区以创建我们可以确定日期的上下文。对于任何特定时刻,世界各地的日期都会因地区而异。

        以continent/region 的格式指定proper time zone name,例如America/Montreal、Africa/Casablanca 或Pacific/Auckland。切勿使用 3-4 个字母的缩写,例如 EST 或 IST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

        ZoneId z = ZoneId.of( "America/Montreal" ); 
        ZonedDateTime zdt = instant.atZone( z );
        

        zdt.toString(): 2017-04-28T01:15:02-07:00[美国/洛杉矶]

        通过这些ZonedDateDate 对象,您可以按日期进行比较。您可以提取 LocalDate 对象。 LocalDate 类表示没有时间和时区的仅日期值。

        LocalDate ld = zdt.toLocalDate();
        

        ld.toString(): 2017-04-28

        因此,您可以使用 LocalDate 作为键和 List 或 Set 的 ZonedDateTime 对象作为值的 Map。借助现代 lambda 语法,您可以使用 Streams 进行映射。


        关于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 类?

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-27
          • 1970-01-01
          • 1970-01-01
          • 2019-09-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多