Commit 6ff317427050b8f6c90b4bffb1673a546ccdb61e
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 编译通过
Showing
3 changed files
with
43 additions
and
6 deletions
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 | } | ... | ... |