如何从 java.sql.Timestamp 转换为 java.util.Date?

Posted

技术标签:

【中文标题】如何从 java.sql.Timestamp 转换为 java.util.Date?【英文标题】:How to convert from java.sql.Timestamp to java.util.Date? 【发布时间】:2012-05-24 04:30:08 【问题描述】:

这段代码

startDate = new Date(timestampValue.getTime));

给我:

2012-16-02 05:16:17

什么时候

System.out.println(timestampValue);

返回:

2012-01-02 05:16:17.0

【问题讨论】:

你想要他们做什么?您希望它们具有保存的字符串表示形式,还是要将对象转换为以编程方式使用? 一个主题中的问题:) 如何从 java.sql.Timestamp 转换为 java.util.Date?... 我想做什么?只需从时间戳转换为日期并具有相同的值...我知道...日期没有纳秒...剂量很重要... 无需转换。时间戳日期。 如果它很简单并且 Timestamp 是一个 Date 告诉我为什么有区别......?例如......在转换之后和之前? @HotLicks 您的评论不正确且不明智。虽然在技术上是正确的,但 java.sql.Timestamp 确实从 java.util.Date 继承,这种继承是一种 hack。 The doc 明确表示您应该将 j.sql.Timestamp 视为 j.u.Date 的子类。请参阅 Alex Shesterov 在this Answer 上的评论。 【参考方案1】:

java.sql.TimeStamp 类扩展自 java.util.Date

您可以直接将TimeStamp 对象分配给Date 引用:

TimeStamp timeStamp = //whatever value you have;
Date startDate = timestampValue;

【讨论】:

@jelies:不,不应该。根据Java docs:Due to the differences between the Timestamp class and the java.util.Date class ... it is recommended that code not view Timestamp values generically as an instance of java.util.Date. The inheritance relationship between Timestamp and java.util.Date really denotes implementation inheritance, and not type inheritance. 哇,你是对的......这种继承非常具有误导性:/正确答案是here。 这个答案不应该被投票 - 它是不正确的。一旦开始比较它们等操作,混合使用 Timestamp 和 Date 实例将导致难以发现错误。【参考方案2】:

您应该改用Calendar:

Calendar start = Calendar.getInstance();
start.setTimeInMillis( timeStampValue.getTime() );

【讨论】:

是的,它几乎可以工作,但现在我遇到了 priefaces 日历组件的问题......它只支持 java.util.Date :D【参考方案3】:

tl;博士

Instant instant = myResultSet.getObject( … , Instant.class ) ;

…或者,如果您的 JDBC 驱动程序不支持可选的Instant,则需要支持OffsetDateTime

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

避免使用java.util.Datejava.sql.Timestamp。它们已被java.time 类取代。具体来说,Instant 类表示UTC 中时间轴上的一个时刻,分辨率为nanoseconds(最多九 (9) 位小数)。

不同的值→未验证的问题

解决问题的主要部分:“当 java.util.Date 和 java.sql.Timestamp 对象从另一个派生时,为什么会有不同的日期?”

您的代码一定有问题。您没有发布您的代码,因此我们无法查明问题所在。

首先,您为 java.util.Date 的值显示的字符串值并非来自其默认的 toString 方法,因此您显然正在执行其他操作。

其次,当我运行类似的代码时,我确实得到了完全相同的日期时间值。

首先创建一个 java.sql.Timestamp 对象。

// Timestamp
long millis1 =  new java.util.Date().getTime();
java.sql.Timestamp ts = new java.sql.Timestamp(millis1);

现在提取 count-of-milliseconds-since-epoch 以实例化 java.util.Date 对象。

// Date
long millis2 = ts.getTime();
java.util.Date date = new java.util.Date( millis2 );

将值转储到控制台。

System.out.println("millis1 = " + millis1 );
System.out.println("ts = " + ts );
System.out.println("millis2 = " + millis2 );
System.out.println("date = " + date );

运行时。

millis1 = 1434666385642
ts = 2015-06-18 15:26:25.642
millis2 = 1434666385642
date = Thu Jun 18 15:26:25 PDT 2015

