Java使用长纪元时间戳来检测日变化的最有效方法

Posted

技术标签:

【中文标题】Java使用长纪元时间戳来检测日变化的最有效方法【英文标题】:Java most efficient way using a long epoch timestamp to detect a change in day 【发布时间】:2021-04-30 12:04:33 【问题描述】:

问题情况:我有大量记录都标有时间戳。我正在遍历所有这些以执行此操作,但我需要检测一天何时发生变化。

现在对于我正在执行的每个循环:

cal.setTimeInMillis(record.time);
int currentDay = cal.get(Calendar.DAY_OF_WEEK); 

当它运行数十万次时,它是否像我想象的那样慢? 我想我错过了一个非常简单的模数答案或其他东西。

编辑:时区无关紧要,我收集的信息更多地解决了某人的消耗性报告。 24 小时每份报告更准确,因此实际上我不必担心是凌晨 5 点至凌晨 5 点还是下午 3 点至下午 3 点,只要我能够收集 24 小时的信息即可。

谢谢大家

【问题讨论】:

嗯,你希望它表现得如何,如何处理闰年、闰秒等。日期库会处理所有这些,但它肯定需要几纳秒- 你是否真的以有意义的方式衡量了性能,它真的很慢吗? 将一天的结束转换为时间戳并与record.time进行比较可能更有效 ideone.com/23p0Y6 1M 次迭代耗时 0.76 秒。好像不慢我会更关心它的正确性(例如,您是否在正确的时区计算日期)。 添加了一个编辑,我真的不用担心时区,我只想分成 24 小时的块。 您的 24 小时数据块有哪些限制?您的意思是从当前时刻开始,然后以 24 小时为增量前进/后退吗?你需要更清楚地考虑这一点。说“当一天改变了”同时又说“分成 24 小时的时间段”是矛盾的。投票结束,因为不清楚。 【参考方案1】:

经过 Andy Turner 的时间测试,我不一定相信您需要任何优化的解决方案。无论如何,timsmelik 的建议非常简单:将日期变化的时间转换为自纪元以来的毫秒数,因此您只需要比较 long 值。我没有发现它对可读性的伤害非常严重。所以这里是代码。我正在使用并热烈推荐 java.time,现代 Java 日期和时间 API,如果只是用于从小时到毫秒的转换以及打印结果。即使这样的转换看起来微不足道,最好还是让标准库来做。它更不言自明,更不容易出错,读者更容易说服自己它是正确的。

    final long twentyfourHoursAsMillis = Duration.ofHours(24).toMillis();
    
    // Times are already sorted descending (from newest to oldest)
    long[] times =  1_611_718_370_000L, 1_611_632_000_000L,
                     1_611_631_970_000L, 1_611_459_150_000L ;
    List<List<Long>> chunks = new ArrayList<>();
    List<Long> currentChunk  = new ArrayList<>();
    
    // Process first time separately to get started
    currentChunk.add(times[0]);
    long timeOfNextChunk = times[0] - twentyfourHoursAsMillis;
    // Process remaining times
    for (int i = 1; i < times.length; i++) 
        long currentTime = times[i];
        if (currentTime <= timeOfNextChunk) 
            chunks.add(currentChunk);
            currentChunk = new ArrayList<>();
            do 
                timeOfNextChunk -= twentyfourHoursAsMillis;
             while (currentTime <= timeOfNextChunk);
        
        
        currentChunk.add(currentTime);
    
    // Save last chunk, why not?
    chunks.add(currentChunk);
    
    // Print result
    for (List<Long> chunk : chunks) 
        String chunkAsString = chunk.stream()
                .map(Instant::ofEpochMilli)
                .map(Instant::toString)
                .collect(Collectors.joining(", "));
        System.out.println(chunkAsString);
    

输出是:

2021-01-27T03:32:50Z, 2021-01-26T03:33:20Z
2021-01-26T03:32:50Z
2021-01-24T03:32:30Z

我正在打印Instant 对象。他们总是以 UTC 打印。对于您的情况,如果您需要打印时间,您可能需要做其他事情。

您应该检查您的假设,即时间是按排序顺序排列的。

我相信你的话,并在 24 小时内将其分成几块。 24 小时甚至可能不意味着凌晨 5 点 - 凌晨 5 点,但可能意味着例如从 3 月 13 日美国东部标准时间上午 5 点到 3 月 14 日美国东部时间 6 点,因为与此同时夏季时间 (DST) 已经开始。如果您希望在同一时钟时间进行拆分,可以修改代码以执行此操作。

【讨论】:

以上是关于Java使用长纪元时间戳来检测日变化的最有效方法的主要内容,如果未能解决你的问题,请参考以下文章

在Java中检测偶数的最有效方法是什么? [重复]

处理时钟变化时保存的纪元时间

Java将日期转换为纪元值会产生错误的输出

如何将(round)纪元时间转换为最接近的小时和日期wrt IST(在Java中)

如何检测 Amazon S3 中的变化? [复制]

检测段和连接器集合中所有闭合路径的最有效方法是啥?