论坛首页 Java企业应用论坛

Gregorian Calendar ------ 有趣的日历

浏览 10176 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-12-01  
项目有个需求,每天生成一个文件。开始觉得用一个TimeTask或者ScheduledThreadPoolExecutor或者quartz来做,突然觉得太overweight了。后来想到了log4j的DailyRollingFileAppender,果然是我想要的,类似于quartz,通过与类似nextFireTime的参数作比较,判断是否触发append到新文件,不过这不是这篇博文要讲的。我有注意到了这个类,在DailyRollingFileAppender有个inner class RollingCalendar。

这个类的作用也说明了,是computes the start of the next interval
/**
 *  RollingCalendar is a helper class to DailyRollingFileAppender.
 *  Given a periodicity type and the current time, it computes the
 *  start of the next interval.  
 * */
class RollingCalendar extends GregorianCalendar {
  // ...... 不关心,省略掉好了
  }



本人才疏学浅,真的不知道为啥GregorianCalendar要叫这个英文名字,一看原来还是jdk自带的类。。所有膜拜了一下google,wiki大神,与大家分享一下

以下是来自API的翻译:
引用

GregorianCalendar 是 Calendar 的一个具体子类,提供了世界上大多数国家/地区使用的标准日历系统。

GregorianCalendar 是一种混合日历,在单一间断性的支持下同时支持儒略历格里高利历系统,在默认情况下,它对应格里高利日历创立时的格里高利历日期(某些国家/地区是在 1582 年 10 月 15 日创立,在其他国家/地区要晚一些)。可由调用者通过调用 setGregorianChange() 来更改起始日期。

历史上,在那些首先采用格里高利历的国家/地区中,1582 年 10 月 4 日(儒略历)之后就是 1582 年 10 月 15 日(格里高利历)。此日历正确地模拟了这些变化。在开始格里高利历之前,GregorianCalendar 实现的是儒略历。格里高利历和儒略历之间的唯一区别就是闰年规则。儒略历指定每 4 年就为闰年,而格里高利历则忽略不能被 400 整除的世纪年

GregorianCalendar 可实现预期的 格里高利历和儒略历。也就是说,可以通过在时间上无限地向后或向前外推当前规则来计算日期。因此,对于所有的年份,都可以使用 GregorianCalendar 来生成有意义并且一致的结果。但是,采用现代儒略历规则时,使用 GregorianCalendar 得到的日期只在历史上从公元 4 年 3 月 1 日之后是准确的。在此日期之前,闰年规则的应用没有规则性,在 45 BC 之前,甚至不存在儒略历。

在格里高利历创立以前,新年是 3 月 25 日。为了避免混淆,此日历始终使用 1 月 1 日为新年。如果想要格里高利历转换之前并且处于 1 月 1 日和 3 月 24 日之间的日期,则可以进行手动调整。

为 WEEK_OF_YEAR 字段所计算的值的范围从 1 到 53。一年的第一个星期始于 getFirstDayOfWeek() 的最早 7 天,至少包含该年的 getMinimalDaysInFirstWeek() 各天。这取决于 getMinimalDaysInFirstWeek()、getFirstDayOfWeek() 的值以及 1 月 1 日是星期几。一年的第一个星期和下一年的第一个星期之间的各个星期按顺序从 2 到 52 或 53(根据需要)进行编号。

例如,1998 年 1 月 1 日是星期四。如果 getFirstDayOfWeek() 为 MONDAY,并且 getMinimalDaysInFirstWeek() 为 4(这些值反映了 ISO 8601 和很多国家/地区标准),则 1998 年的第一个星期开始于 1997 年 12 月 29 日,结束于 1998 年 1 月 4 日。但是,如果 getFirstDayOfWeek() 为 SUNDAY,那么 1998 年的第一个星期开始于 1998 年 1 月 4 日,结束于 1998 年 1 月 10 日;1998 年头三天是 1997 年第 53 个星期的一部分。