所以问题中显示的代码确实是从 java.sql.Timestamp 转换为 java.util.Date 的有效方法,尽管您将丢失任何 nanoseconds 数据。

java.util.Date someDate = new Date( someJUTimestamp.getTime() ); 

字符串输出的不同格式

请注意,toString 方法的输出是不同的格式,如文档所述。 java.sql.Timestamp 遵循 SQL 格式,类似于ISO 8601 格式,但中间没有T

忽略继承

正如在其他答案和问题上的 cmets 中所讨论的,您应该忽略 java.sql.Timestamp 继承自 java.util.Date 的事实。 The j.s.Timestamp doc 明确指出您应该将一个视为另一个的子类型:(强调我的)

由于上面提到的 Timestamp 类和 java.util.Date 类之间的差异,建议代码不要将 Timestamp 值一般视为 java.util.Date 的实例。 Timestamp 和 java.util.Date 的继承关系实际上是实现继承,而不是类型继承。

如果您忽略 Java 团队的建议并采取这样的观点,那么一个关键问题是 您将丢失数据:任何可能来自数据库丢失,因为 Date 只有 millisecond 分辨率。

基本上,早期 Java 中的所有旧日期时间类都是一团糟:java.util.Datej.u.Calendarjava.text.SimpleDateFormatjava.sql.Timestamp/.Date/.Time。它们是业界最早在日期时间框架上做出的勇敢努力之一,但最终失败了。具体来说,java.sql.Timestamp 是一个带有纳秒的 java.util.Date;这是一个 hack,不是好的设计。

java.time

避免与早期版本的 Java 捆绑的旧日期时间类。

尽可能使用 Java 8 及更高版本中内置的 java.time package (Tutorial)。

java.time 的基础知识...Instant 是 UTC 时间线上的一个时刻。应用时区 (ZoneId) 以获取 ZonedDateTime

使用 java.time 从 Java 8 开始的示例代码。使用支持 JDBC 4.2 及更高版本的 JDBC 驱动程序,您可以直接与数据库交换 java.time 类;不需要遗留类。

Instant instant = myResultSet.getObject( … , Instant.class) ;  // Instant is the raw underlying data, an instantaneous point on the time-line stored as a count of nanoseconds since epoch.

您可能需要调整到 UTC 以外的时区。

ZoneId z = ZoneId.of( "America/Montreal" );  // Always make time zone explicit rather than relying implicitly on the JVM’s current default time zone being applied.
ZonedDateTime zdt = instant.atZone( z ) ;

执行您的业务逻辑。在这里,我们只是简单地添加一天。

ZonedDateTime zdtNextDay = zdt.plusDays( 1 ); // Add a day to get "day after".

在最后阶段,如果绝对需要,转换为 java.util.Date 以实现互操作性。

java.util.Date dateNextDay = Date.from( zdtNextDay.toInstant( ) );  // WARNING: Losing data (the nanoseconds resolution).

转储到控制台。

System.out.println( "instant = " + instant );
System.out.println( "zdt = " + zdt );
System.out.println( "zdtNextDay = " + zdtNextDay );
System.out.println( "dateNextDay = " + dateNextDay );

运行时。

instant = 2015-06-18T16:44:13.123456789Z
zdt = 2015-06-18T19:44:13.123456789-04:00[America/Montreal]
zdtNextDay = 2015-06-19T19:44:13.123456789-04:00[America/Montreal]
dateNextDay = Fri Jun 19 16:44:13 PDT 2015

转化次数

如果您必须使用遗留类型与尚未针对 java.time 更新的旧代码进行接口,您可以转换。使用添加到旧 java.util.Date 和 java.sql.* 类的新方法进行转换。

Instant instant = myJavaSqlTimestamp.toInstant() ;

……和……

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

有关转换的更多信息,请参阅教程章节 Legacy Date-Time Code。

小数秒

注意小数秒的分辨率。从纳秒到毫秒的转换意味着可能会丢失一些数据。

Milliseconds java.util.Date Joda-Time(启发 java.time 的框架) Nanoseconds java.sql.Timestamp java.time

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

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

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

从哪里获得 java.time 类?

