【问题标题】:Convert LocalDate to LocalDateTime or java.sql.Timestamp将 LocalDate 转换为 LocalDateTime 或 java.sql.Timestamp
【发布时间】:2012-02-18 00:30:46
【问题描述】:

我正在使用 JodaTime 1.6.2。

我有一个 LocalDate,我需要将其转换为 (Joda) LocalDateTime 或 java.sqlTimestamp 以进行映射。

原因是我已经弄清楚如何在 LocalDateTime 和 java.sql.Timestamp 之间进行转换:

LocalDateTime ldt = new LocalDateTime();
DateTimeFormatter dtf = DateTimeFormatter.forPattern("yyyy-MM-dd HH:mm:ss");
Timestamp ts = Timestamp.valueOf(ldt.toString(dtf));

所以,如果我可以在LocalDate 和LocalDateTime 之间进行转换,那么我可以继续转换为java.sql.Timestamp。感谢您在正确方向上的任何推动!

【问题讨论】:

标签: java timestamp jodatime


【解决方案1】:

乔达时间

要将 JodaTime 的 org.joda.time.LocalDate 转换为 java.sql.Timestamp,只需这样做

Timestamp timestamp = new Timestamp(localDate.toDateTimeAtStartOfDay().getMillis());

要将 JodaTime 的 org.joda.time.LocalDateTime 转换为 java.sql.Timestamp,只需这样做

Timestamp timestamp = new Timestamp(localDateTime.toDateTime().getMillis());

Java时间

要将 Java8 的 java.time.LocalDate 转换为 java.sql.Timestamp,只需这样做

Timestamp timestamp = Timestamp.valueOf(localDate.atStartOfDay());

要将 Java8 的 java.time.LocalDateTime 转换为 java.sql.Timestamp,只需这样做

Timestamp timestamp = Timestamp.valueOf(localDateTime);

【讨论】:

  • 在将LocalDateTime 转换为DateTime 时要小心,因为并非所有LocalDateTimes 都是有效的DateTimes。来源:joda-time.sourceforge.net/faq.html#illegalinstant 刚刚碰到这个。
  • 在 valueOf() 接受字符串时出现参数编译错误。
  • @Patriotic:只有在您实际上没有使用 Java SE 1.8 或更高版本时才会发生这种情况。如答案和提供的 Javadoc 链接中所示(上面答案中的蓝色文本实际上是链接,您可以单击它们以深入了解 Javadoc),Timestamp#valueOf() 方法自 Java SE 1.8 起接受 @987654347 @.
  • java.lang.IllegalArgumentException: 时间戳格式必须是 yyyy-mm-dd hh:mm:ss[.fffffffff];;;;我做Timestamp.valueOf(Timestamp(longtimestampppp).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().toString())
  • 只要按照答案中的最后一个示例,而不是无缘无故地对其进行toString()。
【解决方案2】:

使用 Java 8 time API 的最佳方式:

  LocalDateTime ldt = timeStamp.toLocalDateTime();
  Timestamp ts = Timestamp.valueOf(ldt);

