从时间戳计算日历

class MyDate {
    private int year;
    private int month;
    private int day;
    private int hour;
    private int minute;
    private int second;

    private final long timePerSecond = 1000;
    private final long timePerMinute = 1000*60;
    private final long timePerHour = 3600*1000;
    private final long timePerDay = 24*3600*1000;
    private final long timePerPingNian = 365*timePerDay;
    private final long timePerLeapYear = 366*timePerDay;
    private final long timeOf1970And1971 = timePerPingNian+timePerPingNian;
    private final long timePer4Year = (long)(365.25*4*timePerDay);
    private final long timeEvery400Year = timePer4Year*100 - 3*timePerDay;
    private final long timeOf1970To2000 = timePer4Year*7+timeOf1970And1971;
    private final int[] daysPerMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    private boolean setMinuteAndSecond(long milliTime) {

        assert milliTime<timePerDay;
        if(milliTime>=timePerDay)
            return false;

        hour = (int)(milliTime/timePerHour);
        long t = milliTime%timePerHour;
        minute = (int)(t/timePerMinute);
        t = t%timePerMinute;
        second = (int)(t/timePerSecond);

        return true;
    }

    private boolean setMonthAndDay(long milliTime, boolean isLeapYear) {

        //this func should handle  the case where milliTime == 0;
        //this func get the milliseconds within 1 year;

        assert milliTime<=timePerLeapYear && isLeapYear || milliTime<=timePerPingNian && !isLeapYear;
        if(milliTime>timePerLeapYear && isLeapYear || milliTime>timePerPingNian && !isLeapYear) {
            return false;
        }

        daysPerMonth[1] = isLeapYear ? 29 : 28; //set the days of February;

        int cnt = -1;

        do{
            milliTime -= daysPerMonth[++cnt]*timePerDay;
        }while (milliTime>=0);

        month = cnt+1;  //for that the cnt begin from 0, but month begin from 1;
        long timeOfLastMonth = daysPerMonth[cnt]*timePerDay+milliTime;
        day = (int)(timeOfLastMonth/timePerDay)+1;

        setMinuteAndSecond(timeOfLastMonth % timePerDay);

        return true;
    }

    private boolean setDataFile(long milliTime) {
        if(milliTime<0)
            return false;

        boolean is1970Or1971 = milliTime<timeOf1970And1971 ? true : false;
        boolean is20Century = milliTime<timeOf1970To2000 ? true: false; 
        //if equal is 2000 1 1 0:0:0

        if(is1970Or1971) {
            year = milliTime>=timePerPingNian ? 1971 : 1970;
            setMonthAndDay(year==1971 ? milliTime-timePerPingNian : milliTime, false);
            return true;
        }

        if(is20Century) {
            long t = (milliTime-timeOf1970And1971)/timePer4Year;  
            long t1 = milliTime-timeOf1970And1971-t*timePer4Year;

            long t2 = t1-timePerLeapYear;
            boolean isLeapYear = t2<0;
            long t3 = isLeapYear ? 0 : t2/timePerPingNian+1;

            year = (int)(1972+t*4+t3);

            long l = isLeapYear ? t1 : (t1-t3*timePerPingNian-timePerDay);
            setMonthAndDay(l, isLeapYear);

            return true;
        }

        long p = milliTime-timeOf1970To2000;

        long t1 = p/timeEvery400Year;
        long p1 = p-t1*timeEvery400Year;

        long t2 = p1/timePer4Year;
        long tN = t2/25;    
        //in every 400 years, other year such as xy00(y!=0) is not leap year;

        long p2 = p1-t2*timePer4Year;
        p2 += tN*timePerDay;

        long t3 = p2-timePerLeapYear;

        boolean isLeapYear = t3<0;
        long t4 = isLeapYear ? 0 : t3/timePerPingNian+1;

        year = (int)(2000+t1*400+t2*4+t4);

        long lt = isLeapYear ? p2 : (p2-t4*timePerPingNian-timePerDay);
        setMonthAndDay(lt, isLeapYear);
        return true;
    }
}

思路

设置时分秒(函数setMinuteAndSecond)

  • 函数的输入是 小于 每天毫秒数 的一个整数
  • 因为是从0:0:0开始计时,所以很好算
  • 直接除以每小时毫秒数,结果就是 要求的小时数
  • 然后把取模每小时毫秒数的结果除以每分钟毫秒数,算出来的结果就是分钟数
  • 以此类推,算出秒数

设置月和日(函数setMonthAndDay)

  • 函数的输入为 小于 每年毫秒数 一个整数
  • 依次减去每个月的毫秒数,当减去某个月后,得到负数,说明月份就是这个月。注意,如果减去后得到0,则是下个月的第一毫秒,因为毫秒数是相对1970.1.1.0:0:0计算的。举个例子,毫秒数==一个平年的毫秒数,那么加上1970.1.1.0:0:0后,就变成1971.1.1.0:0:0,而不是1970.12.31.23:59:59
  • 通过上面那个流程,得到属于一个月内的毫秒数(注意,比如说某个月的毫秒数是K,那么0~(K-1)都是属于这个月,但是K不是),然后除以每天的毫秒数,得到 P 。同样,如果整除,说明日期数是 P+1,如果不整除,那也是 P+1(注意,日期是从1开始,而不是从0开始)

设置年份(在函数setDataFile中)

  • 对1970/1971特殊处理,直接判断是否毫秒数是否 一个平年的毫秒数,如果是,那么就是1971。注意,等于也是,原因如上所述。然后调用setMonthAndDay函数,设置日月

  • 对1972.1.1.0:0:0到2000.1.1.0:0:0 特殊处理。先减去1970和1971的总的毫秒数,得到的结果除以每4年的毫秒数,得到H。同样,无论是否整除,年份数是在 [4H+1972,4H+1972+3] ,整除就是 4H+1972 这一年的第一毫秒(0时0分0秒)。因为1970.1.1.0:0:0加上1970和1971总的毫秒数已经是1972.1.1.0:0:0了,再加上整数年 4H 就是(1972+4H).1.1.0:0:0了。

    然后减去一个闰年的毫秒数,因为从1972年算起,每四年的第一年都是闰年,如果结果是负数,说明是闰年(同样的,如果是0,那么并不是闰年,而是闰年下一年的第一毫秒)。否则,把得到结果除以每个平年的毫秒数得到 P ,就是从闰年的下一年 开始的第 P 年,所以,年份就是 1972+4H+1+P

  • 然后,因为当年份数是100的倍数时,只有当年份可以被400整除,才是闰年。而2000年正好就是每400年里的第一年,所以要先计算,毫秒数里总的有多少个400年,如果有 t 个,那么年份数就是 [2000+400t,2000+400t+399]

    接下来就计算总的毫秒数减去1970到2000的毫秒数,再减去总共多少个400年的毫秒数,剩下的毫秒数里,算算有多少个4年,因为每4年是闰年。如果算出来的结果是 d ,那么年份数就是 [2000+400t+4d,2000+400t+4d+3]

    接下来判断剩下的毫秒数是否小于一个闰年的毫秒数,如果是,那么就是闰年,年份数是 2000+400t+4d 。如果不是,就减去一个闰年的毫秒数,然后算一算剩下的有多少个平年的毫秒数,假设算出来的结果是 b ,那么年份数就是 2000+400t+4d+b+1

    接下来调用setMonthAndDay函数设置月份日期

猜你喜欢

转载自blog.csdn.net/h_zx_h_zx/article/details/78151626