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 static 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 private FixedFormat(final String pattern, final String datePattern, final int escapeCount,
91 final char timeSeparator, 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 public String getPattern() {
102 return pattern;
103 }
104
105 public String getDatePattern() {
106 return datePattern;
107 }
108
109
110
111
112 public static FixedFormat lookup(final String nameOrPattern) {
113 for (final FixedFormat type : FixedFormat.values()) {
114 if (type.name().equals(nameOrPattern) || type.getPattern().equals(nameOrPattern)) {
115 return type;
116 }
117 }
118 return null;
119 }
120
121 public int getLength() {
122 return pattern.length() - escapeCount;
123 }
124
125 public int getDatePatternLength() {
126 return getDatePattern() == null ? 0 : getDatePattern().length() - escapeCount;
127 }
128
129 public FastDateFormat getFastDateFormat() {
130 return getDatePattern() == null ? null : FastDateFormat.getInstance(getDatePattern());
131 }
132 }
133
134 public static FixedDateFormat createIfSupported(final String... options) {
135 if (options == null || options.length == 0 || options[0] == null) {
136 return new FixedDateFormat(FixedFormat.DEFAULT);
137 }
138 if (options.length > 1) {
139 return null;
140 }
141 final FixedFormat type = FixedFormat.lookup(options[0]);
142 return type == null ? null : new FixedDateFormat(type);
143 }
144
145 public static FixedDateFormat create(FixedFormat format) {
146 return new FixedDateFormat(format);
147 }
148
149 private final FixedFormat fixedFormat;
150 private final int length;
151 private final int dateLength;
152 private final FastDateFormat fastDateFormat;
153 private final char timeSeparatorChar;
154 private final char millisSeparatorChar;
155 private final int timeSeparatorLength;
156 private final int millisSeparatorLength;
157
158 private volatile long midnightToday = 0;
159 private volatile long midnightTomorrow = 0;
160
161
162
163
164
165
166 private char[] cachedDate;
167
168
169
170
171
172
173
174
175 FixedDateFormat(final FixedFormat fixedFormat) {
176 this.fixedFormat = Objects.requireNonNull(fixedFormat);
177 this.timeSeparatorChar = fixedFormat.timeSeparatorChar;
178 this.timeSeparatorLength = fixedFormat.timeSeparatorLength;
179 this.millisSeparatorChar = fixedFormat.millisSeparatorChar;
180 this.millisSeparatorLength = fixedFormat.millisSeparatorLength;
181 this.length = fixedFormat.getLength();
182 this.dateLength = fixedFormat.getDatePatternLength();
183 this.fastDateFormat = fixedFormat.getFastDateFormat();
184 }
185
186 public String getFormat() {
187 return fixedFormat.getPattern();
188 }
189
190
191
192 private long millisSinceMidnight(final long now) {
193 if (now >= midnightTomorrow || now < midnightToday) {
194 updateMidnightMillis(now);
195 }
196 return now - midnightToday;
197 }
198
199 private void updateMidnightMillis(final long now) {
200
201 updateCachedDate(now);
202
203 midnightToday = calcMidnightMillis(now, 0);
204 midnightTomorrow = calcMidnightMillis(now, 1);
205 }
206
207 static long calcMidnightMillis(final long time, final int addDays) {
208 final Calendar cal = Calendar.getInstance();
209 cal.setTimeInMillis(time);
210 cal.set(Calendar.HOUR_OF_DAY, 0);
211 cal.set(Calendar.MINUTE, 0);
212 cal.set(Calendar.SECOND, 0);
213 cal.set(Calendar.MILLISECOND, 0);
214 cal.add(Calendar.DATE, addDays);
215 return cal.getTimeInMillis();
216 }
217
218 private void updateCachedDate(final long now) {
219 if (fastDateFormat != null) {
220 final StringBuilder result = fastDateFormat.format(now, new StringBuilder());
221 cachedDate = result.toString().toCharArray();
222 }
223 }
224
225
226
227 public String format(final long time) {
228 final char[] result = new char[length];
229 int written = format(time, result, 0);
230 return new String(result, 0, written);
231 }
232
233
234
235 public int format(final long time, final char[] buffer, final int startPos) {
236
237
238
239
240
241 final int ms = (int) (millisSinceMidnight(time));
242 writeDate(buffer, startPos);
243 return writeTime(ms, buffer, startPos + dateLength) - startPos;
244 }
245
246
247
248 private void writeDate(final char[] buffer, final int startPos) {
249 if (cachedDate != null) {
250 System.arraycopy(cachedDate, 0, buffer, startPos, dateLength);
251 }
252 }
253
254
255
256 private int writeTime(int ms, final char[] buffer, int pos) {
257 final int hours = ms / 3600000;
258 ms -= 3600000 * hours;
259
260 final int minutes = ms / 60000;
261 ms -= 60000 * minutes;
262
263 final int seconds = ms / 1000;
264 ms -= 1000 * seconds;
265
266
267 int temp = hours / 10;
268 buffer[pos++] = ((char) (temp + '0'));
269
270
271 buffer[pos++] = ((char) (hours - 10 * temp + '0'));
272 buffer[pos] = timeSeparatorChar;
273 pos += timeSeparatorLength;
274
275
276 temp = minutes / 10;
277 buffer[pos++] = ((char) (temp + '0'));
278
279
280 buffer[pos++] = ((char) (minutes - 10 * temp + '0'));
281 buffer[pos] = timeSeparatorChar;
282 pos += timeSeparatorLength;
283
284
285 temp = seconds / 10;
286 buffer[pos++] = ((char) (temp + '0'));
287 buffer[pos++] = ((char) (seconds - 10 * temp + '0'));
288 buffer[pos] = millisSeparatorChar;
289 pos += millisSeparatorLength;
290
291
292 temp = ms / 100;
293 buffer[pos++] = ((char) (temp + '0'));
294
295 ms -= 100 * temp;
296 temp = ms / 10;
297 buffer[pos++] = ((char) (temp + '0'));
298
299 ms -= 10 * temp;
300 buffer[pos++] = ((char) (ms + '0'));
301 return pos;
302 }
303 }