時間戳窗口轉換

問題起因

最近在做一個基于時間的統(tǒng)計功能,大體需求是統(tǒng)計按照 1min品山、10min胆建、2h、24h 為窗口大小進行數據統(tǒng)計肘交。原始數據的時間字段是 ms 時間戳笆载,思路很簡單就是直接用時間戳減去窗口大小余數,這種方式對 1min涯呻、10min、2h 的處理都沒有問題复罐,但是對 24h 的窗口處理就會有問題,可以見下面的測試市栗。

/**
 * 獲取指定時間時間戳歸屬的時間窗口咳短,盡量刻度到當天
 *
 * @param timestamp 時間戳
 * @param scale     刻度,ms
 * @return {@link long}
 */
public static long getTimestampWindow(long timestamp, long scale) {
    long remain = timestamp % scale;
    return timestamp - remain ;
}

上面就是使用的時間戳窗口計算算法蛛淋。

 public static void main(String[] args) throws ParseException {
     long scale = TimeUnit.HOURS.toMillis(24);
     for (int i = 0; i < 24; i++) {
         Date date = DateUtils.addHours(DateUtils.parseDate("2022-06-24", DateUtil.DATE_PATTERN), i);
         Date scaledDate = new Date(getTimestampWindow(date.getTime(), scale));
         System.out.printf("當前時間:%s,窗口時間:%s%n",
                           DateFormatUtils.format(date, DateUtil.LONG_DATE_PATTERN),
                           DateFormatUtils.format(scaledDate, DateUtil.LONG_DATE_PATTERN));
     }
 }

當使用上面的測試程序進行測試的時候發(fā)現(xiàn)咙好,窗口并未預期的顯示是“2022-06-24 00:00:00”褐荷,而是輸出了“2022-06-23 08:00:00”及“2022-06-24 08:00:00”兩種窗口勾效,一天的數據出現(xiàn)了歸屬跨天問題叛甫。

當然如果使用 Java 里面的日期函數可以很簡單的解決這個問題层宫,但是我們返回時間數據是時間戳,直接做算術運算肯定是效率最高的其监。

當前時間:2022-06-24 00:00:00,窗口時間:2022-06-23 08:00:00
當前時間:2022-06-24 01:00:00,窗口時間:2022-06-23 08:00:00
當前時間:2022-06-24 02:00:00,窗口時間:2022-06-23 08:00:00
當前時間:2022-06-24 03:00:00,窗口時間:2022-06-23 08:00:00
當前時間:2022-06-24 04:00:00,窗口時間:2022-06-23 08:00:00
當前時間:2022-06-24 05:00:00,窗口時間:2022-06-23 08:00:00
當前時間:2022-06-24 06:00:00,窗口時間:2022-06-23 08:00:00
當前時間:2022-06-24 07:00:00,窗口時間:2022-06-23 08:00:00
當前時間:2022-06-24 08:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 09:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 10:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 11:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 12:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 13:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 14:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 15:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 16:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 17:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 18:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 19:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 20:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 21:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 22:00:00,窗口時間:2022-06-24 08:00:00
當前時間:2022-06-24 23:00:00,窗口時間:2022-06-24 08:00:00

問題分析

這是為什么呢萌腿?核心原因是因為我們處在的時區(qū)是東 8 區(qū)抖苦,在比格林尼治時間早 8 小時,時間戳 0 在零時區(qū)(UTC/GMT 0 )表示的是“1970-01-01 00:00:00”锌历,而在東 8 區(qū)(UTC/GMT +8.00)則表示的是“1970-01-01 08:00:00”。

public static void main(String[] args) {
    System.out.println(TimeZone.getDefault());
    System.out.println(DateFormatUtils.format(new Date(0), DateUtil.LONG_DATE_PATTERN));
    System.out.println(TimeZone.getTimeZone("UTC"));
    System.out.println(DateFormatUtils.format(new Date(0), DateUtil.LONG_DATE_PATTERN, TimeZone.getTimeZone("UTC")));
}

sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null]
1970-01-01 08:00:00
sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
1970-01-01 00:00:00

