【问题标题】:Why does Instant.EPOCH and Timestamp.from(Instant.EPOCH) return different results? [duplicate]为什么 Instant.EPOCH 和 Timestamp.from(Instant.EPOCH) 返回不同的结果? [复制]
【发布时间】:2021-09-03 04:56:44
【问题描述】:

使用 java.time 的 Instant 和 java.sql 的 Timestamp,为什么要这样做:

System.out.println("epoch: " + Instant.EPOCH);
System.out.println("timestamp: " + Timestamp.from(Instant.EPOCH));

产生不同的结果:

epoch: 1970-01-01T00:00:00Z
timestamp: 1970-01-01 01:00:00.0

【问题讨论】:

标签: java time java-time


【解决方案1】:

Timestamp 类注入 JVM 的当前默认时区。您应该从不使用这些旧的日期时间类的众多原因之一。仅使用它们的替代品 java.time 类。 Sun、Oracle 和 JCP 社区一致采用了 JSR 310,而放弃了 DateCalendarTimestamp 等可悲的日期时间类。

您的 JVM 在 1970 年第一刻的当前默认时区(如 UTC 所示)使用的是提前一小时的 UTC 偏移量。因此,凌晨 1 点显示,在同一时刻增加一小时,时间为 00:00,在冰岛等地,该时间与 UTC 的偏移量为 0 小时-分钟-秒。

Timestamp#toString 的输出的另一个问题是它忽略了指示其时区或与 UTC 的偏移量。相比之下,java.time.Instant#toString 方法将Z 放在末尾,以根据ISO 8601 标准指示零小时-分钟-秒的偏移量。

Instant 类表示 UTC 中的时刻,始终为 UTC,偏移量为零。所以没有像Timestamp 这样的混乱和模棱两可。

【讨论】:

    【解决方案2】:

    为什么 Instant.EPOCH 和 Timestamp.from(Instant.EPOCH) 返回 不同的结果?

    回响Stultuske's comment

    他们没有,只是格式不同。

    让我们看看如何

    下面给出的是java.sql.Timestamp的层次结构:

    java.lang.Object
        java.util.Date
            java.sql.Timestamp
    

    在文档的同一页上,您会发现以下信息:

    Timestampjava.util.Date的继承关系 真正表示实现继承,而不是类型继承。

    实现继承是一种在子类中重用超类代码的方式,而类型继承是一种为特定实现特化(子类化)超类型的方式**.

    创建java.sql.Timestamp 的目的已在文档同一页的以下行中进行了总结:

    一个围绕java.util.Date 的瘦包装器,它允许 JDBC API 将此标识为 SQL TIMESTAMP 值。

    所以,不要指望java.sql.Timestampjava.util.Date 有很大不同。

    关于java.util.Date

    java.util.Date 对象仅表示自称为“纪元”的标准基准时间(即 1970 年 1 月 1 日 00:00)以来的毫秒数: 00 GMT(或 UTC)。由于它不保存任何时区信息,它的 toString 函数应用 JVM 的时区以返回格式为 EEE MMM dd HH:mm:ss zzz yyyyString,从这个 毫秒 值。要以不同的格式和时区获取 java.util.Date 对象的 String 表示,您需要使用具有所需格式和适用时区的 SimpleDateFormat,例如

    Date date = new Date();
    
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
    
    sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
    String strDateNewYork = sdf.format(date);
    
    sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
    String strDateUtc = sdf.format(date);
    

    另一方面,Instant 表示UTC 中时间轴上的一个瞬时点。

    全部放在演示中:

    import java.sql.Timestamp;
    import java.text.SimpleDateFormat;
    import java.time.Instant;
    import java.util.Date;
    import java.util.Locale;
    import java.util.TimeZone;
    
    public class Main {
        public static void main(String[] args) {
            System.out.println("Instant:   " + Instant.EPOCH);
            System.out.println("Timestamp: " + epochMilliFormatted());
        }
    
        public static String epochMilliFormatted() {
            Date date = new Date(Timestamp.from(Instant.EPOCH).getTime());
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX", Locale.ENGLISH);
            sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
            return sdf.format(date);
        }
    }
    

    输出:

    Instant:   1970-01-01T00:00:00Z
    Timestamp: 1970-01-01T00:00:00Z
    

    输出中的Z 是零时区偏移的timezone designator。它代表 Zulu 并指定 Etc/UTC 时区(其时区偏移量为 +00:00 小时)。

    ONLINE DEMO

    注意:java.util 日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到modern Date-Time API*。从 Trail: Date Time 了解有关现代日期时间 API 的更多信息。


    * 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 和 7 . 如果您正在为一个 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

    ** 要了解有关实现继承和类型继承的更多信息,请查看以下链接:
    1. Multiple Inheritance of State, Implementation, and Type
    2. implementation inheritance vs type inheritance
    3. difference between interface inheritance and implementation inheritance

    【讨论】:

      猜你喜欢
      • 2016-03-31
      • 2010-10-31
      • 2013-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-28
      • 2013-03-10
      相关资源
      最近更新 更多