《跨境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理解成LocalDateTime加ZoneId,即带时区的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皮皮虾 ,会在以后的日子里跟大家一起学习,一起进步! 觉得文章不错的话,可以在 掘金 关注我,这样就不会错过很多技术干货啦~

相关推荐
wuminyu8 分钟前
JVM规范学习总结:解释器与JIT编译器如何处理JVM字节码
java·linux·c语言·jvm·c++
txxzjmzlh18 分钟前
SpringBoot 配置⽂件
java·spring boot·spring
ZhengEnCi38 分钟前
模型训练完整流程:从数据准备到模型上线的 10 个关键步骤(全文可跑)
后端·算法
王中阳Go41 分钟前
后端转 Agent 岗面试怎么答:8 个高频问题与应答口径
人工智能·后端·python·大语言模型
Wang's Blog1 小时前
Java 项目实战: 交友项目 - 搜索附近的功能概述和分析
java·开发语言·交友
程序猿DD1 小时前
OctaFuse Gateway 2.18.0:MCP 接入支持 OAuth,供应商粘性绑定可视化管理
后端
骑着蜗牛撵大象3271 小时前
大模型 Agent 的沙箱护栏:gVisor 隔离、出口白名单与审计闭环
java·开发语言·jvm·安全·agent沙箱·gvisor·microvm
独泪了无痕1 小时前
Hutool之LocalDateTimeUtil:让时间间隔操作如虎添翼
java
三无少女指南2 小时前
从这里开始:Java 后端与 AI 工程的三条阅读路线
java·学习路线·ai工程
ZhengEnCi3 小时前
Agent 规则管理:让 Memory 做索引、让 Skill 存规则——上下文上限实测与分工方案
后端