日期 vs 时间戳 vs 日历?java.time关于 java.time

2022-09-03 04:45:15

我有时会对java中的不同日期类型及其实际用法感到困惑。在这里,我试图总结我的理解

java.sql.Date :-围绕毫秒值的薄包装器,允许 JDBC 将其标识为 SQL DATE 值

java.sql.Timestamp :-围绕 java.util.Date 的精简包装器,允许 JDBC API 将其标识为 SQL TIMESTAMP 值。它增加了保持SQL TIMESTAMP小数秒值的能力,允许小数秒的规格精度达到纳秒

我看到大多数项目更喜欢时间戳而不是日期。我认为这样做的主要原因是时间戳可以保持该值直到纳秒的精度,而数据可以保持到毫秒。正确?

Calendar :-此类设计用于日期操作,例如 :- 用于在特定时间时刻和一组日历字段(如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等)之间进行转换,以及用于操作日历字段(如获取下周的日期)。虽然我不知道为什么这个类是抽象的,当只有一个实现存在,即GregorianCalendar。


答案 1

java.sql.Timestamp 围绕 java.util.Date 的一个精简包装器,它允许 JDBC API 将其标识为 SQL TIMESTAMP 值。

如果您检查java.sql.Timestamp JavaDoc,则非常明确地表明此类从(如java.sql.Date扩展。在现实世界的项目中,将数据存储在数据库中时必须简单明了,主要是因为它存储日期和时间值,而只存储日期值。java.util.Datejava.util.Datejava.sql.Timestampjava.sql.Date

另一方面,它是抽象的,因为除了 之外,还有更多的实现。如果你看到来自 HotSpot 的代码,你会看到它调用 ,并且此方法代码使用 3 种不同的日历:BuddhistCalendarJapaneseImperialCalendarGregorianCalendar。此代码是从 JDK 7 源代码复制的:java.util.Calendarjava.util.GregorianCalendarCalendar#getInstancecreateCalendar(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT))

private static Calendar createCalendar(TimeZone zone,
                                       Locale aLocale) {
    Calendar cal = null;

    String caltype = aLocale.getUnicodeLocaleType("ca");
    if (caltype == null) {
        // Calendar type is not specified.
        // If the specified locale is a Thai locale,
        // returns a BuddhistCalendar instance.
        if ("th".equals(aLocale.getLanguage())
                && ("TH".equals(aLocale.getCountry()))) {
            cal = new BuddhistCalendar(zone, aLocale);
        } else {
            cal = new GregorianCalendar(zone, aLocale);
        }
    } else if (caltype.equals("japanese")) {
        cal = new JapaneseImperialCalendar(zone, aLocale);
    } else if (caltype.equals("buddhist")) {
        cal = new BuddhistCalendar(zone, aLocale);
    } else {
        // Unsupported calendar type.
        // Use Gregorian calendar as a fallback.
        cal = new GregorianCalendar(zone, aLocale);
    }

    return cal;
}

现在,为什么要直接使用而不是?因为您必须在提供抽象类和接口时使用抽象类和接口,而不是直接使用实现。这里可以更好地解释这一点:“编程到接口”是什么意思?CalendarGregorianCalendar

除此之外,如果您要使用日期和时间,我建议使用像Joda-Time这样的库,它已经处理并解决了当前Java Date API的许多问题,并且还提供了检索此日期和时间对象的方法。java.util.Date


答案 2

java.time

您必须首先了解,那些与早期版本的Java捆绑在一起的旧日期时间类是一团混乱的,这些类设计得很糟糕,带有hacks。它们是业界首次尝试使用复杂的日期时间处理设施,值得称赞。但最终他们失败了。

它们已被Java 8及更高版本中内置的新java.time框架所取代。

仅对于日期,不带时间或时区,请使用 java.time.LocalDate。在 UTC 时间轴上稍作停留,请使用 java.time.Instant。要为即时分配不同的时区,请使用 java.time.ZonedDateTime

请注意,与 UTC 的偏移量仅比 UTC 早于或晚于 UTC 数小时和分钟。时区是某个地区的人们使用的偏移量的过去,现在和未来变化的历史。

如果日期时间值的日期时间值的偏移量与 UTC 的偏移量而不是时区,请使用类来表示该值。然后调用其方法,以获取要发送到数据库的对象,该列的类型类似于 SQL 标准 。OffsetDateTimetoInstantInstantTIMESTAMP WITH TIME ZONE

SQL 标准类型(不带,不)故意缺少时区或与 UTC 的偏移量的任何概念。旧版日期时间类无法表示此类值。现在,在java.time中,我们有.TIMESTAMP WITHOUT TIME ZONELocalDateTime

如果您的 JDBC 驱动程序符合 JDBC 4.2 或更高版本,则可以直接与数据库交换 java.time 对象。无需再次使用java.sql日期项类型。

myPreparedStatement.setObject( … , instant ) ;

和检索。

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

调整到特定地区(时区)的人们使用的挂钟时间。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

关于 java.time

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

Joda-Time 项目现在处于维护模式,建议迁移到 java.time 类。

要了解更多信息,请参阅 Oracle 教程。搜索 Stack Overflow 以获取许多示例和解释。规格是JSR 310

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

从哪里获取 java.time 类?

ThreeTen-Extra 项目通过其他类扩展了 java.time。这个项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuarter