2026-06-30 24681c81c09022f584a57006f2534b5f74723414
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
package cn.iocoder.yudao.module.iot.service.rule.scene;
 
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.CharPool;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum;
import cn.iocoder.yudao.module.iot.service.rule.scene.matcher.condition.IotCurrentTimeConditionMatcher;
import cn.iocoder.yudao.module.iot.service.rule.scene.timer.IotTimerConditionEvaluator;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
 
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
 
/**
 * IoT 场景规则时间匹配工具类
 * <p>
 * 提供时间条件匹配的通用方法,供 {@link IotCurrentTimeConditionMatcher} 和 {@link IotTimerConditionEvaluator} 共同使用。
 *
 * @author HUIHUI
 */
@Slf4j
@UtilityClass
public class IotSceneRuleTimeHelper {
 
    /**
     * 时间格式化器 - HH:mm:ss
     */
    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
 
    /**
     * 时间格式化器 - HH:mm
     */
    private static final DateTimeFormatter TIME_FORMATTER_SHORT = DateTimeFormatter.ofPattern("HH:mm");
 
    /**
     * 判断是否为日期时间操作符
     *
     * @param operatorEnum 操作符枚举
     * @return 是否为日期时间操作符
     */
    public static boolean isDateTimeOperator(IotSceneRuleConditionOperatorEnum operatorEnum) {
        return operatorEnum == IotSceneRuleConditionOperatorEnum.DATE_TIME_GREATER_THAN
                || operatorEnum == IotSceneRuleConditionOperatorEnum.DATE_TIME_LESS_THAN
                || operatorEnum == IotSceneRuleConditionOperatorEnum.DATE_TIME_BETWEEN;
    }
 
    /**
     * 判断是否为时间操作符(包括日期时间操作符和当日时间操作符)
     *
     * @param operatorEnum 操作符枚举
     * @return 是否为时间操作符
     */
    public static boolean isTimeOperator(IotSceneRuleConditionOperatorEnum operatorEnum) {
        return operatorEnum != IotSceneRuleConditionOperatorEnum.TIME_GREATER_THAN
                && operatorEnum != IotSceneRuleConditionOperatorEnum.TIME_LESS_THAN
                && operatorEnum != IotSceneRuleConditionOperatorEnum.TIME_BETWEEN
                && !isDateTimeOperator(operatorEnum);
    }
 
    /**
     * 执行时间匹配逻辑
     *
     * @param operatorEnum 操作符枚举
     * @param param        参数值
     * @return 是否匹配
     */
    public static boolean executeTimeMatching(IotSceneRuleConditionOperatorEnum operatorEnum, String param) {
        try {
            LocalDateTime now = LocalDateTime.now();
            if (isDateTimeOperator(operatorEnum)) {
                // 日期时间匹配(时间戳,秒级)
                long currentTimestamp = LocalDateTimeUtils.toEpochSecond(now);
                return matchDateTime(currentTimestamp, operatorEnum, param);
            } else {
                // 当日时间匹配(HH:mm:ss)
                return matchTime(now.toLocalTime(), operatorEnum, param);
            }
        } catch (Exception e) {
            log.error("[executeTimeMatching][operatorEnum({}) param({}) 时间匹配异常]", operatorEnum, param, e);
            return false;
        }
    }
 
    /**
     * 匹配日期时间(时间戳,秒级)
     *
     * @param currentTimestamp 当前时间戳
     * @param operatorEnum     操作符枚举
     * @param param            参数值
     * @return 是否匹配
     */
    @SuppressWarnings("EnhancedSwitchMigration")
    public static boolean matchDateTime(long currentTimestamp, IotSceneRuleConditionOperatorEnum operatorEnum,
                                        String param) {
        try {
            // DATE_TIME_BETWEEN 需要解析两个时间戳,单独处理
            if (operatorEnum == IotSceneRuleConditionOperatorEnum.DATE_TIME_BETWEEN) {
                return matchDateTimeBetween(currentTimestamp, param);
            }
            // 其他操作符只需要解析一个时间戳
            long targetTimestamp = Long.parseLong(param);
            switch (operatorEnum) {
                case DATE_TIME_GREATER_THAN:
                    return currentTimestamp > targetTimestamp;
                case DATE_TIME_LESS_THAN:
                    return currentTimestamp < targetTimestamp;
                default:
                    log.warn("[matchDateTime][operatorEnum({}) 不支持的日期时间操作符]", operatorEnum);
                    return false;
            }
        } catch (Exception e) {
            log.error("[matchDateTime][operatorEnum({}) param({}) 日期时间匹配异常]", operatorEnum, param, e);
            return false;
        }
    }
 
