• 使用时间戳配合LocalDate.ofEpochDay(days)方法获取的日期不准确的问题!


     最近在使用java.time.LocalDate时踩了坑, 归根到底是对jdk中的时间操作不够清晰

    踩坑场景

    以下这一段代码, 你认为能正常返回结果吗? 如果不能, 那么问题在哪里?
    /**
     * 基于当前时间, 进行一定的偏移, 返回偏移后的日期
     * @param offsetMillis 便宜量 (毫秒)
     * @return 日期
     */
    public static LocalDate nowLocalDate(long offsetMillis) {
        long time = System.currentTimeMillis();
        time += offsetMillis;
        long days = time / TimeUnit.DAYS.toMillis(1);
        return LocalDate.ofEpochDay(days);
    }
     

    问题描述

    这一段代码, 假设参数offsetMillis为0的情况下, 在00:00~08:00这段时间返回的结果都是错误的, 是前一日的日期
     

    原理剖析

    System.currentTimeMillis() 获取到的时间戳是在UTC时区下当前时间与1970年1月1日0点的毫秒差, 北京时间所处的时区为CST东八区相比UTC时区早8小时 (北京时间 2022年1月27日凌晨1点时, UTC时区下为2022年1月26日下午17点, 所以获取到当前时间戳后, 必须要先+8h转换为东八区的时间戳, 再进行天数计算
     
    事实上, 时间戳是没有时区概念的, 它指的就是从历史上的某一时刻至今所经历的时光, 这是全球统一的, 你在美国经历了2小时, 他在中国也是经历了2小时, 不会因为所处时区不同而不同
    历史上的某一时刻是: 1970-01-01 00:00:00 (UTC)
    由于历史时刻是以UTC时区为参照的, 所以加上时间戳以后得到的当前时间也必然是UTC时区的时间
     
     
    既然时间戳是基于UTC时区的, 那么为什么我们在东八区开发过程中经常使用它, 却没有产生问题?
    我们在代码中使用 System.currentTimeMillis()有几大场景
    1. 统计耗时: 比如在一段逻辑前后获取时间戳, 并将两者差作为耗时
    2. 记录时刻: 很多时候我们不需要结构化的时间, 仅仅需要记录一个时刻, 用作后续的时刻对比或结构化
    3. 构造Date: 有时我们不得不通过一个给定的时间戳, 将它结构化为Date对象以便后续操作
     
    细品上面这些场景, 确实大部分场景是跟时区无关的, 所以并不会有任何影响, 而第三个场景中, 构造java.util.Date 对象时, Date的构造函数所定义的时间戳参数是基于GMT时区
    而GMT是格林尼治的标准时间, 巧了, 格林尼治正好处在零时区, 所以GMT = UTC+0h
    也不知道是巧合, 还是有意为之, 哈哈
     

    总结

    写了这么久的System.currentTimeMillis(), 一直以为它返回的时间戳是基于当前系统时区(CTS), 没想到它是基于UTC的, 一度陷入沉思, 有被自己菜到, 哈哈...
    需要重新系统性的学习一下Java的时间模块了!
     
     
     
     
  • 相关阅读:
    webpack 模块化 原理
    nodejs 程序 调试
    inno打包教程
    原生xhr、fetch 请求的拦截。mock 技术原理
    package.json 字段说明
    npm 依赖包 的管理【即 node_modules目录的设计原理】
    现在浏览器、webview 中 css的兼容性问题。
    安卓APP(H5本地打包apk应用)
    npm 脚本
    linux系统 离线安装node和nginx(即npm包)
  • 原文地址:https://www.cnblogs.com/imyjy/p/15850728.html
Copyright © 2020-2023  润新知