《跨境i18》 国际化时间转换解决方案~

前言

对于只负责国内业务 的公司来说,我们在业务中想要获取当前时间 ,往往只需要利用Java自带的工具类new Date()、LocalDateTime.now() 方式来获取,但对于一些跨境业务 的公司来说,因为涉及到时区问题,往往需要将当前北京时间转换成其国外的当地时间

国际化时间转换,这就是本文想带大家了解的内容~


基本概念

在进行实际案例操作之前,我们需要先了解一下基本概念~


UTC

UTC(Coodinated Universal Time),协调世界时,又称世界统一时间、世界标准时间、国际协调时间。由于英文(CUT)和法文(TUC)的缩写不同,作为妥协,简称UTC。

UTC 是现在全球通用的时间标准,全球各地都同意将各自的时间进行同步协调。UTC 时间是经过平均太阳时(以格林威治时间GMT为准)、地轴运动修正后的新时标以及以秒为单位的国际原子时所综合精算而成。

上面两句话是我从网上找的,从整句话上来理解UTC感觉还是比较迷茫的,特别是还扯到地理上了,hh

但真正其核心点在于我加粗的文字: 世界标准时间、全球通用的时间标准

UTC就好比0这个数字,就是个标准,大于0为正数,小于0位负数

时区也是如此,比如北京时区就是UTC+8

又或者洛杉矶时区现在是 UTC-8

那么洛杉矶现在 跟北京的时间差就是8 - (-8)就是16个小时了,这么理解起来我感觉还是比较容易的~

需要注意的是,我说的是现在为什么用这个词呢 ,因为接下来就引出了下一个概念: 冬令时、夏令时


冬令时、夏令时

冬令时和夏令时是用于节省日光和能源的时间制度,它们通过在一年中的不同时间调整标准时间来实现。

  1. 夏令时
    • 在夏令时期间,美西时间(Pacific Daylight Time, PDT)比协调世界时(UTC)慢7小时(UTC-7)。
    • 夏令时 通常从每年的三月第二个星期日开始,直到十一月第一个星期日结束。
  2. 冬令时
    • 在冬令时期间,美西时间(Pacific Standard Time, PST)比协调世界时慢8小时(UTC-8)。
    • 冬令时每年的十一月第一个星期日开始,持续到次年的三月第二个星期日

美西时间

所以我说洛杉矶时区现在是 UTC-8,因为随着时间变化,时区也会变成UTC-7


案例

基本概念大致了解后,我们需要通过案例来真正知道到底需要通过怎样的编码来实现国际化时间转换


拿到不同时区的当前时间

首先来一行LocalDateTime.now()拿到当前时间: 2023-11-16T22:26:36.863636

java 复制代码
public static void main(String[] args) {
   LocalDateTime now = LocalDateTime.now();
   System.out.println(now);
}

跟一下源码可见,默认拿的系统时间,即上海时区 ,没啥问题,因为我是中国人(手动狗头)

此外我们还能拿到一个结论,那就是**LocalDateTime.now()本身没有时区概念,最终是需要根据时区来拿到当前时间的**,也没啥问题,都不给时区,人家怎么知道你当前是什么时间,hh

既然如此,我想肯定可以手动传入时区,然后拿到目前时区的当前时间

诺,不出所料,API还是很全面的,支持传入Clock 和 ZoneId

那么我们现在想如果拿到洛杉矶的当前时间,那么传入当前洛杉矶的时区-8即可

java 复制代码
	public static void main(String[] args) {
		System.out.println(LocalDateTime.now(ZoneId.of("-8")));
		System.out.println(LocalDateTime.now(Clock.system(ZoneId.of("-8"))));
	}


拿到不同时区的当前时间的时间戳

Java中,我们如果想拿到当前时间的时间戳,最常见的代码就是System.currentTimeMillis()

java 复制代码
public static void main(String[] args) {
   System.out.println(System.currentTimeMillis());
}

那么除了这种方式,大家还知道别的方式吗?比如LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli()

我们都知道时间戳是没有时区概念的 ,在这一前提下,相信LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli()这段代码就很好理解啦

  1. 通过LocalDateTime.now()拿到当前时间,即默认使用系统时区即上海时区+8
  2. 然后toInstant(ZoneOffset.of("+8")),传入+8因为拿到的当前时间存在+8时区概念,所以我们需要传入+8来抵消时区
  3. 最后toEpochMilli,拿到不存在时区概念的时间戳

不同时区时间互转

在之前我们都是使用的LocalDateTime传入目标时区 ,来获取目标时区的当地时间、时间戳~

而接下来如果想要进行不同时区互相转换,我们则需要ZonedDateTime

可以简单地把ZonedDateTime理解成LocalDateTimeZoneId,即带时区的LocalDateTime

那么我们把当前北京时间转换成对应洛杉矶的时区,编码如下:

java 复制代码
public static void main(String[] args) {
   ZonedDateTime zonedDateTime = LocalDateTime.now().atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneId.of("-8"));
   System.out.println(zonedDateTime.toLocalDateTime());
}

解读一下

  1. LocalDateTime.now()还是拿到当前系统时区,即上海时区的当前时间
  2. atZone(ZoneId.systemDefault()),这里也可以理解为atZone(ZoneId.of("+8")), 表明我们LocalDateTime.now()拿到的是时间时区是+8
  3. .withZoneSameInstant(ZoneId.of("-8"), 表明转换成-8时区
  4. 最后toLocalDateTime,拿到转换后的时间

根据时间戳转换成各个时区的时间

时间戳没有时间概念,所以首先想到看看Instant有没有相关api,如图可见,支持通过毫秒级、秒级时间戳进行转换

我们用毫秒级时间戳转换为例,转换成Instant后,通过atZone表明时区

我们表明为+8时区,因为我们通过System.currentTimeMillis()拿到的也是当前系统的时间戳,最后toLocalDateTime,并与LocalDateTime.now()比较一下,可以看到是基本一致的

再来个案例,我们表明当前拿到时间的时间戳是-8时区的,那么在转换后,我们可见其时间与LocalDateTime.now()相差16个小时,符合预期~


总结

本文从概念到案例由浅入深的带大家了解了在国际化时间转换的一些业务常见的解决方案,如有不足,请大家补充~

我是 Code皮皮虾 ,会在以后的日子里跟大家一起学习,一起进步! 觉得文章不错的话,可以在 掘金 关注我,这样就不会错过很多技术干货啦~

相关推荐
ok!ko2 小时前
设计模式之原型模式(通俗易懂--代码辅助理解【Java版】)
java·设计模式·原型模式
2401_857622662 小时前
SpringBoot框架下校园资料库的构建与优化
spring boot·后端·php
2402_857589362 小时前
“衣依”服装销售平台:Spring Boot框架的设计与实现
java·spring boot·后端
吾爱星辰3 小时前
Kotlin 处理字符串和正则表达式(二十一)
java·开发语言·jvm·正则表达式·kotlin
哎呦没3 小时前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
_.Switch4 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
编程、小哥哥4 小时前
netty之Netty与SpringBoot整合
java·spring boot·spring
IT学长编程5 小时前
计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·玩具租赁系统
莹雨潇潇5 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
杨哥带你写代码5 小时前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端