    /**
     * 匹配日期时间区间
     *
     * @param currentTimestamp 当前时间戳
     * @param param            参数值(格式:startTimestamp,endTimestamp)
     * @return 是否匹配
     */
    public static boolean matchDateTimeBetween(long currentTimestamp, String param) {
        List<String> timestampRange = StrUtil.splitTrim(param, CharPool.COMMA);
        if (timestampRange.size() != 2) {
            log.warn("[matchDateTimeBetween][param({}) 时间戳区间参数格式错误]", param);
            return false;
        }
        long startTimestamp = Long.parseLong(timestampRange.get(0).trim());
        long endTimestamp = Long.parseLong(timestampRange.get(1).trim());
        return currentTimestamp >= startTimestamp && currentTimestamp <= endTimestamp;
    }
 
    /**
     * 匹配当日时间(HH:mm:ss 或 HH:mm)
     *
     * @param currentTime  当前时间
     * @param operatorEnum 操作符枚举
     * @param param        参数值
     * @return 是否匹配
     */
    @SuppressWarnings("EnhancedSwitchMigration")
    public static boolean matchTime(LocalTime currentTime, IotSceneRuleConditionOperatorEnum operatorEnum,
                                    String param) {
        try {
            // TIME_BETWEEN 需要解析两个时间,单独处理
            if (operatorEnum == IotSceneRuleConditionOperatorEnum.TIME_BETWEEN) {
                return matchTimeBetween(currentTime, param);
            }
            // 其他操作符只需要解析一个时间
            LocalTime targetTime = parseTime(param);
            switch (operatorEnum) {
                case TIME_GREATER_THAN:
                    return currentTime.isAfter(targetTime);
                case TIME_LESS_THAN:
                    return currentTime.isBefore(targetTime);
                default:
                    log.warn("[matchTime][operatorEnum({}) 不支持的时间操作符]", operatorEnum);
                    return false;
            }
        } catch (Exception e) {
            log.error("[matchTime][operatorEnum({}) param({}) 时间解析异常]", operatorEnum, param, e);
            return false;
        }
    }
 
    /**
     * 匹配时间区间
     *
     * @param currentTime 当前时间
     * @param param       参数值(格式:startTime,endTime)
     * @return 是否匹配
     */
    public static boolean matchTimeBetween(LocalTime currentTime, String param) {
        List<String> timeRange = StrUtil.splitTrim(param, CharPool.COMMA);
        if (timeRange.size() != 2) {
            log.warn("[matchTimeBetween][param({}) 时间区间参数格式错误]", param);
            return false;
        }
        LocalTime startTime = parseTime(timeRange.get(0).trim());
        LocalTime endTime = parseTime(timeRange.get(1).trim());
        return !currentTime.isBefore(startTime) && !currentTime.isAfter(endTime);
    }
 
    /**
     * 解析时间字符串
     * 支持 HH:mm 和 HH:mm:ss 两种格式
     *
     * @param timeStr 时间字符串
     * @return 解析后的 LocalTime
     */
    public static LocalTime parseTime(String timeStr) {
        Assert.isFalse(StrUtil.isBlank(timeStr), "时间字符串不能为空");
        try {
            // 尝试不同的时间格式
            if (timeStr.length() == 5) { // HH:mm
                return LocalTime.parse(timeStr, TIME_FORMATTER_SHORT);
            } else if (timeStr.length() == 8) { // HH:mm:ss
                return LocalTime.parse(timeStr, TIME_FORMATTER);
            } else {
                throw new IllegalArgumentException("时间格式长度不正确,期望 HH:mm 或 HH:mm:ss 格式");
            }
        } catch (Exception e) {
            log.error("[parseTime][timeStr({}) 时间格式解析失败]", timeStr, e);
            throw new IllegalArgumentException("时间格式无效: " + timeStr, e);
        }
    }
 
}