【问题标题】:Creating a temporary copy of a Calendar object in Java在 Java 中创建日历对象的临时副本
【发布时间】:2013-05-21 20:34:34
【问题描述】:

我需要弄清楚如何创建一个临时的Calendar 对象(已经存在的“永久”日历的副本),以便我可以操作该副本:tempCal.add(unit, value)。我需要保持原来的日历对象不变,所以我真的不想直接在它上面调用add(unit, value)。

由于我创建副本的任何尝试都没有真正奏效,所以我目前的丑陋技巧是调用 permanentCal.add(unit, value),显示所需的结果,然后调用 permanentCal.add (unit, -value) — 这看起来很不酷。

【问题讨论】:

标签: java calendar


【解决方案1】:

java.util.Calendar 有一个clone 方法,你可以使用它。里面的所有数据都是由原语组成的,所以你不会遇到麻烦。

看看这些答案:

【讨论】:

  • 我真的不敢相信我错过了这一点,而且使用 Eclipse 也是如此——该死的方法就在我面前列出...感谢您提供的信息。
【解决方案2】:

(不适用于安卓)

切换到 java 8 的不可变 LocalDateTime,Calendar/Date 的继承者。这个 API 是一个巨大的改进,一开始可能有点不知所措。

minusDays(long) 之类的方法将返回一个新 日期。这使得线程安全和所有。例如,能够共享一个值而不必担心有人更改它。

【讨论】:

  • 建议 java.time 类是正确的。但是LocalDateTime 是错误的特定类。遗留类GregorianCalendar(通常是Calendar后面的具体类)被ZonedDateTime替换。
  • @BasilBourque 完全同意,因为日历主要用于依赖于区域设置的显示。 ZonedDateTime 处理日间节省等。
【解决方案3】:

如果您想使用时间、日、月、周、年等进行计算,您可以使用timeInMillis 进行复制,如下所示:

Calendar calendarCopy = Calendar.getInstance()
calendarCopy.setTimeInMillis(calendarOriginal.getTimeInMillis)
doSomethingWith(calendarCopy)

这样您可以在副本中包含时间、日、月、周、年等。

【讨论】:

  • 不建议进一步使用Calendar。几年前,JSR 310 中定义的 java.time 类取代了那个可怕的类。
  • @BasilBourque 你是对的,但我们使用它来支持旧版本的 Android 而不使用外部库。 ZonedDateTime 仅支持从 Android Oreo 开始。 Google 仍在其新的 Android 架构组件示例中使用 Calendar。
  • 请参阅my Answer,了解有关在早期 Android 中使用 java.time 功能的反向端口的详细信息。没有必要再次使用那些可恶的Calendar 或GregorianCalendar 类。
  • 仅供参考,后向端口包括在传统类和现代类之间轻松来回转换的方法。因此,您可以继续与尚未更新到 java.time 的旧代码进行互操作,同时仅使用现代类执行所有业务逻辑。
【解决方案4】:

java.time.ZonedDateTime

Calendar 类很糟糕,就像它通常的具体类GregorianCalendar 一样。这些遗留类多年前被现代 java.time 类取代,特别是 ZonedDateTime。

遇到Calendar对象时,看看是否确实是GregorianCalendar对象。如果是这样,请使用添加到旧类的新 to…/from… 方法进行转换。

if( myCal instanceof GregorianCalendar ) {
    GregorianCalendar gc = ( GregorianCalendar ) myCal ;  // Cast to the concrete type.
    ZonedDateTime zdt = gc.toZonedDateTime() ;  // Convert from legacy class to modern class.
}

不可变对象

java.time 类明智地使用immutable objects 模式,适合其用途。

因此,您无需操作现有对象中的单个成员字段。相反,您传递一个新的字段值以根据原始值和您的特定不同值的组合生成一个新对象。请参阅with 方法。

加/减时间跨度

在您的情况下,您似乎想要执行加法或减法以到达新的时刻。

使用指定时间跨度:

  • Duration 以小时-分钟-秒为单位
  • Period 表示年-月-日。

示例:添加几天以获得稍后的时间。

Period p = Period.ofDays( 3 ) ;  
ZonedDateTime threeDaysLater = zdt.plus( p ) ;

为了进行此类工作,您可能会发现下面链接的 ThreeTen-Extra 库提供的 Interval 和 LocalDateRange 类很方便。


关于java.time

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

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

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

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

从哪里获得 java.time 类?

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

【讨论】:

    【解决方案5】:

    乔达时间

    如果您想以很酷的方式执行此操作,请使用 Joda-Time 库。

    这个非常成功的第三方开源日期时间框架为现在内置于 Java 8 及更高版本的java.time 框架提供了灵感。

    【讨论】:

    • 这听起来确实很酷,实际上。在 Android 项目中包含 Joda 有多大意义?
    • 只需将 joda jar 添加到libs/ 目录即可,Joda 包含很多日期/时间助手。但是我没有注意到您正在开发 android 应用程序。在这种特殊情况下,Joda 库可能会给您带来开销。
    • 不是问题,更多的是学术问题。
    • Google 找到一些特殊的 Joda-Time 版本,以解决 Android 中导致初始加载缓慢的一些限制。
    猜你喜欢
    • 1970-01-01
    • 2016-08-08
    • 2020-03-03
    • 1970-01-01
    • 2011-04-30
    • 1970-01-01
    • 2011-09-28
    相关资源
    最近更新 更多