1、calendar概述
java官方推荐使用calendar来替换date的使用,calendar与date之间可以自由的进行转换,转换的纽带是time,使用calendar的gettime()方法可以得到一个date类型的对象,这个对象底层是使用date的第二个带long型参数的构造器创建的,这个long型参数是calendar中的time字段中保存的值,这个time字段的值是在具体的实现类中定义赋值的比如gregoriancalendar中的实现computetime(),这个方法的目的就是将field值转换为time值,这个涉及到calendar中的两种模式,之后会有介绍;而通过calendar的settime(date date)方法可以将一个date对象转换为一个calendar对象,这个方法以一个date对象为参数,底层调用的settimeinmillis(long millis)方法,将date.gettime()的值作为参数,再底层会将这个long型参数值赋值给time字段,这时会重计算field值。
calendar与date的转换
1 public static void main(string[] args) { 2 //calendar--->date 3 calendar c = calendar.getinstance(); 4 date d = c.gettime(); 5 //date--->calendar 6 date d1 = new date(); 7 calendar c1 = calendar.getinstance(); 8 c1.settime(d1); 9 10 system.out.println(d);11 system.out.println(c1.get(calendar.year)+年+(c1.get(calendar.month)+1)+月+c1.get(calendar.date)+日);12 }
结果:
sat jul 08 10:39:14 cst 20172017年7月8日
2、calendar中的time与field
calendar中有两种描述时间内容的域,一种就是time,它用来保存calendar对象所代表的时间点据1970年1月1日 00:00:00的毫秒数,另一种就是field,它是一个数组,它表示的并不是一个内容,而是calendar内部定义的最多静态常量字段。
而这一般情况下是同步的,即表述的是同一时间点,但也有可能会出现不同步的情况:
a、起初,field没有设置,time也是无效的
b、如果time被设置,所有的field都会自动被设置为同步的时间点
c、如果某一field被单独设置,time会自动失效
更确切的说,当我们通过calendar.getinstance()方法获取一个全新的calendar对象时,它所代表的时间点是通过time来设置的,而这个time的值是通过system.currenttimemillis()得到的,通过time定义calendar,istimeset为true,表示time值是最新的(真的),arefieldsset为false,表示field字段的值都是旧的(假的),因为当我们重新设置了time值之后,calendar所代表的时间点就发生了变化(这里是首次,相当于从无到有,也算是变化,之后当我们为calendar的time重新设置一个新值时,calendar的时间点就会再次发生变化,它会指向最新的time值所代表的时间点),而这时field中还表示的是原来的时间点内容,然后会调用computefields()方法进行所有字段值的重计算,确保field中的值与time同步,并同时将arefieldsset和areallfieldsset设置为true,表示所有的field代表的时间值也是最新的了(真)。其实我们每次更改time值都会自动触发重计算,来确保两个域所描述的时间点一致(即同步),这也就是上面b所述的内容。
但是如果我们通过set(int field, int value)单独对field中的某行一字段进行更改时,首先会触发一个验证,arefieldsset为真而areallfieldsset为false时,表示只有一部分field是最新的情况,即存在部分field属于旧的情况,针对这种情况会触发field的重新计算;之后会将istimeset设置为false,arefieldsset设置为false,将isset[field]设置为true(将当前field设置为真),这种情况下,当我们使用gettime()获取time值所代表的时间点时,由于istimeset为false,会触发time的重计算,这个计算依据是根据field的值进行的,之后将istimeset设置为true,同样我们在通过get(int field)获取某个field值时也会先验证istimeset是否为true,如果为false,同样会触发time的重计算,然后验证arefieldsset为false,则触发其余field的重计算。
time的重计算是依据field的,确切的说是依据部分field的,而有一部分field也是在field的基础上再计算的,所以可以说有一部分field是固定的,是和time息息相关的,
以上种种所述全部是calendar内部的实现规则,对外而言,我们只需要简单的调用即可,所有这些都被隐藏在内部,从而保证我们通过对外方法获取到的直接就是正确的值。
1 public static void main(string[] args) throws parseexception { 2 system.out.println(-------初始情况-------); 3 calendar c = calendar.getinstance(); 4 system.out.println(c.gettime()); 5 system.out.println(c.get(calendar.date)); 6 system.out.println(c.get(calendar.hour)); 7 system.out.println(-------重设置time-------); 8 c.settime(new simpledateformat(yyyymmdd).parse(20170501)); 9 system.out.println(c.gettime());10 system.out.println(c.get(calendar.date));11 system.out.println(c.get(calendar.hour));12 system.out.println(-------重设置field-------);13 c.set(calendar.month, 4);14 system.out.println(c.gettime());15 system.out.println(c.get(calendar.date));16 system.out.println(c.get(calendar.hour));17 system.out.println(总结:time与field所代表时间点同步,所有的不同步全部在内部处理完成);18 }
结果:
-------初始情况-------sat jul 08 13:08:34 cst 2017
8
1
-------重设置time-------mon may 01 00:00:00 cst 2017
1
0
-------重设置field-------mon may 01 00:00:00 cst 2017
1
0总结:time与field所代表时间点同步,所有的不同步全部在内部处理完成
3、calendar中的两种解析模式
lenient:该模式下可以自动规则化用户赋值给calendar的不规则值,比如1月32日会被解析为2月1日
non-lenient:该模式下不会自动解析不规则的输入,而是一旦发现不规则输入,就会报出异常
这也叫calendar的容错性,lenient的开启与关闭使用setlenient(boolean lenient)方法来设置,true表示开启容错性(默认情况),false表示关闭该功能。
1 public static void main(string[] args) { 2 calendar c = calendar.getinstance(); 3 c.set(calendar.month, 8); 4 c.set(calendar.day_of_month, 33); 5 system.out.println(c.gettime()+\n); 6 c.setlenient(false); 7 c.set(calendar.month, 8); 8 c.set(calendar.day_of_month, 33); 9 system.out.println(c.gettime());10 }
结果:
tue oct 03 13:18:48 cst 2017exception in thread main java.lang.illegalargumentexception: day_of_month
at java.util.gregoriancalendar.computetime(gregoriancalendar.java:2583)
at java.util.calendar.updatetime(calendar.java:2606)
at java.util.calendar.gettimeinmillis(calendar.java:1118)
at java.util.calendar.gettime(calendar.java:1091)
at jdktest.main(jdktest.java:87)
从上面的例子中可以看出,默认情况下,我们为calendar的月份赋值为8即九月份,日期赋值为33即下一月3号,输出为10月3日,容错性将这种不符合规则的输入规则化处理了,而关闭容错性之后,同样的赋值只会报异常java.lang.illegalargumentexception(非法参数异常)。
4、calendar的使用
1 public static void main(string[] args) throws parseexception { 2 //通过simpledateformat解析日期字符串 3 simpledateformat sdf = new simpledateformat(yyyymmdd hh:mm:ss.sss); 4 date date = sdf.parse(20170502 13:33:23.433); 5 //将date格式日期转换成calendar 6 calendar c = calendar.getinstance(); 7 c.settime(date); 8 //获取时间值 9 system.out.println(c.gettime());10 system.out.println(年份为+c.get(calendar.year));11 system.out.println(月份为+c.get(calendar.month));12 system.out.println(日期为+c.get(calendar.date));13 system.out.println(日期为+c.get(calendar.day_of_month));14 system.out.println(日期为+c.get(calendar.day_of_week));15 system.out.println(日期为+c.get(calendar.day_of_week_in_month));16 system.out.println(日期为+c.get(calendar.day_of_year));17 system.out.println(时为+c.get(calendar.hour));18 system.out.println(时为+c.get(calendar.hour_of_day));19 system.out.println(分为+c.get(calendar.minute));20 system.out.println(秒为+c.get(calendar.second));21 system.out.println(毫秒为+c.get(calendar.millisecond));22 system.out.println(星期为+c.get(calendar.week_of_month));23 system.out.println(星期为+c.get(calendar.week_of_year));24 system.out.println(历型为+c.get(calendar.era));25 system.out.println(zone为+c.get(calendar.zone_offset));26 //设置27 c.set(calendar.month, calendar.april);28 system.out.println(修改后月份为+c.get(calendar.month));29 c.set(1999, 0, 23);30 system.out.println(c.gettime());31 c.set(2000, 1, 12, 13, 33, 14);32 system.out.println(c.gettime());33 c.set(2001, 2, 13, 14, 13);34 system.out.println(c.gettime());35 //运算36 system.out.println(-----运算-----);37 c.add(calendar.year, 12);38 system.out.println(c.gettime());39 c.add(calendar.month, -1);40 system.out.println(c.gettime());41 c.roll(calendar.date, true);42 system.out.println(c.gettime());43 c.add(calendar.date, 1);44 system.out.println(c.gettime());45 //roll与add运算对比46 c.set(2000, 1, 29);47 system.out.println(c.gettime());48 c.roll(calendar.date, 1);49 system.out.println(c.gettime());50 c.set(2000, 1, 29);51 c.add(calendar.date, 1);52 system.out.println(c.gettime());53 }
结果:
tue may 02 13:33:23 cst 2017年份为2017
月份为4
日期为2
日期为2
日期为3
日期为1
日期为122
时为1
时为13
分为33
秒为23
毫秒为433
星期为1
星期为18
历型为1
zone为28800000
修改后月份为3
sat jan 23 13:33:23 cst 1999sat feb 12 13:33:14 cst 2000tue mar 13 14:13:14 cst 2001
-----运算-----wed mar 13 14:13:14 cst 2013wed feb 13 14:13:14 cst 2013thu feb 14 14:13:14 cst 2013fri feb 15 14:13:14 cst 2013tue feb 29 14:13:14 cst 2000tue feb 01 14:13:14 cst 2000wed mar 01 14:13:14 cst 2000
对比上面最后的两行输出,可以看出add与roll的运算规则其实是不同的,roll的运算不会影响大规则(这里的大规则指的是月份的改变)的改变,而add会影响。
以上就是对calendar的概述的详细内容。