java Calandar 夏时制 计算指定日期的前一天出错

1. 问题描述: 用java 自带的Calendar 类计算指定日期的前 n 天的日期;

2.现象: 设置当前日期为19870912, n 为-1, 即计算19870912 下一天的日期,计算出来的结果如下,没有得到预期的19870913。

default timeZone:Asia/Shanghai
testDate:19870912   nextDate:19870912 

调用的getDate() 计算逻辑: 将日期转换成毫秒,然后加上n天的毫秒数(n*24*3600*1000L),即为n天后的日期,代码如下:

package com.ibeifeng.senior.kafka;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.SimpleTimeZone;

public class Test {
    public static void main(String[] args) throws ParseException {
       SimpleDateFormat yyyymmdd=new SimpleDateFormat( "yyyyMMdd" );
        String testDateString="19870912";
        //计算testDate的前一天
        Date testDate= yyyymmdd.parse(testDateString);
        Date resDate = getDate(testDate,-1);
        String res = yyyymmdd.format( resDate );
        System.out.println( "testDate:"+testDate +"   nextDate:"+res );


        Date testDate1= yyyymmdd.parse(testDateString);
        System.out.println( "---testDate:"+testDate1  );

        Date resDateGM = getDateGM(testDate1,-1);
        String res1 = yyyymmdd.format( resDateGM );
        System.out.println( "testDate:"+testDate1 +"   nextDate:"+res1 );

        Calendar  calendar2 = Calendar.getInstance();

        String timeZone = calendar2.getTimeZone().getID();
        System.out.println( "default timeZone:"+timeZone );

        Date testDate2= yyyymmdd.parse(testDateString);
        Date resd=getAfterDate(testDate2,-1);
        String res11 = yyyymmdd.format( resd );
        System.out.println( "AddDate:"+testDate2 +"   nextDate:"+res11 );

    }
    //计算在date日期之前的n天的日期
    public static Date  getDate(Date date, int n){
        Calendar  calendar1 = Calendar.getInstance();
        Calendar  calendar2 = Calendar.getInstance();

        String timeZone = calendar1.getTimeZone().getID();
        System.out.println( "default timeZone:"+timeZone );

        calendar2.setTime( date );

        Long c1TimeInMillis = calendar2.getTimeInMillis() - n*24*3600*1000L;
        calendar1.setTimeInMillis(c1TimeInMillis);
        return calendar1.getTime();
    }

    public static Date  getDateGM(Date date, int n){
        Calendar  calendar1 = Calendar.getInstance();
        Calendar  calendar2 = Calendar.getInstance();

        calendar2.setTime( date );

        Long c1TimeInMillis = calendar2.getTimeInMillis() - n*24*3600*1000L;
        calendar1.setTimeInMillis(c1TimeInMillis);
        return calendar1.getTime();
    }
}

调试代码,1.发现计算后的日期 是1987-09-12 23:00:00 ,比预期的结果少一个小时,2.并且testDate 是CDT格式,很奇怪。如图:

查阅资料知:

CDT (中部夏令时间); CST:是中国标准时间;

发现是JVM的默认时区为:Asia/Shanghai,然后Asia/Shanghai 这个时区并不一定与GMT+08这个时区相等,他们是2种定义标准。Asia/Shanghai 这个代表的是中国的时区,但在历史中,有国家(包含中国)政策颁布了在1986-1991年等还存在夏令时。在这样的时间区间,夏季时,会将时间拨快1个小时(即东9区时间),夏季结束时会再次将时间拨回一个小时(即东8区时间)。

虽然Calendar 默认的时区是 Asia/Shanghai,但是Asia/Shanghai 在1986-1991年间仍然存在夏令时,比正常时间多一个小时,这就导致在计算19870912下一天的时候,增加24小时,但日期仍然是 0912日,而不是预期的13日。

3. 解决方案:

方案1. 在计算日期时,Calendor指定时区为 GMT+8,如getDateGM()方法,但是指定时区后,进行set值的时候会将原来CDT时间转换成GMT时间,即 19780912 00:00:00 变为 19780911 23:00:00 ,即对这个0911这个日期进行加24小时,还是不能达到获取后一天的目地。

  public static Date  getDateGM(Date date, int n){

        String timeZone = Calendar.getInstance().getTimeZone().getID();
        System.out.println( "default timeZone:"+timeZone );

        TimeZone.setDefault( TimeZone.getTimeZone( "GMT+8" ) );
        Calendar  calendar1 = Calendar.getInstance(TimeZone.getTimeZone( "GMT+8" ));
        Calendar  calendar2 = Calendar.getInstance(TimeZone.getTimeZone( "GMT+8" ));
        calendar1.clear();
        calendar2.clear();
        String timeZone1 = calendar1.getTimeZone().getID();
        System.out.println( "after timeZone:"+timeZone1 );

        calendar2.setTime( date );

        Long c1TimeInMillis = calendar2.getTimeInMillis() - n*24*3600*1000L;
        calendar1.setTimeInMillis(c1TimeInMillis);
        return calendar1.getTime();
    }

方案2. 使用Calendar 的add() 方法,直接对天进行计算。

  public static Date getAfterDate(Date date , int n){
        Calendar  calendar1 = Calendar.getInstance();
        calendar1.setTime( date );
        calendar1.add( Calendar.DATE,n );
        return calendar1.getTime();
    }

结果:

default timeZone:Asia/Shanghai
testDate:Sat Sep 12 00:00:00 CDT 1987   nextDate:19870912
---testDate:Sat Sep 12 00:00:00 CDT 1987
default timeZone:Asia/Shanghai
after timeZone:GMT+08:00
testDate:Fri Sep 11 23:00:00 GMT+08:00 1987   nextDate:19870912
default timeZone:GMT+08:00
AddDate:Fri Sep 11 23:00:00 GMT+08:00 1987   nextDate:19870911

中国夏时制曾策参看:http://www.qingyunju.com/name/xiashizhi.htm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值