基于时间误差思路下的时间周期度量

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~

相关文章
相关标签/搜索