最近改項目中的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
不管月起始日設置成哪一天,在作月起始日相關的任何邏輯計算時,其實均可以採起一種通用的實現思路,即時間誤差的修正與迴歸。例如,無論當前時間戳是多少,要計算本季度的起始時間,直接將時間戳先修正,而後計算出對應的天然時間概念下的季起始時間,最後再回補上對應的時間誤差便可。class
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產生,理解了這種思路後,不管求月起始日對應的什麼時間週期,代碼實現也都很簡單。方法
月起始日引發的時間週期的變化,緣由在於月起始日發生了變動。所謂解鈴還須繫鈴人,與其封裝形式和邏輯各樣,作各類邊界計算的處理,甚至弄很差還會出現各類莫名的bug。還不如將思路更多集中在月起始日自己,尋求更加通用的計算方式。
end~