亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

算法——指定日期的星期推算

AbnerMing / 2101人閱讀

摘要:儒略日就是指從公元前年月日開始所經(jīng)過的天數(shù),就被指定為公元前年月日到公元前年月日之間的小時(shí),依次順推,每一天都被賦予一個(gè)唯一的數(shù)字。

??最近閑來無事,突然想了解下中國農(nóng)歷與中國陽歷之間的關(guān)系,經(jīng)過一番調(diào)研發(fā)現(xiàn)這里面的水還比較深,涉及天文學(xué)、歷史、宗教等一些知識,發(fā)現(xiàn)挺有意思的就準(zhǔn)備做一系列的總結(jié),主要是防止自己忘記了,而且搜索了一下簡書上的文章也么沒有相關(guān)文章進(jìn)行描述,所以借此機(jī)會(huì)跟大家分享同大家討論,這篇文章是這個(gè)系列的第一篇,主要講是如何推算指定日期的星期問題

根據(jù)已知日期進(jìn)行推算

該方法主要是通過計(jì)算已知日期和指定日期之間的天數(shù)來推算,因?yàn)樾瞧谑且粋€(gè)非常固定的時(shí)間周期,7天一循環(huán),因此通過計(jì)算出相差天數(shù)后,再對7進(jìn)行取余操作就能推算出指定的日期的星期

根據(jù)公歷平閏年計(jì)算

最常見的計(jì)算兩個(gè)日期之間的天數(shù)就是根據(jù)年數(shù)進(jìn)行推算,但是由于有閏年的影像,因此需要考慮閏年的情況,閏年的判斷規(guī)則如下:

公歷年數(shù)是4的倍數(shù),且不是100倍數(shù)

公歷年數(shù)是400倍數(shù)

滿足上述兩個(gè)條件中的一個(gè)既是閏年,該描述可以參考李永樂老師的視頻講解:閏年是怎么回事

依次遍歷年份計(jì)算天數(shù)

經(jīng)過分析我們發(fā)現(xiàn)兩個(gè)日期之間的天數(shù)可分為三部分:

起始日期所在年中剩余的天數(shù)

結(jié)束日期所在年中已經(jīng)度過的天數(shù)

中間年份的整年的天數(shù)

實(shí)現(xiàn)代碼一

上述是一個(gè)通用描述,對于起止時(shí)間正好在一個(gè)年的開始和結(jié)尾,該方案也能描述。
因?yàn)橹虚g是一個(gè)有可能存在閏年的,所需要根據(jù)閏年規(guī)則對每個(gè)年份進(jìn)行判斷,代碼如下:

/**
     * @param startYear 起始年份
     * @param endYear 截止年份
     * @return 從起止年份到截止年份前一年的天數(shù)
     * 常量 YearDays.LEAP_YEAR_DAYS = 366
     * 常量 YearDays.NONLEAP_YEAR_DAYS = 365
     * @throws CalendarException
     */
public static int calculateDaysOfYears(int startYear, int endYear) throws CalendarException {
        if(startYear > endYear) {
            throw new CalendarException(String.format("illegal parameter year, startYear=%s endYear=%s", startYear, endYear));
        }

        int difference = endYear - startYear;

        int totalDays = 0;
        //從起始年的1月1號開始加和,一直到截止年的前一年所有的天數(shù),這樣的計(jì)算需要減去起始年已經(jīng)過過去的天數(shù)
        for(int i= startYear; i < endYear; i++) {
            boolean isLeap = CalendarTool.isLeapyear(i);
            if (isLeap) {
                totalDays += YearDays.LEAP_YEAR_DAYS;
            } else {
                totalDays += YearDays.NONLEAP_YEAR_DAYS;
            }
        }

        return totalDays;
    }

