原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/7136575.html

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. }

结果:

  1. Sat Jul 08 10:39:14 CST 2017
  2. 201778

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. }

结果:

  1. -------初始情况-------
  2. Sat Jul 08 13:08:34 CST 2017
  3. 8
  4. 1
  5. -------重设置time-------
  6. Mon May 01 00:00:00 CST 2017
  7. 1
  8. 0
  9. -------重设置field-------
  10. Mon May 01 00:00:00 CST 2017
  11. 1
  12. 0
  13. 总结:timefield所代表时间点同步,所有的不同步全部在内部处理完成

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. }

结果:

  1. Tue Oct 03 13:18:48 CST 2017
  2.  
  3. Exception in thread "main" java.lang.IllegalArgumentException: DAY_OF_MONTH
  4. at java.util.GregorianCalendar.computeTime(GregorianCalendar.java:2583)
  5. at java.util.Calendar.updateTime(Calendar.java:2606)
  6. at java.util.Calendar.getTimeInMillis(Calendar.java:1118)
  7. at java.util.Calendar.getTime(Calendar.java:1091)
  8. 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. }

结果:

  1. Tue May 02 13:33:23 CST 2017
  2. 年份为2017
  3. 月份为4
  4. 日期为2
  5. 日期为2
  6. 日期为3
  7. 日期为1
  8. 日期为122
  9. 时为1
  10. 时为13
  11. 分为33
  12. 秒为23
  13. 毫秒为433
  14. 星期为1
  15. 星期为18
  16. 历型为1
  17. zone28800000
  18. 修改后月份为3
  19. Sat Jan 23 13:33:23 CST 1999
  20. Sat Feb 12 13:33:14 CST 2000
  21. Tue Mar 13 14:13:14 CST 2001
  22. -----运算-----
  23. Wed Mar 13 14:13:14 CST 2013
  24. Wed Feb 13 14:13:14 CST 2013
  25. Thu Feb 14 14:13:14 CST 2013
  26. Fri Feb 15 14:13:14 CST 2013
  27. Tue Feb 29 14:13:14 CST 2000
  28. Tue Feb 01 14:13:14 CST 2000
  29. Wed Mar 01 14:13:14 CST 2000

  对比上面最后的两行输出,可以看出add与roll的运算规则其实是不同的,roll的运算不会影响大规则(这里的大规则指的是月份的改变)的改变,而add会影响。

  综上所述,我们可以简单的认识一下Calendar类,并学会简单的使用它,对于其内部实现,还需要认真敲一敲源码。

java基础系列--Calendar类的更多相关文章

  1. Java基础(38):Calendar类的应用(优于Date类)

    Calendar 类的应用 Date 类最主要的作用就是获得当前时间,同时这个类里面也具有设置时间以及一些其他的功能,但是由于本身设计的问题,这些方法却遭到众多批评,不建议使用,更推荐使用 Calen ...

  2. java基础系列--Date类

    原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/7126930.html 1.Date类概述 Date类是从JDK1.1就开始存在的老类,其提 ...

  3. Java基础之Calendar类、JNDI之XML

     一.Calendar类 从JDK1.1版本开始,在处理日期和时间时,系统推荐使用Calendar类进行实现.在设计上,Calendar类的功能要比Date类强大很多,而且在实现方式上也比Date类要 ...

  4. Java基础系列--07_Object类的学习及源码分析

    Object: 超类 (1)Object是类层次结构的顶层类,是所有类的根类,超类.   所有的类都直接或者间接的继承自Object类.   所有对象(包括数组)都实现这个类的方法 (2)Object ...

  5. 夯实Java基础系列9:深入理解Class类和Object类

    目录 Java中Class类及用法 Class类原理 如何获得一个Class类对象 使用Class类的对象来生成目标类的实例 Object类 类构造器public Object(); register ...

  6. 夯实Java基础系列14:深入理解Java枚举类

    目录 初探枚举类 枚举类-语法 枚举类的具体使用 使用枚举类的注意事项 枚举类的实现原理 枚举类实战 实战一无参 实战二有一参 实战三有两参 枚举类总结 枚举 API 总结 参考文章 微信公众号 Ja ...

  7. Java基础系列2:深入理解String类

    Java基础系列2:深入理解String类 String是Java中最为常用的数据类型之一,也是面试中比较常被问到的基础知识点,本篇就聊聊Java中的String.主要包括如下的五个内容: Strin ...

  8. Java基础系列--static关键字

    原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/8477914.html 一.概述 static关键字是Java诸多关键字中较常使用的一个,从 ...

  9. Java基础系列-ArrayList

    原创文章,转载请标注出处:<Java基础系列-ArrayList> 一.概述 ArrayList底层使用的是数组.是List的可变数组实现,这里的可变是针对List而言,而不是底层数组. ...

随机推荐

  1. 【JavaScript你需要知道的基础知识~】

    最近开始学习JavaScript,整理了一些相关的基础知识 JS注释方式:// 单行注释(Ctrl+/ )/* 段落注释(Ctrl+shift+/ )*/ [JavaScript基础]JavaScri ...

  2. 关于Laravel中的artisan命令

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Helvetica; color: #454545 } p.p2 { margin: 0.0p ...

  3. php implode()函数详解

    php implode()函数的作用? php 中implode() 函数是返回一个由数组元素组合成的字符串,它与php explode()函数的作用是相反的,php explode() 函数是:使用 ...

  4. Github+Hexo,搭建专有博客

    前言 记得从大二开始,就一直想搭个专属网站,当时使劲抠页面[前端页面是从QQ空间抠的,现在想抠估计没这么容易了],写代码,忙活半天才把程序弄好. 可惜最终项目还是没上线,因为当时有两问题绕不开 需要购 ...

  5. python爬虫从入门到放弃(四)之 Requests库的基本使用

    什么是Requests Requests是用python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库如果你看过上篇文章关于urllib库的使用,你会发现,其 ...

  6. 探讨SQL Server并发处理存在就更新七种解决方案

    前言 本节我们来讲讲并发中最常见的情况存在即更新,在并发中若未存在行记录则插入,此时未处理好极容易出现插入重复键情况,本文我们来介绍对并发中存在就更新行记录的七种方案并且我们来综合分析最合适的解决方案 ...

  7. Java经典编程题50道之十八

    两个乒乓球队进行比赛,各出三人.甲队为a,b,c三人,乙队为x,y,z三人,以抽签决定比赛名单.有人向队员打听比赛的名单:a说他不和x比,c说他不和x. z比.请编程序找出三队赛手的名单. publi ...

  8. Java经典编程题50道之二十六

    请输入星期几的第一个字母来判断一下是星期几,如果第一个字母一样,则继续判断第二个字母. public class Example26 {    public static void main(Stri ...

  9. sock

    头和尾基本用来做校验, 不是拿来做边界的. 头+类型+长度+数据+尾, 这种结构就可以. 拆包就是: 检验头, 然后拆出类型+长度, 然后根据长度拆数据, 然后检验尾巴.

  10. 利用SSH框架开发时遇到的各种Bug及解决方法

    .hibernate自动生成的配置文件 hibernate.cfg.xml 有时候是有问题的,会出现 org.hibernate.HibernateException: Could not parse ...