zhaowenyu
2026-01-14 eeed071b9da26a1c389ab5572b722d36812c10a7
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
package com.ard.sample.utils;
 
import org.springframework.stereotype.Component;
 
import java.time.*;
import java.time.format.DateTimeFormatter;
 
/**
 * 时间戳工具类(支持毫秒级/秒级时间戳,基于Java 8+时间API)
 * 功能:加/减时间、转换为LocalDateTime、格式化字符串等
 */
@Component
public class TimestampUtils {
 
    // 默认时区:北京时间(Asia/Shanghai)
    private static final ZoneId DEFAULT_ZONE = ZoneId.of("Asia/Shanghai");
 
    // 默认日期时间格式:yyyy-MM-dd HH:mm:ss
    private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
 
    // 时间单位常量(毫秒)
    private static final long ONE_SECOND = 1000L;         // 1秒 = 1000毫秒
    private static final long ONE_MINUTE = 60 * ONE_SECOND; // 1分钟 = 60秒
    private static final long ONE_HOUR = 60 * ONE_MINUTE;   // 1小时 = 60分钟
    private static final long ONE_DAY = 24 * ONE_HOUR;      // 1天 = 24小时
 
 
    // -------------------------- 毫秒级时间戳操作 --------------------------
 
    /**
     * 毫秒级时间戳 + N天
     * @param millisTimestamp 原毫秒级时间戳(13位)
     * @param days 天数(正数加,负数减)
     * @return 计算后的毫秒级时间戳
     */
    public long plusDaysByMillis(long millisTimestamp, int days) {
        return Instant.ofEpochMilli(millisTimestamp)
                .plusMillis(days * ONE_DAY)
                .toEpochMilli();
    }
 
    /**
     * 毫秒级时间戳 + N小时
     * @param millisTimestamp 原毫秒级时间戳(13位)
     * @param hours 小时数(正数加,负数减)
     * @return 计算后的毫秒级时间戳
     */
    public long plusHoursByMillis(long millisTimestamp, int hours) {
        return Instant.ofEpochMilli(millisTimestamp)
                .plusMillis(hours * ONE_HOUR)
                .toEpochMilli();
    }
 
    /**
     * 毫秒级时间戳 + N分钟
     * @param millisTimestamp 原毫秒级时间戳(13位)
     * @param minutes 分钟数(正数加,负数减)
     * @return 计算后的毫秒级时间戳
     */
    public long plusMinutesByMillis(long millisTimestamp, int minutes) {
        return Instant.ofEpochMilli(millisTimestamp)
                .plusMillis(minutes * ONE_MINUTE)
                .toEpochMilli();
    }
 
    /**
     * 毫秒级时间戳 + N秒
     * @param millisTimestamp 原毫秒级时间戳(13位)
     * @param seconds 秒数(正数加,负数减)
     * @return 计算后的毫秒级时间戳
     */
    public long plusSecondsByMillis(long millisTimestamp, int seconds) {
        return Instant.ofEpochMilli(millisTimestamp)
                .plusMillis(seconds * ONE_SECOND)
                .toEpochMilli();
    }
 
 
    // -------------------------- 秒级时间戳操作 --------------------------
 
    /**
     * 秒级时间戳 + N天(自动转换为毫秒级计算,结果转回秒级)
     * @param secondTimestamp 原秒级时间戳(10位)
     * @param days 天数(正数加,负数减)
     * @return 计算后的秒级时间戳
     */
    public long plusDaysBySecond(long secondTimestamp, int days) {
        long millis = secondTimestamp * ONE_SECOND;
        long newMillis = plusDaysByMillis(millis, days);
        return newMillis / ONE_SECOND;
    }
 
    /**
     * 秒级时间戳 + N小时
     * @param secondTimestamp 原秒级时间戳(10位)
     * @param hours 小时数(正数加,负数减)
     * @return 计算后的秒级时间戳
     */
    public long plusHoursBySecond(long secondTimestamp, int hours) {
        long millis = secondTimestamp * ONE_SECOND;
        long newMillis = plusHoursByMillis(millis, hours);
        return newMillis / ONE_SECOND;
    }
 
    /**
     * 秒级时间戳 + N分钟
     * @param secondTimestamp 原秒级时间戳(10位)
     * @param minutes 分钟数(正数加,负数减)
     * @return 计算后的秒级时间戳
     */
    public long plusMinutesBySecond(long secondTimestamp, int minutes) {
        long millis = secondTimestamp * ONE_SECOND;
        long newMillis = plusMinutesByMillis(millis, minutes);
        return newMillis / ONE_SECOND;
    }
 
    /**
     * 秒级时间戳 + N秒
     * @param secondTimestamp 原秒级时间戳(10位)
     * @param seconds 秒数(正数加,负数减)
     * @return 计算后的秒级时间戳
     */
    public long plusSecondsBySecond(long secondTimestamp, int seconds) {
        return secondTimestamp + seconds; // 秒级直接加减,无需转毫秒
    }
 
 
    // -------------------------- 时间戳转换为LocalDateTime --------------------------
 
    /**
     * 毫秒级时间戳转换为LocalDateTime(默认时区:北京时间)
     * @param millisTimestamp 毫秒级时间戳(13位)
     * @return LocalDateTime对象
     */
    public LocalDateTime toLocalDateTimeByMillis(long millisTimestamp) {
        return LocalDateTime.ofInstant(
                Instant.ofEpochMilli(millisTimestamp),
                DEFAULT_ZONE
        );
    }
 
