为什么 Timestamp 在单元测试中打印 运行 模型和调试模型之间的差异?

why does Timestamp print difference between run model and debug model in unit test?

    java.sql.Date date = java.sql.Date.valueOf("1900-01-01");
    //-2209017600000
    System.out.println(date.getTime());
    java.sql.Timestamp timestamp = new Timestamp(date.getTime());
    System.out.println(timestamp); 

如果在单元测试中直接运行,结果会是1900-01-01 00:00:00.0

如果运行在单元测试中调试,结果将是1970-01-01 07:30:00.0

如何输出1900-01-01 00:00:00.0?它存储在哪里?

为什么不输出1970-01-01 00:00:00.0?因为我看到 Timestamp 构造函数的注释说自 1970 年 1 月 1 日以来的毫秒数,00:00:00 GMT。负数是 1970 年 1 月 1 日之前的毫秒数,00:00:00 GMT。

tl;博士

避免可怕的旧日期时间 classes。使用 java.time。呸,你看到的所有奇怪行为都消失了,你的问题没有实际意义。

LocalDate                 // A class to represent a date-only value, without time-of-day, without time zone. Replaces `java.sql.Date` which only pretends to be date-only but actually has both a time-of-day and a time zone.
.parse( "1900-01-01" )    // Standard ISO 8601 formatted strings are parsed directly by the *java.time* classes. 
.atStartOfDay(            // Let java.time determine the first moment of a day.
    ZoneId.of( "Pacific/Auckland" ) 
)                         // Returns a `ZonedDateTime` object.
.toString()               // Generates a `String` with text in standard ISO 8601 format, wisely extended by appending the name of the time zone in square brackets.

1900-01-01T00:00+11:30[Pacific/Auckland]

您正在用这些关于遗留日期时间 classes 的问题折磨自己。 Sun、Oracle 和 JCP 社区都在 class 年前采用 JSR 310 时放弃了那些。我建议你也这样做。

从不使用 java.sql.Date

这个 class 是可怕的旧日期时间 classes 的一部分,几年前被 java.time class是的。尤其是这个java.sql.Date设计的特别烂。它扩展 java.util.Date 而文档告诉我们忽略该继承的事实。作为一个子class,它假装是一个只有日期的值但实际上有一个从另一个Date继承的时间被错误地命名为同时具有日期和时间。此外,时区隐藏在这些 classes 的深处,尽管没有任何 getter 或 setter 方法无法访问。令人困惑?是的,一团糟。永远不要使用 java.sql.Date

而是使用 java.time.LocalDate.

LocalDate ld = LocalDate.parse( "1900-01-01" ) ;

ld.toString(): 1900-01-01

从不使用 java.sql.Timestamp

java.sql.Date 一样,java.sql.Timestamp class 已在多年前更换。使用 java.time.Instant。如果递给 Timestamp,立即使用添加到旧 classes 的新转换方法进行转换。

如果您想要特定日期的一天中的第一时刻,请让 LocalDate 确定。第一时刻是 而不是 总是 00:00:00,所以永远不要假设。指定人们使用您关心的特定挂钟时间的地区的时区。

指定 proper time zone name in the format of continent/region, such as America/Montreal, Africa/CasablancaPacific/Auckland。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们 不是 真正的时区,没有标准化,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = ld.atStartOfDay( z ) ;

要以 UTC 格式查看同一时刻,请提取 InstantInstant class represents a moment on the timeline in UTC with a resolution of nanoseconds(最多九 (9) 位小数)。

Instant instant = zdt.toInstant() ;

如果您想要 UTC 中一天的第一时刻,请使用 OffsetDateTime

OffsetDateTime odt = ld.atOffset( ZoneOffset.UTC ) ;

转化

如果您必须与尚未更新为 java.time classes 的旧代码进行互操作,您可以来回转换。调用添加到旧 classes 的新方法。

java.sql.Timestamp ts = Timestamp.from( instant ) ;

……和……

Instant instant = ts.toInstant() ;

日期同上。

java.sql.Date d = java.sql.Date.valueOf( ld ) ;

……和……

LocalDate ld = d.toLocalDate() ;

关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

要了解更多信息,请参阅 Oracle 教程。并在 Stack Overflow 中搜索许多示例和解释。规格为 JSR 310.

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

从哪里获得java.time classes?

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.