Calendar工具类解释
首先解释下Calendar工具类的作用。根据API的解释,Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些基础方法,其中瞬间可用毫秒值来表示,它是距历元(即格林威治标准时间 1970 年 1 月 1 日的 00:00:00.000,格里高利历)的偏移量。
那么Calendar工具类是如何界定跨年或者跨月份的星期定义呢?举个例子:如上图所示,2020年1月1日是星期三,那么它是算2020年的第一周呢还是2019年的最后一周?诸如如此的跨年份或者跨月份导致星期界定不明的情况,Calendar工具类提供了两个方法去个性化定义此类问题,一个方法是getFirstDayOfWeek(),另一个方法是getMinimalDaysInFirstWeek(),这两个方法相辅相成,共同完成对此类问题的定义。下面对这两个方法进行详细介绍。
getFirstDayOfWeek()和getMinimalDaysInFirstWeek()方法
getFirstDayOfWeek()方法官方API是这么解释的:获取一星期的第一天。而getMinimalDaysInFirstWeek()方法官方API是这么定义的:获取一年中第一个星期所需的最少天数。那么这两个方法是如何共同定义的呢?先放官方api解释:
Calendar 使用两个参数定义了特定于语言环境的 7 天制星期:星期的第一天和第一个星期中的最小一天(从 1 到 7)。这些数字取自构造 Calendar 时的语言环境资源数据。还可以通过为其设置值的方法来显式地指定它们。在设置或获得 WEEK_OF_MONTH 或 WEEK_OF_YEAR 字段时,Calendar 必须确定一个月或一年的第一个星期,以此作为参考点。一个月或一年的第一个星期被确定为开始于 getFirstDayOfWeek() 的最早七天,它最少包含那一个月或一年的 getMinimalDaysInFirstWeek() 天数。第一个星期之前的各星期编号为 ...、-1、0;之后的星期编号为 2、3、...。注意,get() 返回的标准化编号方式可能有所不同。例如,特定 Calendar 子类可能将某一年第 1 个星期之前的那个星期指定为前一年的第 n 个星期。
是不是感觉一头雾水?那么接下来通过几个例子就能简单明了解释他俩各自产生的效果了。
首先我们定义一星期的第一天为周一(MONDAY),然后要求一年的第一周必须要6天,即如下所示:那么对于2020年1月1号而言,因为定义了一周开始是周一,那么1月1号所在的周为20191230-20200105这个星期,然后我们又规定了一年的第一周至少6天才能算该年第一周,但是在20191230-20200105这个星期内,只有12345号在2020年,共5天不满足条件,因此2020年1月1号将归属于2019年的最后一周而不是2020年的第一周,运行结果如下所示:
那么如果我们把getMinimalDaysInFirstWeek()方法的参数改为5天而一星期的开始仍未周一呢?也就是说一年的第一周至少5天,由日历可知,20191230-20200105这个星期内,12345号都在2020年,即满足了getMinimalDaysInFirstWeek()方法的条件,因此此时2020年1月1号将被归属到2020年的第一周,运行结果如下:
同理,我们修改一下一周开始的时间,规定为一周开始时间是周日(SUNDAY),那么2020年1月1号在20191229-20200104这个星期内,getMinimalDaysInFirstWeek()参数我们不变仍未之前的5天,那么由日历可知,在20191229-20200104这个星期内,只有1234号这四天在2020年,不满足至少5天的条件,因此此时2020年1月1号将被划分到2019年的最后一周,结果如下:
那么如果说一周开始是周日的话怎么修改才能让2020年1月1号算在2020年的第一周呢?只需要规定一年的第一周至少4天即可,也就是getMinimalDaysInFirstWeek()方法的参数小于4就行了,我们将参数改为4,运行结果如下:
果然2020年1月1号归属到2020年第一周去了。
参数细节
getFirstDayOfWeek()方法的参数是周一到周日没什么问题,但是getMinimalDaysInFirstWeek()的参数范围又是多少呢?正常按照我们的理解参数范围1-7都是很好理解的,但是当参数不在这个范围内又会发生什么?首先我们将参数规定为8看看会发生什么,一周开始定为周一。
对于2020年1月1号,自然不满足条件,只能被归属到2019年最后一周,但是若是2020年1月6号呢?它属于20200106-20200112这个星期,但是跨年的那个星期按照我们的理解只有5天是小于我们规定的8天的,因此它属于一年的第一周?运行结果:
没问题,符合我们的期望,如果说负数呢?
仍未第一周,因此我们可以总结一下getMinimalDaysInFirstWeek()参数的范围为0-7,超出这个范围的参数无意义。
方法细节(重要!)
对于getMinimalDaysInFirstWeek()和getFirstDayOfWeek()方法,并不是说设置了这两个方法的值之后,就能取到你所设置的值的日期,例如你定义一周开始是周一,如果是当前是周一的话,通过get (Calendar.DAY_OF_WEEK)你认为就能取到1,但是测试发现结果仍然为2,因为默认一周开始就是周日(1)。那么难道说我这个设置一周开始为周一没有生效?
其实并不是这样,对于这两个方法而言,当你在这两个方法设置了参数时,只能对WEEK_OF_MONTH 与WEEK_OF_YEAR 生效,即当你想要获取当前日期对象在当前月份是第几周或者当前年份第几周时才会生效,就正如本文前面所打印的结果一样,只会对WEEK_OF_MONTH 与WEEK_OF_YEAR起作用。总结
getMinimalDaysInFirstWeek()和getFirstDayOfWeek()方法其实是相辅相成的,因此当我们需要自定义跨年星期的时候最好是两个方法的参数都设置一下,这样对于程序而言更为严谨。