Calendar类中add/set/roll方法的区别

Calendar类中有三个方法更改日期的某个字段:set()、add() 和 roll()。

set(f, value) 将日历字段 f 更改为 value。此外,它设置了一个内部成员变量,以指示日历字段 f 已经被更改。尽管日历字段 f 是立即更改的,但是直到下次调用 get()、getTime()、getTimeInMillis()、add() 或 roll()时才会重新计算日历的时间值(以毫秒为单位)。因此,多次调用 set() 不会触发多次不必要的计算。使用 set()更改日历字段的结果是,其他日历字段也可能发生更改,这取决于日历字段、日历字段值和日历系统。此外,在重新计算日历字段之后,get(f) 没必要通过调用 set 方法返回 value 集合。具体细节是通过具体的日历类确定的。

示例:假定 GregorianCalendar 最初被设置为 1999 年 8 月 31 日。调用 set(Calendar.MONTH, Calendar.SEPTEMBER) 将该日期设置为 1999 年 9 月 31 日。如果随后调用 getTime(),那么这是解析 1999 年 10 月 1 日的一个暂时内部表示。但是,在调用 getTime() 之前调用 set(Calendar.DAY_OF_MONTH, 30) 会将该日期设置为 1999 年 9 月 30 日,因为在调用 set() 之后没有发生重新计算。

add(f, delta) 将 delta 添加到 f 字段中。这等同于调用 set(f, get(f) + delta),但要带以下两个调整:

  • Add 规则 1。调用后 f 字段的值减去调用前 f 字段的值等于 delta,以字段 f 中发生的任何溢出为模。溢出发生在字段值超出其范围时,结果,下一个更大的字段会递增或递减,并将字段值调整回其范围内。
  • Add 规则 2。如果期望某一个更小的字段是不变的,但让它等于以前的值是不可能的,因为在字段 f发生更改之后,或者在出现其他约束之后,比如时区偏移量发生更改,它的最大值和最小值也在发生更改,然后它的值被调整为尽量接近于所期望的值。更小的字段表示一个更小的时间单元。HOUR 是一个比 DAY_OF_MONTH 小的字段。对于不期望是不变字段的更小字段,无需进行任何调整。日历系统会确定期望不变的那些字段。

此外,与 set() 不同,add() 强迫日历系统立即重新计算日历的毫秒数和所有字段。

示例:假定 GregorianCalendar 最初被设置为 1999 年 8 月 31 日。调用 add(Calendar.MONTH, 13) 将日历设置为 2000 年 9 月 30 日。Add 规则 1 将 MONTH 字段设置为 September,因为向 August 添加 13 个月得出的就是下一年的 September。因为在 GregorianCalendar 中,DAY_OF_MONTH 不可能是 9 月 31 日,所以 add 规则 2 将DAY_OF_MONTH 设置为 30,即最可能的值。尽管它是一个更小的字段,但不能根据规则 2 调整 DAY_OF_WEEK,因为在 GregorianCalendar 中的月份发生变化时,该值也需要发生变化。

roll(f, delta) 将 delta 添加到 f 字段中,但不更改更大的字段。这等同于调用 add(f, delta),但要带以下调整:

  • Roll 规则。在完成调用后,更大的字段无变化。更大的字段表示一个更大的时间单元。DAY_OF_MONTH是一个比 HOUR 大的字段。

示例:请参阅 GregorianCalendar.roll(int, int)。

使用模型。为了帮助理解 add() 和 roll() 的行为,假定有一个用户界面组件,它带有用于月、日、年和底层GregorianCalendar 的递增或递减按钮。如果从界面上读取的日期为 1999 年 1 月 31 日,并且用户按下月份的递增按钮,那么应该得到什么?如果底层实现使用 set(),那么可以将该日期读为 1999 年 3 月 3 日。更好的结果是 1999 年 2 月 28 日。此外,如果用户再次按下月份的递增按钮,那么该日期应该读为 1999 年 3 月 31 日,而不是 1999 年 3 月 28 日。通过保存原始日期并使用 add() 或 roll(),根据是否会影响更大的字段,用户界面可以像大多数用户所期望的那样运行。

假设:f= 2001-1-30 f.add(Calendar.MONTH, 13) = 2002.2.28 f.set(Calendar.MONTH,1) = 2002.3.2 f.roll(Calendar.MONTH, 13) = 2001.2.28

Add:修改后如果符合实际,会调整,但不会改变调整的值,如例子中的MONTH。 Set: 会改变如把2月改为3月。 roll:于Add类似,不同在于不会改变更大的日期单位,如还是2001 不会为2002。

下面为代码演示:

    Calendar c=Calendar.getInstance();
    //c.setTimeInMillis(System.currentTimeMillis());

    c.set(2001,0,30);
    c.add(Calendar.MONTH, 13); 
    System.out.println(c.getTime().toString()); 
    c.set(2001,0,30);
    c.set(Calendar.MONTH,1); 
    System.out.println(c.getTime().toString()); 
    c.set(2001,0,30);
    c.roll(Calendar.MONTH, 13); 
    System.out.println(c.getTime().toString()); 

结果:

    Thu Feb 28 10:22:37 CST 2002
    Fri Mar 02 10:22:37 CST 2001
    Wed Feb 28 10:22:37 CST 2001

注意,Calendar.MONTH是从0开始的,也就是说一月用0表示

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏电光石火

ssm整合Redis

这次谈谈Redis,关于Redis应该很多朋友就算没有用过也听过,算是这几年最流行的NoSql之一了。  Redis的应用场景非常多这里就不一一列举了,这次...

43280
来自专栏转载gongluck的CSDN博客

CTreeCtrl 控件使用总结

一 基础操作  1 插入节点 1)插入根节点 //插入根节点 HTREEITEM hRoot;   CString str=L"ROOT" hRoot=nT...

42880
来自专栏面朝大海春暖花开

redis实现分布式锁工具类 灰常好用

54020
来自专栏我有一个梦想

CTreeCtrl 控件使用总结

一 基础操作  1 插入节点 1)插入根节点 //插入根节点   HTREEITEM hRoot;   CString str=L"ROOT"   hRoot=...

228100
来自专栏强仔仔

SpringBoot中Redis的set、map、list、value、实体类等基本操作介绍

今天给大家介绍一下SpringBoot中Redis的set、map、list、value等基本操作的具体使用方法 上一节中给大家介绍了如何在SpringBoot...

76380
来自专栏电光石火

ssm整合Redis

这次谈谈Redis,关于Redis应该很多朋友就算没有用过也听过,算是这几年最流行的NoSql之一了。 

1.7K50
来自专栏腾讯Bugly的专栏

深入源码探索 ReactNative 通信机制

本文从源码角度剖析 ReactNative 中 Java <> Js 的通信机制(基于最新的 ReactNative for Android Release 2...

34890
来自专栏个人随笔

论 ArrayList如何实现线程安全

假如你创建的代码如下:List<Map<String,Object>> data=new ArrayList<Map<String,Object...

481120
来自专栏大大的微笑

web项目定时执行任务

首先写了个servlet 例如 package com.uap.weixin.service; import java.text.DateFormat; im...

25260
来自专栏Kirito的技术分享

Spring Data Redis(二)--序列化

默认序列化方案 在上一篇文章《Spring Data Redis(一)》中,我们执行了这样一个操作: redisTemplate.opsForValue().s...

988110

扫码关注云+社区

领取腾讯云代金券