1 package emissary.util;
2
3 import emissary.test.core.junit5.UnitTest;
4
5 import jakarta.annotation.Nullable;
6 import org.junit.jupiter.api.BeforeAll;
7 import org.junit.jupiter.api.Test;
8
9 import java.time.LocalDateTime;
10 import java.time.ZoneOffset;
11
12 import static org.junit.jupiter.api.Assertions.assertEquals;
13 import static org.junit.jupiter.api.Assertions.assertNull;
14
15 class DateTimeFormatParserTest extends UnitTest {
16
17 private static final long EXPECTED_FULL = 1451931630;
18 private static final long EXPECTED_NO_TIME = 1451865600;
19 private static final long EXPECTED_NO_SECS = 1451931600;
20 private static final long EXPECTED_NO_HR_SEC = 1451866800;
21 private static final long EXPECTED_ALT_TIME = 1451894523;
22 private static final long EXPECTED_ALT_TIME_NO_SECS = 1451894520;
23
24 @BeforeAll
25 public static void setupClass() {
26
27
28 UnitTest.setupSystemProperties();
29 }
30
31
32
33
34
35
36
37
38 private static void test(@Nullable String date, long expected, String msg) {
39 LocalDateTime unknownParse = DateTimeFormatParser.parseDate(date, false);
40 assertEquals(expected, unknownParse == null ? 0L : unknownParse.toEpochSecond(ZoneOffset.UTC), "Error on: " + msg);
41 }
42
43
44
45
46
47
48
49 private static void test(String date, long expected) {
50 long unknownParse = DateTimeFormatParser.parseDate(date, false).toEpochSecond(ZoneOffset.UTC);
51 assertEquals(expected, unknownParse, "Flexible parse failed");
52
53 long knownParse = DateTimeFormatParser.parseDate(date, false).toEpochSecond(ZoneOffset.UTC);
54 assertEquals(expected, knownParse, "Manual parse failed");
55
56
57 assertEquals(unknownParse, knownParse, "Parsed date/times are not the same");
58 }
59
60
61
62
63
64
65
66
67 @Test
68 void stripThreeLetterTimeZonesWhenThereIsAnOffset() {
69
70 test("Mon, 4 Jan 2016 13:20:30 EST", EXPECTED_FULL);
71
72
73 test("Mon, 4 Jan 2016 18:20:30 +0000(EST)", EXPECTED_FULL);
74 test("Mon, 4 Jan 2016 16:20:30 -0200(EST)", EXPECTED_FULL);
75 test("Mon, 4 Jan 2016 18:20:30 +0000 (EST)", EXPECTED_FULL);
76 test("Mon, 4 Jan 2016 18:20:30 +0000EST", EXPECTED_FULL);
77 test("Mon, 4 Jan 2016 18:20:30 +0000 EST", EXPECTED_FULL);
78 test("Mon, 4 Jan 2016 18:20:30 EST+0000", EXPECTED_FULL);
79 test("Mon, 4 Jan 2016 18:20:30 EST +0000", EXPECTED_FULL);
80 test("Mon, 4 Jan 2016 18:20:30EST+0000", EXPECTED_FULL);
81 test("Mon, 4 Jan 2016 18:20:30EST +0000", EXPECTED_FULL);
82 }
83
84 @Test
85 void parse_yyyyMMddTHHmmssSSSX() {
86 test("2016-01-04T18:20:30.000Z", EXPECTED_FULL);
87 test("2016-01-04T18:20:30Z", EXPECTED_FULL);
88 test("2016-01-04T18:20:30+00:00", EXPECTED_FULL);
89 test("2016-01-04T13:20:30-05:00", EXPECTED_FULL);
90 test("2016-01-04T18:20:30+0000", EXPECTED_FULL);
91 test("2016-01-04T13:20:30-0500", EXPECTED_FULL);
92 test("2016-01-04 18:20:30", EXPECTED_FULL);
93 test("2016-01-04 18:20:30+0000", EXPECTED_FULL);
94 test("2016-01-04 18:20:30 +0000", EXPECTED_FULL);
95 test("2016-01-04 18:20:30 GMT+0000", EXPECTED_FULL);
96 test("2016-01-04 18:20:30 GMT", EXPECTED_FULL);
97 test("2016-01-04 18:20", EXPECTED_NO_SECS);
98 test("2016-01-04/18/20", EXPECTED_NO_SECS);
99 test("2016-01-04", EXPECTED_NO_TIME);
100 test("2016-1-4T8:2:3.000Z", EXPECTED_ALT_TIME);
101 test("2016-1-4 8:2:3.000", EXPECTED_ALT_TIME);
102 test("2016-1-4 8:2:3", EXPECTED_ALT_TIME);
103 test("2016-1-4T8:2:3Z", EXPECTED_ALT_TIME);
104 test("2016-01-04T18:20:30", EXPECTED_FULL);
105 test("2016-1-4T8:2:3+00:00", EXPECTED_ALT_TIME);
106 test("2016-1-4T3:2:3-05:00", EXPECTED_ALT_TIME);
107 test("2016-1-4T8:2:3+0000", EXPECTED_ALT_TIME);
108 test("2016-1-4T3:2:3-0500", EXPECTED_ALT_TIME);
109 test("2016-01-04 18:20", EXPECTED_NO_SECS);
110 test("2016-01-04 18:20 GMT", EXPECTED_NO_SECS);
111 test("2016-01-04 18:20 +00:00", EXPECTED_NO_SECS);
112 test("2016-01-04 18:20 +0000", EXPECTED_NO_SECS);
113 test("2016-1-4 8:2", EXPECTED_ALT_TIME_NO_SECS);
114 test("2016-01-04", EXPECTED_NO_TIME);
115 test("2016-1-4", EXPECTED_NO_TIME);
116 }
117
118 @Test
119 void parse_EdMMMyyHmmssZ() {
120 test("Mon, 4 Jan 16 18:20:30 +0000", EXPECTED_FULL);
121 test("Mon, 4 Jan 16 18:20:30+0000", EXPECTED_FULL);
122 test("Mon, 4 Jan 16 18:20:30 GMT+0000", EXPECTED_FULL);
123 test("Mon, 4 Jan 16 13:20:30 -0500", EXPECTED_FULL);
124 test("Mon, 4 Jan 16 18:20:30", EXPECTED_FULL);
125 test("Mon, 4 Jan 16 8:20:30 -1000", EXPECTED_FULL);
126 test("Mon, 4 Jan 16", EXPECTED_NO_TIME);
127 test("Mon,4 Jan 16", EXPECTED_NO_TIME);
128 test("Mon, 4Jan16", EXPECTED_NO_TIME);
129 test("4 Jan 16 18:20 UTC", EXPECTED_NO_SECS);
130 test("4 Jan 16 13:20 -0500", EXPECTED_NO_SECS);
131 test("4 Jan 16 18:20", EXPECTED_NO_SECS);
132 test("4 Jan 16 18:20 +0000", EXPECTED_NO_SECS);
133 test("4 Jan 16 18:20+0000", EXPECTED_NO_SECS);
134 test("4 Jan 16 18:20 +00:00", EXPECTED_NO_SECS);
135 test("4 Jan 16", EXPECTED_NO_TIME);
136 test("4Jan16", EXPECTED_NO_TIME);
137 }
138
139
140 @Test
141 void parse_EdMMMyyyyKmmssaZ() {
142 test("Mon, 4 Jan 2016 06:20:30 PM +0000", EXPECTED_FULL);
143 test("Mon, 4 Jan 2016 06:20:30 PM GMT+0000", EXPECTED_FULL);
144 test("Mon, 4 Jan 2016 06:20:30 PM GMT", EXPECTED_FULL);
145 test("Mon, 4 Jan 2016 01:20:30 PM -0500", EXPECTED_FULL);
146 test("Mon, 4 Jan 2016 1:20:30 PM -0500", EXPECTED_FULL);
147 test("Sun, 3 Jan 2016 7:20:00 PM -0500", EXPECTED_NO_HR_SEC);
148 test("Mon, 4 Jan 2016 0:20:00 AM", EXPECTED_NO_HR_SEC);
149 test("Mon,4 Jan 2016 06:20:30 PM", EXPECTED_FULL);
150 test("4 Jan 2016 06:20:30 PM", EXPECTED_FULL);
151 test("4 Jan 2016 06:20:30 PM +0000", EXPECTED_FULL);
152 }
153
154 @Test
155 void parse_EdMMMyyyyHmmssZz() {
156 test("Mon, 4 Jan 2016 18:20:30 +0000 (Europe/Dublin)", EXPECTED_FULL);
157 test("Mon, 4 Jan 2016 18:20:30 +0000 (Zulu)", EXPECTED_FULL);
158 test("Mon, 4 Jan 2016 18:20:30 +0000 (UTC)", EXPECTED_FULL);
159 test("Mon, 4 Jan 2016 18:20:30 +0000 (GMT)", EXPECTED_FULL);
160 test("Mon, 4 Jan 2016 13:20:30 -0500 (EST)", EXPECTED_FULL);
161 test("Mon, 4 Jan 2016 13:20:30 -0500 (US/Eastern)", EXPECTED_FULL);
162 test("Mon, 4 Jan 2016 18:20:30 +0000", EXPECTED_FULL);
163 test("Mon, 4 Jan 2016 8:20:30 -1000", EXPECTED_FULL);
164 test("Mon, 4 Jan 2016 13:20:30 -0500", EXPECTED_FULL);
165 test("Mon, 4 Jan 2016 18:20:30 UTC", EXPECTED_FULL);
166 test("Mon, 4 Jan 2016 18:20:30 GMT", EXPECTED_FULL);
167 test("Mon, 4 Jan 2016 18:20:30 GMT+0000", EXPECTED_FULL);
168 test("Mon, 4 Jan 2016 13:20:30 -0500", EXPECTED_FULL);
169 test("Mon, 4 Jan 2016 0:20:00 +0000", EXPECTED_NO_HR_SEC);
170 test("Mon, 4 Jan 2016 0:20:00 AM", EXPECTED_NO_HR_SEC);
171 test("Sun, 3 Jan 2016 19:20:00 PM -0500", EXPECTED_NO_HR_SEC);
172 test("Mon, 4 Jan 2016 18:20:30", EXPECTED_FULL);
173 test("Mon, 4 Jan 2016 18:20 +0000", EXPECTED_NO_SECS);
174 test("Mon, 4 Jan 2016 13:20 -0500", EXPECTED_NO_SECS);
175 test("Mon, 4 Jan. 2016 18:20:30 +0000", EXPECTED_FULL);
176 test("Mon, 4 Jan. 2016 13:20:30 -0500", EXPECTED_FULL);
177 test("Mon 4 Jan. 2016 18:20:30 +0000", EXPECTED_FULL);
178 test("Mon 4 Jan. 2016 18:20:30+0000", EXPECTED_FULL);
179 test("Mon 4 Jan. 2016 13:20:30 -0500", EXPECTED_FULL);
180 test("Mon, 4 Jan, 2016 18:20:30 PM", EXPECTED_FULL);
181 test("Mon, 4 Jan, 2016", EXPECTED_NO_TIME);
182 test("Mon 4Jan2016", EXPECTED_NO_TIME);
183 test("Mon, 4Jan2016", EXPECTED_NO_TIME);
184 test("4 Jan 2016 18:20:30 +0000", EXPECTED_FULL);
185 test("4 Jan 2016 18:20:30+0000", EXPECTED_FULL);
186 test("4 Jan 2016 13:20:30 -0500", EXPECTED_FULL);
187 test("4 Jan 2016 18:20 UTC", EXPECTED_NO_SECS);
188 test("4 Jan 2016 13:20 -0500", EXPECTED_NO_SECS);
189 test("4 Jan 2016 18:20", EXPECTED_NO_SECS);
190 test("4 Jan 2016", EXPECTED_NO_TIME);
191 test("4Jan2016", EXPECTED_NO_TIME);
192 }
193
194 @Test
195 void parse_EMMMdyyyyKmma() {
196 test("Mon, Jan 4, 2016 06:20 PM", EXPECTED_NO_SECS);
197 test("Mon, Jan 4, 2016 6:20 PM", EXPECTED_NO_SECS);
198 test("Mon, Jan 04, 2016 06:20 PM", EXPECTED_NO_SECS);
199 test("Mon Jan 04, 2016 06:20 PM", EXPECTED_NO_SECS);
200 test("Mon Jan 04 2016 06:20 PM", EXPECTED_NO_SECS);
201 test("Mon,Jan 04 2016 06:20 PM", EXPECTED_NO_SECS);
202 }
203
204 @Test
205 void parse_EMMMdyyyyHmmssz() {
206 test("Mon, Jan 4, 2016 18:20:30 UTC", EXPECTED_FULL);
207 test("Mon, Jan 04, 2016 18:20:30 UTC", EXPECTED_FULL);
208 test("Mon, Jan 4, 2016 13:20:30 -0500", EXPECTED_FULL);
209 test("Mon, Jan 04, 2016 13:20:30 -0500", EXPECTED_FULL);
210 test("Mon, Jan 4, 2016 18:20:30", EXPECTED_FULL);
211 test("Mon, Jan 04, 2016 18:20:30", EXPECTED_FULL);
212 test("Mon Jan 04 2016 18:20:30", EXPECTED_FULL);
213 test("Mon Jan 04 2016 18:20:30 UTC", EXPECTED_FULL);
214 test("Mon Jan 04 2016 13:20:30 -0500", EXPECTED_FULL);
215 test("Mon Jan 04 2016 8:20:30 -1000", EXPECTED_FULL);
216 test("Mon, Jan 4, 2016, 18:20:30 PM +0000", EXPECTED_FULL);
217 test("Mon, Jan 4, 2016, 18:20:30 PM GMT+0000", EXPECTED_FULL);
218 test("Mon, Jan 4, 2016, 13:20:30 PM -0500", EXPECTED_FULL);
219 test("Mon, Jan 4, 2016, 18:20:30 PM UTC", EXPECTED_FULL);
220 test("Mon, Jan 4, 2016, 18:20:30 PM", EXPECTED_FULL);
221 test("Mon, Jan 4, 2016, 18:20:30", EXPECTED_FULL);
222 test("Mon, Jan 4, 2016", EXPECTED_NO_TIME);
223 test("Jan 04, 2016 18:20:30", EXPECTED_FULL);
224 test("Jan 04, 2016, 18:20:30", EXPECTED_FULL);
225 test("Jan 04 2016 18:20:30", EXPECTED_FULL);
226 test("Jan 04 2016 18:20:30 PM", EXPECTED_FULL);
227 test("Jan 04 2016 18:20:30 +0000", EXPECTED_FULL);
228 test("Jan 04 2016 18:20:30 GMT", EXPECTED_FULL);
229 test("Jan 04 2016 18:20:30", EXPECTED_FULL);
230 test("Jan 4 2016 18:20:30", EXPECTED_FULL);
231 test("Jan 4, 2016", EXPECTED_NO_TIME);
232 }
233
234 @Test
235 void parse_EddMMMyyyyHmmssZ() {
236 test("Mon 04-Jan-2016 18:20:30 +0000", EXPECTED_FULL);
237 test("Mon 04-Jan-2016 18:20:30 GMT+0000", EXPECTED_FULL);
238 test("Mon 04-Jan-2016 18:20:30 GMT", EXPECTED_FULL);
239 test("Mon 04-Jan-2016 13:20:30 -0500", EXPECTED_FULL);
240 test("Mon 04-Jan-2016 18:20:30", EXPECTED_FULL);
241 test("Mon 04-Jan-2016 8:20:30 -1000", EXPECTED_FULL);
242 test("Mon 04-Jan-2016", EXPECTED_NO_TIME);
243 test("Mon, 04-Jan-2016", EXPECTED_NO_TIME);
244 test("Mon,04-Jan-2016", EXPECTED_NO_TIME);
245 test("04-Jan-2016 18:20:30 +0000", EXPECTED_FULL);
246 test("04-Jan-2016 18:20:30 GMT+0000", EXPECTED_FULL);
247 test("04-Jan-2016 18:20:30 GMT", EXPECTED_FULL);
248 test("04-Jan-2016 13:20:30 -0500", EXPECTED_FULL);
249 test("04-Jan-2016 18:20:30", EXPECTED_FULL);
250 test("04-Jan-2016", EXPECTED_NO_TIME);
251 }
252
253 @Test
254 void parse_EMMMdHHmmsszzzyyyy() {
255 test("Mon Jan 04 18:20:30 GMT 2016", EXPECTED_FULL);
256 test("Mon Jan 04 13:20:30 EST 2016", EXPECTED_FULL);
257 test("Mon Jan 04 13:20 EST 2016", EXPECTED_NO_SECS);
258 test("Mon Jan 04 18:20:30 2016", EXPECTED_FULL);
259 test("Mon Jan 4 18:20:30 2016", EXPECTED_FULL);
260 test("Mon Jan 4 18:20 2016", EXPECTED_NO_SECS);
261 test("Mon, Jan 4 18:20 2016", EXPECTED_NO_SECS);
262 test("Mon,Jan 4 18:20 2016", EXPECTED_NO_SECS);
263 test("Jan 4 18:20 2016", EXPECTED_NO_SECS);
264 test("Jan 04 18:20:30 GMT 2016", EXPECTED_FULL);
265 test("Jan 04 13:20:30 EST 2016", EXPECTED_FULL);
266 test("Jan 04 13:20 EST 2016", EXPECTED_NO_SECS);
267 test("Jan 04 18:20:30 2016", EXPECTED_FULL);
268 }
269
270 @Test
271 void parse_MdyyKmma() {
272 test("01/04/16 06:20 PM", EXPECTED_NO_SECS);
273 test("1/4/16 6:20 PM", EXPECTED_NO_SECS);
274 test("01/04/16 06:20:30 PM", EXPECTED_FULL);
275 test("1/4/16 06:20:30 PM", EXPECTED_FULL);
276 test("01/04/16 00:20 AM", EXPECTED_NO_HR_SEC);
277 test("01/04/1606:20 PM", EXPECTED_NO_SECS);
278 test("01/04/1606:20:30 PM", EXPECTED_FULL);
279 test("01/04/1600:20 AM", EXPECTED_NO_HR_SEC);
280 }
281
282 @Test
283 void parse_MdyyHmmssaz() {
284 test("01/04/16 18:20:30 GMT", EXPECTED_FULL);
285 test("1/4/16 18:20:30 GMT", EXPECTED_FULL);
286 test("01/04/16 18:20:30 PM +0000", EXPECTED_FULL);
287 test("1/4/16 18:20:30 PM +0000", EXPECTED_FULL);
288 test("1/4/16 8:20:30 AM -1000", EXPECTED_FULL);
289 test("1/4/16 8:20:30 -1000", EXPECTED_FULL);
290 test("01/04/16 18:20:30 PM GMT", EXPECTED_FULL);
291 test("1/4/16 18:20:30 PM GMT", EXPECTED_FULL);
292 test("01/04/16 18:20:30 PM GMT+0000", EXPECTED_FULL);
293 test("1/4/16 18:20:30 PM GMT+0000", EXPECTED_FULL);
294 test("01/04/16 18:20:30 PM", EXPECTED_FULL);
295 test("01/04/16 18:20:30", EXPECTED_FULL);
296 test("01/04/16 18:20", EXPECTED_NO_SECS);
297 test("1/4/16 18:20", EXPECTED_NO_SECS);
298 test("01/04/1618:20:30GMT", EXPECTED_FULL);
299 test("01/04/1618:20:30PM+0000", EXPECTED_FULL);
300 test("01/04/1618:20:30PMGMT", EXPECTED_FULL);
301 test("01/04/1618:20:30PM", EXPECTED_FULL);
302 test("01/04/1618:20:30", EXPECTED_FULL);
303 test("01/04/1618:20", EXPECTED_NO_SECS);
304 }
305
306 @Test
307 void parse_HHmmddMMyyyy() {
308 test("04-01-2016", EXPECTED_NO_TIME);
309 test("04.01.2016", EXPECTED_NO_TIME);
310 test("04/01/2016", EXPECTED_NO_TIME);
311 test("182004012016", EXPECTED_NO_SECS);
312 }
313
314 @Test
315 void parse_yyyyMMddHHmmssS() {
316 test("2016/01/04 18:20:30.0", EXPECTED_FULL);
317 test("2016/01/0418:20:30.0", EXPECTED_FULL);
318 test("2016/01/041820300", EXPECTED_FULL);
319 test("2016/01/04182030", EXPECTED_FULL);
320 test("2016/01/04 18:20:30", EXPECTED_FULL);
321 test("2016/01/04 18:20:30 +0000", EXPECTED_FULL);
322 test("2016/01/04 18:20:30 GMT+0000", EXPECTED_FULL);
323 test("2016/01/04 18:20:30 GMT", EXPECTED_FULL);
324 test("2016/01/04 18:20:30+0000", EXPECTED_FULL);
325 test("2016/01/0418:20:30+0000", EXPECTED_FULL);
326 test("2016/01/04 182030", EXPECTED_FULL);
327 test("2016/01/041820", EXPECTED_NO_SECS);
328 test("2016/01/04", EXPECTED_NO_TIME);
329 }
330
331 @Test
332 void parse_yyyy_MM_ddHHmmssS() {
333 test("2016:01:04 18:20:30.0", EXPECTED_FULL);
334 test("2016:01:04 18:20:30", EXPECTED_FULL);
335 test("2016:01:04 18:20:30 +0000", EXPECTED_FULL);
336 test("2016:01:04 18:20:30 GMT+0000", EXPECTED_FULL);
337 test("2016:01:04 18:20:30 GMT", EXPECTED_FULL);
338 test("2016:01:04 18:20:30+0000", EXPECTED_FULL);
339 test("2016:01:04 18:20", EXPECTED_NO_SECS);
340 test("2016:01:04", EXPECTED_NO_TIME);
341 }
342
343 @Test
344 void parse_yyyyMMddHHmmss() {
345 test("20160104182030", EXPECTED_FULL);
346 }
347
348 @Test
349 void parse_yyyyMMdd() {
350 test("20160104", EXPECTED_NO_TIME);
351 }
352
353 @Test
354 void parse_yyyyDDDHHmmss() {
355 test("2016004182030", EXPECTED_FULL);
356 }
357
358 @Test
359 void parse_yyyyDDDHHmm() {
360 test("20160041820", EXPECTED_NO_SECS);
361 }
362
363 @Test
364 void parse_yyyyDDD() {
365 test("2016004", EXPECTED_NO_TIME);
366 }
367
368 @Test
369 void parse_yyyy_DDD() {
370 test("2016-004", EXPECTED_NO_TIME);
371 }
372
373
374 @Test
375 void testCleanDateString() {
376
377 test("2016-01-04\t\t18:20", EXPECTED_NO_SECS, "TABS");
378 test("2016-01-04 18:20", EXPECTED_NO_SECS, "SPACES");
379 test("2016-01-04 18:20=0D", EXPECTED_NO_SECS, "qp'ified ending");
380 }
381
382
383 @Test
384 void testBad() {
385 test("", 0L, "EMPTY");
386 test(null, 0L, "NULL");
387 assertNull(DateTimeFormatParser.parseDate("1234", false));
388 assertNull(DateTimeFormatParser.parseDate("1234", false));
389 test("17.Mar.2016", 0L, "UNKNOWN");
390 test("Mon, 2 Feb 2017 06:20:30 PM +0000", 0L, "UNKNOWN");
391 }
392 }