java夏令时问题呈现
一,先看看中國(guó)的夏令時(shí)
?1986年至1991年,中華人民共和國(guó)在全國(guó)范圍實(shí)行了六年夏令時(shí),每年從4月中旬的第一個(gè)星期日2時(shí)整(北京時(shí)間)到9月中旬第一個(gè)星期日的凌晨2時(shí)整;
? 十日為旬。 上旬 每月第一日至第十日的十天,為上旬。 中旬 每月十一日到二十日的十天,為中旬,下旬同理
可以通過(guò)如下代碼找出這6的異常點(diǎn)
?
public static void testDayTime(TimeZone timeZone){SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println("Time Zone is " + timeZone.getDisplayName() + " " + timeZone.getID());Calendar start = Calendar.getInstance(timeZone);start.setTime(new Date(0));//UTC 1970-01-01System.out.println("start=" + fmt.format(start.getTime()));long end = Calendar.getInstance(timeZone).getTimeInMillis();//current timeboolean find = false;for(long i = start.getTimeInMillis(); i < end; i= start.getTimeInMillis() ){start.add(Calendar.DATE, 1); //add one dayif((start.getTimeInMillis() - i)%(24*3600*1000L) != 0){find = true;System.out.println("from " + fmt.format(new Date(i)) +"to " + fmt.format(start.getTime()) +" has " + (start.getTimeInMillis() - i) + "ms" +"[" + (start.getTimeInMillis() - i)/(3600*1000L) + "hours]");}}if(!find){System.out.println("Every day is ok.");}}public static void main(String argv[] ) throws Exception{TimeZone timeZone = TimeZone.getDefault();WhatTime.testDayTime(timeZone);System.out.println("----------------------------------------------------------------");timeZone = TimeZone.getTimeZone("GMT");WhatTime.testDayTime(timeZone);} from 1986-05-03 08:00:00to 1986-05-04 08:00:00 has 82800000ms[23hours] from 1986-09-13 08:00:00to 1986-09-14 08:00:00 has 90000000ms[25hours] from 1987-04-11 08:00:00to 1987-04-12 08:00:00 has 82800000ms[23hours] from 1987-09-12 08:00:00to 1987-09-13 08:00:00 has 90000000ms[25hours] from 1988-04-09 08:00:00to 1988-04-10 08:00:00 has 82800000ms[23hours] from 1988-09-10 08:00:00to 1988-09-11 08:00:00 has 90000000ms[25hours] from 1989-04-15 08:00:00to 1989-04-16 08:00:00 has 82800000ms[23hours] from 1989-09-16 08:00:00to 1989-09-17 08:00:00 has 90000000ms[25hours] from 1990-04-14 08:00:00to 1990-04-15 08:00:00 has 82800000ms[23hours] from 1990-09-15 08:00:00to 1990-09-16 08:00:00 has 90000000ms[25hours] from 1991-04-13 08:00:00to 1991-04-14 08:00:00 has 82800000ms[23hours] from 1991-09-14 08:00:00to 1991-09-15 08:00:00 has 90000000ms[25hours] ----------------------------------------------------------------然后我們?cè)贉?zhǔn)確的找下是那幾個(gè)時(shí)間點(diǎn)有問(wèn)題
?
?
// // 比如1986年的夏令時(shí)時(shí)間,從代碼來(lái)看,是從1986-05-04 00:00:00到1986-09-13 22:59:59 // 但是java也不一定對(duì),需要看老人或者看當(dāng)年的報(bào)紙才能知道準(zhǔn)確的夏令時(shí)時(shí)間@Testpublic void test4() throws Exception {SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");TimeZone zone = TimeZone.getDefault();Date d12=sf.parse("1986-05-03 23:59:00");//Date d13=sf.parse("1986-05-04 00:00:00");//Date d14=sf.parse("1986-06-04 00:00:00");//Date d15=sf.parse("1986-09-13 22:59:59");// Date d16=sf.parse("1986-09-13 23:00:00");// //突變點(diǎn)System.out.println("===1986-05-04 00:00:00實(shí)際時(shí)間====="+sf.parse("1986-05-04 00:00:00").toLocaleString());System.out.println("===1986-09-13 22:59:59實(shí)際時(shí)間====="+sf.parse("1986-09-13 22:59:59").toLocaleString());System.out.println("===1986-09-13 23:00:00實(shí)際時(shí)間====="+sf.parse("1986-09-13 23:00:00").toLocaleString());System.out.println("===1986-09-13 23:59:59實(shí)際時(shí)間====="+sf.parse("1986-09-13 23:59:59").toLocaleString());Date d21=sf.parse("1987-04-11 23:59:00");//Date d22=sf.parse("1987-04-12 00:00:00");//Date d23=sf.parse("1987-09-12 22:59:59");//Date d24=sf.parse("1987-09-12 23:00:00");//Date d31=sf.parse("1988-04-09 23:59:59");//Date d32=sf.parse("1988-04-10 00:00:00");//Date d33=sf.parse("1988-09-10 22:59:59");//Date d34=sf.parse("1988-09-10 23:00:00");//System.out.println("===============");Date d41=sf.parse("1989-04-15 23:59:59");//Date d42=sf.parse("1989-04-16 00:00:00");//Date d43=sf.parse("1989-09-16 22:59:59");//Date d44=sf.parse("1989-09-16 23:00:00");//System.out.println("===============");Date d51=sf.parse("1990-04-14 23:59:59");//Date d52=sf.parse("1990-04-15 00:00:00");//Date d53=sf.parse("1990-09-15 22:59:59");//Date d54=sf.parse("1990-09-15 23:00:00");//System.out.println("===============");Date d61=sf.parse("1991-04-13 23:59:59");//Date d62=sf.parse("1991-04-14 00:00:00");//Date d63=sf.parse("1991-09-14 22:59:59");//Date d64=sf.parse("1991-09-14 23:00:00");//System.out.println("=========1986=======");System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d12));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d13));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d14));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d15));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d16));System.out.println("=========1987=======");System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d21));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d22));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d23));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d24));System.out.println("=========1988=======");System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d31));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d32));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d33));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d34));System.out.println("=========1989=======");System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d41));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d42));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d43));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d44));System.out.println("=========1990=======");System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d51));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d52));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d53));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d54));System.out.println("======1991==========");System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d61));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d62));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d63));System.out.println("目標(biāo)時(shí)區(qū)是否使用了夏令時(shí):"+isDaylight(zone, d64));//6個(gè)突變點(diǎn)如下,只在開(kāi)始實(shí)行的時(shí)候變化System.out.println("===1986-05-04 00:00:00實(shí)際時(shí)間====="+sf.parse("1986-05-04 00:00:00").toLocaleString());System.out.println("===1987-04-12 00:00:00實(shí)際時(shí)間====="+sf.parse("1987-04-12 00:00:00").toLocaleString());System.out.println("===1988-04-10 00:00:00實(shí)際時(shí)間====="+sf.parse("1988-04-10 00:00:00").toLocaleString());System.out.println("===1990-04-15 00:00:00實(shí)際時(shí)間====="+sf.parse("1990-04-15 00:00:00").toLocaleString());System.out.println("===1991-04-14 00:00:00實(shí)際時(shí)間====="+sf.parse("1991-04-14 00:00:00").toLocaleString());}//判斷是否在夏令時(shí)private boolean isDaylight(TimeZone zone,Date date) {//正常邏輯是:時(shí)區(qū)使用了夏令時(shí)再判斷時(shí)間,這里因?yàn)橹袊?guó)取消了if (zone.getID().equals("Asia/Shanghai")) {return zone.inDaylightTime(date);}return zone.useDaylightTime()&&zone.inDaylightTime(date);}
通過(guò)上面,找到了6個(gè)突變點(diǎn):
?
1986-05-04 00:00:00
1987-04-12 00:00:00
1988-04-10 00:00:00
1989-04-16 00:00:00
1990-04-15 00:00:00
1991-04-14 00:00:00
?/**
? ? ? * 說(shuō)明:這6個(gè)夏令時(shí)日期會(huì)導(dǎo)致實(shí)際存入數(shù)據(jù)庫(kù)的date日期發(fā)生變化,比如寫(xiě)的是1986-05-04,實(shí)際存入的是1986-05-04 01:00:00
? ? ? * 如果之后在數(shù)據(jù)庫(kù)里面進(jìn)行日期匹配的時(shí)候會(huì)出現(xiàn)問(wèn)題,你需要trunc(date)來(lái)比較
? ? ? *?
? ? ? *?
? ? ? * 這里有2個(gè)問(wèn)題,
? ? ? * 1.為什么夏令時(shí)結(jié)束的時(shí)候不會(huì)突變呢,比如:1986-09-13 23:00:00這個(gè)時(shí)候結(jié)束了夏令時(shí)
? ? ? * 按理實(shí)際的時(shí)間應(yīng)該是變?yōu)?1986-09-13 22:00:00, 結(jié)果沒(méi)有變,那么減少的那一個(gè)小時(shí)去哪里了呢?怎么體現(xiàn)?(待琢磨。。。)
? ? ? * 2.上面得到的夏令時(shí)時(shí)間范圍跟實(shí)際規(guī)定的真的一樣嗎?
? ? ? *?
? ? ? * 下面我們看看美國(guó)的夏令時(shí)是不是也是這種情況
? ? ? */
?
//再來(lái)看下美國(guó)夏令時(shí)的突變時(shí)間@Testpublic void test6() throws Exception {//中間相隔13個(gè)小時(shí) 中國(guó)+8 紐約-5ChangeZone("2016-3-13 14:59:59", "PRC","America/New_York", "yyyy-MM-dd HH:mm:ss");//2016-03-13 01:59:59ChangeZone("2016-3-13 15:00:00", "PRC","America/New_York", "yyyy-MM-dd HH:mm:ss");//2016-03-13 03:00:00ChangeZone("2016-11-6 13:59:59", "PRC","America/New_York", "yyyy-MM-dd HH:mm:ss");//2016-11-06 01:59:59//這個(gè)結(jié)果是不對(duì)的,應(yīng)該02:00:00,結(jié)果還是01:00:00ChangeZone("2016-11-6 14:00:00", "PRC","America/New_York", "yyyy-MM-dd HH:mm:ss");//2016-11-06 01:00:00}/***通過(guò)以上測(cè)試可以發(fā)現(xiàn):無(wú)論是中國(guó)還是美國(guó)的夏令時(shí)*依然存在上面的2個(gè)問(wèn)題:*1.夏令時(shí)在結(jié)束的時(shí)間點(diǎn)是不會(huì)突變的,具體原因待查*2.通過(guò)代碼判斷的夏令時(shí)時(shí)間段比 實(shí)際宣傳的少一個(gè)小時(shí)*/public static void ChangeZone(String time, String srcID, String destID,String pattern) throws ParseException {// 設(shè)置默認(rèn)時(shí)區(qū)TimeZone zone = TimeZone.getTimeZone(srcID);TimeZone.setDefault(zone);Date date = new SimpleDateFormat(pattern).parse(time);// 設(shè)置目標(biāo)時(shí)區(qū)TimeZone destzone = TimeZone.getTimeZone(destID);SimpleDateFormat sdf = new SimpleDateFormat(pattern);// 設(shè)置要格式化的時(shí)區(qū)sdf.setTimeZone(destzone);String changTime = sdf.format(date);// 獲取目標(biāo)時(shí)區(qū)System.out.println("修改時(shí)區(qū)后" + destzone.getID() + "的時(shí)間:" + changTime);}?
?
?
?
?
小結(jié):
雖然存在這2個(gè)問(wèn)題,但是時(shí)間并不影響我們代碼邏輯,
唯一要注意的是夏令時(shí)開(kāi)始時(shí)那6個(gè)突變點(diǎn),是真實(shí)的會(huì)影響日期的準(zhǔn)確性,在數(shù)據(jù)庫(kù)進(jìn)行date比較時(shí),必須要截取日期來(lái)比較
*1.夏令時(shí)在結(jié)束的時(shí)間點(diǎn)是不會(huì)突變的,具體原因待查*2.通過(guò)代碼判斷的夏令時(shí)時(shí)間段比 實(shí)際宣傳的少一個(gè)小時(shí)如果你想解決第一個(gè)問(wèn)題,即在夏令時(shí)結(jié)束的時(shí)候,也讓其時(shí)間突變,
參考我的另外一篇文章:
http://blog.csdn.net/u011165335/article/details/76636296
?
?
?
總結(jié)
以上是生活随笔為你收集整理的java夏令时问题呈现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 浏览器 模拟定位
- 下一篇: K12在线教育新的机遇——直播