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


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

System.currentTimeMillis

  • System.currentTimeMillis获取当前毫秒数,与时区无关。这个Java静态方法,同一时刻在不同时区的机器上执行,结果是一致的。
  • Javanew Date()方法,也是通过System.currentTimeMillis创建当前时间对象。使用new Date()时,已经默认取当前系统时区了,所以显示的当前时区正确数字的时间。
  • java.util.Date类的部分源码如下:
	/**
     * Allocates a <code>Date</code> 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 <code>Date</code> 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;
    }
  • 再看一下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.
     *
     * <p> See the description of the class <code>Date</code> 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();
  • 可以看到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);
    }
}

运行结果

zone = Asia/Shanghai, os = Windows 10
local = 2023-06-15T00:45:24.420
time1 = 1686761124378
time2 = 1686789924420
time3 = 1686761124420
  • 换了台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);
    }
}

运行结果

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

最终结果

  • 其实只要服务器设置的时区是正确的,无论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);
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坚持是一种态度

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值