一文读透时区和时间戳以及基于Java的操作

重要概念

1. UTC 和 UTC+8

UTC 是世界标准时间, UTC+8 是东八区标准时间,中国就属于东八区, 也就是北京时间。
+8 就是加8个小时。 时区的划分图示如下:

也就是说:
假如现在是UTC时间是 2023-08-08 01:00:00 (2023年8月8号凌晨1点),那么北京时间现在就是 2023-08-08 09:00:00 (上午9点)。

2. 时间戳

时间戳是一个数字,以UTC 的1970年1月1日作为开始时间, 也就是0开始, 后面的时间减去这个时间得到的秒数。
比如 UTC的 1970-01-01 00:00:00 的时间戳是 0 。 一分钟后 1970-01-01 00:01:00 的时间戳是 60。

为什么以这个时间作为开始呢?
因为这是 UNIX操作系统的约定, 约定 1970年1月1日作为时间纪元的开始, 后面很多计算机相关的语言,系统等都遵循了这个约定。

获取某个时间的时间戳

	@Test
	public void Timestamp(){
		LocalDateTime dateTime = LocalDateTime.of(1970, 1, 1, 0, 0, 0);// 获取时间戳(秒数)
		long timestamp = dateTime.toEpochSecond(ZoneOffset.UTC);//设置时区后获取时间戳
		System.out.println("Timestamp: " + timestamp); //0, 时间戳开始
	}
  • LocalDateTime 是一个不带时区信息的时间
  • ZoneOffset.UTC 则代表UTC 的时区

Java还提供了一个简便的方式获取当前时间的时间戳。

System.currentTimeMillis()

获取某个时区的时间

ZonedDateTime 是一个需要指定时区的时间, 比如北京时间的1970年1月1日的上午8点,可以如下表示:

ZonedDateTime utc8DateTime= ZonedDateTime.of(1970, 1, 1, 8, 0, 0,0, ZoneId.of("UTC+8"));

因为东八区的时间比UTC标准时间快8个小时,所以上面的时间也就是时间戳的开始时间。

	@Test
	public void zoneTimeStamp(){
		ZonedDateTime utc8DateTime= ZonedDateTime.of(1970, 1, 1, 8, 0, 0,0, ZoneId.of("UTC+8"));
		long timestamp =utc8DateTime.toEpochSecond();
		System.out.println("Timestamp1: " + timestamp);  //0
	}

当然,时区时间也可以从 LocalDateTime 转换而来,比如:

		LocalDateTime lcoalDateTime = LocalDateTime.of(1970, 1, 1, 8, 0, 0);
		ZonedDateTime zonedDateTime = ZonedDateTime.of(lcoalDateTime, ZoneId.of("UTC+8"));
		timestamp =zonedDateTime.toEpochSecond();
		Assert.assertEquals(0, timestamp);

时间的格式化显示

使用 DateTimeFormatter 可以将时间显示为不同格式的字符串, 示例代码如下:

	
	@Test
	public void dateTimeformatter() {
		LocalDateTime lcoalDateTime = LocalDateTime.of(1970, 1, 1, 8, 0, 0);
		ZonedDateTime zonedDateTime = ZonedDateTime.of(lcoalDateTime, ZoneId.of("UTC+8"));
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); 
		String lcoalDateTimeStr = formatter.format(lcoalDateTime);
		Assert.assertEquals("1970-01-01 08:00:00", lcoalDateTimeStr);
		
		String zonedDateTimeStr =  formatter.format(zonedDateTime);
		Assert.assertEquals("1970-01-01 08:00:00", zonedDateTimeStr);
	}

获取当前的北京时间

通过 ZonedDateTime.now() 可以获取当前的时间:

	@Test
	public void getCurrentUtc8Time() {
        // 获取UTC+8时区
        ZoneId utc8ZoneId = ZoneId.of("UTC+8");
        // 获取当前时间
        ZonedDateTime now = ZonedDateTime.now(utc8ZoneId);
        // 格式化为字符串
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");     
        String currentTime = now.format(formatter);
        // 输出时间
        System.out.println("Current time in UTC+8: " + currentTime);
	}

如果要获取的是 UTC标准时间,则需要修改上面获取的时区即可:

ZoneId.of("UTC");

时间戳转换为时间

通过Instant 可以将一个时间戳转换为时间。

	@Test
	public void timeMillisToUtc() {
		long timeMillis = 0L;
		Instant instant = Instant.ofEpochMilli(timeMillis);
		LocalDateTime utcDateTime = LocalDateTime.ofInstant(instant, ZoneId.of("UTC"));
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		String utcTime = utcDateTime.format(formatter);
		Assert.assertEquals("1970-01-01 00:00:00", utcTime);
	}

注意: 时间戳和时间无关

在实际的开发中, 遇到这样一种场景: 某些应用的授权 Token的有效截止时间是时间戳的格式,也就是一个长整型的数字, 有人会问: “这个是已经+8处理的时间吗?”,显然,这句话问的就很外行了。

一个时间戳对应的就是一个时间,也就是基于 UTC的开始时间的一个时间, 这个时间戳可以转换为不同时区的时间,但是时间戳本身并没有时区的差异。也就是说, 时间戳是0 , 对应的就是UTC时间的1970年1月1日的零点, 也就是1970年1月1日的上午8点。

总结

  • LocalDateTime 是一个和时区无关的时间处理类
  • ZonedDateTime 是一个和时区有关的时间处理类
  • 时间戳的开始时间是1970年1月1日的零点,也就是北京时间的上午8点。
  • 时间戳和时区无关

在线示例



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

oscar999

送以玫瑰,手留余香

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

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

打赏作者

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

抵扣说明:

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

余额充值