为 WEEK_OF_MONTH 字段所计算的值的范围从 0 到 6。一个月的第一个星期(WEEK_OF_MONTH = 1 的日期)是该月至少连续 getMinimalDaysInFirstWeek() 天中的最早日期,结束于 getFirstDayOfWeek() 的前一天。与一年的第一个星期不同,一个月的第一个星期可能短于 7 天,也不必从 getFirstDayOfWeek() 这一天开始,并且不包括前一个月的日期。在第一个星期之前该月日期的 WEEK_OF_MONTH 为 0。

例如,如果 getFirstDayOfWeek() 为 SUNDAY,getMinimalDaysInFirstWeek() 为 4,那么 1998 年 1 月的第一个星期是从 1 月 4 日星期日到 1 月 10 日星期六。这些天的 WEEK_OF_MONTH 为 1。1 月 1 日星期四到 1 月 3 日星期六的 WEEK_OF_MONTH 为 0。如果 getMinimalDaysInFirstWeek() 变为 3,则 1 月 1 日到 1 月 3 日的 WEEK_OF_MONTH 为 1。

clear 方法将日历字段设置为未定义。GregorianCalendar 为每个日历字段使用以下默认值(如果该值未定义)。


1582年之前的事情就不管了,我们就用好Gregorian历就可以了。上面红色的话,我们用2011年1月1日来做测试看看

实际代码测试:

public class GregorianCalendarDemo {

    private GregorianCalendar calendar;

    public final static int SUNDAY = 1;
    public final static int MONDAY = 2;
    public final static int TUESDAY = 3;
    public final static int WEDNESDAY = 4;
    public final static int THURSDAY = 5;
    public final static int FRIDAY = 6;
    public final static int SATURDAY = 7;


    @BeforeMethod
    public void setup() {
        calendar = new GregorianCalendar();

    }

    @Test
    public void getFirstDayOfWeek_accuracy() {
        // 每周的第一天是周日
        Assert.assertEquals(calendar.getFirstDayOfWeek(), SUNDAY);
        // 设定每周的第一天是周一
        calendar.setFirstDayOfWeek(MONDAY);
        // 每周的第一天是周一
        Assert.assertEquals(calendar.getFirstDayOfWeek(), MONDAY);
    }

    @Test
    public void getFirstWeekOfYear_accuracy() {
        //在我的机器上面,返回的是1,看来中国不属于“ISO 8601 和很多国家/地区标准”
        //这表示,含有2011年第一天的那周,都算为2011年第一周
        Assert.assertEquals(calendar.getMinimalDaysInFirstWeek(), 1);
        calendar.setTime(new GregorianCalendar(2010, 11, 31).getTime());// 这是2010年12月31日, Month value is 0-based.
        Assert.assertEquals(calendar.get(Calendar.WEEK_OF_YEAR), 1); // 这个2011年的第一周

        calendar.setTime(new GregorianCalendar(2010, 11, 26).getTime());// 这是2010年12月25日, Month value is 0-based.
        Assert.assertEquals(calendar.get(Calendar.WEEK_OF_YEAR), 1); // 这也是2011年的第一周

        //让中国属于 “ISO 8601 和很多国家/地区标准”
        calendar.setMinimalDaysInFirstWeek(4);
        //这表示,至少2011年1月份前4天在的同一周,那这一周就视为2011年的,正好只有1、2号在同一周,3、4号不再,那么这周还算2010年的
        Assert.assertEquals(calendar.getMinimalDaysInFirstWeek(), 4);
        calendar.setTime(new GregorianCalendar(2011, 0, 1).getTime());// 这是2011年1月1日, Month value is 0-based.
        Assert.assertEquals(calendar.get(Calendar.WEEK_OF_YEAR), 52); // 这个2010年的第52周

        calendar.setTime(new GregorianCalendar(2011, 0, 2).getTime());// 这是2011年1月2日, Month value is 0-based.
        Assert.assertEquals(calendar.get(Calendar.WEEK_OF_YEAR), 1); // 这个2011年的第1周,因为一周的第一天是SUNDAY

        //但是,如果我们设定一周的开始是周一的话
        calendar.setFirstDayOfWeek(MONDAY);
        Assert.assertEquals(calendar.get(Calendar.WEEK_OF_YEAR), 1); // error 返回说明是2010年的第52周
    }
}

