java时间操作三部曲之java.util.Calendar
Calendar是个抽象类,它为特定瞬间与一组诸如 YEAR
、MONTH
、DAY_OF_MONTH
、HOUR
等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。瞬间可用毫秒值来表示,它是距历元(即格林威治标准时间 1970 年 1 月 1 日的 00:00:00.000,格里高利历)的偏移量。它有一个具体的实现类GregorianCalendar子类。
Calendar类中定义了大量的常量用于方便获取某一瞬间的个个元素点,比如年,月,日,在当年中的第几天,在当月中的第几天等等。
public static void main(String[] args) { Calendar c=Calendar.getInstance();//2016-11-01 09:27 System.out.println(c); }
//下面数据为输出数据 java.util.GregorianCalendar[ time=1477963633233, (日历当前设置时间,毫秒单位) areFieldsSet=true,(如果 fields[] 与当前的设置时间同步,则返回 true。) areAllFieldsSet=true, lenient=true, ( Calendar 有两种解释日历字段的模式,即 lenient 和 non-lenient。当 Calendar 处于 lenient 模式时,它可接受比它所生成的日历字段范围更大范围内的值。
当 Calendar 重新计算日历字段值,以便由 get() 返回这些值时,所有日历字段都被标准化。例如,lenient 模式下的 GregorianCalendar 将 MONTH == JANUARY、DAY_OF_MONTH == 32
解释为 February 1。 当 Calendar 处于 non-lenient 模式时,如果其日历字段中存在任何不一致性,它都会抛出一个异常。例如,GregorianCalendar 总是在 1 与月份的长度之间生成 DAY_OF_MONTH 值。
如果已经设置了任何超出范围的字段值,那么在计算时间或日历字段值时,处于 non-lenient 模式下的 GregorianCalendar 会抛出一个异常。) zone=sun.util.calendar.ZoneInfo[ id="Asia/Shanghai", offset=28800000, dstSavings=0, useDaylight=false, transitions=19, lastRule=null], firstDayOfWeek=1, minimalDaysInFirstWeek=1, ERA=1, YEAR=2016,(年) MONTH=10,(月,10+1,因为是从0开始的) WEEK_OF_YEAR=45,(在当前年是第几周) WEEK_OF_MONTH=1,(在当前月是第几周) DAY_OF_MONTH=1,(指示一个月中的某天,一个月中第一天的值为 1。) DAY_OF_YEAR=306,(在一年中的第几天) DAY_OF_WEEK=3,(在一周的第几天,第一天为周日) DAY_OF_WEEK_IN_MONTH=1,当前月的第几个星期 AM_PM=0,(指示 HOUR 是在中午之前还是在中午之后。例如,在 10:04:15.250 PM 这一时刻,AM_PM 为 PM。) HOUR=9,(小时,12时制,值为1-11) HOUR_OF_DAY=9,(24小时制,时间0-23) MINUTE=27,(分钟) SECOND=13,(秒) MILLISECOND=233,(毫秒) ZONE_OFFSET=28800000, DST_OFFSET=0]
类构造函数
1.protected Calendar() 关键字可以看出,Calendar不希望我们外部直接创建实例,其实Calendar是一个抽象类,不能直接实例化的。
类方法
1.static Calendar getInstance() 因为该类是抽象类无法实例化,因此类的创造者提供了获取Calendar实例的方法,看一下源码
public static Calendar getInstance() { return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT)); } private static Calendar createCalendar(TimeZone zone,Locale aLocale) { CalendarProvider provider =LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale).getCalendarProvider(); if (provider != null) { try { return provider.getInstance(zone, aLocale); } catch (IllegalArgumentException iae) { // fall back to the default instantiation } } Calendar cal = null; if (aLocale.hasExtensions()) { String caltype = aLocale.getUnicodeLocaleType("ca"); if (caltype != null) { switch (caltype) { case "buddhist": cal = new BuddhistCalendar(zone, aLocale); break; case "japanese": cal = new JapaneseImperialCalendar(zone, aLocale); break; case "gregory": cal = new GregorianCalendar(zone, aLocale); break; } } } if (cal == null) { // If no known calendar type is explicitly specified, // perform the traditional way to create a Calendar: // create a BuddhistCalendar for th_TH locale, // a JapaneseImperialCalendar for ja_JP_JP locale, or // a GregorianCalendar for any other locales. // NOTE: The language, country and variant strings are interned. if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") { cal = new BuddhistCalendar(zone, aLocale); } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja" && aLocale.getCountry() == "JP") { cal = new JapaneseImperialCalendar(zone, aLocale); } else { cal = new GregorianCalendar(zone, aLocale); } } return cal; }
其实返回的就是GregorianCalendar的实例对象
2.setTime 和 getTime 方法 设置或返回一个表示此 Calendar
时间值(从历元至现在的毫秒偏移量)的 Date
对象。
Calendar c = Calendar.getInstance(); Date date_one = new Date(1421565547000L); c.setTime(date_one); System.out.println(c.get(Calendar.YEAR)+"年 "+(c.get(Calendar.MONTH)+1)+"月 "+c.get(Calendar.DAY_OF_MONTH)+"日");//2015年 1月 18日
3.set(int field,int value) 以及该方法的重载,将给定的日历字段设置为给定值。不管处于何种宽松性模式下,该值都不由此方法进行解释。
在使用set方法之前,必须先clear一下,否则很多信息会继承自系统当前时间
重载:set(int year,int month,int date);后面还可以加时,分,秒
Calendar c=Calendar.getInstance(); Date date_one=new Date(1421565547000L); c.setTime(date_one); System.out.println(c.get(Calendar.YEAR)+"年 "+(c.get(Calendar.MONTH)+1)+"月 "+c.get(Calendar.DAY_OF_MONTH)+"日");//2015年 1月 18日 c.set(Calendar.YEAR,2016); System.out.println(c.get(Calendar.YEAR)+"年 "+(c.get(Calendar.MONTH)+1)+"月 "+c.get(Calendar.DAY_OF_MONTH)+"日");//2016年 1月 18日 c.set(2016, (11-1), 01, 13, 43,23); System.out.println(c.get(Calendar.YEAR)+"年 "+(c.get(Calendar.MONTH)+1)+"月 "+c.get(Calendar.DAY_OF_MONTH)+"日 "+c.get(Calendar.HOUR_OF_DAY)+":"+c.get(Calendar.MINUTE));//2016年 11月 1日 13:43
4.clear() 将此 Calendar
的所日历字段值和时间值(从历元至现在的毫秒偏移量)设置成未定义。也可以针对某一个属性设为为定义,就是用clear(int field)
5.before() 和 after() 这两个方法和Date对象的before 和 after 用法一致
6.add(int field,int amount) 根据日历的规则,为给定的日历字段添加或减去指定的时间量。例如,要从当前日历时间减去 5 天,可以通过调用以下方法做到这一点:
add(Calendar.DAY_OF_MONTH, -5)
常见问题
1.在获取某一瞬间的各种属性的时候,使用这个类比较方便,因为这个类提供了大量的常量使用,例如:
Date date = new Date(); Calendar c = Calendar.getInstance(); c.setTime(date); //Calendar.YEAR:日期中的年 int year = c.get(Calendar.YEAR); //Calendar.MONTH:日期中的月,需要加1 int mounth = c.get(Calendar.MONTH) + 1; //Calendar.DATE:日期中的日 int day = c.get(Calendar.DATE); //Calendar.HOUR:日期中的小时(12小时制) int hour = c.get(Calendar.HOUR); //Calendar.HOUR_OF_DAY:24小时制 int HOUR_OF_DAY = c.get(Calendar.HOUR_OF_DAY); //Calendar.MINUTE:日期中的分钟 int minute = c.get(Calendar.MINUTE); //Calendar.SECOND:日期中的秒 int second = c.get(Calendar.SECOND); System.err.println(year + "-" + mounth + "-" + day + " " + hour + ":" + minute + ":" + second); //Calendar.WEEK_OF_YEAR:当前年中星期数 int WEEK_OF_YEAR = c.get(Calendar.WEEK_OF_YEAR); //Calendar.WEEK_OF_MONTH:当前月中星期数 int WEEK_OF_MONTH = c.get(Calendar.WEEK_OF_MONTH); //Calendar.DAY_OF_YEAR:当前年中的第几天 int DAY_OF_YEAR = c.get(Calendar.DAY_OF_YEAR); //Calendar.DAY_OF_MONTH:当前月中的第几天 int DAY_OF_MONTH = c.get(Calendar.DAY_OF_MONTH); //Calendar.DAY_OF_WEEK:当前星期的第几天(星期天表示第一天,星期六表示第七天) int DAY_OF_WEEK = c.get(Calendar.DAY_OF_WEEK); //Calendar.DAY_OF_WEEK_IN_MONTH:当前月中的第几个星期 int DAY_OF_WEEK_IN_MONTH = c.get(Calendar.DAY_OF_WEEK_IN_MONTH);
2.计算某一月份的最大天数
Calendar time=Calendar.getInstance(); time.clear(); time.set(Calendar.YEAR,year); time.set(Calendar.MONTH,month-1);//注意,Calendar对象默认一月为0 int day=time.getActualMaximum(Calendar.DAY_OF_MONTH);//本月份的天数
3.计算两个任意时间中间的间隔天数
public static void main(String[] args) { Calendar begin = Calendar.getInstance(); begin.set(2016, 10, 30); Calendar end = Calendar.getInstance(); end.set(2016, 10, 15); System.out.println(CalendarTest.getDaysBetween(begin, end)); } public static int getDaysBetween (Calendar begin, Calendar end) { if (begin.after(end)) { Calendar temp = begin; begin = end; end = temp; } int days = end.get(Calendar.DAY_OF_YEAR) - begin.get(Calendar.DAY_OF_YEAR); int y2 = end.get(Calendar.YEAR); if (begin.get(Calendar.YEAR) != y2) { begin = (Calendar) begin.clone(); do { days += begin.getActualMaximum(Calendar.DAY_OF_YEAR);//得到当年的实际天数 begin.add(Calendar.YEAR, 1); } while (begin.get(Calendar.YEAR) != y2); } return days; }
4.在我们总结老的时间操作类的时候,java 8 又更新了新的时间操作包,可以阅读一下后面推荐的东西
http://www.open-open.com/lib/view/open1422849534537.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步