Java SE 8Java SE 9Java SE 10 及更高版本 内置。 标准 Java API 的一部分,带有捆绑实现。 Java 9 添加了一些小功能和修复。 Java SE 6Java SE 7 ThreeTen-Backport 中的大部分 java.time 功能都向后移植到 Java 6 和 7。 Android java.time 类的 android 捆绑包实现的更高版本。 对于早期的 Android (ThreeTenABP 项目适应 ThreeTen-Backport(如上所述)。见How to use ThreeTenABP…

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

【讨论】:

this 应该是公认的答案。如果有人仍然可以给一个非常好的答案加分,我会用这个答案来做到这一点。【参考方案4】:

问题可能来自于 Date 已被弃用的事实。

考虑使用

java.util.日历

Joda-Time

2015 年编辑:

Java 8 及更高版本内置了新的java.time package,类似于Joda-Time。

【讨论】:

嗯....我只是关注priefaces....并且在primefaces日历中他们仍然使用java.util.Date ....我会用Calendar检查它:) java.util.Date 类没有完全被弃用,只是它的许多方法被弃用了。但是,正如这个答案正确暗示的那样,java.util.Date 类 已被 Joda-Time 和 java.time 过时,应尽可能避免使用。 @MarcinPetrów 尽可能使用 java.time(如果在 Java 8 之前,则使用 Joda-Time,或者 Joda-Time 具有 java.time 中缺少的功能,例如 Interval)来执行所有业务逻辑。在最后时刻,通过调用 Joda-Time 中的 DateTime::toDate 方法,在必要时转换为 java.util.Date 以实现互操作性,或者对于 java.time,请参阅 Legacy Date-Time Code 上的教程章节。 同样适用于许多其他 3rd 方包,例如仅支持 java.util.Date 和 java.util.Calendar 的 Apache POI。正如@BasilBourque 所说,在您的主要编程逻辑中使用最新的类,然后在 api 处转换为 3rd 方包。将来升级时也可以更轻松地进行维护。【参考方案5】:

花哨的新 Java 8 方式是Date.from(timestamp.toInstant())。请参阅我的类似答案elsewhere。

【讨论】:

【参考方案6】:
public static Date convertTimestampToDate(Timestamp timestamp)  
        Instant ins=timestamp.toLocalDateTime().atZone(ZoneId.systemDefault()).toInstant();
        return  Date.from(ins);

【讨论】:

通常我们希望在 Answers 上看到一些划分或解释。 Stack Overflow 不仅仅是一个 sn-p 库。能解释一下吗? 您应该在代码中添加一些解释。仅代码的答案是不受欢迎的。为什么你的代码有效,它如何回答这个问题?将其包含在您的答案中。【参考方案7】:
java.sql.ResultSet rs;
//fill rs somehow
java.sql.Timestamp timestamp = rs.getTimestamp(1); //get first column
long milliseconds = timestamp.getTime() + (timestamp.getNanos() / 1000000);
java.util.Date date = return new java.util.Date(milliseconds);

【讨论】:

这将返回错误的分钟,例如 2015-12-03 15:37:59.503【参考方案8】:

时间戳是一个日期:https://docs.oracle.com/javase/7/docs/api/java/sql/Timestamp.html

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

【讨论】:

不是一个好的答案。 Date 和 Timestamp 之间的这种继承关系是一种 hack,一种糟糕的类设计。 documentation 明确警告您“不要将时间戳值一般视为 java.util.Date 的实例”。请参阅my Answer 了解更多信息。

以上是关于如何从 java.sql.Timestamp 转换为 java.util.Date?的主要内容,如果未能解决你的问题,请参考以下文章

使用 JOOQ 在 java.sql.Timestamp 和 java.time.Instant 之间转换时遇到问题

将 java.time.Instant 转换为没有区域偏移的 java.sql.Timestamp

将 Java 字符串转换为 sql.Timestamp

将 java.sql.Timestamp 转换为 Java 8 ZonedDateTime?

无法在 Spring Data Cloud Spanner 中将 java.sql.Timestamp 转换为 com.google.cloud.Timestamp

将 java.sql.Timestamp 转换为 javax.xml.datatype.XMLGregorianCalendar 而不会丢失 nanos