我們這里只討論能被 24 小時整除的窗口窗慎,也就是 2h卤材、12h 這樣的捉邢,而不討論 5h商膊,7h 這樣的窗口,因為對后面的窗口藐翎,勢必存在跨天問題。也就是說如果用取余的方式來計算時間窗口的話吝镣,當時間能被 24 整除但是如果大于 8 小時(12h昆庇、24h)或者不能被 8 整除(3h、6h)時候就會出現(xiàn)歸屬窗口跨天問題整吆。

窗口為 6h
窗口為 12h
窗口為 24h

如上圖所示,其中帶 - 號的代表上一天的時間拴测,大家可以想下是不是這樣?這個有點繞屿愚,一定要記得起始時間戳 0 代表的時間是 8 點。

如果能理解這個务荆,其實就會發(fā)現(xiàn)對一個 24h 的窗口來說妆距,今天 1 點的數據歸屬到昨天的 8 小時這個窗口是正常的函匕,但是這個的確看起來很怪。如果時間窗口是 24h浦箱,對我們的思維來說祠锣,今天所有產生的數據就應該是歸屬到今天。

問題解決

既然知道了問題的原因伴网,也知道了需求方式,也就比較容易解決這個問題沸伏。思想其實很簡單动分,就是先把時間戳向后拉 8 小時毅糟,讓“時間戳 0 代表的時間是 0 點”澜公。在算完窗口之后,再將時間窗口向前拉 8 小時迹辐,獲得真實的歸屬窗口。

    /**
     * 獲取指定時間時間戳歸屬的時間窗口明吩,盡量刻度到當天
     *
     * @param timestamp 時間戳
     * @param scale     刻度殷费,ms
     * @return {@link long}
     */
    public static long getTimestampWindow(long timestamp, long scale) {
        timestamp = timestamp + TIMESTAMP_8H;
        long remain = timestamp % scale;
        return timestamp - remain - TIMESTAMP_8H;
    }

算法變成如上所示低葫,再運行測試程序躏鱼,就會發(fā)現(xiàn)時間窗口歸屬符合我們的期望了氮采。

當前時間:2022-06-24 00:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 01:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 02:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 03:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 04:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 05:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 06:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 07:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 08:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 09:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 10:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 11:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 12:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 13:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 14:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 15:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 16:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 17:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 18:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 19:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 20:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 21:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 22:00:00,窗口時間:2022-06-24 00:00:00
當前時間:2022-06-24 23:00:00,窗口時間:2022-06-24 00:00:00
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末鹊漠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子躯概,更是在濱河造成了極大的恐慌畔师,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件看锉,死亡現(xiàn)場離奇詭異,居然都是意外死亡呻此,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門焚鲜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來放前,“玉大人,你說我怎么就攤上這事凭语。” “怎么了吨些?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵虫几,是天一觀的道長。 經常有香客問我辆脸,道長,這世上最難降的妖魔是什么啡氢? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮亭枷,結果婚禮上,老公的妹妹穿的比我還像新娘叨粘。我一直安慰自己,他們只是感情好升敲,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布驴党。 她就那樣靜靜地躺著,像睡著了一般港庄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鹏氧,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天,我揣著相機與錄音歼捏,去河邊找鬼笨篷。 笑死,一個胖子當著我的面吹牛率翅,可吹牛的內容都是我干的袖迎。 我是一名探鬼主播冕臭,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼辜贵,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了托慨?” 一聲冷哼從身側響起暇榴,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蕉世,失蹤者是張志新(化名)和其女友劉穎婆硬,沒想到半個月后狠轻,有當地人在樹林里發(fā)現(xiàn)了一具尸體彬犯,經...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年蜜自,在試婚紗的時候發(fā)現(xiàn)自己被綠了卢佣。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡戈鲁,死狀恐怖,靈堂內的尸體忽然破棺而出婆殿,到底是詐尸還是另有隱情,我是刑警寧澤婆芦,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布喂饥,位于F島的核電站,受9級特大地震影響员帮,放射性物質發(fā)生泄漏。R本人自食惡果不足惜捞高,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望氢哮。 院中可真熱鬧型檀,春花似錦冗尤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悬蔽。三九已至捉兴,卻和暖如春蝎困,著一層夾襖步出監(jiān)牢的瞬間倍啥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工始藕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人伍派。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓剩胁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親昵观。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355