使用Java类Calendar获取当前时刻年月日周分秒

1 简介

在实际项目中,经常需要对时间的处理,例如在网页上会显示今天是

2018-12-18 09:44:29 周二 第51周

等信息。对于这类经常出现的问题,Java为开发人员提供了Calendar类来进行日期-时间的操作。
Calendar类位于包util工具包,使用时用import导入

import java.util.Calendar

Calendar类是一个抽象类,它为特定瞬间与一组诸如YEAR、MONTH、DAY_OF_WEEK、HOUR等日历字段之间的转换提供了一些方法。
瞬间可用毫秒值来表示,它是距历元(即格林威治标准时间1970-1-1 00:00:00.000,格里高利历)的偏移量。
Calendar对象能够生成为特定语言和日历风格实现日期-时间格式化所需要的所有日历字段值,例如日语-格里高利历,日语-传统日历。Calendar定义了某些日历字段返回值的范围,以及这些值得含义。
Calendar类类型描述如下:

public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {

类图如下
在这里插入图片描述

注意:IDEA可以生成上图,使用的快捷键为Ctrl + Alt+ Shift + U,在弹出的框架结构图中,可以使用空格添加更多的类。并且按住Alt可以弹出放大镜功能。
Calendar为抽象类,因此时无法直接使用构造函数来创建实例的,但该类提供了函数getInstance函数,来创建实例

/**
 * Gets a calendar using the default time zone and locale. The
 * <code>Calendar</code> returned is based on the current time
 * in the default time zone with the default
 * {@link Locale.Category#FORMAT FORMAT} locale.
 *
 * @return a 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;
}

2 构造函数
该类没有构造函数,但提供了几种getInstance方法。

public static Calendar getInstance()
public static Calendar getInstance(TimeZone zone)
public static Calendar getInstance(Locale aLocale)
public static Calendar getInstance(TimeZone zone,
                                   Locale aLocale)
private static Calendar createCalendar(TimeZone zone,
                                       Locale aLocale) //核心

3 功能函数
更改字段的三种方法

set(), add(), roll()

set(f, value)将日历字段f更改为value。它设置了一个内部成员变量,以指示日历字段f已经被更改。尽管日历字段f是立即更改的,但是直到下次调用get(),getTime(), getTimeInMillis(), add(), 或roll()时,才会重新计算日历的时间值。多次调用set不会触发多次不必要的计算。
add(f, delta)将delta添加到f字段中,等同于set(f, get(f)+delta)。与set不同,add强迫日历系统立即重新计算日历的毫秒数和所有字段。
roll(f, delta)将delta添加到f字段中,但不要更改更大的字段。

3.1 字段摘抄

static int    描述
APRIL     指示在格里高利历和罗马儒略历中一年中第四个月
August, FEBUARY, JUNE, JULY, JANUARY
DAY_OF_WEEK	指示一个星期中的某天,可能值为SUNDAY, MONDAY… SATURDAY
HOUR、 MONTH、YEAR、HOUR、MINUTE、SECOND、MILLISECOND
isSet   通知是否设置了该日历某一指定字段的标志。新的对象没有设置任何字段。


DAY_OF_MONTH    一个月中的第几天
DAY_OF_WEEK      一周中第几天
DAY_OF_YEAR       一年的第300天
DAY_OF_WEEK_IN_MONTH  指示当月中第几个星期

HOUR  指示上午或下午的小时
HOUR_OF_DAY  指示一天中的小时

WEEK_OF_MONTH  指示当月中的星期数
WEEK_OF_YEAR    指示当前年中的星期数

3.2 方法摘要

    abstract public void add(int field, int amount);

根据日历的规则,为给定的日历字段添加或减去指定的时间量。
public final Date getTime()
返回一个此Calendar时间值
public final void setTime(Date date) {
    setTimeInMillis(date.getTime());
}
使用给定的Date设置此Calendar时间
public long getTimeInMillis()
返回此Calendar的时间值,以毫秒为单位
public int get(int field)
返回给定日历字段的值,在lenient模式下,所有日历字段均被标准化。在non-lenient,所有日历字段都是经过验证的,如果任何日历字段有超过范围的值,则此方法抛出一个异常。标准化和验证都是通过complete()方法处理,这个过程与日历系统有关。
public void set(int field, int value)
public final void set(int year, int month, int date)
设置日历字段YEAR、MONTH、DAY_OF_MONTH的值,保留其他日历字段以前的值。如果不需要这样做,则先调用clear()
public final void set(int year, int month, int date, int hourOfDay, int minute)
public final void set(int year, int month, int date, int hourOfDay, int minute,
                      int second)
public final boolean isSet(int field)
确定给定日历字段是否已经设置了一个值,其中包括因为调用get方法触发内部字段计算而导致已经设置该值得情况。

4 重要特性

4.1 获得并设置日历字段值

可以通过调用set方法来设置日历字段值,在需要计算时间值,距历元所经过的毫秒或日历字段之前,不会解释Calendar中所有字段设置。调用get,getTimeInMillis,getTime,add和roll涉及此类运算。

4.2 宽松性

Calendar有两种解释日历字段的模式,即lenient和non-lenient。当处于lenient模式时,它接受比它所生成的日历字段范围更大范围内的值。当Calendar重新计算日历字段值,以便由get返回这些值时,所有日历字段都被标准化。
当 Calendar处于non-lenient模式时,如果其日历字段中存在任何不一致时,它都会抛出一个异常。例如DAY_OF_MONTH设置了32便会抛出异常。

4.3 星期

Calendar使用两个参数定义了特定语言环境的7天制星期:星期的第一天和第一个星期中的最小1天(从1到7)。这些数字取自构造Calendar时的语言环境资源数据。还可以通过为其设置值得方法来显示指定它们。
在设置或获得WEEK_OF_MONTH或WEEK_OF_YEAR字段时,Calendar必须确定一个月或一年的第一个星期,以此作为参考点。一个月或一年的第一个星期被确定开始于getFirstDayOfWeek()的最早七天,它最少包含那一个月或一年的getMinimalDaysInFirstWeek()天数。第一个星期之前的各星期编号为…,-1, 0;之后的星期编号为2、3、…。注意,get()返回的标准化编号方式可能不一致。

4.4 日历字段解析

在计算日历字段中的日期和时间时,可能没有足够的信息用于计算(例如只有年和月,没有日),或者可能有不一致的信息(例如,Tuesday, July 15, 1996)(格林威治时间)实际上,1996-7-15为星期一。如果日历字段值中存在任何冲突,则Calendar将为最近设置的日历字段提供优先权。
4.5 星期理解

https://blog.csdn.net/hj7jay/article/details/68922055

5 代码片段

使用Calendar类可以方便的完成如下的问题:

  1. 获取当前时间中年份、月份、日期、时分秒

  2. 获取当前日期为本年(本月、本周)的第几天

  3. 获取今天是本年(本月)的第几周

  4. 计算两个日历对象间隔的天数[毫秒/(246060*1000)]

  5. 获取明年最后一天(第一天的日期)的日期

  6. 获取某年(某月)最大天数

  7. 获取当前时间几天后(几天前,几个月前后,几年前后)的日期

  8. 2018年第三周的周一是哪一天
    代码片段之一:通过Calendar对象可以获得如下内容

    import java.text.SimpleDateFormat;
    import java.util.Calendar;

    public class Main {

    public static void test() {
        Calendar cal = Calendar.getInstance();
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(cal.toString());
        System.out.println(sdf.format(cal.getTime()));
        int year = cal.get(Calendar.YEAR);
        //比当前月份少1
        int month = cal.get(Calendar.MONTH)+1;
        //date表示日期,day表示天数,所以date与day_of_month相同
        int date = cal.get(Calendar.DATE);
        int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
        int firstDay = cal.getFirstDayOfWeek();
        //public final static int SUNDAY = 1;表示一周开始的第一天为周日
        System.out.println("firstDay:" + firstDay);
        //表示本周的第几天,从周日开始计算
        int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
        int dayOfYear = cal.get(Calendar.DAY_OF_YEAR);
        //12小时制
        int hour = cal.get(Calendar.HOUR);
        //24小时制
        int hourOfDay = cal.get(Calendar.HOUR_OF_DAY);
        int minute = cal.get(Calendar.MINUTE);
        int second = cal.get(Calendar.SECOND);
        int millisecond = cal.get(Calendar.MILLISECOND);
        int maxDate = cal.getActualMaximum(Calendar.DATE);
        System.out.println("现在的年份为:" + year);
        System.out.println("现在的月份为:" + month);
        //2018年12月18号
        System.out.println("现在的号为:" + date);
        System.out.println("现在的号为:" + dayOfMonth);
        System.out.println("现在是星期:" + dayOfWeek);
        System.out.println("现在过了的天数为:" + dayOfYear);
        System.out.println("现在几点:" + hour);
        System.out.println("现在几点:" + hourOfDay);
        System.out.println("现在几分:" + minute);
        System.out.println("现在几秒:" + second);
        System.out.println("现在几毫秒:" + millisecond);
        System.out.println("本月最后一天是:" + maxDate);
        System.out.println("Hello World!");
    }
    
    public static void test2() {
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = Calendar.getInstance();
        //calendar.clear();
        //calendar.set(Calendar.YEAR, 2018);
        //calendar.set(Calendar.MONTH, 12);
        calendar.add(Calendar.YEAR, 3);
        int year = calendar.get(Calendar.YEAR);
        int  month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DATE);
        System.out.println(calendar.get(Calendar.YEAR));
        System.out.println(sdf.format(calendar.getTime()));
        System.out.println("3年后: " + "为"+year+"年"+month+"月"+day+"日");
    }
    
    //演示获取某月的最后一天的日期
    public static void test3() {
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        // 假设求6月的最后一天
        int currentMonth = 6;
        // 先求出7月份的第一天,实际中这里6为外部传递进来的currentMonth变量
        // 1
        calendar.set(calendar.get(Calendar.YEAR), currentMonth, 1);
    
        calendar.add(Calendar.DATE, -1);
    
        // 获取日
        int day = calendar.get(Calendar.DAY_OF_MONTH);
    
        System.out.println("6月份的最后一天为" + day + "号");
    
    }
    
    
    //求某一个月份的最大天数为几号
    public static void test4(int year,int month){
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH,month-1);//默认1月为0月
        //由于6月份的天数从1到30,因此最大为30,最小为1
        int day = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        System.out.println(year+"年"+month+"月"+"的最大天数是:"+day);
    }
    
    public static void weekNum(int year,int month,int day){
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH,month-1);
        calendar.set(Calendar.DAY_OF_MONTH, day);
        /*计算某一天是该年的第几个星期*/
        int weekOfYear = calendar.get(Calendar.WEEK_OF_YEAR);
        System.out.println(year+"年"+month+"月"+day+"日是这年中的第"+weekOfYear+"个星期");
        /*计算某一天是该月的第几个星期*/
        int weekOfMonth= calendar.get(Calendar.WEEK_OF_MONTH);
        System.out.println(year+"年"+month+"月"+day+"日是这个月中的第"+weekOfMonth+"个星期");
    }
    
    
    
    public static void main(String[] args) {
        test();
        test2();
        test3();
        test4(2017, 6);
        weekNum(2020, 6, 18);
    }
    

    }

输出结果如下:

java.util.GregorianCalendar[time=1545138281220,areFieldsSet=true,areAllFieldsSet=true,lenient=true,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=2018,MONTH=11,WEEK_OF_YEAR=51,WEEK_OF_MONTH=4,DAY_OF_MONTH=18,DAY_OF_YEAR=352,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=3,AM_PM=1,HOUR=9,HOUR_OF_DAY=21,MINUTE=4,SECOND=41,MILLISECOND=220,ZONE_OFFSET=28800000,DST_OFFSET=0]
2018-12-18 21:04:41
firstDay:1
现在的年份为:2018
现在的月份为:12
现在的号为:18
现在的号为:18
现在是星期:3
现在过了的天数为:352
现在几点:9
现在几点:21
现在几分:4
现在几秒:41
现在几毫秒:220
本月最后一天是:31
Hello World!
2021
2021-12-18 21:04:41
3年后: 为2021年11月18日
6月份的最后一天为30号
2017年6月的最大天数是:30
2020年6月18日是这年中的第25个星期
2020年6月18日是这个月中的第3个星期

6 引用

http://www.cnblogs.com/huangminwen/p/6041168.html
https://blog.csdn.net/weixin_36380516/article/details/76222261#

  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值