那么,红色部分的说明可以修改为2011年1月1日是星期六,如果 getFirstDayOfWeek() 为 SUNDAY,并且 getMinimalDaysInFirstWeek() 为 1,则 2011 年的第一个星期开始于 2010 年 12 月 26 日,结束于 2011 年 1 月 1 日。
但是,如果 getFirstDayOfWeek() 为 MONDAY,并且getMinimalDaysInFirstWeek() 为4, 那么 2011 年的第一个星期开始于 2010 年 12 月 27 日,结束于 2011 年 1 月 2 日;2011 年头2天是 2010 年第 52 个星期的一部分


WEEK_OF_MONTH可以按照上面的方法自行测试。

GregorianCalendar用于定时任务:

    // 获得下一分钟的时间
    @Test
    public void getNextMinuteTime() {
        Date date = new Date();

        calendar.setTime(date);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.MINUTE, 1);
        System.out.println("this time: " + date);
        System.out.println("next minute time: " + calendar.getTime());
    }

    // 获得下周的第一天的时间
    @Test
    public void getTopOfWeekTime() {
        Date date = new Date();

        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.WEEK_OF_YEAR, 1);
        System.out.println("this time: " + date);
        System.out.println("next week time: " + calendar.getTime());
    }

    // 获得下个月第一天的时间
    @Test
    public void getTopOfMonthTime() {
        Date date = new Date();

        calendar.setTime(date);
        calendar.set(Calendar.DATE, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.MONTH, 1);
        System.out.println("this time: " + date);
        System.out.println("next month time: " + calendar.getTime());
    }


这样自己就能通过Gregoriancalendar实现一个简单的定时任务了。
   发表时间:2010-12-03  
GregorianCalendar:罗马日历,
0 请登录后投票
   发表时间:2011-01-20  
格林威治历,记得微软的Windows(好像是XP和之前的版本)在日历处理上就有个Bug,但JDK的这个实现目前还没有发现什么问题。
0 请登录后投票
   发表时间:2011-01-21  
写的什么?
0 请登录后投票
   发表时间:2011-01-21  
这些东西不是很基础吗
0 请登录后投票
   发表时间:2011-02-12  
beneo 写道
项目有个需求,每天生成一个文件。开始觉得用一个TimeTask或者ScheduledThreadPoolExecutor或者quartz来做,突然觉得太overweight了。后来想到了log4j的DailyRollingFileAppender,果然是我想要的,类似于quartz,通过与类似nextFireTime的参数作比较,判断是否触发append到新文件,不过这不是这篇博文要讲的。我有注意到了这个类,在DailyRollingFileAppender有个inner class RollingCalendar。

这个类的作用也说明了,是computes the start of the next interval
/**
 *  RollingCalendar is a helper class to DailyRollingFileAppender.
 *  Given a periodicity type and the current time, it computes the
 *  start of the next interval.  
 * */
class RollingCalendar extends GregorianCalendar {
  // ...... 不关心,省略掉好了
  }



本人才疏学浅,真的不知道为啥GregorianCalendar要叫这个英文名字,一看原来还是jdk自带的类。。所有膜拜了一下google,wiki大神,与大家分享一下

以下是来自API的翻译:
引用

GregorianCalendar 是 Calendar 的一个具体子类,提供了世界上大多数国家/地区使用的标准日历系统。

GregorianCalendar 是一种混合日历,在单一间断性的支持下同时支持儒略历格里高利历系统,在默认情况下,它对应格里高利日历创立时的格里高利历日期(某些国家/地区是在 1582 年 10 月 15 日创立,在其他国家/地区要晚一些)。可由调用者通过调用 setGregorianChange() 来更改起始日期。

