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 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.date.DatePattern;
5 5 import cn.hutool.core.date.LocalDateTimeUtil;
6   -import cn.hutool.core.date.TemporalAccessorUtil;
7 6 import cn.hutool.core.lang.Assert;
8 7 import cn.hutool.core.util.StrUtil;
9 8 import cn.iocoder.yudao.framework.common.enums.DateIntervalEnum;
... ... @@ -16,6 +15,7 @@ import java.time.temporal.ChronoUnit;
16 15 import java.time.temporal.TemporalAdjusters;
17 16 import java.util.ArrayList;
18 17 import java.util.List;
  18 +import java.util.TimeZone;
19 19  
20 20 import static cn.hutool.core.date.DatePattern.*;
21 21  
... ... @@ -34,6 +34,11 @@ public class LocalDateTimeUtils {
34 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 44 * 相比 {@link LocalDateTimeUtil#parse(CharSequence)} 方法来说,会尽量去解析,直到成功
... ... @@ -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 97 * @param year 年
... ... @@ -393,7 +419,18 @@ public class LocalDateTimeUtils {
393 419 * @throws DateTimeException 如果转换过程中发生时间超出范围或其他时间处理异常
394 420 */
395 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 3 import cn.hutool.core.lang.Assert;
4 4 import cn.hutool.core.text.CharPool;
5 5 import cn.hutool.core.util.StrUtil;
  6 +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
6 7 import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
7 8 import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition.IotCurrentTimeConditionMatcher;
8 9 import cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotTimerConditionEvaluator;
... ... @@ -11,7 +12,6 @@ import lombok.extern.slf4j.Slf4j;
11 12  
12 13 import java.time.LocalDateTime;
13 14 import java.time.LocalTime;
14   -import java.time.ZoneId;
15 15 import java.time.format.DateTimeFormatter;
16 16 import java.util.List;
17 17  
... ... @@ -73,7 +73,7 @@ public class IotSceneRuleTimeHelper {
73 73 LocalDateTime now = LocalDateTime.now();
74 74 if (isDateTimeOperator(operatorEnum)) {
75 75 // 日期时间匹配(时间戳,秒级)
76   - long currentTimestamp = now.atZone(ZoneId.systemDefault()).toEpochSecond();
  76 + long currentTimestamp = LocalDateTimeUtils.toEpochSecond(now);
77 77 return matchDateTime(currentTimestamp, operatorEnum, param);
78 78 } else {
79 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 2  
3 3 import cn.hutool.core.collection.CollStreamUtil;
4 4 import cn.hutool.core.date.DateUtil;
5   -import cn.hutool.core.date.LocalDateTimeUtil;
6 5 import cn.hutool.core.lang.Assert;
7 6 import cn.hutool.core.util.ObjectUtil;
8 7 import cn.hutool.crypto.SecureUtil;
... ... @@ -10,6 +9,7 @@ import cn.hutool.crypto.digest.HmacAlgorithm;
10 9 import cn.hutool.json.JSONObject;
11 10 import cn.hutool.json.JSONUtil;
12 11 import cn.iocoder.yudao.framework.common.core.KeyValue;
  12 +import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
13 13 import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
14 14 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsReceiveRespDTO;
15 15 import cn.iocoder.yudao.module.system.framework.sms.core.client.dto.SmsSendRespDTO;
... ... @@ -120,7 +120,7 @@ public class QiniuSmsClient extends AbstractSmsClient {
120 120 .setSuccess("DELIVRD".equals(statusObj.getStr("status"))) // 是否接收成功
121 121 .setErrorMsg(statusObj.getStr("status")) // 状态报告编码
122 122 .setMobile(statusObj.getStr("mobile")) // 手机号
123   - .setReceiveTime(LocalDateTimeUtil.of(statusObj.getLong("delivrd_at") * 1000L)) // 状态报告时间
  123 + .setReceiveTime(LocalDateTimeUtils.ofEpochSecond(statusObj.getLong("delivrd_at"))) // 状态报告时间
124 124 .setSerialNo(statusObj.getStr("message_id")) // 发送序列号
125 125 .setLogId(statusObj.getLong("seq")); // 用户序列号
126 126 }
... ...