【Java】时区时间转换 Instant 和 LocalDateTime类的使用

背景

在做国际化相关的时间场景时,经常会遇到时区转换带来的难题。比如说,时区时间的对齐,这种场景会遇到韩国用户要求一个定时任务在韩国时间早上执行,美国客户要求一个定时任务在UTC时间执行,处理稍微不善,就会出现和目标时间点相差8个小时的情况。再比如说,时间格式上的要求,这种情况多出现于接口对接,例如有些接口参数会以时间戳的形式,有些则会以字符串,"2022/11/13 14:47:14",这种情况一般会指定这个时间所对应的时区,毕竟每个时区都会存在一个14:47:14。

处理时间

将上面的问题归纳总结,其实可以归为两类问题,一类是时间怎么转换,另外一类是时间怎么做处理。 对于Java内的时间,我常用的类有两个 Instant类 和 Calendar类,Calendar类是java.util包下的类,而Instant类则在java.time包下,java.time是在Java1.8版本内新加入,专门处理时间的类。

时间转换

首先是将字符串转换为时间戳的方法,字符串可能会有不同的标准,你可以选择 DateTimeFormatter类 中自带的标准,可以直接用 DateTimeFormatter.ofPattern 方法进行自定义。

使用.atZone()方法可以指定时区,不同的时区会转换成不同的时间戳,代表不同的实际时间。

    public static void main(String[] argv) {
        String strDate = "2022/11/13 14:47:14";
        long time = LocalDateTime.parse(strDate, 
        		DateTimeFormatter.ofPattern("yyyy/MM/d HH:mm:ss"))
        		.atZone(ZoneId.of("UTC")).toInstant().toEpochMilli();
        System.out.println(time);
        // 1668350834000
        // 北京时间(东八区) 2022-11-13 22:47:14 
        // 可以简单理解为 太阳从东方升起 所以在时间上 东七区 会比 东八区晚一个小时
    }

LocalDateTime类,听上去是是根据服务器的Local时区做的一个转换,但一旦你点到这个类里面去,他的第一行注释就说明了他是一个和时区无关的类。

A date-time without a time-zone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30.

如果将时间戳转为字符串,则可以使用Instant.ofEpochMilli()方法,后再用.atZone()指定时区。

    public static void main(String[] argv) {
        String strDate = Instant.ofEpochMilli(1668350834000L)
        .atZone(ZoneId.of("UTC"))
        .format(DateTimeFormatter.ofPattern("yyyy/MM/d HH:mm:ss"));
        System.out.println(strDate);
        // UTC 时间的 2022/11/13 14:47:14
    }

时间处理

主要涉及到的时间处理会有年月日的加减法,比如说,一个月付会员这个月的18号付了钱,那么怎么计算才能计算到下一个月。如果硬要用秒级别的加减法去加上43200000毫秒也不是不行。但涉及到逻辑分支就太多了,比如说这个月是大月(加31天的毫秒)还是小月(加30天的毫秒),今年是平年(二月份加28天的毫秒)还是闰年(加29天的毫秒)。
    public static void main(String[] argv) {
        ZonedDateTime zone = Instant.ofEpochMilli(1643446640000L).atZone(ZoneId.of("UTC"));
        //2022-1-29 16:57:20
        zone = zone.plusMonths(1);
        System.out.println(zone.toLocalDateTime().atZone(ZoneId.of("UTC")));
        //2022-02-28T08:57:20Z[UTC]
    }

这边是一个极端的例子,2022年的1月29号往后一个月到底应该是2月28号,还是应该是3月1号。在我们的场景是一个令人费解的问题。一个月到底是30天还是31天,甚至是29天,28天,都不是一个可以简单区分的。但如果你用得是ZoneDateTime类的计算方式,答案则是月底到月底。

参考文档

[Converting string to 'Instant'](https://stackoverflow.com/questions/50299639/converting-string-to-instant)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值