1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.lang3.time;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertNotEquals;
21 import static org.junit.jupiter.api.Assertions.assertNotNull;
22 import static org.junit.jupiter.api.Assertions.assertNotSame;
23 import static org.junit.jupiter.api.Assertions.assertSame;
24 import static org.junit.jupiter.api.Assertions.fail;
25
26 import java.text.FieldPosition;
27 import java.text.Format;
28 import java.text.ParseException;
29 import java.text.ParsePosition;
30 import java.text.SimpleDateFormat;
31 import java.time.Instant;
32 import java.time.LocalDate;
33 import java.time.ZoneId;
34 import java.time.format.DateTimeFormatter;
35 import java.util.Calendar;
36 import java.util.Date;
37 import java.util.Locale;
38 import java.util.TimeZone;
39 import java.util.concurrent.ExecutorService;
40 import java.util.concurrent.Executors;
41 import java.util.concurrent.TimeUnit;
42 import java.util.concurrent.atomic.AtomicInteger;
43 import java.util.concurrent.atomic.AtomicLongArray;
44
45 import org.apache.commons.lang3.AbstractLangTest;
46 import org.junit.jupiter.api.Test;
47 import org.junitpioneer.jupiter.DefaultLocale;
48 import org.junitpioneer.jupiter.DefaultTimeZone;
49
50
51
52
53 class FastDateFormatTest extends AbstractLangTest {
54
55 private static final String ISO_8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZZ";
56
57 private static final int NTHREADS = 10;
58
59 private static final int NROUNDS = 10000;
60
61 final Locale FINNISH = Locale.forLanguageTag("fi");
62 final Locale HUNGARIAN = Locale.forLanguageTag("hu");
63
64 private void assertCalendar(final TimeZone expectedTimeZone, final Date expectedDate, final Calendar actual) {
65 assertSame(expectedTimeZone, actual.getTimeZone());
66
67 assertEquals(expectedDate, actual.getTime());
68 }
69
70 private AtomicLongArray measureTime(final Format printer, final Format parser) throws InterruptedException {
71 final ExecutorService pool = Executors.newFixedThreadPool(NTHREADS);
72 final AtomicInteger failures = new AtomicInteger();
73 final AtomicLongArray totalElapsed = new AtomicLongArray(2);
74 try {
75 for (int i = 0; i < NTHREADS; ++i) {
76 pool.submit(() -> {
77 for (int j = 0; j < NROUNDS; ++j) {
78 try {
79 final Date date = new Date();
80
81 final long t0Millis = System.currentTimeMillis();
82 final String formattedDate = printer.format(date);
83 totalElapsed.addAndGet(0, System.currentTimeMillis() - t0Millis);
84
85 final long t1Millis = System.currentTimeMillis();
86 final Object pd = parser.parseObject(formattedDate);
87 totalElapsed.addAndGet(1, System.currentTimeMillis() - t1Millis);
88
89 if (!date.equals(pd)) {
90 failures.incrementAndGet();
91 }
92 } catch (final Exception e) {
93 failures.incrementAndGet();
94 e.printStackTrace();
95 }
96 }
97 });
98 }
99 } finally {
100 pool.shutdown();
101
102
103
104 if (!pool.awaitTermination(30, TimeUnit.SECONDS)) {
105 pool.shutdownNow();
106 fail("did not complete tasks");
107 }
108 }
109 assertEquals(0, failures.get());
110 return totalElapsed;
111 }
112
113 @DefaultLocale(language = "en", country = "US")
114 @Test
115 void test_changeDefault_Locale_DateInstance() {
116 final FastDateFormat format1 = FastDateFormat.getDateInstance(FastDateFormat.FULL, Locale.GERMANY);
117 final FastDateFormat format2 = FastDateFormat.getDateInstance(FastDateFormat.FULL);
118 Locale.setDefault(Locale.GERMANY);
119 final FastDateFormat format3 = FastDateFormat.getDateInstance(FastDateFormat.FULL);
120
121 assertSame(Locale.GERMANY, format1.getLocale());
122 assertEquals(Locale.US, format2.getLocale());
123 assertSame(Locale.GERMANY, format3.getLocale());
124 assertNotSame(format1, format2);
125 assertNotSame(format2, format3);
126 }
127
128 @DefaultLocale(language = "en", country = "US")
129 @Test
130 void test_changeDefault_Locale_DateTimeInstance() {
131 final FastDateFormat format1 = FastDateFormat.getDateTimeInstance(FastDateFormat.FULL, FastDateFormat.FULL, Locale.GERMANY);
132 final FastDateFormat format2 = FastDateFormat.getDateTimeInstance(FastDateFormat.FULL, FastDateFormat.FULL);
133 Locale.setDefault(Locale.GERMANY);
134 final FastDateFormat format3 = FastDateFormat.getDateTimeInstance(FastDateFormat.FULL, FastDateFormat.FULL);
135
136 assertSame(Locale.GERMANY, format1.getLocale());
137 assertEquals(Locale.US, format2.getLocale());
138 assertSame(Locale.GERMANY, format3.getLocale());
139 assertNotSame(format1, format2);
140 assertNotSame(format2, format3);
141 }
142
143
144
145
146
147
148 @Test
149 void test_getInstance() {
150 final FastDateFormat format1 = FastDateFormat.getInstance();
151 final FastDateFormat format2 = FastDateFormat.getInstance();
152 assertSame(format1, format2);
153 }
154
155 @Test
156 void test_getInstance_String() {
157 final FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy");
158 final FastDateFormat format2 = FastDateFormat.getInstance("MM-DD-yyyy");
159 final FastDateFormat format3 = FastDateFormat.getInstance("MM-DD-yyyy");
160 assertNotSame(format1, format2);
161 assertSame(format2, format3);
162 assertEquals("MM/DD/yyyy", format1.getPattern());
163 assertEquals(TimeZone.getDefault(), format1.getTimeZone());
164 assertEquals(TimeZone.getDefault(), format2.getTimeZone());
165 assertNotNull(FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZ"));
166 }
167
168 @DefaultLocale(language = "en", country = "US")
169 @Test
170 void test_getInstance_String_Locale() {
171 final FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy", Locale.GERMANY);
172 final FastDateFormat format2 = FastDateFormat.getInstance("MM/DD/yyyy");
173 final FastDateFormat format3 = FastDateFormat.getInstance("MM/DD/yyyy", Locale.GERMANY);
174
175 assertNotSame(format1, format2);
176 assertSame(format1, format3);
177 assertEquals(Locale.GERMANY, format1.getLocale());
178 }
179
180 @DefaultLocale(language = "en", country = "US")
181 @DefaultTimeZone("America/New_York")
182 @Test
183 void test_getInstance_String_TimeZone() {
184
185 final FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy",
186 TimeZones.getTimeZone("Atlantic/Reykjavik"));
187 final FastDateFormat format2 = FastDateFormat.getInstance("MM/DD/yyyy");
188 final FastDateFormat format3 = FastDateFormat.getInstance("MM/DD/yyyy", TimeZone.getDefault());
189 final FastDateFormat format4 = FastDateFormat.getInstance("MM/DD/yyyy", TimeZone.getDefault());
190 final FastDateFormat format5 = FastDateFormat.getInstance("MM-DD-yyyy", TimeZone.getDefault());
191 final FastDateFormat format6 = FastDateFormat.getInstance("MM-DD-yyyy");
192
193 assertNotSame(format1, format2);
194 assertEquals(TimeZones.getTimeZone("Atlantic/Reykjavik"), format1.getTimeZone());
195 assertEquals(TimeZone.getDefault(), format2.getTimeZone());
196 assertSame(format3, format4);
197 assertNotSame(format3, format5);
198 assertNotSame(format4, format6);
199 }
200
201 @DefaultLocale(language = "en", country = "US")
202 @DefaultTimeZone("America/New_York")
203 @Test
204 void test_getInstance_String_TimeZone_Locale() {
205 final FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy",
206 TimeZones.getTimeZone("Atlantic/Reykjavik"), Locale.GERMANY);
207 final FastDateFormat format2 = FastDateFormat.getInstance("MM/DD/yyyy", Locale.GERMANY);
208 final FastDateFormat format3 = FastDateFormat.getInstance("MM/DD/yyyy",
209 TimeZone.getDefault(), Locale.GERMANY);
210
211 assertNotSame(format1, format2);
212 assertEquals(TimeZones.getTimeZone("Atlantic/Reykjavik"), format1.getTimeZone());
213 assertEquals(TimeZone.getDefault(), format2.getTimeZone());
214 assertEquals(TimeZone.getDefault(), format3.getTimeZone());
215 assertEquals(Locale.GERMANY, format1.getLocale());
216 assertEquals(Locale.GERMANY, format2.getLocale());
217 assertEquals(Locale.GERMANY, format3.getLocale());
218 }
219
220 @Test
221 void testCheckDefaults() {
222 final FastDateFormat format = FastDateFormat.getInstance();
223 final FastDateFormat medium = FastDateFormat.getDateTimeInstance(FastDateFormat.SHORT, FastDateFormat.SHORT);
224 assertEquals(medium, format);
225
226 final SimpleDateFormat sdf = new SimpleDateFormat();
227 assertEquals(sdf.toPattern(), format.getPattern());
228
229 assertEquals(Locale.getDefault(), format.getLocale());
230 assertEquals(TimeZone.getDefault(), format.getTimeZone());
231 }
232
233 @Test
234 void testCheckDifferingStyles() {
235 final FastDateFormat shortShort = FastDateFormat.getDateTimeInstance(FastDateFormat.SHORT, FastDateFormat.SHORT, Locale.US);
236 final FastDateFormat shortLong = FastDateFormat.getDateTimeInstance(FastDateFormat.SHORT, FastDateFormat.LONG, Locale.US);
237 final FastDateFormat longShort = FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.SHORT, Locale.US);
238 final FastDateFormat longLong = FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.LONG, Locale.US);
239
240 assertNotEquals(shortShort, shortLong);
241 assertNotEquals(shortShort, longShort);
242 assertNotEquals(shortShort, longLong);
243 assertNotEquals(shortLong, longShort);
244 assertNotEquals(shortLong, longLong);
245 assertNotEquals(longShort, longLong);
246 }
247
248 @Test
249 void testDateDefaults() {
250 assertEquals(FastDateFormat.getDateInstance(FastDateFormat.LONG, Locale.CANADA),
251 FastDateFormat.getDateInstance(FastDateFormat.LONG, TimeZone.getDefault(), Locale.CANADA));
252
253 assertEquals(FastDateFormat.getDateInstance(FastDateFormat.LONG, TimeZones.getTimeZone("America/New_York")),
254 FastDateFormat.getDateInstance(FastDateFormat.LONG, TimeZones.getTimeZone("America/New_York"), Locale.getDefault()));
255
256 assertEquals(FastDateFormat.getDateInstance(FastDateFormat.LONG),
257 FastDateFormat.getDateInstance(FastDateFormat.LONG, TimeZone.getDefault(), Locale.getDefault()));
258 }
259
260 @Test
261 void testLang1152() {
262 final TimeZone utc = FastTimeZone.getGmtTimeZone();
263 final Date date = new Date(Long.MAX_VALUE);
264
265 String dateAsString = FastDateFormat.getInstance("yyyy-MM-dd", utc, Locale.US).format(date);
266 assertEquals("292278994-08-17", dateAsString);
267
268 dateAsString = FastDateFormat.getInstance("dd/MM/yyyy", utc, Locale.US).format(date);
269 assertEquals("17/08/292278994", dateAsString);
270 }
271 @Test
272 void testLang1267() {
273 FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
274 }
275
276 @Test
277 void testLang1641() {
278 assertSame(FastDateFormat.getInstance(ISO_8601_DATE_FORMAT), FastDateFormat.getInstance(ISO_8601_DATE_FORMAT));
279
280 assertSame(FastDateFormat.getInstance(ISO_8601_DATE_FORMAT, FastTimeZone.getGmtTimeZone()),
281 FastDateFormat.getInstance(ISO_8601_DATE_FORMAT, FastTimeZone.getGmtTimeZone()));
282
283 assertSame(FastDateFormat.getInstance(ISO_8601_DATE_FORMAT, TimeZone.getDefault()),
284 FastDateFormat.getInstance(ISO_8601_DATE_FORMAT, TimeZone.getDefault()));
285
286 assertNotSame(FastDateFormat.getInstance(ISO_8601_DATE_FORMAT, TimeZones.getTimeZone("Australia/Broken_Hill")),
287 FastDateFormat.getInstance(ISO_8601_DATE_FORMAT, TimeZones.getTimeZone("Australia/Yancowinna")));
288 }
289
290
291
292
293 @Test
294 @DefaultTimeZone("America/Toronto")
295 void testLang1791() {
296 final Instant now = Instant.now();
297 final String pattern = "yyyyMMddHH";
298 final FastDateFormat gmtFormatter = FastDateFormat.getInstance(pattern, TimeZones.GMT);
299 final Calendar gmtCal = Calendar.getInstance(TimeZones.GMT);
300 final TimeZone timeZone = gmtCal.getTimeZone();
301 final Date date = gmtCal.getTime();
302 final String gmtString = gmtFormatter.format(gmtCal);
303
304 assertCalendar(timeZone, date, gmtCal);
305 assertEquals(DateTimeFormatter.ofPattern(pattern).withZone(ZoneId.of("GMT")).format(now), gmtString);
306 final FastDateFormat defaultFormatter = FastDateFormat.getInstance(pattern);
307 final String defaultString = defaultFormatter.format(gmtCal);
308
309 assertCalendar(timeZone, date, gmtCal);
310 assertEquals(DateTimeFormatter.ofPattern(pattern).withZone(ZoneId.systemDefault()).format(now), defaultString);
311 }
312
313
314
315
316 @Test
317 void testLang954() {
318 final String pattern = "yyyy-MM-dd'T'";
319 FastDateFormat.getInstance(pattern);
320 }
321
322
323
324
325
326
327 @Test
328 void testParseCentralEuropeanSummerTime() throws ParseException {
329 assertNotNull(FastDateFormat.getInstance("dd.MM.yyyy HH:mm:ss", Locale.GERMANY).parse("26.10.2014 02:00:00"));
330 assertNotNull(FastDateFormat.getInstance("dd.MM.yyyy HH:mm:ss z", Locale.US).parse("26.10.2014 02:00:00 CEST"));
331 assertNotNull(FastDateFormat.getInstance("dd.MM.yyyy HH:mm:ss z", Locale.GERMANY).parse("26.10.2014 02:00:00 MESZ"));
332 }
333
334 @Test
335 void testParseSync() throws InterruptedException {
336 final String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS";
337 final SimpleDateFormat inner = new SimpleDateFormat(pattern);
338 final Format sdf = new Format() {
339 private static final long serialVersionUID = 1L;
340
341 @Override
342 public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition fieldPosition) {
343 synchronized (this) {
344 return inner.format(obj, toAppendTo, fieldPosition);
345 }
346 }
347
348 @Override
349 public Object parseObject(final String source, final ParsePosition pos) {
350 synchronized (this) {
351 return inner.parseObject(source, pos);
352 }
353 }
354 };
355 final AtomicLongArray sdfTime = measureTime(sdf, sdf);
356
357 final Format fdf = FastDateFormat.getInstance(pattern);
358 final AtomicLongArray fdfTime = measureTime(fdf, fdf);
359
360
361
362 }
363
364 @Test
365 void testStandaloneLongMonthForm() {
366 final TimeZone utc = FastTimeZone.getGmtTimeZone();
367 final Instant testInstant = LocalDate.of(1970, 9, 15).atStartOfDay(ZoneId.of("UTC")).toInstant();
368 final Date date = Date.from(testInstant);
369
370 String dateAsString = FastDateFormat.getInstance("yyyy-LLLL-dd", utc, Locale.GERMAN).format(date);
371 assertEquals("1970-September-15", dateAsString);
372
373 dateAsString = FastDateFormat.getInstance("yyyy-LLLL-dd", utc, FINNISH).format(date);
374 assertEquals("1970-syyskuu-15", dateAsString);
375
376 dateAsString = FastDateFormat.getInstance("yyyy-LLLL-dd", utc, HUNGARIAN).format(date);
377 assertEquals("1970-szeptember-15", dateAsString);
378 }
379
380 @Test
381 void testStandaloneShortMonthForm() {
382 final TimeZone utc = FastTimeZone.getGmtTimeZone();
383 final Instant testInstant = LocalDate.of(1970, 9, 15).atStartOfDay(ZoneId.of("UTC")).toInstant();
384 final Date date = Date.from(testInstant);
385
386 String dateAsString = FastDateFormat.getInstance("yyyy-LLL-dd", utc, Locale.GERMAN).format(date);
387 assertEquals("1970-Sep-15", dateAsString);
388
389 dateAsString = FastDateFormat.getInstance("yyyy-LLL-dd", utc, FINNISH).format(date);
390 assertEquals("1970-syys-15", dateAsString);
391
392 dateAsString = FastDateFormat.getInstance("yyyy-LLL-dd", utc, HUNGARIAN).format(date);
393 assertEquals("1970-szept.-15", dateAsString);
394 }
395
396 @Test
397 void testTimeDateDefaults() {
398 assertEquals(FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, Locale.CANADA),
399 FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, TimeZone.getDefault(), Locale.CANADA));
400
401 assertEquals(FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, TimeZones.getTimeZone("America/New_York")),
402 FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, TimeZones.getTimeZone("America/New_York"), Locale.getDefault()));
403
404 assertEquals(FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM),
405 FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, TimeZone.getDefault(), Locale.getDefault()));
406 }
407
408 @Test
409 void testTimeDefaults() {
410 assertEquals(FastDateFormat.getTimeInstance(FastDateFormat.LONG, Locale.CANADA),
411 FastDateFormat.getTimeInstance(FastDateFormat.LONG, TimeZone.getDefault(), Locale.CANADA));
412
413 assertEquals(FastDateFormat.getTimeInstance(FastDateFormat.LONG, TimeZones.getTimeZone("America/New_York")),
414 FastDateFormat.getTimeInstance(FastDateFormat.LONG, TimeZones.getTimeZone("America/New_York"), Locale.getDefault()));
415
416 assertEquals(FastDateFormat.getTimeInstance(FastDateFormat.LONG),
417 FastDateFormat.getTimeInstance(FastDateFormat.LONG, TimeZone.getDefault(), Locale.getDefault()));
418 }
419 }