背景
夏令时(Daylight Saving Time),又称日光节约时间。通过将时钟往前调一个小时,从而让人早睡早起,节约使用灯光。
在我国曾经在一段时间内使用过夏令时,在编程时会导致一些问题。比如我们在计算生日的时候,从数据库中取得日期信息一般是不会带上时区信息的。在数据库中存储的形式是:1986-05-05 00:00:00,而通过JDBC读取的时候就会变成这样的形式:1986-05-05 00:00:00 +0900。
这个的时间转换为东八区时间之后,会发生这样的问题,生日提前了一天,变成了:1986-05-04 23:00:00 +0800。
接下来提供一种解决方案,去除从字符串或者是数据库中读取的夏令时日期,会少一个小时的问题。
解决方案
通过Calendar得到Date中DST的偏移量,并且将偏移量加入到Date中,并且对夏令时第一天进行特殊判断,因为在夏令时第一天的开始是从凌晨一点开始的,比如1986-05-03 23:59:59 +0800的下一秒就是1986-05-04 01:00:00 +0900。
public static Date removeChineseDst(Date originDate) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(originDate);
int dstOffset = calendar.get(Calendar.DST_OFFSET);
int month = calendar.get(Calendar.MONTH);
if (dstOffset > 0 && 3 <= month && month <= 4) {
calendar.add(Calendar.HOUR_OF_DAY, -1);
if (calendar.get(Calendar.DST_OFFSET) == 0) {
return originDate;
}
calendar.add(Calendar.HOUR_OF_DAY, 1);
}
calendar.add(Calendar.MILLISECOND, dstOffset);
return calendar.getTime();
}
测试代码如下
package com.johnson.common.util;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.junit.Test;
public class DateUtilTest {
@Test
public void test_removeChinaDst() throws ParseException {
SimpleDateFormat outputFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = formatter.parse("1986-05-04 00:00:00");
System.out.println(outputFormatter.format(date));
date = DateUtil.removeChineseDst(date);
System.out.println(outputFormatter.format(date));
date = formatter.parse("1986-05-05 00:00:00");
System.out.println(outputFormatter.format(date));
date = DateUtil.removeChineseDst(date);
System.out.println(outputFormatter.format(date));
}
}
扩展
中国时区知识
中国使用的时区是Asia/Shanghai,这个时区在1901-1927年采用的是上海地方时,比东八区标准时快了5分55秒。
中国夏令时区间
年份 | 时间区间 |
---|---|
1986 | 05-04~09-14 |
1987 | 04-12~09-12 |
1988 | 04-10~09-10 |
1989 | 04-16~09-16 |
1990 | 04-15~09-15 |
1991 | 04-14~09-14 |