Commit 6ff317427050b8f6c90b4bffb1673a546ccdb61e

Authored by YunaiV
1 parent c24a3a02

fix(system/iot):统一时间戳转换默认时区

- common:LocalDateTimeUtils 增加 GMT+8 默认时区的 ofEpochSecond / toEpochSecond 重载

- system:七牛短信回调使用默认时区解析秒级时间戳,避免本机时区影响接收时间

- iot:当前时间规则使用默认时区转 epoch,修复非 GMT+8 环境下匹配结果错误

验证:

- yudao-module-system 单测通过

- yudao-module-iot-biz 单测通过

- yudao-module-iot-gateway 编译通过
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/date/LocalDateTimeUtils.java
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.framework.common.util.date; @@ -3,7 +3,6 @@ package cn.iocoder.yudao.framework.common.util.date;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.date.DatePattern; 4 import cn.hutool.core.date.DatePattern;
5 import cn.hutool.core.date.LocalDateTimeUtil; 5 import cn.hutool.core.date.LocalDateTimeUtil;
6 -import cn.hutool.core.date.TemporalAccessorUtil;  
7 import cn.hutool.core.lang.Assert; 6 import cn.hutool.core.lang.Assert;
8 import cn.hutool.core.util.StrUtil; 7 import cn.hutool.core.util.StrUtil;
9 import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum; 8 import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum;
@@ -16,6 +15,7 @@ import java.time.temporal.ChronoUnit; @@ -16,6 +15,7 @@ import java.time.temporal.ChronoUnit;
16 import java.time.temporal.TemporalAdjusters; 15 import java.time.temporal.TemporalAdjusters;
17 import java.util.ArrayList; 16 import java.util.ArrayList;
18 import java.util.List; 17 import java.util.List;
  18 +import java.util.TimeZone;
19 19
20 import static cn.hutool.core.date.DatePattern.*; 20 import static cn.hutool.core.date.DatePattern.*;
21 21
@@ -34,6 +34,11 @@ public class LocalDateTimeUtils { @@ -34,6 +34,11 @@ public class LocalDateTimeUtils {
34 public static DateTimeFormatter UTC_MS_WITH_XXX_OFFSET_FORMATTER = createFormatter(UTC_MS_WITH_XXX_OFFSET_PATTERN); 34 public static DateTimeFormatter UTC_MS_WITH_XXX_OFFSET_FORMATTER = createFormatter(UTC_MS_WITH_XXX_OFFSET_PATTERN);
35 35
36 /** 36 /**
  37 + * 默认时区
  38 + */
  39 + private static final ZoneId DEFAULT_ZONE_ID = TimeZone.getTimeZone(DateUtils.TIME_ZONE_DEFAULT).toZoneId();
  40 +
  41 + /**
37 * 解析时间 42 * 解析时间
38 * 43 *
39 * 相比 {@link LocalDateTimeUtil#parse(CharSequence)} 方法来说,会尽量去解析,直到成功 44 * 相比 {@link LocalDateTimeUtil#parse(CharSequence)} 方法来说,会尽量去解析,直到成功
@@ -66,6 +71,27 @@ public class LocalDateTimeUtils { @@ -66,6 +71,27 @@ public class LocalDateTimeUtils {
66 } 71 }
67 72
68 /** 73 /**
  74 + * 将 Unix 秒时间戳转换为默认时区的本地时间
  75 + *
  76 + * @param epochSecond Unix 秒时间戳
  77 + * @return 本地时间
  78 + */
  79 + public static LocalDateTime ofEpochSecond(long epochSecond) {
  80 + return ofEpochSecond(epochSecond, DEFAULT_ZONE_ID);
  81 + }
  82 +
  83 + /**
  84 + * 将 Unix 秒时间戳转换为指定时区的本地时间
  85 + *
  86 + * @param epochSecond Unix 秒时间戳
  87 + * @param zoneId 时区编号
  88 + * @return 本地时间
  89 + */
  90 + public static LocalDateTime ofEpochSecond(long epochSecond, ZoneId zoneId) {
  91 + return LocalDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), zoneId);
  92 + }
  93 +
  94 + /**
69 * 创建指定时间 95 * 创建指定时间
70 * 96 *
71 * @param year 年 97 * @param year 年
@@ -393,7 +419,18 @@ public class LocalDateTimeUtils { @@ -393,7 +419,18 @@ public class LocalDateTimeUtils {
393 * @throws DateTimeException 如果转换过程中发生时间超出范围或其他时间处理异常 419 * @throws DateTimeException 如果转换过程中发生时间超出范围或其他时间处理异常
394 */ 420 */
395 public static Long toEpochSecond(LocalDateTime sourceDateTime) { 421 public static Long toEpochSecond(LocalDateTime sourceDateTime) {
396 - return TemporalAccessorUtil.toInstant(sourceDateTime).getEpochSecond(); 422 + return toEpochSecond(sourceDateTime, DEFAULT_ZONE_ID);
  423 + }
  424 +
  425 + /**
  426 + * 将给定的 {@link LocalDateTime} 按指定时区转换为自 Unix 纪元时间(1970-01-01T00:00:00Z)以来的秒数。
  427 + *
  428 + * @param sourceDateTime 需要转换的本地日期时间,不能为空
  429 + * @param zoneId 时区编号
  430 + * @return 自 1970-01-01T00:00:00Z 起的秒数(epoch second)
  431 + */
  432 + public static Long toEpochSecond(LocalDateTime sourceDateTime, ZoneId zoneId) {
  433 + return sourceDateTime.atZone(zoneId).toEpochSecond();
397 } 434 }
398 435
399 } 436 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleTimeHelper.java
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.service.rule.scene; @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.service.rule.scene;
3 import cn.hutool.core.lang.Assert; 3 import cn.hutool.core.lang.Assert;
4 import cn.hutool.core.text.CharPool; 4 import cn.hutool.core.text.CharPool;
5 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
  6 +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
