基於時間誤差思路下的時間週期度量

1、背景

最近改項目中的bug,遇到一類問題:當月起始日能夠設置的狀況下(1日到28日),須要計算出對應的月、季度、年等相關的時間範圍,以及對應的如上月、上季、去年等,和給定時間戳的所屬年、季度、月份等各類時間求取。bash

爲簡單起見,舉個栗子: 如若是月起始日設置成了5,那麼本月的時間範圍是:工具

2019.10.05 00:00:00 - 2019.11.04 23:59:59
複製代碼

本季度的時間範圍是:ui

2019.10.05 00:00:00 - 2020.01.04 23:59:59
複製代碼

項目中大量的地方須要用到此類計算。所以,相應的時間獲取被封裝成了工具類。這自己並無什麼問題,但問題在於封裝的工具類中每一個時間週期的獲取寫法多種多樣,例如獲取上月起始時間,下個季度起始時間等等方法思路各不相同,加上不一樣的人都有去實現本身須要的方法,所以,整個工具類看下來,一是很差理解,二是各類潛藏的bug。spa

見得最多的,是判斷各類邊界狀況,而後對應各類處理邏輯。。code

有沒有簡單些的方法呢?get

實際上是有的。ast


2、思路與實現

2.1 思路

不管月起始日設置成哪一天,在作月起始日相關的任何邏輯計算時,其實均可以採起一種通用的實現思路,即時間誤差的修正與迴歸。例如,無論當前時間戳是多少,要計算本季度的起始時間,直接將時間戳先修正,而後計算出對應的天然時間概念下的季起始時間,最後再回補上對應的時間誤差便可。class

2.2 實現

Talk is cheap. Show me the code.
複製代碼

/**
 *  根據月起始日,計算對應時間戳的季度開始時間
 *
 * @param monthStart
 * @param timeStamp
 * @return
 */
public static long getFixedQuarterBeginTimeBySetting(int monthStart, long timeStamp){
    Calendar c = Calendar.getInstance();
    c.setTimeInMillis(timeStamp);

    // 修正偏移時間
    c.add(Calendar.DAY_OF_MONTH, -monthStart + 1);

    // 得到修正後的天然季度開始時間
    long fixedNatureQuarterBeginTime = DateUtils.getNatureQuarterBeginTimeInMillis(c.getTimeInMillis());
    c.setTimeInMillis(fixedNatureQuarterBeginTime);

    // 回補月起始日
    c.add(Calendar.DAY_OF_MONTH, monthStart - 1);

    return c.getTimeInMillis();
}

/**
 *  根據月起始日,計算對應時間戳的季度結束時間
 *
 * @param monthStart
 * @param timeStamp
 * @return
 */
public static long getFixedQuarterEndTimeBySetting(int monthStart, long timeStamp){
    // 獲取季度開始時間
    long fixedQuarterBeginTime = getFixedQuarterBeginTimeBySetting(monthStart, timeStamp);

    Calendar c = Calendar.getInstance();
    c.setTimeInMillis(fixedQuarterBeginTime);
    // 月份加3
    c.add(Calendar.MONTH, 3);

    // 時間戳退1
    return c.getTimeInMillis() - 1;
}

/**
 *  根據月起始日,計算對應時間戳的上個季度開始時間
 *
 * @param monthStart
 * @param timeStamp
 * @return
 */
public static long getFixedLastQuarterBeginTimeBySetting(int monthStart, long timeStamp){
    long fixedQuarterBeginTime = getFixedQuarterBeginTimeBySetting(monthStart, timeStamp);

    return getFixedQuarterBeginTimeBySetting(monthStart, fixedQuarterBeginTime - 1);
}

/**
 *  根據月起始日,計算對應時間戳的上個季度結束時間
 *
 * @param monthStart
 * @param timeStamp
 * @return
 */
public static long getFixedLastQuarterEndTimeBySetting(int monthStart, long timeStamp){
    long fixedQuarterEndTime = getFixedQuarterBeginTimeBySetting(monthStart, timeStamp);

    return fixedQuarterEndTime - 1;
}

/**
 * 根據月起始日,計算對應時間戳的年開始時間
 *
 * @param monthStart
 * @param timeStamp
 * @return
 */
public static long getFixedYearBeginTimeBySetting(int monthStart, long timeStamp) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(timeStamp);

    // 修正誤差
    calendar.add(Calendar.DAY_OF_MONTH, -monthStart + 1);

    // 獲取修正誤差後的天然時間
    long fixedNatureYearBeginTime = DateUtils.getNatureYearBeginTime(calendar.getTimeInMillis());

    calendar.setTimeInMillis(fixedNatureYearBeginTime);

    // 回補月起始日
    calendar.add(Calendar.DAY_OF_MONTH, monthStart - 1);

    return calendar.getTimeInMillis();
}
複製代碼

很輕鬆的,咱們將本來可能須要的複雜的時間範圍計算方式,通通基於一樣的思路,即時間誤差的修正與迴歸,轉變成了求得修正後的時間戳後的天然時間週期,最後再回歸到最終想要的結果。bug

這樣一個最明顯的好處是,整個工具類實現思路是徹底一致的,且在求取時間週期時,通常狀況下,也不會有什麼bug產生,理解了這種思路後,不管求月起始日對應的什麼時間週期,代碼實現也都很簡單。方法


3、結語

月起始日引發的時間週期的變化,緣由在於月起始日發生了變動。所謂解鈴還須繫鈴人,與其封裝形式和邏輯各樣,作各類邊界計算的處理,甚至弄很差還會出現各類莫名的bug。還不如將思路更多集中在月起始日自己,尋求更加通用的計算方式。

end~

相關文章
相關標籤/搜索