Java时间戳转换错误

时间:2014-07-07 07:42:28

标签: java sql

这是我的时间戳问题:

在MySql数据库中,列名为creation_date,数据类型为timestamp

列中的值为2014-07-04 17:35:07.0 当我尝试使用java代码将其转换为毫秒时,它显示不同的行为

例如

如果我使用hibernate获取它并打印timestamp.getTime()它会显示1404484507000

但在做的时候

Timestamp t=new Timestamp(2014, 7, 4, 17, 35, 7, 0);
System.out.println("t.getTime() - "+t.getTime());

显示61365297907000

这里出了什么问题。

3 个答案:

答案 0 :(得分:1)

您是否为正在调用的(已弃用的)构造函数阅读了documentation?特别是:

  

年 - 年减去1900年   月 - 0到11

我强烈建议你不要打电话给那个构造函数。如果您使用的是Java 8,请使用java.time.Instant,然后使用java.sql.Timestamp.fromInstant

否则,您可以调用构造函数取long(毫秒数),然后单独设置nanos部分。

请注意,值1404484507000代表UTC时间14:35:07,因此您的数据库可能正在执行时区转换。

答案 1 :(得分:1)

tl; dr

来自数据库。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;  // Most databases including MySQL store a moment in a column of a data type akin to the SQL-standard `TIMESTAMP WITH TIME ZONE` as UTC. So retrieve as a `OffsetDateTime` object, expecting its zone to be set to UTC. 
ZonedDateTime zdt = odt.atZoneSameInstant( ZoneId.of( "Pacific/Auckland" ) ) ;  // Adjust into any time zone you desire. Same moment, different wall-clock time.

数据库。

myPreparedStatement.setObject(       // As of JDBC 4.2, exchange java.time objects with your database, not mere integers or strings.
    … , 
    ZonedDateTime.of(
        2014 , 7 , 4 ,
        17 , 35 , 7 , 0 ,
        ZoneId.of( "Africa/Tunis" )  // Specify the time zone giving context to that date and time – where on earth did you mean 5 PM?
    )
    .toOffsetDateTime()              // Adjust from that zone to UTC.
    .withOffsetSameInstant(
        ZoneOffset.UTC
    ) 
) ;

java.time

现代解决方案使用 java.time 类。

LocalDate ld = LocalDate.of( 2014 , Month.JULY , 4 ) ;  // Or use integer `7` for July, 1-12 for January-December.
LocalTime lt = LocalTime.of( 17 , 35 , 7 );

要确定时刻,您需要的不仅仅是日期和时间。您需要一个时区来提供上下文。您是指日本的下午5点,法国的下午5点,还是魁北克的下午5点?那将是三个不同时刻中的任何一个。

时区对于确定日期至关重要。在任何给定时刻,日期都会在全球范围内变化。例如,Paris France午夜之后的几分钟是新的一天,而Montréal Québec仍然是“昨天”。

如果未指定时区,则JVM隐式应用其当前的默认时区。该默认值可能在运行时(!)期间change at any moment,因此您的结果可能会有所不同。最好将desired/expected time zone明确指定为参数。

如果要使用JVM的当前默认时区,请提出要求并作为参数传递。如果省略,则会隐式应用JVM的当前默认值。最好明确一点,因为默认值可能会在运行时的任何时候被JVM中任何应用程序的任何线程中的任何代码更改。

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

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

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;

从该区域调整为UTC。

OffsetDateTime odt = zdt.toOffsetDateTime().withOffsetSameInstant( ZoneOffset.UTC ) ;

从JDBC 4.2开始,我们可以直接与数据库交换 java.time 对象。

myPreparedStatement.setObject( … , odt ) ;

和检索。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

请注意,我们从未要求epoch reference中的整数。我们使用智能对象,而不是哑的整数或字符串。

对于Hibernate,我不是用户,但是我知道它已经更新为可以与 java.time 类一起使用。


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

答案 2 :(得分:0)

MySQL使用与Java不同的日期格式。

您可以使用getTime和getDate函数从ResultSet转换它:

String query = "SELECT date FROM bean";
[...]
bean.setDate(toJavaDate(resultSet.getDate(1), resultSet.getTime(1)));

toJavaDate代码是:

public java.util.Date toJavaDate(java.sql.Date sqlDate, java.sql.Time sqlTime){
    Calendar calendar = new GregorianCalendar();

    calendar.set(Calendar.YEAR, sqlDate.getYear() + 1900);
    calendar.set(Calendar.MONTH, sqlDate.getMonth());
    calendar.set(Calendar.DAY_OF_MONTH, sqlDate.getDate());
    calendar.set(Calendar.HOUR_OF_DAY, sqlTime.getHours());
    calendar.set(Calendar.MINUTE, sqlTime.getMinutes());
    calendar.set(Calendar.SECOND, sqlTime.getSeconds());

    return calendar.getTime();        
}

反向操作,以便在MySQL表中保存新日期:

String query = "UPDATE bean SET date = '" + toSqlDate(bean.getDate());

其中toSqlDate是:

public String toSqlDate(java.util.Date javaDate){
        String sqlDate = (javaDate.getYear()+1900)+"-"+javaDate.getMonth()+"-"+javaDate.getDate()+" "
                     +javaDate.getHours()+":"+javaDate.getMinutes()+":"+javaDate.getSeconds();
    return sqlDate;        
}

现在你可以重新检查毫秒:

long milliseconds = date.getTime();