因?yàn)樾枰?jì)算截止年月已經(jīng)度過的天數(shù),所以我復(fù)用了這個(gè)計(jì)算邏輯,以為剩余的天數(shù) = 年內(nèi)總天數(shù) - 已經(jīng)過的天數(shù)基于這個(gè)公式就能算出其實(shí)年份剩余的天數(shù)

 /**
     * 計(jì)算一年中到指定日期時(shí)已經(jīng)度過的天數(shù)
     * @param year 年
     * @param month 枚舉類型,定義了sort月數(shù)和 days天數(shù)兩個(gè)屬性
     * @param day 所在月的日期
     * @return
     */
    public static int calculatePassedDays(int year, CalendarMonth month, int day) throws CalendarException {
        CalendarTool.checkParam(year, month, day);

        int monthValue = month.getSort();

        int passedTotal = 0;
        for(int i = 1; i < monthValue; i++) {
            CalendarMonth passedMonth = CalendarMonth.getMonthBySort(i);
            if(passedMonth.equals(CalendarMonth.FEBRUARY)) {
                boolean isLeap = CalendarTool.isLeapyear(year);
                if(isLeap) {
                    passedTotal += 29;
                    continue;
                }
            }
            passedTotal += passedMonth.getDays();
        }

        return passedTotal + day;
    }

舉個(gè)例子驗(yàn)證一下:已知1977年3月27日是星期天,計(jì)算2005年5月31日是星期幾,按照上述的算法進(jìn)行計(jì)算得到天數(shù)是10292,然后用10292 % 7 = 2得到余數(shù)為2,那么2005年5月31日就是星期二。

實(shí)現(xiàn)代碼二

上述方法需要依次遍歷起止年份之間的所有年份進(jìn)行平閏年的判斷,比較復(fù)雜,判斷起來比較麻煩,其實(shí)我們只需要知道兩個(gè)年份之間的閏年個(gè)數(shù)就可以解決我們的問題了,閏年的個(gè)數(shù)的計(jì)算公式:(分?jǐn)?shù)結(jié)構(gòu)部分表示向下取整)
$$ leap = leftlfloorfrac y4 ight floor - leftlfloorfrac y{100} ight floor + leftlfloorfrac y{400} ight floor$$

公式中的y表示的當(dāng)前年份,該公式結(jié)果是從公元元年到y(tǒng)年中所有閏年的個(gè)數(shù),如果y年是閏年的話,y年也算在內(nèi)。

這個(gè)公式中臨界值確定需要注意,就是在起止年份,如果起止年份是閏年的話,要看起止年份是過了2月,這個(gè)直接關(guān)系到是+1天還是不加1天的問題。

這樣就不需要遍歷每個(gè)年份是否為閏年了,而直接計(jì)算天數(shù)即可,只需要將之前小節(jié)中計(jì)算整年天數(shù)代碼進(jìn)行調(diào)整,如下:

 /**
     * @param startYear 起始年份
     * @param endYear 截止年份
     * @return 從起止年份到截止年份前一年的天數(shù)
     * 常量 YearDays.LEAP_YEAR_DAYS = 366
     * 常量 YearDays.NONLEAP_YEAR_DAYS = 365
     * @throws CalendarException
     */
    public static int calculateDays(int startYear, int endYear) throws CalendarException {

        startYear -= 1;
        endYear -= 1;
        int startLeaps = Integer.valueOf(startYear / 4) - Integer.valueOf(startYear / 100) + Integer.valueOf(startYear / 400);
        int endLeaps = Integer.valueOf(endYear / 4) - Integer.valueOf(endYear / 100) + Integer.valueOf(endYear / 400);

        int totalDays = endLeaps * YearDays.LEAP_YEAR_DAYS + (endYear - endLeaps) * YearDays.NONLEAP_YEAR_DAYS -(startLeaps * YearDays.LEAP_YEAR_DAYS + (startYear - startLeaps) * YearDays.NONLEAP_YEAR_DAYS);

        return totalDays;
    }

年數(shù)-1是因?yàn)槠鹬鼓攴莶⒉皇峭暾?,?jì)算之前的一年就不用考慮起止年份是否為閏年和月份是否過了2月份了,簡化了邏輯判斷。這樣代碼比之前的方法看起來精簡了不少。

代碼出處

上述代碼片段可能不能滿足大家的需要,所以附上代碼出處

根據(jù)儒略日進(jìn)行推算

上面的方法是根據(jù)平閏年進(jìn)行推算的,需要進(jìn)行復(fù)雜的平閏年判斷,就算第二種方法也是簡化了起止年份之間的年份的閏年判斷,開始和結(jié)束年份的閏年判斷再計(jì)算度過了多少天的時(shí)候還是要進(jìn)行判斷的,通過儒略日可以規(guī)避平閏年的判斷。

