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

时间:2018-09-03 20:35:56

标签: java timestamp sqldatetime

    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以来的毫秒数。负数是格林尼治标准时间1970年1月1日00:00:00之前的毫秒数。

1 个答案:

答案 0 :(得分:1)

tl; dr

避免使用可怕的旧日期时间类。使用 java.time 。 of,您看到的所有奇怪行为都消失了,您的问题也没有解决。

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 [太平洋/奥克兰]

您正在用有关遗留日期时间类的这些问题来折磨自己。 Sun,Oracle和JCP社区几年前在采用JSR 310时都放弃了这些课程。我建议你也这样做。

请勿使用java.sql.Date

该类是可怕的旧日期时间类的一部分,该类早在几年前就被 java.time 类所取代。特别是这个java.sql.Date的设计特别糟糕。它扩展了java.util.Date,而文档告诉我们忽略了该继承的事实。作为子类,它假装为仅日期的值,但实际上具有从其他Date继承的日期时间,而后者又被错误地命名为日期和一天中的时间。此外,时区潜伏在这些类中,尽管没有任何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类在几年前被替换。使用java.time.Instant。如果交给Timestamp,请立即使用添加到旧类中的新转换方法进行转换。

如果您要在特定日期的第一天,让LocalDate确定。第一个时刻不是不是始终是00:00:00,所以不要以为是。指定人们使用您关心的特定挂钟时间的地区的时区。

continent/region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用3-4个字母的缩写,例如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

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

要在UTC中查看同一时刻,请提取InstantInstant类表示UTC中时间轴上的时刻,分辨率为nanoseconds(十进制小数的九(9)位)。

Instant instant = zdt.toInstant() ;

如果您想在UTC的第一时间,请使用OffsetDateTime

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

转化

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

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框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

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

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore