1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j.core.util.datetime;
19
20 import java.util.Calendar;
21 import java.util.Objects;
22
23
24
25
26
27
28
29
30 public class FixedDateFormat {
31
32
33
34
35
36 public enum FixedFormat {
37
38
39
40 ABSOLUTE("HH:mm:ss,SSS", null, 0, ':', 1, ',', 1),
41
42
43
44
45 ABSOLUTE_PERIOD("HH:mm:ss.SSS", null, 0, ':', 1, '.', 1),
46
47
48
49
50 COMPACT("yyyyMMddHHmmssSSS", "yyyyMMdd", 0, ' ', 0, ' ', 0),
51
52
53
54
55 DATE("dd MMM yyyy HH:mm:ss,SSS", "dd MMM yyyy ", 0, ':', 1, ',', 1),
56
57
58
59
60 DATE_PERIOD("dd MMM yyyy HH:mm:ss.SSS", "dd MMM yyyy ", 0, ':', 1, '.', 1),
61
62
63
64
65 DEFAULT("yyyy-MM-dd HH:mm:ss,SSS", "yyyy-MM-dd ", 0, ':', 1, ',', 1),
66
67
68
69
70 DEFAULT_PERIOD("yyyy-MM-dd HH:mm:ss.SSS", "yyyy-MM-dd ", 0, ':', 1, '.', 1),
71
72
73
74
75 ISO8601_BASIC("yyyyMMdd'T'HHmmss,SSS", "yyyyMMdd'T'", 2, ' ', 0, ',', 1),
76
77
78
79
80 ISO8601("yyyy-MM-dd'T'HH:mm:ss,SSS", "yyyy-MM-dd'T'", 2, ':', 1, ',', 1);
81
82 private final String pattern;
83 private final String datePattern;
84 private final int escapeCount;
85 private final char timeSeparatorChar;
86 private final int timeSeparatorLength;
87 private final char millisSeparatorChar;
88 private final int millisSeparatorLength;
89
90 FixedFormat(final String pattern, final String datePattern, final int escapeCount, final char timeSeparator,
91 final int timeSepLength, final char millisSeparator, final int millisSepLength) {
92 this.timeSeparatorChar = timeSeparator;
93 this.timeSeparatorLength = timeSepLength;
94 this.millisSeparatorChar = millisSeparator;
95 this.millisSeparatorLength = millisSepLength;
96 this.pattern = Objects.requireNonNull(pattern);
97 this.datePattern = datePattern;
98 this.escapeCount = escapeCount;
99 }
100
101
102
103
104
105
106 public String getPattern() {
107 return pattern;
108 }
109
110
111
112
113
114
115 public String getDatePattern() {
116 return datePattern;
117 }
118
119
120
121
122
123
124
125 public static FixedFormat lookup(final String nameOrPattern) {
126 for (final FixedFormat type : FixedFormat.values()) {
127 if (type.name().equals(nameOrPattern) || type.getPattern().equals(nameOrPattern)) {
128 return type;
129 }
130 }
131 return null;
132 }
133
134
135
136
137
138
139 public int getLength() {
140 return pattern.length() - escapeCount;
141 }
142
143
144
145
146
147
148 public int getDatePatternLength() {
149 return getDatePattern() == null ? 0 : getDatePattern().length() - escapeCount;
150 }
151
152
153
154
155
156
157
158 public FastDateFormat getFastDateFormat() {
159 return getDatePattern() == null ? null : FastDateFormat.getInstance(getDatePattern());
160 }
161 }
162
163 private final FixedFormat fixedFormat;
164 private final int length;
165 private final FastDateFormat fastDateFormat;
166 private final char timeSeparatorChar;
167 private final char millisSeparatorChar;
168 private final int timeSeparatorLength;
169 private final int millisSeparatorLength;
170
171 private volatile long midnightToday = 0;
172 private volatile long midnightTomorrow = 0;
173
174
175
176
177
178
179 private char[] cachedDate;
180 private int dateLength;
181
182
183
184
185
186
187
188
189 FixedDateFormat(final FixedFormat fixedFormat) {
190 this.fixedFormat = Objects.requireNonNull(fixedFormat);
191 this.timeSeparatorChar = fixedFormat.timeSeparatorChar;
192 this.timeSeparatorLength = fixedFormat.timeSeparatorLength;
193 this.millisSeparatorChar = fixedFormat.millisSeparatorChar;
194 this.millisSeparatorLength = fixedFormat.millisSeparatorLength;
195 this.length = fixedFormat.getLength();
196 this.fastDateFormat = fixedFormat.getFastDateFormat();
197 }
198
199 public static FixedDateFormat createIfSupported(final String... options) {
200 if (options == null || options.length == 0 || options[0] == null) {
201 return new FixedDateFormat(FixedFormat.DEFAULT);
202 }
203 if (options.length > 1) {
204 return null;
205 }
206 final FixedFormat type = FixedFormat.lookup(options[0]);
207 return type == null ? null : new FixedDateFormat(type);
208 }
209
210
211
212
213
214
215
216 public static FixedDateFormat create(final FixedFormat format) {
217 return new FixedDateFormat(format);
218 }
219
220
221
222
223
224
225 public String getFormat() {
226 return fixedFormat.getPattern();
227 }
228
229
230
231 private long millisSinceMidnight(final long now) {
232 if (now >= midnightTomorrow || now < midnightToday) {
233 updateMidnightMillis(now);
234 }
235 return now - midnightToday;
236 }
237
238 private void updateMidnightMillis(final long now) {
239
240 updateCachedDate(now);
241
242 midnightToday = calcMidnightMillis(now, 0);
243 midnightTomorrow = calcMidnightMillis(now, 1);
244 }
245
246 static long calcMidnightMillis(final long time, final int addDays) {
247 final Calendar cal = Calendar.getInstance();
248 cal.setTimeInMillis(time);
249 cal.set(Calendar.HOUR_OF_DAY, 0);
250 cal.set(Calendar.MINUTE, 0);
251 cal.set(Calendar.SECOND, 0);
252 cal.set(Calendar.MILLISECOND, 0);
253 cal.add(Calendar.DATE, addDays);
254 return cal.getTimeInMillis();
255 }
256
257 private void updateCachedDate(final long now) {
258 if (fastDateFormat != null) {
259 final StringBuilder result = fastDateFormat.format(now, new StringBuilder());
260 cachedDate = result.toString().toCharArray();
261 dateLength = result.length();
262 }
263 }
264
265
266
267 public String format(final long time) {
268 final char[] result = new char[length << 1];
269 final int written = format(time, result, 0);
270 return new String(result, 0, written);
271 }
272
273
274
275 public int format(final long time, final char[] buffer, final int startPos) {
276
277
278
279
280
281 final int ms = (int) (millisSinceMidnight(time));
282 writeDate(buffer, startPos);
283 return writeTime(ms, buffer, startPos + dateLength) - startPos;
284 }
285
286
287
288 private void writeDate(final char[] buffer, final int startPos) {
289 if (cachedDate != null) {
290 System.arraycopy(cachedDate, 0, buffer, startPos, dateLength);
291 }
292 }
293
294
295
296 private int writeTime(int ms, final char[] buffer, int pos) {
297 final int hours = ms / 3600000;
298 ms -= 3600000 * hours;
299
300 final int minutes = ms / 60000;
301 ms -= 60000 * minutes;
302
303 final int seconds = ms / 1000;
304 ms -= 1000 * seconds;
305
306
307 int temp = hours / 10;
308 buffer[pos++] = ((char) (temp + '0'));
309
310
311 buffer[pos++] = ((char) (hours - 10 * temp + '0'));
312 buffer[pos] = timeSeparatorChar;
313 pos += timeSeparatorLength;
314
315
316 temp = minutes / 10;
317 buffer[pos++] = ((char) (temp + '0'));
318
319
320 buffer[pos++] = ((char) (minutes - 10 * temp + '0'));
321 buffer[pos] = timeSeparatorChar;
322 pos += timeSeparatorLength;
323
324
325 temp = seconds / 10;
326 buffer[pos++] = ((char) (temp + '0'));
327 buffer[pos++] = ((char) (seconds - 10 * temp + '0'));
328 buffer[pos] = millisSeparatorChar;
329 pos += millisSeparatorLength;
330
331
332 temp = ms / 100;
333 buffer[pos++] = ((char) (temp + '0'));
334
335 ms -= 100 * temp;
336 temp = ms / 10;
337 buffer[pos++] = ((char) (temp + '0'));
338
339 ms -= 10 * temp;
340 buffer[pos++] = ((char) (ms + '0'));
341 return pos;
342 }
343 }