历史上,在那些首先采用格里高利历的国家/地区中,1582 年 10 月 4 日(儒略历)之后就是 1582 年 10 月 15 日(格里高利历)。此日历正确地模拟了这些变化。在开始格里高利历之前,GregorianCalendar 实现的是儒略历。格里高利历和儒略历之间的唯一区别就是闰年规则。儒略历指定每 4 年就为闰年,而格里高利历则忽略不能被 400 整除的世纪年

GregorianCalendar 可实现预期的 格里高利历和儒略历。也就是说,可以通过在时间上无限地向后或向前外推当前规则来计算日期。因此,对于所有的年份,都可以使用 GregorianCalendar 来生成有意义并且一致的结果。但是,采用现代儒略历规则时,使用 GregorianCalendar 得到的日期只在历史上从公元 4 年 3 月 1 日之后是准确的。在此日期之前,闰年规则的应用没有规则性,在 45 BC 之前,甚至不存在儒略历。

在格里高利历创立以前,新年是 3 月 25 日。为了避免混淆,此日历始终使用 1 月 1 日为新年。如果想要格里高利历转换之前并且处于 1 月 1 日和 3 月 24 日之间的日期,则可以进行手动调整。

为 WEEK_OF_YEAR 字段所计算的值的范围从 1 到 53。一年的第一个星期始于 getFirstDayOfWeek() 的最早 7 天,至少包含该年的 getMinimalDaysInFirstWeek() 各天。这取决于 getMinimalDaysInFirstWeek()、getFirstDayOfWeek() 的值以及 1 月 1 日是星期几。一年的第一个星期和下一年的第一个星期之间的各个星期按顺序从 2 到 52 或 53(根据需要)进行编号。

例如,1998 年 1 月 1 日是星期四。如果 getFirstDayOfWeek() 为 MONDAY,并且 getMinimalDaysInFirstWeek() 为 4(这些值反映了 ISO 8601 和很多国家/地区标准),则 1998 年的第一个星期开始于 1997 年 12 月 29 日,结束于 1998 年 1 月 4 日。但是,如果 getFirstDayOfWeek() 为 SUNDAY,那么 1998 年的第一个星期开始于 1998 年 1 月 4 日,结束于 1998 年 1 月 10 日;1998 年头三天是 1997 年第 53 个星期的一部分。

为 WEEK_OF_MONTH 字段所计算的值的范围从 0 到 6。一个月的第一个星期(WEEK_OF_MONTH = 1 的日期)是该月至少连续 getMinimalDaysInFirstWeek() 天中的最早日期,结束于 getFirstDayOfWeek() 的前一天。与一年的第一个星期不同,一个月的第一个星期可能短于 7 天,也不必从 getFirstDayOfWeek() 这一天开始,并且不包括前一个月的日期。在第一个星期之前该月日期的 WEEK_OF_MONTH 为 0。

例如,如果 getFirstDayOfWeek() 为 SUNDAY,getMinimalDaysInFirstWeek() 为 4,那么 1998 年 1 月的第一个星期是从 1 月 4 日星期日到 1 月 10 日星期六。这些天的 WEEK_OF_MONTH 为 1。1 月 1 日星期四到 1 月 3 日星期六的 WEEK_OF_MONTH 为 0。如果 getMinimalDaysInFirstWeek() 变为 3,则 1 月 1 日到 1 月 3 日的 WEEK_OF_MONTH 为 1。

clear 方法将日历字段设置为未定义。GregorianCalendar 为每个日历字段使用以下默认值(如果该值未定义)。


1582年之前的事情就不管了,我们就用好Gregorian历就可以了。上面红色的话,我们用2011年1月1日来做测试看看

实际代码测试:

public class GregorianCalendarDemo {

    private GregorianCalendar calendar;

    public final static int SUNDAY = 1;
    public final static int MONDAY = 2;
    public final static int TUESDAY = 3;
    public final static int WEDNESDAY = 4;
    public final static int THURSDAY = 5;
    public final static int FRIDAY = 6;
    public final static int SATURDAY = 7;


    @BeforeMethod
    public void setup() {
        calendar = new GregorianCalendar();

    }

