zoukankan      html  css  js  c++  java
  • 基于时间偏差思路下的时间周期度量

    一、背景

    最近改项目中的bug,遇到一类问题:当月起始日可以设置的情况下(1日到28日),需要计算出对应的月、季度、年等相关的时间范围,以及对应的如上月、上季、去年等,和给定时间戳的所属年、季度、月份等各种时间求取。

    为简单起见,举个栗子: 如如果月起始日设置成了5,那么本月的时间范围是:

    2019.10.05 00:00:00 - 2019.11.04 23:59:59
    复制代码

    本季度的时间范围是:

    2019.10.05 00:00:00 - 2020.01.04 23:59:59
    复制代码

    项目中大量的地方需要用到此类计算。因此,相应的时间获取被封装成了工具类。这本身并没有什么问题,但问题在于封装的工具类中每个时间周期的获取写法多种多样,例如获取上月起始时间,下个季度起始时间等等方法思路各不相同,加上不同的人都有去实现自己需要的方法,因此,整个工具类看下来,一是不好理解,二是各种潜藏的bug。

    见得最多的,是判断各种边界情况,然后对应各种处理逻辑。。

    有没有简单些的方法呢?

    其实是有的。


    二、思路与实现

    2.1 思路

    无论月起始日设置成哪一天,在做月起始日相关的任何逻辑计算时,其实都可以采取一种通用的实现思路,即时间偏差的修正与回归。例如,不管当前时间戳是多少,要计算本季度的起始时间,直接将时间戳先修正,然后计算出对应的自然时间概念下的季起始时间,最后再回补上对应的时间偏差即可。

    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。还不如将思路更多集中在月起始日本身,寻求更加通用的计算方式。

    end~


    作者:HappyCorn
    链接:https://juejin.im/post/5db188586fb9a020531fab1d
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    关于网页代码加密解密保护,保障页面安全
    DS--知识积累
    知识积累
    Nested DollsHDU1677
    CF335B
    HDU2385Stock
    滚动数组处理数据很大的公共子序列问题
    HDU4635
    HDU4638
    HDU4639
  • 原文地址:https://www.cnblogs.com/lwbqqyumidi/p/11991810.html
Copyright © 2011-2022 走看看