    /**
     * 秒级时间戳转换为LocalDateTime(默认时区:北京时间)
     * @param secondTimestamp 秒级时间戳(10位)
     * @return LocalDateTime对象
     */
    public LocalDateTime toLocalDateTimeBySecond(long secondTimestamp) {
        return LocalDateTime.ofInstant(
                Instant.ofEpochSecond(secondTimestamp), // 直接用ofEpochSecond处理秒级
                DEFAULT_ZONE
        );
    }
 
 
    // -------------------------- 时间戳格式化为字符串 --------------------------
 
    /**
     * 毫秒级时间戳格式化为字符串(默认格式:yyyy-MM-dd HH:mm:ss)
     * @param millisTimestamp 毫秒级时间戳(13位)
     * @return 格式化后的字符串
     */
    public String formatByMillis(long millisTimestamp) {
        return formatByMillis(millisTimestamp, DEFAULT_FORMATTER);
    }
 
    /**
     * 毫秒级时间戳格式化为自定义格式字符串
     * @param millisTimestamp 毫秒级时间戳(13位)
     * @param formatter 自定义格式器(如:DateTimeFormatter.ofPattern("yyyy/MM/dd"))
     * @return 格式化后的字符串
     */
    public String formatByMillis(long millisTimestamp, DateTimeFormatter formatter) {
        LocalDateTime dateTime = toLocalDateTimeByMillis(millisTimestamp);
        return dateTime.format(formatter);
    }
 
    /**
     * 秒级时间戳格式化为字符串(默认格式:yyyy-MM-dd HH:mm:ss)
     * @param secondTimestamp 秒级时间戳(10位)
     * @return 格式化后的字符串
     */
    public String formatBySecond(long secondTimestamp) {
        return formatBySecond(secondTimestamp, DEFAULT_FORMATTER);
    }
 
    /**
     * 秒级时间戳格式化为自定义格式字符串
     * @param secondTimestamp 秒级时间戳(10位)
     * @param formatter 自定义格式器
     * @return 格式化后的字符串
     */
    public String formatBySecond(long secondTimestamp, DateTimeFormatter formatter) {
        LocalDateTime dateTime = toLocalDateTimeBySecond(secondTimestamp);
        return dateTime.format(formatter);
    }
 
    /**
     * 取原时间戳的时间部分,与当前日期组合成新时间戳
     * @param originalTimestamp 原时间戳(毫秒,如System.currentTimeMillis()返回值)
     * @return 组合后的新时间戳(毫秒)
     */
    public Long combine( Long originalTimestamp) {
        // 1. 校验原时间戳合法性
        if (originalTimestamp == null || originalTimestamp < 0) {
            throw new IllegalArgumentException("原时间戳无效");
        }
 
        // 2. 解析原时间戳,提取时间部分(时、分、秒、毫秒)
        // 原时间戳转换为ZonedDateTime(带时区的日期时间)
        ZonedDateTime originalZoned = Instant.ofEpochMilli(originalTimestamp)
                .atZone(DEFAULT_ZONE);
        // 提取时间部分:时、分、秒、纳秒(纳秒需转换为毫秒级精度)
        int hour = originalZoned.getHour();
        int minute = originalZoned.getMinute();
        int second = originalZoned.getSecond();
        int nanoOfSecond = originalZoned.getNano(); // 纳秒(1毫秒=1,000,000纳秒)
        int milliOfSecond = nanoOfSecond / 1_000_000; // 取毫秒部分(0-999)
 
 
        // 3. 获取当前日期(年月日)
        LocalDate currentDate = LocalDate.now(DEFAULT_ZONE);
 
 
        // 4. 组合新的日期时间:当前年月日 + 原时间的时分秒毫秒
        LocalTime combinedTime = LocalTime.of(hour, minute, second, nanoOfSecond);
        LocalDateTime combinedDateTime = LocalDateTime.of(currentDate, combinedTime);
 
 
        // 5. 转换为新时间戳(毫秒)
        return combinedDateTime.atZone(DEFAULT_ZONE)
                .toInstant()
                .toEpochMilli();
    }
 
    /**
     * 获取指定时间戳当天0点0分0秒的时间戳(带时区处理)
     * @param timestamp 指定时间戳(毫秒,如System.currentTimeMillis()返回值)
     * @return 当天0点的时间戳(毫秒)
     */
    public Long getDayStartTimestamp(Long timestamp) {
        // 校验参数合法性
        if (timestamp == null || timestamp < 0) {
            throw new IllegalArgumentException("时间戳无效(不能为null或负数)");
        }
        // 1. 将时间戳转换为带时区的日期时间
        ZonedDateTime zonedDateTime = Instant.ofEpochMilli(timestamp)
                .atZone(DEFAULT_ZONE);
 
        // 2. 获取当天的起始时刻(00:00:00.000)
        // atStartOfDay(zoneId) 会自动处理时区特殊情况(如夏令时切换)
        ZonedDateTime dayStart = zonedDateTime.toLocalDate()
                .atStartOfDay(DEFAULT_ZONE);
 
        // 3. 转换为毫秒级时间戳
        return dayStart.toInstant().toEpochMilli();
    }
}