儒略日

儒略日是一種不記年,不記月,只記日的歷法,是由法國學(xué)者Joseph Justus Scaliger(1540-1609)在1583年提出來的一種以天數(shù)為計(jì)量單位的流水日歷。儒略日就是指從公元前4713年1月1日UTC 12:00開始所經(jīng)過的天數(shù),JD0就被指定為公元前4713年1月1日 12:00到公元前4713年1月2日12:00之間的24小時(shí),依次順推,每一天都被賦予一個(gè)唯一的數(shù)字。使用儒略日可以把不同歷法的年表統(tǒng)一起來,很方便地在各種歷法中追溯日期。如果計(jì)算兩個(gè)日期之間的天數(shù),利用儒略日計(jì)算也很方便,先計(jì)算出兩個(gè)日期的儒略日數(shù),然后直接相減就可以得到兩個(gè)日期相隔的天數(shù)。

儒略日公式

$$ julian = leftlfloor 1461 imes frac{y + 4716}{4} ight floor + leftlfloor 153 imes frac{m + 1}{4} ight floor + d + c - 1524.5 $$
y表示年份
m表示月份,如果m≤2則m修正為m+12,同時(shí)y修正為y-1
d表示日期
c的求值公式
$$ c = 2 - leftlfloorfrac{y}{100} ight floor + leftlfloorfrac{y}{400} ight floor $$

實(shí)現(xiàn)代碼
public static int calculateDaysWithJulian(int year, CalendarMonth month, int day) throws CalendarException {
        CalendarTool.checkParam(year, month, day);

        int monthVal = month.getSort();
        if(month.compare(CalendarMonth.FEBRUARY) <= 0) {
            monthVal = month.getSort() + 12;
            year = year - 1;
        }

        //計(jì)算 c 值
        int c = 2 - Integer.valueOf(year/100) + Integer.valueOf(year/400);

        //因?yàn)槿迓匀盏拈_始是從中午12點(diǎn)開始的,所以需要加0.5天, 0.0000115740天=1秒
        day += 0.5000115740;
        return (int) (Integer.valueOf(1461 * (year + 4716) / 4) + Integer.valueOf(153 * (monthVal + 1)/5) + day + c - 1514.5);
    }

這樣通過儒略日公式進(jìn)行推算,代碼較之前代碼更加精簡

代碼出處

儒略日計(jì)算代碼出處

直接定位日期所在星期

前面所述的推送方法都是基于已知日期的星期,然后計(jì)算與所指定的日期之間的天數(shù)來進(jìn)行推算,在已知日期之后向后推算,在已知日期之前的向前推算,不是很方便。基于公元元年1月1日為周一,那么前一天就是下面介紹一個(gè)直接定位日期所在星期日,基于這個(gè)想法退出下面的公式。

計(jì)算公式

$$ weekday = ( y + leftlfloorfrac{y}{4} ight floor + leftlfloorfrac{c}{4} ight floor -2c + leftlfloor 13 imes frac{m+1}{5} ight floor + d - 1 ) \% 7 $$
上述公式適用1582年10月15日及之后的日期,對于1582年10月4及之前的公式:
$$ weekday = ( y + leftlfloorfrac{y}{4} ight floor + leftlfloorfrac{c}{4} ight floor -2c + leftlfloor 13 imes frac{m+1}{5} ight floor + d + 3 ) \% 7 $$

