Java中Calendar类的常用方法

项目当中,我们经常会涉及到对时间的处理。Date 类最主要的作用就是获得当前时间,同时这个类里面也具有设置时间以及一些其他的功能,但是由于本身设计的问题,这些方法却遭到众多批评,不建议使用,而是更推荐使用 Calendar 类进行时间和日期的处理。

原理简介

Java中提供了Calendar这个专门用于对日历进行操作的类,那么这个类有什么特殊的地方呢,首先我们来看Calendar的声明:

public abstract class Calendar 
	extends Objectimplements Serializable, Cloneable, Comparable<Calendar>{}

该类被abstract所修饰,说明该类是一个抽象类,所以不能直接通过new该类对象来进行实例化,为此Calendar类提供了两种实例化方式:
方法1:通过创建其子类的对象(GregorianCalendar)的对象来进行实例化
方法2:调用其静态方法getInstance()方法来进行实例化,以获得此类型的一个通用的对象,getInstance方法返回一个Calendar对象(该对象为Calendar的子类所创建的对象),其日历字段已由当前日期和时间初始化(通常都选择方法2来进行实例化。)

Calendar nowTime = Calendar.getInstance();//使用默认时区和语言环境获得一个日历

Calendar类常用方法:

get(int field)方法中filed参数表示的是日历中的字段,日历中的字段可以使用Calendar类的静态成员变量值获取,该方法的作用是返回指定日历字段的值,返回值为int类型。
set(int field,int value)中field参数的意思同上,该方法的作用是将指定的日历字段field设置为给定的值value,该方法没有返回值,表示的意思是通过该方法修改的是对象calendar本身。
add(int field, int amount)中field参数的意思同上,该方法的作用是将指定的日历字段field加上(或减去)指定的时间量amount,amount是增加/减少指定的值  正数:增加  负数:减少,该方法没有返回值,表示的意思是通过该方法修改的是对象calendar本身。
getTime()该方法的作用是将一个Calendar类的日历转换为一个相对应的Date类的日期,该方法的返回值为Date类的对象(这里的Date类指的是java.util包下的Date)setTime(Date date)该方法的作用是将传入的Date类日期转换为一个相对应的Calendar类的日历,由于该方法无返回值,所以通过该方法修改的是对象calendar本身(谁调用修改谁)

获取时间(使用get()方法)

import java.util.Calendar;
import java.util.Date;

public class CalendarClassMethodTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Calendar calendar = Calendar.getInstance();
        //以2021-10-24 00:34:13为例
		//获取当前年
		int year = calendar.get(Calendar.YEAR);  //year=2021
		//获取当前月,注意月份下标从0开始,所以取月份要+1(即0表示1月,依次类推)
		int month = calendar.get(Calendar.MONTH)+1;  //month=10
		//获取当前日(两种方法等价)
		int day_of_month = calendar.get(Calendar.DAY_OF_MONTH);   //day_of_month=24
		int day = calendar.get(Calendar.DATE);  //day=24
		//获取当前小时(24小时制)
		int hour24 = calendar.get(Calendar.HOUR_OF_DAY);  //hour24=0				 
		//获取当前小时(12小时制)     
		int hour12 = calendar.get(Calendar.HOUR); 		//	hour12=0		
		//获取当前分钟     
		int minute = calendar.get(Calendar.MINUTE);   //minute=34 			
		//获取当前秒     
		int second = calendar.get(Calendar.SECOND);   // second=13
		//获取当月day的最大值(查看当前月一共有几天)
		int max_day_of_month = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); //max_day_of_month=31
        //获取当前日为星期几:用数字(1~7)表示(星期日~星期六),使用时通常会-1
      	int day_of_week = calendar.get(Calendar.DAY_OF_WEEK) - 1;	//day_of_week=0
      	//获取当前时间为上午还是下午(上午为0,下午为1)     
      	int amOrPm = calendar.get(Calendar.AM_PM);  //amOrPm=0
        //获取当前日历是当前月的的第几个星期(一个月的1号为第一周,8号为第二周)   
	    int day_of_week_in_month = calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH);  //day_of_week_in_month=4
        //获取当前日历是当前月的星期数(可是它的值不同于DAY_OF_WEEK_IN_MONTH,它计算当前星期的标准不同,例如说这个月的1号是星期三那么是第一周,那么到了5号星期日就已经是第二周了,如果按DAY_OF_WEEK_IN_MONTH的计算5号才第一周)
        int week_of_month = calendar.get(Calendar.WEEK_OF_MONTH); //week_of_month=5
	    //当前年的第几天     
	    int day_of_year = calendar.get(Calendar.DAY_OF_YEAR);   //day_of_year=297
		}
}	

设置时间(使用set()方法)

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class CalendarClassMethodTest2 {

	public static void main(String[] args) {
		  // TODO Auto-generated method stub
		  Calendar calendar = Calendar.getInstance();   //Calendar类的实例化
		  //当前时间:2021-10-26 10:05:07
		  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    //对Date类型的数据进行格式化
		  Date date1 = calendar.getTime();    //将一个Calendar类的日历转换为一个相对应的Date类的日期
		  String str1 = sdf.format(date1);    //对日期进行格式化
		  System.out.println(str1);
		  /* 
		              设置年月日时分秒(月份的下标从 0 开始,设置时需要注意)
		              方法1:一个字段一个字段设置
		              方法2:一次性设置,使用set(int field,int value)的重载方法set(int year, int month, int date, int hourOfDay, int minute, int second)来进行设置。
		   */		  
		  calendar.set(Calendar.YEAR, 2020);
		  calendar.set(Calendar.MONTH, 0);      
	      calendar.set(Calendar.DAY_OF_MONTH, 10);
	      calendar.set(Calendar.HOUR_OF_DAY,11);
	      calendar.set(Calendar.MINUTE,15);
	      calendar.set(Calendar.SECOND,20);
	      System.out.println(sdf.format(calendar.getTime()));
          //将其设置为2020-10-6 12:20:40
	      calendar.set(2020,10,6,12,20,40);
	      System.out.println(sdf.format(calendar.getTime()));    
	}

}