用于与您的模型一起放入的 JPA (https://weblogs.java.net/blog/montanajava/archive/2014/06/17/using-java-8-datetime-classes-jpa):

@Converter(autoApply = true)
public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Timestamp> {
    @Override
    public Timestamp convertToDatabaseColumn(LocalDateTime ldt) {
        return Timestamp.valueOf(ldt);
    }

    @Override
    public LocalDateTime convertToEntityAttribute(Timestamp ts) {
        return ts.toLocalDateTime();
    }
}

所以现在是相对时区独立时间。 此外,它很容易做到:

  LocalDate ld = ldt.toLocalDate();
  LocalTime lt = ldt.toLocalTime();

格式:

 DateTimeFormatter DATE_TME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
 String str = ldt.format(DATE_TME_FORMATTER);
 ldt = LocalDateTime.parse(str, DATE_TME_FORMATTER);

更新:postgres 9.4.1208、HSQLDB 2.4.0 等无需任何对话即可理解 Java 8 Time API!

【讨论】:

【解决方案3】:

tl;博士

Joda-Time 项目处于维护模式,现在被 java.time 类取代。

  • 只需使用java.time.Instant 类。
  • 不需要:
    • LocalDateTime
    • java.sql.Timestamp
    • 字符串

以 UTC 捕获当前时刻。

Instant.now()  

将该时刻存储在数据库中:

myPreparedStatement.setObject( … , Instant.now() )  // Writes an `Instant` to database.

从数据库中检索那个时刻:

myResultSet.getObject( … , Instant.class )  // Instantiates a `Instant`

将挂钟时间调整为特定时区的时间。

instant.atZone( z )  // Instantiates a `ZonedDateTime`

LocalDateTime 是错误的类

其他答案是正确的,但他们没有指出 LocalDateTime 是错误的类。

在 java.time 和 Joda-Time 中,LocalDateTime 故意缺少任何时区或与 UTC 偏移的概念。因此,它确实不代表一个时刻,并且不是时间线上的一个点。 LocalDateTime 代表关于大约 26-27 小时范围内潜在时刻的粗略概念。

当区域/偏移量未知(不是很好的情况)或区域偏移量不确定时,使用LocalDateTime。例如,“圣诞节从 2018 年 12 月 25 日的第一刻开始”将表示为 LocalDateTime。

使用ZonedDateTime 表示特定时区的某个时刻。例如,在Pacific/Auckland 或America/Montreal 等任何特定区域开始的圣诞节将用ZonedDateTime 对象表示。

暂时始终使用 UTC,请使用 Instant。

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

应用时区。同一时刻,时间轴上的同一点,但以不同的挂钟时间查看。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;  // Same moment, different wall-clock time.

所以,如果我可以在 LocalDate 和 LocalDateTime 之间进行转换,

不,错误的策略。如果您有仅日期值,并且需要日期时间值,则必须指定时间。对于特定区域,该时间可能在该日期无效 - 在这种情况下,ZonedDateTime 类会根据需要自动调整时间。

LocalDate ld = LocalDate.of( 2018 , Month.JANUARY , 23 ) ;
LocalTime lt = LocalTime.of( 14 , 0 ) ;  // 14:00 = 2 PM.
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;

如果您想将一天中的第一个时刻作为您的时间,让 java.time 确定那个时刻。不要假设一天从 00:00:00 开始。夏令时 (DST) 等异常情况意味着一天可能从另一个时间开始,例如 01:00:00。

ZonedDateTime zdt = ld.atStartOfDay( z ) ;

java.sql.Timestamp 是错误的类

java.sql.Timestamp 是麻烦的旧日期时间类的一部分,这些类现在已经遗留,完全被 java.time 类所取代。该类用于表示UTC 中的一个时刻,分辨率为nanoseconds。现在,java.time.Instant 可以实现这一目的。

JDBC 4.2 与 getObject/setObject

从JDBC 4.2 及以后,您的JDBC driver 可以通过调用直接与数据库交换java.time 对象:

例如:

myPreparedStatement.setObject( … , instant ) ;

……和……

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

转换传统 ⬌ 现代

如果您必须与尚未更新到 java.time 的旧代码交互,请使用添加到旧类的新方法来回转换。

Instant instant = myJavaSqlTimestamp.toInstant() ;  // Going from legacy class to modern class.

……和……

java.sql.Timestamp myJavaSqlTimestamp = java.sql.Timestamp.from( instant ) ;  // Going from modern class to legacy class.

关于java.time

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

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

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

【讨论】:

    【解决方案4】:

    根据您的时区,您可能会损失几分钟(1650-01-01 00:00:00 变为 1649-12-31 23:52:58)

    使用下面的代码来避免这种情况

    new Timestamp(localDateTime.getYear() - 1900, localDateTime.getMonthOfYear() - 1, localDateTime.getDayOfMonth(), localDateTime.getHourOfDay(), localDateTime.getMinuteOfHour(), localDateTime.getSecondOfMinute(), fractional);
    

    【讨论】:

      【解决方案5】:

      对java.time.LocalDate 对象的函数调用asStartOfDay() 返回一个java.time.LocalDateTime 对象

      【讨论】:

        【解决方案6】:

        由于 Joda 逐渐消失,有人可能希望在 Java 8 中将 LocaltDate 转换为 LocalDateTime。在 Java 8 中,LocalDateTime 将提供一种使用 LocalDate 和 @ 创建 LocalDateTime 实例的方法987654330@。检查here.

        public static LocalDateTime of(LocalDate date, 本地时间)

        示例是,

            // just to create a sample LocalDate
            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
            LocalDate ld = LocalDate.parse("20180306", dtf);
        
            // convert ld into a LocalDateTime
            // We need to specify the LocalTime component here as well, it can be any accepted value
            LocalDateTime ldt = LocalDateTime.of(ld, LocalTime.of(0,0)); // 2018-03-06T00:00
        

        仅供参考,获取下面的纪元秒数可以使用,

            ZoneId zoneId = ZoneId.systemDefault();
            long epoch = ldt.atZone(zoneId).toEpochSecond(); 
        
            // If you only care about UTC
            long epochUTC = ldt.toEpochSecond(ZoneOffset.UTC);
        

        【讨论】:

        • 这里根本不需要使用LocalDateTime。该类故意缺少任何时区或与 UTC 偏移的概念。所以它在这里没有用处。相反:LocalDate.parse( “20180306” , DateTimeFormatter.BASIC_ISO_DATE ).atStartOfDay( ZoneId.of( “Africa/Tunis” ).toEpochSecond() 不要假设一天从 00:00 开始,并非总是如此。
        • 你的意思是什么不要假设一天从 00.00 开始
        • Daylight Saving Time (DST) 等异常意味着在某些地方的某些日期,一天可能从另一个时间开始,例如 01:00:00。因此,与其假设,不如让 java.time 通过调用java.time.LocalDate.atStartOfDay 来确定第一个时刻以获取ZonedDateTime。请参阅my Answer 中的示例。正如我所评论的那样,LocalDateTime 类在这一切中都是无用的并且适得其反。
        • 所以对于LocalDateTime,我们必须使用ZoneId ?
        • 我认为你错过了我的所有观点。在此页面上重新阅读我的答案。搜索 Stack Overflow 以从更多示例和讨论中了解更多信息。但我会在这里最后一次说:LocalDateTime 不 适合手头的问题。 LocalDateTime 确实不代表片刻。 LocalDateTime与任何特定的地区或时区无关,尽管名称乍一看可能暗示其他含义 - 了解有关本课程的意图和详细信息的更多信息。 LocalDateTime 类确实有目的,但不是本问题中看到的目的。
        【解决方案7】:

        Java8 +

        import java.time.Instant;
        Instant.now().getEpochSecond(); //timestamp in seconds format (int)
        Instant.now().toEpochMilli(); // timestamp in milliseconds format (long)
        

        【讨论】:

        • 有用,但似乎并不能真正回答问题。
        • 感谢代码,但与问题无关。
        猜你喜欢
        • 2019-01-11
        • 2013-03-04
        • 2020-12-08
        • 1970-01-01
        • 2013-01-27
        • 2012-09-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多