• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
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.assertNotSame;
22 import static org.junit.jupiter.api.Assertions.assertSame;
23 import static org.junit.jupiter.api.Assertions.fail;
24 
25 import java.text.FieldPosition;
26 import java.text.Format;
27 import java.text.ParsePosition;
28 import java.text.SimpleDateFormat;
29 import java.time.Instant;
30 import java.time.LocalDate;
31 import java.time.ZoneId;
32 import java.util.Date;
33 import java.util.Locale;
34 import java.util.TimeZone;
35 import java.util.concurrent.ExecutorService;
36 import java.util.concurrent.Executors;
37 import java.util.concurrent.TimeUnit;
38 import java.util.concurrent.atomic.AtomicInteger;
39 import java.util.concurrent.atomic.AtomicLongArray;
40 
41 import org.apache.commons.lang3.AbstractLangTest;
42 import org.junit.jupiter.api.Test;
43 import org.junitpioneer.jupiter.DefaultLocale;
44 import org.junitpioneer.jupiter.DefaultTimeZone;
45 
46 /**
47  * Unit tests {@link org.apache.commons.lang3.time.FastDateFormat}.
48  *
49  * @since 2.0
50  */
51 public class FastDateFormatTest extends AbstractLangTest {
52     private static final int NTHREADS = 10;
53 
54     private static final int NROUNDS = 10000;
55 
56     final Locale FINNISH = Locale.forLanguageTag("fi");
57     final Locale HUNGARIAN = Locale.forLanguageTag("hu");
58 
measureTime(final Format printer, final Format parser)59     private AtomicLongArray measureTime(final Format printer, final Format parser) throws InterruptedException {
60         final ExecutorService pool = Executors.newFixedThreadPool(NTHREADS);
61         final AtomicInteger failures = new AtomicInteger(0);
62         final AtomicLongArray totalElapsed = new AtomicLongArray(2);
63         try {
64             for (int i = 0; i < NTHREADS; ++i) {
65                 pool.submit(() -> {
66                     for (int j = 0; j < NROUNDS; ++j) {
67                         try {
68                             final Date date = new Date();
69 
70                             final long t0Millis = System.currentTimeMillis();
71                             final String formattedDate = printer.format(date);
72                             totalElapsed.addAndGet(0, System.currentTimeMillis() - t0Millis);
73 
74                             final long t1Millis = System.currentTimeMillis();
75                             final Object pd = parser.parseObject(formattedDate);
76                             totalElapsed.addAndGet(1, System.currentTimeMillis() - t1Millis);
77 
78                             if (!date.equals(pd)) {
79                                 failures.incrementAndGet();
80                             }
81                         } catch (final Exception e) {
82                             failures.incrementAndGet();
83                             e.printStackTrace();
84                         }
85                     }
86                 });
87             }
88         } finally {
89             pool.shutdown();
90             // depending on the performance of the machine used to run the parsing,
91             // the tests can run for a while. It should however complete within
92             // 30 seconds. Might need increase on very slow machines.
93             if (!pool.awaitTermination(30, TimeUnit.SECONDS)) {
94                 pool.shutdownNow();
95                 fail("did not complete tasks");
96             }
97         }
98         assertEquals(0, failures.get());
99         return totalElapsed;
100     }
101 
102     @DefaultLocale(language = "en", country = "US")
103     @Test
test_changeDefault_Locale_DateInstance()104     public void test_changeDefault_Locale_DateInstance() {
105         final FastDateFormat format1 = FastDateFormat.getDateInstance(FastDateFormat.FULL, Locale.GERMANY);
106         final FastDateFormat format2 = FastDateFormat.getDateInstance(FastDateFormat.FULL);
107         Locale.setDefault(Locale.GERMANY);
108         final FastDateFormat format3 = FastDateFormat.getDateInstance(FastDateFormat.FULL);
109 
110         assertSame(Locale.GERMANY, format1.getLocale());
111         assertEquals(Locale.US, format2.getLocale());
112         assertSame(Locale.GERMANY, format3.getLocale());
113         assertNotSame(format1, format2);
114         assertNotSame(format2, format3);
115     }
116 
117     @DefaultLocale(language = "en", country = "US")
118     @Test
test_changeDefault_Locale_DateTimeInstance()119     public void test_changeDefault_Locale_DateTimeInstance() {
120         final FastDateFormat format1 = FastDateFormat.getDateTimeInstance(FastDateFormat.FULL, FastDateFormat.FULL, Locale.GERMANY);
121         final FastDateFormat format2 = FastDateFormat.getDateTimeInstance(FastDateFormat.FULL, FastDateFormat.FULL);
122         Locale.setDefault(Locale.GERMANY);
123         final FastDateFormat format3 = FastDateFormat.getDateTimeInstance(FastDateFormat.FULL, FastDateFormat.FULL);
124 
125         assertSame(Locale.GERMANY, format1.getLocale());
126         assertEquals(Locale.US, format2.getLocale());
127         assertSame(Locale.GERMANY, format3.getLocale());
128         assertNotSame(format1, format2);
129         assertNotSame(format2, format3);
130     }
131 
132     /*
133      * Only the cache methods need to be tested here.
134      * The print methods are tested by {@link FastDateFormat_PrinterTest}
135      * and the parse methods are tested by {@link FastDateFormat_ParserTest}
136      */
137     @Test
test_getInstance()138     public void test_getInstance() {
139         final FastDateFormat format1 = FastDateFormat.getInstance();
140         final FastDateFormat format2 = FastDateFormat.getInstance();
141         assertSame(format1, format2);
142     }
143 
144     @Test
test_getInstance_String()145     public void test_getInstance_String() {
146         final FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy");
147         final FastDateFormat format2 = FastDateFormat.getInstance("MM-DD-yyyy");
148         final FastDateFormat format3 = FastDateFormat.getInstance("MM-DD-yyyy");
149 
150         assertNotSame(format1, format2);
151         assertSame(format2, format3);
152         assertEquals("MM/DD/yyyy", format1.getPattern());
153         assertEquals(TimeZone.getDefault(), format1.getTimeZone());
154         assertEquals(TimeZone.getDefault(), format2.getTimeZone());
155     }
156 
157     @DefaultLocale(language = "en", country = "US")
158     @Test
test_getInstance_String_Locale()159     public void test_getInstance_String_Locale() {
160         final FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy", Locale.GERMANY);
161         final FastDateFormat format2 = FastDateFormat.getInstance("MM/DD/yyyy");
162         final FastDateFormat format3 = FastDateFormat.getInstance("MM/DD/yyyy", Locale.GERMANY);
163 
164         assertNotSame(format1, format2);
165         assertSame(format1, format3);
166         assertEquals(Locale.GERMANY, format1.getLocale());
167     }
168 
169     @DefaultLocale(language = "en", country = "US")
170     @DefaultTimeZone("America/New_York")
171     @Test
test_getInstance_String_TimeZone()172     public void test_getInstance_String_TimeZone() {
173 
174         final FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy",
175                 TimeZone.getTimeZone("Atlantic/Reykjavik"));
176         final FastDateFormat format2 = FastDateFormat.getInstance("MM/DD/yyyy");
177         final FastDateFormat format3 = FastDateFormat.getInstance("MM/DD/yyyy", TimeZone.getDefault());
178         final FastDateFormat format4 = FastDateFormat.getInstance("MM/DD/yyyy", TimeZone.getDefault());
179         final FastDateFormat format5 = FastDateFormat.getInstance("MM-DD-yyyy", TimeZone.getDefault());
180         final FastDateFormat format6 = FastDateFormat.getInstance("MM-DD-yyyy");
181 
182         assertNotSame(format1, format2);
183         assertEquals(TimeZone.getTimeZone("Atlantic/Reykjavik"), format1.getTimeZone());
184         assertEquals(TimeZone.getDefault(), format2.getTimeZone());
185         assertSame(format3, format4);
186         assertNotSame(format3, format5);
187         assertNotSame(format4, format6);
188     }
189 
190     @DefaultLocale(language = "en", country = "US")
191     @DefaultTimeZone("America/New_York")
192     @Test
test_getInstance_String_TimeZone_Locale()193     public void test_getInstance_String_TimeZone_Locale() {
194         final FastDateFormat format1 = FastDateFormat.getInstance("MM/DD/yyyy",
195                 TimeZone.getTimeZone("Atlantic/Reykjavik"), Locale.GERMANY);
196         final FastDateFormat format2 = FastDateFormat.getInstance("MM/DD/yyyy", Locale.GERMANY);
197         final FastDateFormat format3 = FastDateFormat.getInstance("MM/DD/yyyy",
198                 TimeZone.getDefault(), Locale.GERMANY);
199 
200         assertNotSame(format1, format2);
201         assertEquals(TimeZone.getTimeZone("Atlantic/Reykjavik"), format1.getTimeZone());
202         assertEquals(TimeZone.getDefault(), format2.getTimeZone());
203         assertEquals(TimeZone.getDefault(), format3.getTimeZone());
204         assertEquals(Locale.GERMANY, format1.getLocale());
205         assertEquals(Locale.GERMANY, format2.getLocale());
206         assertEquals(Locale.GERMANY, format3.getLocale());
207     }
208 
209     @Test
testCheckDefaults()210     public void testCheckDefaults() {
211         final FastDateFormat format = FastDateFormat.getInstance();
212         final FastDateFormat medium = FastDateFormat.getDateTimeInstance(FastDateFormat.SHORT, FastDateFormat.SHORT);
213         assertEquals(medium, format);
214 
215         final SimpleDateFormat sdf = new SimpleDateFormat();
216         assertEquals(sdf.toPattern(), format.getPattern());
217 
218         assertEquals(Locale.getDefault(), format.getLocale());
219         assertEquals(TimeZone.getDefault(), format.getTimeZone());
220     }
221 
222     @Test
testCheckDifferingStyles()223     public void testCheckDifferingStyles() {
224         final FastDateFormat shortShort = FastDateFormat.getDateTimeInstance(FastDateFormat.SHORT, FastDateFormat.SHORT, Locale.US);
225         final FastDateFormat shortLong = FastDateFormat.getDateTimeInstance(FastDateFormat.SHORT, FastDateFormat.LONG, Locale.US);
226         final FastDateFormat longShort = FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.SHORT, Locale.US);
227         final FastDateFormat longLong = FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.LONG, Locale.US);
228 
229         assertNotEquals(shortShort, shortLong);
230         assertNotEquals(shortShort, longShort);
231         assertNotEquals(shortShort, longLong);
232         assertNotEquals(shortLong, longShort);
233         assertNotEquals(shortLong, longLong);
234         assertNotEquals(longShort, longLong);
235     }
236 
237     @Test
testDateDefaults()238     public void testDateDefaults() {
239         assertEquals(FastDateFormat.getDateInstance(FastDateFormat.LONG, Locale.CANADA),
240                 FastDateFormat.getDateInstance(FastDateFormat.LONG, TimeZone.getDefault(), Locale.CANADA));
241 
242         assertEquals(FastDateFormat.getDateInstance(FastDateFormat.LONG, TimeZone.getTimeZone("America/New_York")),
243                 FastDateFormat.getDateInstance(FastDateFormat.LONG, TimeZone.getTimeZone("America/New_York"), Locale.getDefault()));
244 
245         assertEquals(FastDateFormat.getDateInstance(FastDateFormat.LONG),
246                 FastDateFormat.getDateInstance(FastDateFormat.LONG, TimeZone.getDefault(), Locale.getDefault()));
247     }
248 
249     @Test
testLANG_1152()250     public void testLANG_1152() {
251         final TimeZone utc = FastTimeZone.getGmtTimeZone();
252         final Date date = new Date(Long.MAX_VALUE);
253 
254         String dateAsString = FastDateFormat.getInstance("yyyy-MM-dd", utc, Locale.US).format(date);
255         assertEquals("292278994-08-17", dateAsString);
256 
257         dateAsString = FastDateFormat.getInstance("dd/MM/yyyy", utc, Locale.US).format(date);
258         assertEquals("17/08/292278994", dateAsString);
259     }
260     @Test
testLANG_1267()261     public void testLANG_1267() {
262         FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
263     }
264 
265     /**
266      * According to LANG-954 (https://issues.apache.org/jira/browse/LANG-954) this is broken in Android 2.1.
267      */
268     @Test
testLANG_954()269     public void testLANG_954() {
270         final String pattern = "yyyy-MM-dd'T'";
271         FastDateFormat.getInstance(pattern);
272     }
273 
274     @Test
testParseSync()275     public void testParseSync() throws InterruptedException {
276         final String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS";
277         final SimpleDateFormat inner = new SimpleDateFormat(pattern);
278         final Format sdf= new Format() {
279             private static final long serialVersionUID = 1L;
280 
281             @Override
282             public StringBuffer format(final Object obj,
283                     final StringBuffer toAppendTo,
284                     final FieldPosition fieldPosition) {
285                 synchronized(this) {
286                     return inner.format(obj, toAppendTo, fieldPosition);
287                 }
288             }
289 
290             @Override
291             public Object parseObject(final String source, final ParsePosition pos) {
292                 synchronized(this) {
293                     return inner.parseObject(source, pos);
294                 }
295             }
296         };
297         final AtomicLongArray sdfTime= measureTime(sdf, sdf);
298 
299         final Format fdf = FastDateFormat.getInstance(pattern);
300         final AtomicLongArray fdfTime= measureTime(fdf, fdf);
301 
302         //System.out.println(">>FastDateFormatTest: FastDatePrinter:"+fdfTime.get(0)+"  SimpleDateFormat:"+sdfTime.get(0));
303         //System.out.println(">>FastDateFormatTest: FastDateParser:"+fdfTime.get(1)+"  SimpleDateFormat:"+sdfTime.get(1));
304     }
305 
306     @Test
testTimeDateDefaults()307     public void testTimeDateDefaults() {
308         assertEquals(FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, Locale.CANADA),
309                 FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, TimeZone.getDefault(), Locale.CANADA));
310 
311         assertEquals(FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, TimeZone.getTimeZone("America/New_York")),
312                 FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, TimeZone.getTimeZone("America/New_York"), Locale.getDefault()));
313 
314         assertEquals(FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM),
315                 FastDateFormat.getDateTimeInstance(FastDateFormat.LONG, FastDateFormat.MEDIUM, TimeZone.getDefault(), Locale.getDefault()));
316     }
317 
318     @Test
testTimeDefaults()319     public void testTimeDefaults() {
320         assertEquals(FastDateFormat.getTimeInstance(FastDateFormat.LONG, Locale.CANADA),
321                 FastDateFormat.getTimeInstance(FastDateFormat.LONG, TimeZone.getDefault(), Locale.CANADA));
322 
323         assertEquals(FastDateFormat.getTimeInstance(FastDateFormat.LONG, TimeZone.getTimeZone("America/New_York")),
324                 FastDateFormat.getTimeInstance(FastDateFormat.LONG, TimeZone.getTimeZone("America/New_York"), Locale.getDefault()));
325 
326         assertEquals(FastDateFormat.getTimeInstance(FastDateFormat.LONG),
327                 FastDateFormat.getTimeInstance(FastDateFormat.LONG, TimeZone.getDefault(), Locale.getDefault()));
328     }
329 
330     @Test
testStandaloneShortMonthForm()331     public void testStandaloneShortMonthForm() {
332         final TimeZone utc = FastTimeZone.getGmtTimeZone();
333         final Instant testInstant = LocalDate.of(1970, 9, 15).atStartOfDay(ZoneId.of("UTC")).toInstant();
334         final Date date = Date.from(testInstant);
335 
336         String dateAsString = FastDateFormat.getInstance("yyyy-LLL-dd", utc, Locale.GERMAN).format(date);
337         assertEquals("1970-Sep-15", dateAsString);
338 
339         dateAsString = FastDateFormat.getInstance("yyyy-LLL-dd", utc, FINNISH).format(date);
340         assertEquals("1970-syys-15", dateAsString);
341 
342         dateAsString = FastDateFormat.getInstance("yyyy-LLL-dd", utc, HUNGARIAN).format(date);
343         assertEquals("1970-szept.-15", dateAsString);
344     }
345 
346     @Test
testStandaloneLongMonthForm()347     public void testStandaloneLongMonthForm() {
348         final TimeZone utc = FastTimeZone.getGmtTimeZone();
349         final Instant testInstant = LocalDate.of(1970, 9, 15).atStartOfDay(ZoneId.of("UTC")).toInstant();
350         final Date date = Date.from(testInstant);
351 
352         String dateAsString = FastDateFormat.getInstance("yyyy-LLLL-dd", utc, Locale.GERMAN).format(date);
353         assertEquals("1970-September-15", dateAsString);
354 
355         dateAsString = FastDateFormat.getInstance("yyyy-LLLL-dd", utc, FINNISH).format(date);
356         assertEquals("1970-syyskuu-15", dateAsString);
357 
358         dateAsString = FastDateFormat.getInstance("yyyy-LLLL-dd", utc, HUNGARIAN).format(date);
359         assertEquals("1970-szeptember-15", dateAsString);
360     }
361 }
362