1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package libcore.libcore.icu;
18 
19 import android.icu.util.Calendar;
20 import android.icu.util.TimeZone;
21 import android.icu.util.ULocale;
22 
23 import java.util.function.BiFunction;
24 
25 import static android.icu.util.TimeZone.GMT_ZONE;
26 import static android.icu.util.ULocale.ENGLISH;
27 import static libcore.icu.DateIntervalFormat.formatDateRange;
28 import static libcore.icu.DateUtilsBridge.*;
29 
30 public class DateIntervalFormatTest extends junit.framework.TestCase {
31   private static final long MINUTE = 60 * 1000;
32   private static final long HOUR = 60 * MINUTE;
33   private static final long DAY = 24 * HOUR;
34   private static final long MONTH = 31 * DAY;
35   private static final long YEAR = 12 * MONTH;
36 
37   // These are the old CTS tests for DateIntervalFormat.formatDateRange.
test_formatDateInterval()38   public void test_formatDateInterval() throws Exception {
39     TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
40 
41     Calendar c = Calendar.getInstance(tz, ULocale.US);
42     c.set(Calendar.MONTH, Calendar.JANUARY);
43     c.set(Calendar.DAY_OF_MONTH, 19);
44     c.set(Calendar.HOUR_OF_DAY, 3);
45     c.set(Calendar.MINUTE, 30);
46     c.set(Calendar.SECOND, 15);
47     c.set(Calendar.MILLISECOND, 0);
48     long timeWithCurrentYear = c.getTimeInMillis();
49 
50     c.set(Calendar.YEAR, 2009);
51     long fixedTime = c.getTimeInMillis();
52 
53     c.set(Calendar.MINUTE, 0);
54     c.set(Calendar.SECOND, 0);
55     long onTheHour = c.getTimeInMillis();
56 
57     long noonDuration = (8 * 60 + 30) * 60 * 1000 - 15 * 1000;
58     long midnightDuration = (3 * 60 + 30) * 60 * 1000 + 15 * 1000;
59 
60     ULocale de_DE = new ULocale("de", "DE");
61     ULocale en_US = new ULocale("en", "US");
62     ULocale es_ES = new ULocale("es", "ES");
63     ULocale es_US = new ULocale("es", "US");
64 
65     assertEquals("Monday", formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_WEEKDAY));
66     assertEquals("January 19", formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR, FORMAT_SHOW_DATE));
67     assertEquals("3:30 AM", formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_SHOW_TIME));
68     assertEquals("January 19, 2009", formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_YEAR));
69     assertEquals("January 19", formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_NO_YEAR));
70     assertEquals("January", formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR, FORMAT_NO_MONTH_DAY));
71     assertEquals("3:30 AM", formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_12HOUR | FORMAT_SHOW_TIME));
72     assertEquals("03:30", formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_24HOUR | FORMAT_SHOW_TIME));
73     assertEquals("3:30 AM", formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_12HOUR /*| FORMAT_CAP_AMPM*/ | FORMAT_SHOW_TIME));
74     assertEquals("12:00 PM", formatDateRange(en_US, tz, fixedTime + noonDuration, fixedTime + noonDuration, FORMAT_12HOUR | FORMAT_SHOW_TIME));
75     assertEquals("12:00 PM", formatDateRange(en_US, tz, fixedTime + noonDuration, fixedTime + noonDuration, FORMAT_12HOUR | FORMAT_SHOW_TIME /*| FORMAT_CAP_NOON*/));
76     assertEquals("12:00 PM", formatDateRange(en_US, tz, fixedTime + noonDuration, fixedTime + noonDuration, FORMAT_12HOUR /*| FORMAT_NO_NOON*/ | FORMAT_SHOW_TIME));
77     assertEquals("12:00 AM", formatDateRange(en_US, tz, fixedTime - midnightDuration, fixedTime - midnightDuration, FORMAT_12HOUR | FORMAT_SHOW_TIME /*| FORMAT_NO_MIDNIGHT*/));
78     assertEquals("3:30 AM", formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_SHOW_TIME | FORMAT_UTC));
79     assertEquals("3 AM", formatDateRange(en_US, tz, onTheHour, onTheHour, FORMAT_SHOW_TIME | FORMAT_ABBREV_TIME));
80     assertEquals("Mon", formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_WEEKDAY));
81     assertEquals("Jan 19", formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR, FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH));
82     assertEquals("Jan 19", formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
83 
84     assertEquals("1/19/2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * HOUR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
85     assertEquals("1/19/2009 – 1/22/2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
86     assertEquals("1/19/2009 – 4/22/2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
87     assertEquals("1/19/2009 – 2/9/2012", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
88 
89     assertEquals("19.1.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
90     assertEquals("19.–22.01.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
91     assertEquals("19.01. – 22.04.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
92     assertEquals("19.01.2009 – 09.02.2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
93 
94     assertEquals("19/1/2009", formatDateRange(es_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
95     assertEquals("19/1/2009–22/1/2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
96     assertEquals("19/1/2009–22/4/2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
97     assertEquals("19/1/2009–9/2/2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
98 
99     assertEquals("19/1/2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
100     assertEquals("19/1/2009–22/1/2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
101     assertEquals("19/1/2009–22/4/2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
102     assertEquals("19/1/2009–9/2/2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
103 
104     // These are some random other test cases I came up with.
105 
106     assertEquals("January 19 – 22, 2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY, 0));
107     assertEquals("Jan 19 – 22, 2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
108     assertEquals("Mon, Jan 19 – Thu, Jan 22, 2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
109     assertEquals("Monday, January 19 – Thursday, January 22, 2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
110 
111     assertEquals("January 19 – April 22, 2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH, 0));
112     assertEquals("Jan 19 – Apr 22, 2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
113     assertEquals("Mon, Jan 19 – Wed, Apr 22, 2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
114     assertEquals("January – April 2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
115 
116     assertEquals("Jan 19, 2009 – Feb 9, 2012", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
117     assertEquals("Jan 2009 – Feb 2012", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
118     assertEquals("January 19, 2009 – February 9, 2012", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, 0));
119     assertEquals("Monday, January 19, 2009 – Thursday, February 9, 2012", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
120 
121     // The same tests but for de_DE.
122 
123     assertEquals("19.–22. Januar 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, 0));
124     assertEquals("19.–22. Jan. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
125     assertEquals("Mo., 19. – Do., 22. Jan. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
126     assertEquals("Montag, 19. – Donnerstag, 22. Januar 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
127 
128     assertEquals("19. Januar – 22. April 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, 0));
129     assertEquals("19. Jan. – 22. Apr. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
130     assertEquals("Mo., 19. Jan. – Mi., 22. Apr. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
131     assertEquals("Januar–April 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
132 
133     assertEquals("19. Jan. 2009 – 9. Feb. 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
134     assertEquals("Jan. 2009 – Feb. 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
135     assertEquals("19. Januar 2009 – 9. Februar 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, 0));
136     assertEquals("Montag, 19. Januar 2009 – Donnerstag, 9. Februar 2012", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
137 
138     // The same tests but for es_US.
139 
140     assertEquals("19–22 de enero de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, 0));
141     assertEquals("19–22 de ene. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
142     assertEquals("lun., 19 de ene. – jue., 22 de ene. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
143     assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
144 
145     assertEquals("19 de enero–22 de abril de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, 0));
146     assertEquals("19 de ene. – 22 de abr. 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
147     assertEquals("lun., 19 de ene. – mié., 22 de abr. de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
148     assertEquals("enero–abril de 2009", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
149 
150     assertEquals("19 de ene. de 2009 – 9 de feb. de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
151     assertEquals("ene. de 2009 – feb. de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
152     assertEquals("19 de enero de 2009–9 de febrero de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, 0));
153     assertEquals("lunes, 19 de enero de 2009–jueves, 9 de febrero de 2012", formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
154 
155     // The same tests but for es_ES.
156 
157     assertEquals("19–22 de enero de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, 0));
158     assertEquals("19–22 ene. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
159     assertEquals("lun., 19 ene. – jue., 22 ene. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
160     assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
161 
162     assertEquals("19 de enero–22 de abril de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, 0));
163     assertEquals("19 ene. – 22 abr. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
164     assertEquals("lun., 19 ene. – mié., 22 abr. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
165     assertEquals("enero–abril de 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
166 
167     assertEquals("19 ene. 2009 – 9 feb. 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
168     assertEquals("ene. 2009 – feb. 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
169     assertEquals("19 de enero de 2009–9 de febrero de 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, 0));
170     assertEquals("lunes, 19 de enero de 2009–jueves, 9 de febrero de 2012", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
171   }
172 
173   // http://b/8862241 - we should be able to format dates past 2038.
174   // See also http://code.google.com/p/android/issues/detail?id=13050.
test8862241()175   public void test8862241() throws Exception {
176     ULocale l = ULocale.US;
177     TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
178     Calendar c = Calendar.getInstance(tz, l);
179     c.clear();
180     c.set(2042, Calendar.JANUARY, 19, 3, 30);
181     long jan_19_2042 = c.getTimeInMillis();
182     c.set(2046, Calendar.OCTOBER, 4, 3, 30);
183     long oct_4_2046 = c.getTimeInMillis();
184     int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL;
185     assertEquals("Jan 19, 2042 – Oct 4, 2046", formatDateRange(l, tz, jan_19_2042, oct_4_2046, flags));
186   }
187 
188   // http://b/10089890 - we should take the given time zone into account.
test10089890()189   public void test10089890() throws Exception {
190     ULocale l = ULocale.US;
191     TimeZone utc = TimeZone.getTimeZone("UTC");
192     TimeZone pacific = TimeZone.getTimeZone("America/Los_Angeles");
193     int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL | FORMAT_SHOW_TIME | FORMAT_24HOUR;
194 
195     // The Unix epoch is UTC, so 0 is 1970-01-01T00:00Z...
196     assertEquals("Jan 1, 1970, 00:00 – Jan 2, 1970, 00:00", formatDateRange(l, utc, 0, DAY + 1, flags));
197     // But MTV is hours behind, so 0 was still the afternoon of the previous day...
198     assertEquals("Dec 31, 1969, 16:00 – Jan 1, 1970, 16:00", formatDateRange(l, pacific, 0, DAY, flags));
199   }
200 
201   // http://b/10318326 - we can drop the minutes in a 12-hour time if they're zero,
202   // but not if we're using the 24-hour clock. That is: "4 PM" is reasonable, "16" is not.
test10318326()203   public void test10318326() throws Exception {
204     long midnight = 0;
205     long teaTime = 16 * HOUR;
206 
207     int time12 = FORMAT_12HOUR | FORMAT_SHOW_TIME;
208     int time24 = FORMAT_24HOUR | FORMAT_SHOW_TIME;
209     int abbr12 = time12 | FORMAT_ABBREV_ALL;
210     int abbr24 = time24 | FORMAT_ABBREV_ALL;
211 
212     ULocale l = ULocale.US;
213     TimeZone utc = TimeZone.getTimeZone("UTC");
214 
215     // Full length on-the-hour times.
216     assertEquals("00:00", formatDateRange(l, utc, midnight, midnight, time24));
217     assertEquals("12:00 AM", formatDateRange(l, utc, midnight, midnight, time12));
218     assertEquals("16:00", formatDateRange(l, utc, teaTime, teaTime, time24));
219     assertEquals("4:00 PM", formatDateRange(l, utc, teaTime, teaTime, time12));
220 
221     // Abbreviated on-the-hour times.
222     assertEquals("00:00", formatDateRange(l, utc, midnight, midnight, abbr24));
223     assertEquals("12 AM", formatDateRange(l, utc, midnight, midnight, abbr12));
224     assertEquals("16:00", formatDateRange(l, utc, teaTime, teaTime, abbr24));
225     assertEquals("4 PM", formatDateRange(l, utc, teaTime, teaTime, abbr12));
226 
227     // Abbreviated on-the-hour ranges.
228     assertEquals("00:00 – 16:00", formatDateRange(l, utc, midnight, teaTime, abbr24));
229     assertEquals("12 AM – 4 PM", formatDateRange(l, utc, midnight, teaTime, abbr12));
230 
231     // Abbreviated mixed ranges.
232     assertEquals("00:00 – 16:01", formatDateRange(l, utc, midnight, teaTime + MINUTE, abbr24));
233     assertEquals("12:00 AM – 4:01 PM", formatDateRange(l, utc, midnight, teaTime + MINUTE, abbr12));
234   }
235 
236   // http://b/10560853 - when the time is not displayed, an end time 0 ms into the next day is
237   // considered to belong to the previous day.
test10560853_when_time_not_displayed()238   public void test10560853_when_time_not_displayed() throws Exception {
239     ULocale l = ULocale.US;
240     TimeZone utc = TimeZone.getTimeZone("UTC");
241 
242     long midnight = 0;
243     long midnightNext = 1 * DAY;
244 
245     int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY;
246 
247     // An all-day event runs until 0 milliseconds into the next day, but is formatted as if it's
248     // just the first day.
249     assertEquals("Thursday, January 1, 1970", formatDateRange(l, utc, midnight, midnightNext, flags));
250 
251     // Run one millisecond over, though, and you're into the next day.
252     long nextMorning = 1 * DAY + 1;
253     assertEquals("Thursday, January 1 – Friday, January 2, 1970", formatDateRange(l, utc, midnight, nextMorning, flags));
254 
255     // But the same reasoning applies for that day.
256     long nextMidnight = 2 * DAY;
257     assertEquals("Thursday, January 1 – Friday, January 2, 1970", formatDateRange(l, utc, midnight, nextMidnight, flags));
258   }
259 
260   // http://b/10560853 - when the start and end times are otherwise on the same day,
261   // an end time 0 ms into the next day is considered to belong to the previous day.
test10560853_for_single_day_events()262   public void test10560853_for_single_day_events() throws Exception {
263     ULocale l = ULocale.US;
264     TimeZone utc = TimeZone.getTimeZone("UTC");
265 
266     int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
267 
268     assertEquals("January 1, 1970, 22:00 – 00:00", formatDateRange(l, utc, 22 * HOUR, 24 * HOUR, flags));
269     assertEquals("January 1, 1970, 22:00 – January 2, 1970, 00:30", formatDateRange(l, utc, 22 * HOUR, 24 * HOUR + 30 * MINUTE, flags));
270   }
271 
272   // The fix for http://b/10560853 didn't work except for the day around the epoch, which was
273   // all the unit test checked!
test_single_day_events_later_than_epoch()274   public void test_single_day_events_later_than_epoch() throws Exception {
275     ULocale l = ULocale.US;
276     TimeZone utc = TimeZone.getTimeZone("UTC");
277 
278     int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
279 
280     Calendar c = Calendar.getInstance(utc, l);
281     c.clear();
282     c.set(1980, Calendar.JANUARY, 1, 0, 0);
283     long jan_1_1980 = c.getTimeInMillis();
284     assertEquals("January 1, 1980, 22:00 – 00:00",
285                  formatDateRange(l, utc, jan_1_1980 + 22 * HOUR, jan_1_1980 + 24 * HOUR, flags));
286     assertEquals("January 1, 1980, 22:00 – January 2, 1980, 00:30",
287                  formatDateRange(l, utc, jan_1_1980 + 22 * HOUR, jan_1_1980 + 24 * HOUR + 30 * MINUTE, flags));
288   }
289 
290   // The fix for http://b/10560853 didn't work except for UTC, which was
291   // all the unit test checked!
test_single_day_events_not_in_UTC()292   public void test_single_day_events_not_in_UTC() throws Exception {
293     ULocale l = ULocale.US;
294     TimeZone pacific = TimeZone.getTimeZone("America/Los_Angeles");
295 
296     int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
297 
298     Calendar c = Calendar.getInstance(pacific, l);
299     c.clear();
300     c.set(1980, Calendar.JANUARY, 1, 0, 0);
301     long jan_1_1980 = c.getTimeInMillis();
302     assertEquals("January 1, 1980, 22:00 – 00:00",
303                  formatDateRange(l, pacific, jan_1_1980 + 22 * HOUR, jan_1_1980 + 24 * HOUR, flags));
304 
305     c.set(1980, Calendar.JULY, 1, 0, 0);
306     long jul_1_1980 = c.getTimeInMillis();
307     assertEquals("July 1, 1980, 22:00 – 00:00",
308                  formatDateRange(l, pacific, jul_1_1980 + 22 * HOUR, jul_1_1980 + 24 * HOUR, flags));
309   }
310 
311   // http://b/10209343 - even if the caller didn't explicitly ask us to include the year,
312   // we should do so for years other than the current year.
test10209343_when_not_this_year()313   public void test10209343_when_not_this_year() {
314     ULocale l = ULocale.US;
315     TimeZone utc = TimeZone.getTimeZone("UTC");
316 
317     int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_TIME | FORMAT_24HOUR;
318 
319     assertEquals("Thursday, January 1, 1970, 00:00", formatDateRange(l, utc, 0L, 0L, flags));
320 
321     long t1833 = ((long) Integer.MIN_VALUE + Integer.MIN_VALUE) * 1000L;
322     assertEquals("Sunday, November 24, 1833, 17:31", formatDateRange(l, utc, t1833, t1833, flags));
323 
324     long t1901 = Integer.MIN_VALUE * 1000L;
325     assertEquals("Friday, December 13, 1901, 20:45", formatDateRange(l, utc, t1901, t1901, flags));
326 
327     long t2038 = Integer.MAX_VALUE * 1000L;
328     assertEquals("Tuesday, January 19, 2038, 03:14", formatDateRange(l, utc, t2038, t2038, flags));
329 
330     long t2106 = (2L + Integer.MAX_VALUE + Integer.MAX_VALUE) * 1000L;
331     assertEquals("Sunday, February 7, 2106, 06:28", formatDateRange(l, utc, t2106, t2106, flags));
332   }
333 
334   // http://b/10209343 - for the current year, we should honor the FORMAT_SHOW_YEAR flags.
test10209343_when_this_year()335   public void test10209343_when_this_year() {
336     // Construct a date in the current year (whenever the test happens to be run).
337     ULocale l = ULocale.US;
338     TimeZone utc = TimeZone.getTimeZone("UTC");
339     Calendar c = Calendar.getInstance(utc, l);
340     c.set(Calendar.MONTH, Calendar.FEBRUARY);
341     c.set(Calendar.DAY_OF_MONTH, 10);
342     c.set(Calendar.HOUR_OF_DAY, 0);
343     long thisYear = c.getTimeInMillis();
344 
345     // You don't get the year if it's this year...
346     assertEquals("February 10", formatDateRange(l, utc, thisYear, thisYear, FORMAT_SHOW_DATE));
347 
348     // ...unless you explicitly ask for it.
349     assertEquals(String.format("February 10, %d", c.get(Calendar.YEAR)),
350                  formatDateRange(l, utc, thisYear, thisYear, FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR));
351 
352     // ...or it's not actually this year...
353     Calendar c2 = (Calendar) c.clone();
354     c2.set(Calendar.YEAR, 1980);
355     long oldYear = c2.getTimeInMillis();
356     assertEquals("February 10, 1980", formatDateRange(l, utc, oldYear, oldYear, FORMAT_SHOW_DATE));
357 
358     // (But you can disable that!)
359     assertEquals("February 10", formatDateRange(l, utc, oldYear, oldYear, FORMAT_SHOW_DATE | FORMAT_NO_YEAR));
360 
361     // ...or the start and end years aren't the same...
362     assertEquals(String.format("February 10, 1980 – February 10, %d", c.get(Calendar.YEAR)),
363                  formatDateRange(l, utc, oldYear, thisYear, FORMAT_SHOW_DATE));
364 
365     // (And you can't avoid that --- icu4c steps in and overrides you.)
366     assertEquals(String.format("February 10, 1980 – February 10, %d", c.get(Calendar.YEAR)),
367                  formatDateRange(l, utc, oldYear, thisYear, FORMAT_SHOW_DATE | FORMAT_NO_YEAR));
368   }
369 
370   // http://b/8467515 - yet another y2k38 bug report.
test8467515()371   public void test8467515() throws Exception {
372     ULocale l = ULocale.US;
373     TimeZone utc = TimeZone.getTimeZone("UTC");
374     int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_YEAR | FORMAT_ABBREV_MONTH | FORMAT_ABBREV_WEEKDAY;
375     long t;
376 
377     Calendar calendar = Calendar.getInstance(utc, l);
378     calendar.clear();
379 
380     calendar.set(2038, Calendar.JANUARY, 19, 12, 0, 0);
381     t = calendar.getTimeInMillis();
382     assertEquals("Tue, Jan 19, 2038", formatDateRange(l, utc, t, t, flags));
383 
384     calendar.set(1900, Calendar.JANUARY, 1, 0, 0, 0);
385     t = calendar.getTimeInMillis();
386     assertEquals("Mon, Jan 1, 1900", formatDateRange(l, utc, t, t, flags));
387   }
388 
389   // http://b/12004664
test12004664()390   public void test12004664() throws Exception {
391     TimeZone utc = TimeZone.getTimeZone("UTC");
392     Calendar c = Calendar.getInstance(utc, ULocale.US);
393     c.clear();
394     c.set(Calendar.YEAR, 1980);
395     c.set(Calendar.MONTH, Calendar.FEBRUARY);
396     c.set(Calendar.DAY_OF_MONTH, 10);
397     c.set(Calendar.HOUR_OF_DAY, 0);
398     long thisYear = c.getTimeInMillis();
399 
400     int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_YEAR;
401     assertEquals("Sunday, February 10, 1980", formatDateRange(new ULocale("en", "US"), utc, thisYear, thisYear, flags));
402 
403     // If we supported non-Gregorian calendars, this is what that we'd expect for these ULocales.
404     // This is really the correct behavior, but since java.util.Calendar currently only supports
405     // the Gregorian calendar, we want to deliberately force icu4c to agree, otherwise we'd have
406     // a mix of calendars throughout an app's UI depending on whether Java or native code formatted
407     // the date.
408     // assertEquals("یکشنبه ۲۱ بهمن ۱۳۵۸ ه‍.ش.", formatDateRange(new ULocale("fa"), utc, thisYear, thisYear, flags));
409     // assertEquals("AP ۱۳۵۸ سلواغه ۲۱, یکشنبه", formatDateRange(new ULocale("ps"), utc, thisYear, thisYear, flags));
410     // assertEquals("วันอาทิตย์ 10 กุมภาพันธ์ 2523", formatDateRange(new ULocale("th"), utc, thisYear, thisYear, flags));
411 
412     // For now, here are the localized Gregorian strings instead...
413     assertEquals("یکشنبه ۱۰ فوریهٔ ۱۹۸۰", formatDateRange(new ULocale("fa"), utc, thisYear, thisYear, flags));
414     assertEquals("يونۍ د ۱۹۸۰ د فبروري ۱۰", formatDateRange(new ULocale("ps"), utc, thisYear, thisYear, flags));
415     assertEquals("วันอาทิตย์ที่ 10 กุมภาพันธ์ ค.ศ. 1980", formatDateRange(new ULocale("th"), utc, thisYear, thisYear, flags));
416   }
417 
418   // http://b/13234532
test13234532()419   public void test13234532() throws Exception {
420     ULocale l = ULocale.US;
421     TimeZone utc = TimeZone.getTimeZone("UTC");
422 
423     int flags = FORMAT_SHOW_TIME | FORMAT_ABBREV_ALL | FORMAT_12HOUR;
424 
425     assertEquals("10 – 11 AM", formatDateRange(l, utc, 10*HOUR, 11*HOUR, flags));
426     assertEquals("11 AM – 1 PM", formatDateRange(l, utc, 11*HOUR, 13*HOUR, flags));
427     assertEquals("2 – 3 PM", formatDateRange(l, utc, 14*HOUR, 15*HOUR, flags));
428   }
429 
430   // http://b/20708022
testEndOfDayOnLastDayOfMonth()431   public void testEndOfDayOnLastDayOfMonth() throws Exception {
432     final ULocale locale = new ULocale("en");
433     final TimeZone timeZone = TimeZone.getTimeZone("UTC");
434 
435     assertEquals("11:00 PM – 12:00 AM", formatDateRange(locale, timeZone,
436             1430434800000L, 1430438400000L, FORMAT_SHOW_TIME));
437   }
438 
439   // http://b/68847519
testEndAtMidnight_dateAndTime()440   public void testEndAtMidnight_dateAndTime() {
441     BiFunction<Long, Long, String> fmt = (from, to) -> formatDateRange(
442             ENGLISH, GMT_ZONE, from, to, FORMAT_SHOW_DATE | FORMAT_SHOW_TIME | FORMAT_24HOUR);
443     // If we're showing times and the end-point is midnight the following day, we want the
444     // behaviour of suppressing the date for the end...
445     assertEquals("February 27, 2007, 04:00 – 00:00", fmt.apply(1172548800000L, 1172620800000L));
446     // ...unless the start-point is also midnight, in which case we need dates to disambiguate.
447     assertEquals("February 27, 2007, 00:00 – February 28, 2007, 00:00",
448             fmt.apply(1172534400000L, 1172620800000L));
449     // We want to show the date if the end-point is a millisecond after midnight the following
450     // day, or if it is exactly midnight the day after that.
451     assertEquals("February 27, 2007, 04:00 – February 28, 2007, 00:00",
452             fmt.apply(1172548800000L, 1172620800001L));
453     assertEquals("February 27, 2007, 04:00 – March 1, 2007, 00:00",
454             fmt.apply(1172548800000L, 1172707200000L));
455     // We want to show the date if the start-point is anything less than a minute after midnight,
456     // since that gets displayed as midnight...
457     assertEquals("February 27, 2007, 00:00 – February 28, 2007, 00:00",
458             fmt.apply(1172534459999L, 1172620800000L));
459     // ...but not if it is exactly one minute after midnight.
460     assertEquals("February 27, 2007, 00:01 – 00:00", fmt.apply(1172534460000L, 1172620800000L));
461   }
462 
463   // http://b/68847519
testEndAtMidnight_dateOnly()464   public void testEndAtMidnight_dateOnly() {
465     BiFunction<Long, Long, String> fmt = (from, to) -> formatDateRange(
466             ENGLISH, GMT_ZONE, from, to, FORMAT_SHOW_DATE);
467     // If we're only showing dates and the end-point is midnight of any day, we want the
468     // behaviour of showing an end date one earlier. So if the end-point is March 2, 2007 00:00,
469     // show March 1, 2007 instead (whether the start-point is midnight or not).
470     assertEquals("February 27 – March 1, 2007", fmt.apply(1172534400000L, 1172793600000L));
471     assertEquals("February 27 – March 1, 2007", fmt.apply(1172548800000L, 1172793600000L));
472     // We want to show the true date if the end-point is a millisecond after midnight.
473     assertEquals("February 27 – March 2, 2007", fmt.apply(1172534400000L, 1172793600001L));
474 
475     // 2006-02-27 00:00:00.000 GMT - 2007-03-02 00:00:00.000 GMT
476     assertEquals("February 27, 2006 – March 1, 2007", fmt.apply(1140998400000L, 1172793600000L));
477 
478     // Spans a leap year's Feb 29th.
479     assertEquals("February 27 – March 1, 2004", fmt.apply(1077840000000L, 1078185600000L));
480   }
481 }
482