6 import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum; 7 import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
7 import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition.IotCurrentTimeConditionMatcher; 8 import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition.IotCurrentTimeConditionMatcher;
8 import cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotTimerConditionEvaluator; 9 import cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotTimerConditionEvaluator;
@@ -11,7 +12,6 @@ import lombok.extern.slf4j.Slf4j; @@ -11,7 +12,6 @@ import lombok.extern.slf4j.Slf4j;
11 12
12 import java.time.LocalDateTime; 13 import java.time.LocalDateTime;
13 import java.time.LocalTime; 14 import java.time.LocalTime;
14 -import java.time.ZoneId;  
15 import java.time.format.DateTimeFormatter; 15 import java.time.format.DateTimeFormatter;
16 import java.util.List; 16 import java.util.List;
17 17
@@ -73,7 +73,7 @@ public class IotSceneRuleTimeHelper { @@ -73,7 +73,7 @@ public class IotSceneRuleTimeHelper {
73 LocalDateTime now = LocalDateTime.now(); 73 LocalDateTime now = LocalDateTime.now();
74 if (isDateTimeOperator(operatorEnum)) { 74 if (isDateTimeOperator(operatorEnum)) {
75 // 日期时间匹配(时间戳,秒级) 75 // 日期时间匹配(时间戳,秒级)
76 - long currentTimestamp = now.atZone(ZoneId.systemDefault()).toEpochSecond(); 76 + long currentTimestamp = LocalDateTimeUtils.toEpochSecond(now);
77 return matchDateTime(currentTimestamp, operatorEnum, param); 77 return matchDateTime(currentTimestamp, operatorEnum, param);
78 } else { 78 } else {
79 // 当日时间匹配(HH:mm:ss) 79 // 当日时间匹配(HH:mm:ss)
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/framework/sms/core/client/impl/QiniuSmsClient.java
@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.system.framework.sms.core.client.impl; @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.system.framework.sms.core.client.impl;
2 2
3 import cn.hutool.core.collection.CollStreamUtil; 3 import cn.hutool.core.collection.CollStreamUtil;
4 import cn.hutool.core.date.DateUtil; 4 import cn.hutool.core.date.DateUtil;
5 -import cn.hutool.core.date.LocalDateTimeUtil;  
6 import cn.hutool.core.lang.Assert; 5 import cn.hutool.core.lang.Assert;
7 import cn.hutool.core.util.ObjectUtil; 6 import cn.hutool.core.util.ObjectUtil;
8 import cn.hutool.crypto.SecureUtil; 7 import cn.hutool.crypto.SecureUtil;
@@ -10,6 +9,7 @@ import cn.hutool.crypto.digest.HmacAlgorithm; @@ -10,6 +9,7 @@ import cn.hutool.crypto.digest.HmacAlgorithm;
10 import cn.hutool.json.JSONObject; 9 import cn.hutool.json.JSONObject;
11 import cn.hutool.json.JSONUtil; 10 import cn.hutool.json.JSONUtil;
12 import cn.iocoder.yudao.framework.common.core.KeyValue; 11 import cn.iocoder.yudao.framework.common.core.KeyValue;
  12 +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
13 import cn.iocoder.yudao.framework.common.util.http.HttpUtils; 13 import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
14 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO; 14 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
15 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO; 15 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO;
@@ -120,7 +120,7 @@ public class QiniuSmsClient extends AbstractSmsClient { @@ -120,7 +120,7 @@ public class QiniuSmsClient extends AbstractSmsClient {
120 .setSuccess("DELIVRD".equals(statusObj.getStr("status"))) // 是否接收成功 120 .setSuccess("DELIVRD".equals(statusObj.getStr("status"))) // 是否接收成功
121 .setErrorMsg(statusObj.getStr("status")) // 状态报告编码 121 .setErrorMsg(statusObj.getStr("status")) // 状态报告编码
122 .setMobile(statusObj.getStr("mobile")) // 手机号 122 .setMobile(statusObj.getStr("mobile")) // 手机号
123 - .setReceiveTime(LocalDateTimeUtil.of(statusObj.getLong("delivrd_at") * 1000L)) // 状态报告时间 123 + .setReceiveTime(LocalDateTimeUtils.ofEpochSecond(statusObj.getLong("delivrd_at"))) // 状态报告时间
124 .setSerialNo(statusObj.getStr("message_id")) // 发送序列号 124 .setSerialNo(statusObj.getStr("message_id")) // 发送序列号
125 .setLogId(statusObj.getLong("seq")); // 用户序列号 125 .setLogId(statusObj.getLong("seq")); // 用户序列号
126 } 126 }