问题发生的原因
在测试样例中测试Calendar类时,发现每次使用Calendar类的getTimeMillis方法返回结果都不一样
public void testIntervals() {
DutyIntervalSet intervalSet = emptyInstance();initLabels();
Calendar day1 = Calendar.getInstance();
day1.set(2021, 6, 25);
Calendar day2 = Calendar.getInstance();
day2.set(2021, 6, 26);
assertEquals(null, intervalSet.intervals(label1));
intervalSet.insert(day1.getTimeInMillis(), day2.getTimeInMillis(), label1);
assertEquals("{ [1=[1627142400000, 1627228800000]] }", intervalSet.intervals(label1).toString());
}
Calendar类是一个抽象类,在实际使用时实现特定的子类的对象,创建对象的过程对程序员来说是透明的,我们需要使用getInstance方法创建对象。
我们知道Calendar.getTimeMillis返回的是返回从格林威治标准时间 1970 年 1 月 1 日的 00:00:00:000到Calendar对象表示的时间之间的long类型毫秒数。
当我们对Calendar对象进行时间设置时,需要调用set方法:
void set(int field, int value)
用给定的值设置时间字段。void set(int year, int month, int date)
设置年、月、日的值。void set(int year, int month, int date, int hour, int minute)
设置年、月、日、小时、分钟的值。void set(int year, int month, int date, int hour, int minute, int second)
设置年、月、日、小时、分钟、秒的值。
而在我使用set使用“年-月-日”格式对Calendar对象进行初始化时,调用方法void set(int year, int month, int date) 对对象的年(Calendar.YEAR)、月(Calendar.MONTH)、日(Calendar.DATE)位进行赋值,但对于我们没有具体赋值的其他位(如小时(Calendar.HOUR/Calendar.HOUR_OF_DAY)、分钟(Calendar.MINUTE)、秒(Calendar.SECOND)等),set没有具体的数据,于是使用随机数进行赋值。
也就是说我们调用void set(int year, int month, int date) 并不是调用
void set(int year, int month, int date, 0, 0, 0) ,也就是说我们有时、分、秒、毫秒四位数值没有统一设置,这与我们通常的想法不同。
Date类也会出现同样的问题,这对一些需要精确数值的情况不友好。
解决办法
1.Calendard对象在调用set前使用clear方法
Calendar.clear方法将所有的日历字段值和Calendar的时间值为undefined,默认值即格林威治标准时间 1970 年 1 月 1 日的 00:00:00:000的相关数据。Calendar实现类可能会使用默认字段值的日期和时间计算。
void clear()
将所有的日历字段值和Calendar的时间值为undefined
则我们情况可以改为
public void testIntervals() {
DutyIntervalSet intervalSet = emptyInstance();initLabels();
Calendar day1 = Calendar.getInstance();
day1.clear();
day1.set(2021, 6, 25);
Calendar day2 = Calendar.getInstance();
day2.clear();
day2.set(2021, 6, 26);
assertEquals(null, intervalSet.intervals(label1));
intervalSet.insert(day1.getTimeInMillis(), day2.getTimeInMillis(), label1);
assertEquals("{ [1=[1627142400000, 1627228800000]] }", intervalSet.intervals(label1).toString());
}
2.使用Calendar.set方法强制将某个位改为0
这种情况更加灵活,我们可以根据不同情况将不同位置零。
void set(int field, int value)
用给定的值设置时间字段
其中field为Calendar类中设置的各个常量
常量 | 描述 |
Calendar.YEAR | 年份 |
Calendar.MONTH | 月份 |
Calendar.DATE | 日期 |
Calendar.DAY_OF_MONTH | 日期,和上面的字段意义完全相同 |
Calendar.HOUR | 12小时制的小时 |
Calendar.HOUR_OF_DAY | 24小时制的小时 |
Calendar.MINUTE | 分钟 |
Calendar.SECOND | 秒 |
Calendar.DAY_OF_WEEK | 星期几 |
则我的情况可以改为
public void testIntervals() {
DutyIntervalSet intervalSet = emptyInstance();initLabels();
Calendar day1 = Calendar.getInstance();
day1.set(2021, 6, 25);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
Calendar day2 = Calendar.getInstance();
day2.set(2021, 6, 26);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
assertEquals(null, intervalSet.intervals(label1));
intervalSet.insert(day1.getTimeInMillis(), day2.getTimeInMillis(), label1);
assertEquals("{ [1=[1627142400000, 1627228800000]] }", intervalSet.intervals(label1).toString());
}
Date情况与Calendar类似,而正可以通过getTime的long值随便转换。