一个简单、通用、高效的计算某天起始时间的算法

我们在做业务的时候,按天查询数据的时候可能要计算某天的起始时间和结束时间。

通常情况下,我们都是先获取这一天的年月日,然后时分秒用0填充构造一个新的时间对象,返回时间戳。

如下面的一个Java的示例:

import java.util.Calendar;

public class Test {
    Long getDailyStartTime(Long timeStamp) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(timeStamp);
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            return calendar.getTimeInMillis();
  }
}

不同的编程语言有不同的语法,但是基本思路是一致的。

但是仔细一想,发现这种方法太麻烦。

我们计算某天的开始时间戳,本质就是抹零

所以我们可以这样思考,我们只需要计算某时间到零点时间戳的天数,再乘以每天的秒数即可。

这里的零点时间戳,即为1970年1月1日0点0分0秒。

那么这个公式可以表示为

floor((某时间戳-零点时间戳)/一天包含的秒数) * 一天包含的秒数

但这里需要注意的是,Unix 时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。

所以上述方法算出的是UTC+0的0点时间戳,实际上我们是东八区(UTC+8),是有时差的,所以我们还得考虑时区因素。

我们location的1970年1月1日0点的实际时间戳是 0-8*3600

所以,我们最终的计算方式用C语言表示为:

int getDailyStartTime(int ts)
{
    return  ((ts + 8*3600)/(24*3600))*24*3600-8*3600;
}

用此思路,也可以计算某小时的起始时间戳,而且因为不涉及时区,更简单。

int getHourStartTime(int ts)
{
    return  (ts/3600)*3600;
}

注意了,此方法只能计算天,小时,分钟等单位固定的起始时间戳,不能计算年和月, 因为不同的年份和月份所包含的秒数是不同的。