测试结果:

2021-10-26 10:05:07
2020-01-10 11:15:20
2020-11-06 12:20:40

时间计算(使用add()方法)

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class CalendarClassMethodTest3 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//设置时间为2020-1-30 23:59:59  由于月份的下标从0开始,所以在设置月份时要-1。
		Calendar calendar = Calendar.getInstance();  //Calendar类的实例化
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");   对Date类型的数据进行格式化	
		System.out.println(sdf.format(calendar.getTime()));//将一个Calendar类的日历转换为一个相对应的Date类的日期,在对Date类型的数据进行格式化并输出。
		calendar.set(2020, 0, 30, 23, 59, 59);
		System.out.println(sdf.format(calendar.getTime()));
		//当时间为当晚最后一秒时,add一秒,日历会自动进入下一天。
        calendar.add(Calendar.SECOND, 1);
        System.out.println(sdf.format(calendar.getTime()));
        //当时间为当月最后一天时,add一月,日历会自动进入到下个月最后一天。
        calendar.add(Calendar.MONTH, 1);
        System.out.println(sdf.format(calendar.getTime()));
        calendar.add(Calendar.HOUR_OF_DAY, 5);
        System.out.println(sdf.format(calendar.getTime()));
        calendar.add(Calendar.MINUTE, -15);
        System.out.println(sdf.format(calendar.getTime()));
        calendar.add(Calendar.DAY_OF_MONTH, 15);
        System.out.println(sdf.format(calendar.getTime()));
        //时间重制为当前时间
        Date date = new Date();  //获取系统当前时间
        calendar.setTime(date);  //将一个Date类的日期转换为一个相对应的Calendar类的日历
        System.out.println(sdf.format(calendar.getTime()));
	}
}	

测试结果:

2021-10-26 10:36:27
2020-01-30 23:59:59
2020-01-31 00:00:00
2020-02-29 00:00:00
2020-02-29 05:00:00
2020-02-29 04:45:00
2020-03-15 04:45:00
2021-10-26 10:36:27

注意事项

1. Calendar的容错性
我们直接举例说明:
调用Calendar对象的set()方法改变指定时间字段的值时,有可能传入一个不合法的参数,例如:为MONTH字段设置13,这将会导致什么结果呢?

//Calendar:容错性测试
	@Test
	public void testCalender() {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Calendar calendar = Calendar.getInstance(); //Calendar类的实例化(当前时间:2021-10-26 10:58:11)	
		// Calendar容错性:true-打开;false-关闭
		calendar.setLenient(false);
		calendar.set(Calendar.MONTH, 13);		System.out.println("A="+simpleDateFormat.format(calendar.getTime()));	// A标记
	}

当打开calendar.setLenient(true)时(默认):

A处代码可以正常运行,因为将MONTH字段设置为13,将会使YEAR字段计算加1; 输出结果:A=2022-02-26 10:58:11。

当关闭calendar.setLenient(false)时:

A处将会出现运行异常(java.lang.IllegalArgumentException: MONTH),因为设置的MONTH字段超出了所允许的范围。

关键在于程序中注释有“容错性”的代码行:

Calendar提供一个setLenient用于设置它的容错性,Calendar默认支持比较好的容错性,通过setLenient(false)关闭Calendar的容错性,让它进行严格的参数检查。

Calendar有两种解释日历字段的模式:lenient模式,non-lenient模式

当处于lenient模式时,每个字段都可接受超出范围的值;
当处于non-lenient模式时,每个字段都进行严格的参数检查,不接收超出字段的值。

2. set()的延迟性
set(int field, int value)方法的作用是将日历的某个字段修改为指定的value值,此外它还设置了一个内部成员变量,以指示日历字段field已经被更改。尽管日历字段field是立即更改的,但该Calendar所代表的事件却不会立即修改,直到下次调用get()、getTime()、getTimeInMillis()、add()或roll()时才会重新计算日历的时间。

这被称为set()方法的延迟修改,采用延迟修改的优势是多次调用set()不会触发多次不必要的运算,下面来看一个例子:

// set():延迟修改性
	@Test
	public void testCalender1() {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        calendar.set(2021, 2, 31);
        calendar.set(Calendar.MONTH, 8);
 		//包含getTime()方法,注释掉此行代码,运行结果截然不同        System.out.println("A="+simpleDateFormat.format(calendar.getTime())); // A标记
        calendar.set(Calendar.DATE, 5);
        System.out.println("B="+simpleDateFormat.format(calendar.getTime())); // B标记
	}

打印结果:
注释掉 A行 之前:(set一次,get一次,一步一运算)
A=2021-10-01 11:08:15
B=2021-10-05 11:08:15
注释掉 A行 之后:(set两次,get一次,最后再运算)
B=2021-09-05 11:08:42
小结
1:Calendar 类区分不同的时区输出时间格式;
2:Calendar 类的计算优势非常明显,不需要考虑每个月有多少天,非常便利。举个例子:如果要计算昨天的日期,你要考虑昨天是不是某月的最后一天,某年的最后一天,要考虑平年、闰年,考虑上个月是31天,30天,29天还是28天…但是Calendar类省去了你所有的顾虑,直接减1天就可以输出正确的日期了;
3:Calendar 类使用时要注意它的容错性和延迟性。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值