實(shí)現(xiàn)代碼
/***
     * 計(jì)算指定日其所在的星期
     * 兼容1582年前后10月4日之前和1582年10月15之后的所有時(shí)間
     * @param year
     * @param month
     * @param day
     * @return
     * @throws CalendarException
     */
    public static int calculateweek(int year, CalendarMonth month, int day) throws CalendarException {

        int m = month.getSort();
        if(month.compare(CalendarMonth.MARCH) < 0) {
            m = month.getSort() + 12;
            year = year - 1;
        }

        int c = year / 100;
        int y = year % 100;

        int week = 0;
        if(year == 1582 && month.equals(CalendarMonth.OCTOBER) && day > 4 && day < 15) {
            throw new CalendarException(String.format("illegal date exception, date=%s-%s-%s not exist", year, month.getSort(), day));
        } else {
            if(year < 1582 || (year == 1582 && month.compare(CalendarMonth.OCTOBER) < 0) || (year == 1582 && month.equals(CalendarMonth.OCTOBER) && day <= 4)) {
                week = Integer.valueOf(y + Integer.valueOf(y / 4) + Integer.valueOf(c / 4) - 2*c + Integer.valueOf(13 * (m + 1) / 5) + day + 3) % 7;
            } else {
                week = Integer.valueOf(y + Integer.valueOf(y / 4) + Integer.valueOf(c / 4) - 2*c + Integer.valueOf(13 * (m + 1) / 5) + day - 1) % 7;
            }
        }

        // 公式會(huì)產(chǎn)生負(fù)數(shù),修正即可
        if(week < 0)
            week = (week + 7) % 7;

        return week;

    }
代碼出處

儒略日定位計(jì)算代碼出處

這篇文章主要是從網(wǎng)上搜集來的知識并不是自己讀書的來,以下是主要文檔的出處
相關(guān)文檔:
https://blog.csdn.net/orbit/a...
https://blog.csdn.net/orbit/a...
http://www.365yg.com/i6550819...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/71394.html

相關(guān)文章

  • 帶你開發(fā)一個(gè)日歷控件

    摘要:直接使用事件代理機(jī)制,將事件綁定在整個(gè)日歷的上即可,這樣事件只用在創(chuàng)建時(shí)初始化一次即可,簡單高效省內(nèi)存。 首發(fā)我的博客 - https://blog.cdswyda.com/post/2017121010 日歷控件多的不勝枚舉,為什么我們還要再造一個(gè)輪子呢? 因?yàn)榇蠖鄶?shù)日歷控件都是用于選擇日期的,有種需求是要在日歷上展示各種各樣的內(nèi)容,這樣的日歷控件較少,而且試用下來并不滿意。 因此就...

    shiina 評論0 收藏0
  • Calendar -『為移動(dòng)端而生』自定義日歷

    摘要:,歡迎使用中文文檔在后面自我介紹是為了滿足移動(dòng)端對各種場景的需求而生的,兼容性強(qiáng),靈活度高。如空數(shù)組默認(rèn)設(shè)置成當(dāng)月日數(shù)組的每一位分別是年月日。 Calendar - A Flexible Calendar for Mobile Intro Calendar was born for several product requirements in the mobile. It’s f...

    MycLambert 評論0 收藏0
  • Calendar -『為移動(dòng)端而生』自定義日歷

    摘要:,歡迎使用中文文檔在后面自我介紹是為了滿足移動(dòng)端對各種場景的需求而生的,兼容性強(qiáng),靈活度高。如空數(shù)組默認(rèn)設(shè)置成當(dāng)月日數(shù)組的每一位分別是年月日。 Calendar - A Flexible Calendar for Mobile Intro Calendar was born for several product requirements in the mobile. It’s f...

    Gu_Yan 評論0 收藏0
  • 簡介:CII最佳實(shí)踐徽章 - CNCF畢業(yè)標(biāo)準(zhǔn)要求之一

    摘要:已經(jīng)實(shí)現(xiàn)并維護(hù)了核心基礎(chǔ)結(jié)構(gòu)計(jì)劃的最佳實(shí)踐徽章。年中國開源峰會(huì)提案征集現(xiàn)已開放在中國開源峰會(huì)上,與會(huì)者將共同合作及共享信息,了解最新和最有趣的開源技術(shù),包括容器云技術(shù)網(wǎng)絡(luò)微服務(wù)等并獲得如何在開源社區(qū)中導(dǎo)向和引領(lǐng)的信息。 從沙箱或孵化狀態(tài)畢業(yè),或者作為一個(gè)新項(xiàng)目加入作為一個(gè)畢業(yè)項(xiàng)目,項(xiàng)目必須符合孵化階段標(biāo)準(zhǔn)以及: 有來自至少兩個(gè)機(jī)構(gòu)的提交者。 已經(jīng)實(shí)現(xiàn)并維護(hù)了核心基礎(chǔ)結(jié)構(gòu)計(jì)劃(CII)...

    jzman 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<