• Java获取当前时区时间LocalDateTime与System.currentTimeMillis



    全球根据纬度不同,划分不同的时区。对于此时此刻,大家同处同一个时间点,但是,每个时区的时间表示是不同的。Java可以使用 System.currentTimeMillisLocalDateTime相关代码获取当前时区时间。
    注:之前文章有表达不清楚之处,看到评论后,重新修改了下

    System.currentTimeMillis

    • System.currentTimeMillis获取当前毫秒数,与时区无关。这个Java静态方法,同一时刻在不同时区的机器上执行,结果是一致的。
    • Javanew Date()方法,也是通过System.currentTimeMillis创建当前时间对象。使用new Date()时,已经默认取当前系统时区了,所以显示的当前时区正确数字的时间。
    • java.util.Date类的部分源码如下:
    	/**
         * Allocates a Date object and initializes it so that
         * it represents the time at which it was allocated, measured to the
         * nearest millisecond.
         *
         * @see     java.lang.System#currentTimeMillis()
         */
        public Date() {
            this(System.currentTimeMillis());
        }
    
        /**
         * Allocates a Date object and initializes it to
         * represent the specified number of milliseconds since the
         * standard base time known as "the epoch", namely January 1,
         * 1970, 00:00:00 GMT.
         *
         * @param   date   the milliseconds since January 1, 1970, 00:00:00 GMT.
         * @see     java.lang.System#currentTimeMillis()
         */
        public Date(long date) {
            fastTime = date;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 再看一下java.lang.System类的具体源码
    	/**
         * Returns the current time in milliseconds.  Note that
         * while the unit of time of the return value is a millisecond,
         * the granularity of the value depends on the underlying
         * operating system and may be larger.  For example, many
         * operating systems measure time in units of tens of
         * milliseconds.
         *
         * 

    See the description of the class Date for * a discussion of slight discrepancies that may arise between * "computer time" and coordinated universal time (UTC). * * @return the difference, measured in milliseconds, between * the current time and midnight, January 1, 1970 UTC. * @see java.util.Date */ public static native long currentTimeMillis();

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 可以看到currentTimeMillis取的是 between "computer time" and coordinated universal time (UTC),取的是机器时间(computer time)与那个时刻(midnight, January 1, 1970 UTC)的差值
    • 针对不同的时区(UTC+N),当前机器时间(computer time)是不同的,但是都是同一时刻(只是时间显示不同),而我们规定的那个时刻(midnight, January 1, 1970 UTC)是不变的,所以两个时刻的差值是不变的,即获取的系统毫秒数一致
    • 换个思路,System.currentTimeMillis获得的是自1970-01-01 00:00:00.000到当前时刻的类型为long的时间毫秒数。但是我们要想到,对于那个时刻(midnight, January 1, 1970 UTC)显示的时间也是不同的,例如东八区就是 1970-01-01 08:00:00.000。现在东八区与UTC差8小时,在1970年也是差8小时
    • 获取的毫秒数是系统当前时区的1970-01-01 00:00:00.000以来的毫秒数,如果使用的是linux系统默认时区(0),则对于我国的+8时区刚好差8小时毫秒数
    import java.time.LocalDateTime;
    import java.time.ZoneOffset;
    import java.util.TimeZone;
    
    public class TimeTest {
    
        /*
          System.currentTimeMillis() 获取的当前时间与 格林尼治标准时间1970年零点 相差的毫秒数
          东八区比UTC快8小时,东八区时间当做UTC时间去计算毫秒数,就会比实际多8 * 60 * 60 * 1000
          LocalDateTime.now()获取的是当前时区的时间,但它的结果值不带时区属性,把它按照UTC时区计算毫秒数,发现刚好相差8小时
         */
        public static void main(String[] args) {
            String os = System.getProperty("os.name");
            TimeZone zone = TimeZone.getDefault();
            System.out.println("zone = " + zone.getID() + ", os = " + os);
    
            long time1 = System.currentTimeMillis();
            LocalDateTime local = LocalDateTime.now();
            long time2 = local.toInstant(ZoneOffset.UTC).toEpochMilli();
            long time3 = time2 - 8 * 60 * 60 * 1000;
    
    
            System.out.println("local = " + local);
            System.out.println("time1 = " + time1);
            System.out.println("time2 = " + time2);
            System.out.println("time3 = " + time3);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    运行结果

    zone = Asia/Shanghai, os = Windows 10
    local = 2023-06-15T00:45:24.420
    time1 = 1686761124378
    time2 = 1686789924420
    time3 = 1686761124420
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 换了台Linux系统机器,也设置为东八区,可以看到获取的毫秒数(对应截图时间)也和Windows机器没差别
      在这里插入图片描述
    • 将此机器切换成UTC时区,执行Java程序,再切回东八区执行,可以明细看到毫秒数一致(对应截图里的时间)
      在这里插入图片描述

    LocalDateTime

    • LocalDateTime 本身不包含时区信息,它存储了年、月、日、小时、分钟、秒和纳秒等数字。
    • LocalDateTime 默认只是存储当前系统所在时区当前时刻的年月日时分秒的数字
    • LocalDateTime.now 可以在传递参数时指定时区
    • toInstant()可以指定时区生成毫秒数(这里指定国际时间 UTC 0,实际上就是 System.currentTimeMillis() + 时区偏移毫秒数)
    import java.time.Instant;
    import java.time.LocalDateTime;
    import java.time.ZoneOffset;
    import java.util.Calendar;
    import java.util.TimeZone;
    
    
    public class Test3 {
    
        public static void main(String[] args) {
    		
    		
            String os = System.getProperty("os.name");
            TimeZone zone = TimeZone.getDefault();
            System.out.println("zone = " + zone.getID() + ", os = " + os);
    		
    		long time1 = System.currentTimeMillis();
    		
    		// LocalDateTime itself does not contain time zone information, it stores numbers such as year, month, day, hour, minute, second, and nanosecond.
            LocalDateTime local = LocalDateTime.now();
    		System.out.println("local = " + local);
    		long time2 = local.toInstant(ZoneOffset.UTC).toEpochMilli();
    		
    		// LocalDateTime.now can specify the time zone when passing the parameter
    		LocalDateTime dtUtc = LocalDateTime.now(ZoneOffset.UTC);	
    		System.out.println("dtUtc = " + dtUtc);
            long time3 = dtUtc.toInstant(ZoneOffset.UTC).toEpochMilli();
    
    		Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
    		long time4 = calendar.getTime().getTime() ;//+ 8 * 60 * 60 * 1000;	
            
    		System.out.println("time1 = " + time1);
    		System.out.println("time2 = " + time2);
    		System.out.println("time3 = " + time3);
    		System.out.println("time4 = " + time3);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    运行结果

    zone = Asia/Shanghai, os = Windows 10
    local = 2022-09-04T16:25:27.030469500
    dtUtc = 2022-09-04T08:25:27.031493500
    time1 = 1662279926996
    time2 = 1662308727030
    time3 = 1662279927031
    time4 = 1662279927031
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    最终结果

    • 其实只要服务器设置的时区是正确的,无论LocalDateTime.now()还是System.currentTimeMillis()都是正确的,都没有问题
    • 如果时区不正确,例如写代码时没考虑时区写的平台与部署的平台时区不一致(仅考虑系统时区为UTCCST),就要考虑针对时区处理下8小时毫秒数差距
    • 在不确定代码部署的平台的时区的情况下,又在最终结果里需要北京时间毫秒数(例如平台给前端雷达等设备校时,需要东八区),该怎么办?
    • 可以使用LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli()获取当前时间点的时区时间(年月日时分秒)相对于0时区(UTC)的毫秒数。再获取系统时区,判断是否为Asia/Shanghai,若不是(即时区为linux默认UTC时区),则加8小时毫秒数(8 * 60 * 60 * 1000)获得的毫秒数就是对的了
       // LocalDateTime 本身不包含时区信息(只是当前系统所在时区当前时刻的年月日时分秒)
       // toInstant可以指定时区生成毫秒数(这里指定国际时间 UTC 0,实际上就是 System.currentTimeMillis() + 时区偏移毫秒数)
       long time = LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli();
    
       TimeZone zone = TimeZone.getDefault();
       // 东八区为北京/上海时间,国内一般使用 UTC +8(但是linux服务器、docker初始都是 UTC 0,差8小时)
       if (!"Asia/Shanghai".equals(zone.getID())) {
           time += 8 * 60 * 60 * 1000;
       }
       System.out.println("当前zone为:" + zone + ", 当前时间为:" + time);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    基于Nginx和Consul构建自动发现的Docker服务架构——非常之详细
    前端面试宝典 - Javascript 基础知识
    物流服务与管理主要学什么
    入行3D建模难不难学习?10年建模师:这3种人,一辈子都学不会
    web网页设计期末课程大作业 HTML+CSS+JavaScript重庆火锅(代码质量好)
    springMVC拦截器
    算法练习- LeetCode 剑指 Offer 39. 数组中出现次数超过一半的数字
    模具制造厂ERP都有哪些牌子?模具制造厂ERP有什么用
    HCIA-Access V2.5 华为认证接入网络工程师学习笔记第三章
    2652. 倍数求和
  • 原文地址:https://blog.csdn.net/u010882234/article/details/126690484