    @Test
    public void getFirstDayOfWeek_accuracy() {
        // 每周的第一天是周日
        Assert.assertEquals(calendar.getFirstDayOfWeek(), SUNDAY);
        // 设定每周的第一天是周一
        calendar.setFirstDayOfWeek(MONDAY);
        // 每周的第一天是周一
        Assert.assertEquals(calendar.getFirstDayOfWeek(), MONDAY);
    }

    @Test
    public void getFirstWeekOfYear_accuracy() {
        //在我的机器上面,返回的是1,看来中国不属于“ISO 8601 和很多国家/地区标准”
        //这表示,含有2011年第一天的那周,都算为2011年第一周
        Assert.assertEquals(calendar.getMinimalDaysInFirstWeek(), 1);
        calendar.setTime(new GregorianCalendar(2010, 11, 31).getTime());// 这是2010年12月31日, Month value is 0-based.
        Assert.assertEquals(calendar.get(Calendar.WEEK_OF_YEAR), 1); // 这个2011年的第一周

        calendar.setTime(new GregorianCalendar(2010, 11, 26).getTime());// 这是2010年12月25日, Month value is 0-based.
        Assert.assertEquals(calendar.get(Calendar.WEEK_OF_YEAR), 1); // 这也是2011年的第一周

        //让中国属于 “ISO 8601 和很多国家/地区标准”
        calendar.setMinimalDaysInFirstWeek(4);
        //这表示,至少2011年1月份前4天在的同一周,那这一周就视为2011年的,正好只有1、2号在同一周,3、4号不再,那么这周还算2010年的
        Assert.assertEquals(calendar.getMinimalDaysInFirstWeek(), 4);
        calendar.setTime(new GregorianCalendar(2011, 0, 1).getTime());// 这是2011年1月1日, Month value is 0-based.
        Assert.assertEquals(calendar.get(Calendar.WEEK_OF_YEAR), 52); // 这个2010年的第52周

        calendar.setTime(new GregorianCalendar(2011, 0, 2).getTime());// 这是2011年1月2日, Month value is 0-based.
        Assert.assertEquals(calendar.get(Calendar.WEEK_OF_YEAR), 1); // 这个2011年的第1周,因为一周的第一天是SUNDAY

        //但是,如果我们设定一周的开始是周一的话
        calendar.setFirstDayOfWeek(MONDAY);
        Assert.assertEquals(calendar.get(Calendar.WEEK_OF_YEAR), 1); // error 返回说明是2010年的第52周
    }
}

那么,红色部分的说明可以修改为2011年1月1日是星期六,如果 getFirstDayOfWeek() 为 SUNDAY,并且 getMinimalDaysInFirstWeek() 为 1,则 2011 年的第一个星期开始于 2010 年 12 月 26 日,结束于 2011 年 1 月 1 日。
但是,如果 getFirstDayOfWeek() 为 MONDAY,并且getMinimalDaysInFirstWeek() 为4, 那么 2011 年的第一个星期开始于 2010 年 12 月 27 日,结束于 2011 年 1 月 2 日;2011 年头2天是 2010 年第 52 个星期的一部分


WEEK_OF_MONTH可以按照上面的方法自行测试。

GregorianCalendar用于定时任务:

    // 获得下一分钟的时间
    @Test
    public void getNextMinuteTime() {
        Date date = new Date();

        calendar.setTime(date);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.MINUTE, 1);
        System.out.println("this time: " + date);
        System.out.println("next minute time: " + calendar.getTime());
    }

    // 获得下周的第一天的时间
    @Test
    public void getTopOfWeekTime() {
        Date date = new Date();

        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.WEEK_OF_YEAR, 1);
        System.out.println("this time: " + date);
        System.out.println("next week time: " + calendar.getTime());
    }

    // 获得下个月第一天的时间
    @Test
    public void getTopOfMonthTime() {
        Date date = new Date();

        calendar.setTime(date);
        calendar.set(Calendar.DATE, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.MONTH, 1);
        System.out.println("this time: " + date);
        System.out.println("next month time: " + calendar.getTime());
    }


这样自己就能通过Gregoriancalendar实现一个简单的定时任务了。

0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics