java夏令时问题呈现
一,先看看中國的夏令時
?1986年至1991年,中華人民共和國在全國范圍實行了六年夏令時,每年從4月中旬的第一個星期日2時整(北京時間)到9月中旬第一個星期日的凌晨2時整;
? 十日為旬。 上旬 每月第一日至第十日的十天,為上旬。 中旬 每月十一日到二十日的十天,為中旬,下旬同理
可以通過如下代碼找出這6的異常點
?
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] ----------------------------------------------------------------然后我們再準確的找下是那幾個時間點有問題
?
?
// // 比如1986年的夏令時時間,從代碼來看,是從1986-05-04 00:00:00到1986-09-13 22:59:59 // 但是java也不一定對,需要看老人或者看當年的報紙才能知道準確的夏令時時間@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");// //突變點System.out.println("===1986-05-04 00:00:00實際時間====="+sf.parse("1986-05-04 00:00:00").toLocaleString());System.out.println("===1986-09-13 22:59:59實際時間====="+sf.parse("1986-09-13 22:59:59").toLocaleString());System.out.println("===1986-09-13 23:00:00實際時間====="+sf.parse("1986-09-13 23:00:00").toLocaleString());System.out.println("===1986-09-13 23:59:59實際時間====="+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("目標時區是否使用了夏令時:"+isDaylight(zone, d12));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d13));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d14));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d15));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d16));System.out.println("=========1987=======");System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d21));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d22));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d23));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d24));System.out.println("=========1988=======");System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d31));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d32));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d33));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d34));System.out.println("=========1989=======");System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d41));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d42));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d43));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d44));System.out.println("=========1990=======");System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d51));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d52));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d53));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d54));System.out.println("======1991==========");System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d61));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d62));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d63));System.out.println("目標時區是否使用了夏令時:"+isDaylight(zone, d64));//6個突變點如下,只在開始實行的時候變化System.out.println("===1986-05-04 00:00:00實際時間====="+sf.parse("1986-05-04 00:00:00").toLocaleString());System.out.println("===1987-04-12 00:00:00實際時間====="+sf.parse("1987-04-12 00:00:00").toLocaleString());System.out.println("===1988-04-10 00:00:00實際時間====="+sf.parse("1988-04-10 00:00:00").toLocaleString());System.out.println("===1990-04-15 00:00:00實際時間====="+sf.parse("1990-04-15 00:00:00").toLocaleString());System.out.println("===1991-04-14 00:00:00實際時間====="+sf.parse("1991-04-14 00:00:00").toLocaleString());}//判斷是否在夏令時private boolean isDaylight(TimeZone zone,Date date) {//正常邏輯是:時區使用了夏令時再判斷時間,這里因為中國取消了if (zone.getID().equals("Asia/Shanghai")) {return zone.inDaylightTime(date);}return zone.useDaylightTime()&&zone.inDaylightTime(date);}
通過上面,找到了6個突變點:
?
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
?/**
? ? ? * 說明:這6個夏令時日期會導致實際存入數據庫的date日期發生變化,比如寫的是1986-05-04,實際存入的是1986-05-04 01:00:00
? ? ? * 如果之后在數據庫里面進行日期匹配的時候會出現問題,你需要trunc(date)來比較
? ? ? *?
? ? ? *?
? ? ? * 這里有2個問題,
? ? ? * 1.為什么夏令時結束的時候不會突變呢,比如:1986-09-13 23:00:00這個時候結束了夏令時
? ? ? * 按理實際的時間應該是變為:1986-09-13 22:00:00, 結果沒有變,那么減少的那一個小時去哪里了呢?怎么體現?(待琢磨。。。)
? ? ? * 2.上面得到的夏令時時間范圍跟實際規定的真的一樣嗎?
? ? ? *?
? ? ? * 下面我們看看美國的夏令時是不是也是這種情況
? ? ? */
?
//再來看下美國夏令時的突變時間@Testpublic void test6() throws Exception {//中間相隔13個小時 中國+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//這個結果是不對的,應該02:00:00,結果還是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}/***通過以上測試可以發現:無論是中國還是美國的夏令時*依然存在上面的2個問題:*1.夏令時在結束的時間點是不會突變的,具體原因待查*2.通過代碼判斷的夏令時時間段比 實際宣傳的少一個小時*/public static void ChangeZone(String time, String srcID, String destID,String pattern) throws ParseException {// 設置默認時區TimeZone zone = TimeZone.getTimeZone(srcID);TimeZone.setDefault(zone);Date date = new SimpleDateFormat(pattern).parse(time);// 設置目標時區TimeZone destzone = TimeZone.getTimeZone(destID);SimpleDateFormat sdf = new SimpleDateFormat(pattern);// 設置要格式化的時區sdf.setTimeZone(destzone);String changTime = sdf.format(date);// 獲取目標時區System.out.println("修改時區后" + destzone.getID() + "的時間:" + changTime);}?
?
?
?
?
小結:
雖然存在這2個問題,但是時間并不影響我們代碼邏輯,
唯一要注意的是夏令時開始時那6個突變點,是真實的會影響日期的準確性,在數據庫進行date比較時,必須要截取日期來比較
*1.夏令時在結束的時間點是不會突變的,具體原因待查*2.通過代碼判斷的夏令時時間段比 實際宣傳的少一個小時如果你想解決第一個問題,即在夏令時結束的時候,也讓其時間突變,
參考我的另外一篇文章:
http://blog.csdn.net/u011165335/article/details/76636296
?
?
?
總結
以上是生活随笔為你收集整理的java夏令时问题呈现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浏览器 模拟定位
- 下一篇: K12在线教育新的机遇——直播