问题描述
公司的一个报表需要按周进行数据的统计汇总,在mysql中使用yearweek()函数将时间转化为年份和周数
SELECT YEARWEEK('2000-01-01');
-> 199952
在代码中使用Calendar获取时间是今年的第几周
//获取传入时间的在一年中的周次
public String getWeeks(String times){
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
String weeks=null;
try {
date = format.parse(times);
} catch (ParseException e) {
e.printStackTrace();
}
Calendar calendar = Calendar.getInstance();
calendar.setFirstDayOfWeek(Calendar.MONDAY);
calendar.setTime(date);
int week=calendar.get(Calendar.WEEK_OF_YEAR);
if(week<10){
weeks="0"+week;
}
else {
weeks=week+"";
}
return weeks;
}
当查询今年的数据时,我们发现两者的数值不一致。并造成后面的周数始终相差1。
问题分析
在Calendar中如果我们设置周一为一周的开始第一天,用calendar.get(Calendar.WEEK_OF_YEAR)获取到时当前星期在今年的星期数,但如果这个星期是跨年的,无论你当前时间是哪一年,calendar.get(Calendar.WEEK_OF_YEAR)得到的都会是1。这个也是跨年周的问题。
MySQL 的 YEARWEEK 是获取年份和周数的一个函数,函数形式为 YEARWEEK(date[,mode])
例如 2010-3-14 ,礼拜天
SELECT YEARWEEK(‘2010-3-14’) 返回 11
SELECT YEARWEEK(‘2010-3-14’,1) 返回 10
其中第二个参数是 mode ,具体指的意思如下
在mysql的文档中对model进行了具体的介绍
对于意义为“with 4 or more days this year”的模式值,根据ISO 8601:1988对周进行编号:
如果包含1月1日的那一周在新年中有4天或更多,它就是第1周。
否则,它就是上一年的最后一周,而下一周则是第一周。
详情请前往:mysql日期函数文档
解决方法:
根据mysql的model参数解释我们就可以对Java代码进行修改。我们只要调用Calendar的setMinimalDaysInFirstWeek(Integer i)函数即可,该函数的意义是每年的第一周最少需要几天。如果包含1月1日的那一周在新年中有4天或更多,它就是第1周。否则,它就是上一年的最后一周,而下一周则是第一周。这样我们就和mysql的yearweek函数保证了一致。
修改后的代码:
//获取传入时间的在一年中的周次
public static String getWeeks(String times){
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
String weeks=null;
try {
date = format.parse(times);
} catch (ParseException e) {
e.printStackTrace();
}
Calendar calendar = Calendar.getInstance();
calendar.setFirstDayOfWeek(Calendar.MONDAY);
calendar.setMinimalDaysInFirstWeek(4);//添加的函数
calendar.setTime(date);
int week=calendar.get(Calendar.WEEK_OF_YEAR);
if(week<10){
weeks="0"+week;
}
else {
weeks=week+"";
}
return weeks;
}
注: 我们的程序只是对数据按周进行汇总统计,对于跨年周是属于上一年的最后一周还是新年的第一周要求并不严格,所以可以这样做。