• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  *  * Redistributions of source code must retain the above copyright notice,
10  *    this list of conditions and the following disclaimer.
11  *
12  *  * Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  *  * Neither the name of JSR-310 nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package org.threeten.bp.chrono;
33 
34 import static org.testng.Assert.assertEquals;
35 import static org.testng.Assert.assertTrue;
36 
37 import java.io.ByteArrayInputStream;
38 import java.io.ByteArrayOutputStream;
39 import java.io.ObjectInputStream;
40 import java.io.ObjectOutputStream;
41 import java.util.ArrayList;
42 import java.util.List;
43 import java.util.Locale;
44 import java.util.Map;
45 
46 import org.testng.Assert;
47 import org.testng.annotations.DataProvider;
48 import org.testng.annotations.Test;
49 import org.threeten.bp.Duration;
50 import org.threeten.bp.LocalDate;
51 import org.threeten.bp.LocalTime;
52 import org.threeten.bp.ZoneId;
53 import org.threeten.bp.ZoneOffset;
54 import org.threeten.bp.ZonedDateTime;
55 import org.threeten.bp.format.ResolverStyle;
56 import org.threeten.bp.temporal.ChronoUnit;
57 import org.threeten.bp.temporal.Temporal;
58 import org.threeten.bp.temporal.TemporalAccessor;
59 import org.threeten.bp.temporal.TemporalAdjuster;
60 import org.threeten.bp.temporal.TemporalAmount;
61 import org.threeten.bp.temporal.TemporalField;
62 import org.threeten.bp.temporal.TemporalUnit;
63 import org.threeten.bp.temporal.ValueRange;
64 
65 /**
66  * Test assertions that must be true for all built-in chronologies.
67  */
68 @SuppressWarnings("rawtypes")
69 @Test
70 public class TestChronoZonedDateTime {
71     //-----------------------------------------------------------------------
72     // regular data factory for names and descriptions of available calendars
73     //-----------------------------------------------------------------------
74     @DataProvider(name = "calendars")
data_of_calendars()75     Chronology[][] data_of_calendars() {
76         return new Chronology[][]{
77                     {HijrahChronology.INSTANCE},
78                     {IsoChronology.INSTANCE},
79                     {JapaneseChronology.INSTANCE},
80                     {MinguoChronology.INSTANCE},
81                     {ThaiBuddhistChronology.INSTANCE},
82         };
83     }
84 
85     @Test(dataProvider="calendars")
test_badWithAdjusterChrono(Chronology chrono)86     public void test_badWithAdjusterChrono(Chronology chrono) {
87         LocalDate refDate = LocalDate.of(1900, 1, 1);
88         ChronoZonedDateTime czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
89         for (Chronology[] clist : data_of_calendars()) {
90             Chronology chrono2 = clist[0];
91             ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
92             TemporalAdjuster adjuster = new FixedAdjuster(czdt2);
93             if (chrono != chrono2) {
94                 try {
95                     czdt.with(adjuster);
96                     Assert.fail("WithAdjuster should have thrown a ClassCastException, "
97                             + "required: " + czdt + ", supplied: " + czdt2);
98                 } catch (ClassCastException cce) {
99                     // Expected exception; not an error
100                 }
101             } else {
102                 ChronoZonedDateTime<?> result = czdt.with(adjuster);
103                 assertEquals(result, czdt2, "WithAdjuster failed to replace date");
104             }
105         }
106     }
107 
108     @Test(dataProvider="calendars")
test_badPlusAdjusterChrono(Chronology chrono)109     public void test_badPlusAdjusterChrono(Chronology chrono) {
110         LocalDate refDate = LocalDate.of(1900, 1, 1);
111         ChronoZonedDateTime czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
112         for (Chronology[] clist : data_of_calendars()) {
113             Chronology chrono2 = clist[0];
114             ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
115             TemporalAmount adjuster = new FixedAdjuster(czdt2);
116             if (chrono != chrono2) {
117                 try {
118                     czdt.plus(adjuster);
119                     Assert.fail("WithAdjuster should have thrown a ClassCastException, "
120                             + "required: " + czdt + ", supplied: " + czdt2);
121                 } catch (ClassCastException cce) {
122                     // Expected exception; not an error
123                 }
124             } else {
125                 // Same chronology,
126                 ChronoZonedDateTime<?> result = czdt.plus(adjuster);
127                 assertEquals(result, czdt2, "WithAdjuster failed to replace date time");
128             }
129         }
130     }
131 
132     @Test(dataProvider="calendars")
test_badMinusAdjusterChrono(Chronology chrono)133     public void test_badMinusAdjusterChrono(Chronology chrono) {
134         LocalDate refDate = LocalDate.of(1900, 1, 1);
135         ChronoZonedDateTime czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
136         for (Chronology[] clist : data_of_calendars()) {
137             Chronology chrono2 = clist[0];
138             ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
139             TemporalAmount adjuster = new FixedAdjuster(czdt2);
140             if (chrono != chrono2) {
141                 try {
142                     czdt.minus(adjuster);
143                     Assert.fail("WithAdjuster should have thrown a ClassCastException, "
144                             + "required: " + czdt + ", supplied: " + czdt2);
145                 } catch (ClassCastException cce) {
146                     // Expected exception; not an error
147                 }
148             } else {
149                 // Same chronology,
150                 ChronoZonedDateTime<?> result = czdt.minus(adjuster);
151                 assertEquals(result, czdt2, "WithAdjuster failed to replace date");
152             }
153         }
154     }
155 
156     @Test(dataProvider="calendars")
test_badPlusPeriodUnitChrono(Chronology chrono)157     public void test_badPlusPeriodUnitChrono(Chronology chrono) {
158         LocalDate refDate = LocalDate.of(1900, 1, 1);
159         ChronoZonedDateTime czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
160         for (Chronology[] clist : data_of_calendars()) {
161             Chronology chrono2 = clist[0];
162             ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
163             TemporalUnit adjuster = new FixedPeriodUnit(czdt2);
164             if (chrono != chrono2) {
165                 try {
166                     czdt.plus(1, adjuster);
167                     Assert.fail("PeriodUnit.doPlus plus should have thrown a ClassCastException, " + czdt
168                             + " can not be cast to " + czdt2);
169                 } catch (ClassCastException cce) {
170                     // Expected exception; not an error
171                 }
172             } else {
173                 // Same chronology,
174                 ChronoZonedDateTime<?> result = czdt.plus(1, adjuster);
175                 assertEquals(result, czdt2, "WithAdjuster failed to replace date");
176             }
177         }
178     }
179 
180     @Test(dataProvider="calendars")
test_badMinusPeriodUnitChrono(Chronology chrono)181     public void test_badMinusPeriodUnitChrono(Chronology chrono) {
182         LocalDate refDate = LocalDate.of(1900, 1, 1);
183         ChronoZonedDateTime czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
184         for (Chronology[] clist : data_of_calendars()) {
185             Chronology chrono2 = clist[0];
186             ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
187             TemporalUnit adjuster = new FixedPeriodUnit(czdt2);
188             if (chrono != chrono2) {
189                 try {
190                     czdt.minus(1, adjuster);
191                     Assert.fail("PeriodUnit.doPlus minus should have thrown a ClassCastException, " + czdt.getClass()
192                             + " can not be cast to " + czdt2.getClass());
193                 } catch (ClassCastException cce) {
194                     // Expected exception; not an error
195                 }
196             } else {
197                 // Same chronology,
198                 ChronoZonedDateTime<?> result = czdt.minus(1, adjuster);
199                 assertEquals(result, czdt2, "WithAdjuster failed to replace date");
200             }
201         }
202     }
203 
204     @Test(dataProvider="calendars")
test_badDateTimeFieldChrono(Chronology chrono)205     public void test_badDateTimeFieldChrono(Chronology chrono) {
206         LocalDate refDate = LocalDate.of(1900, 1, 1);
207         ChronoZonedDateTime czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
208         for (Chronology[] clist : data_of_calendars()) {
209             Chronology chrono2 = clist[0];
210             ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC);
211             TemporalField adjuster = new FixedDateTimeField(czdt2);
212             if (chrono != chrono2) {
213                 try {
214                     czdt.with(adjuster, 1);
215                     Assert.fail("DateTimeField adjustInto() should have thrown a ClassCastException, " + czdt.getClass()
216                             + " can not be cast to " + czdt2.getClass());
217                 } catch (ClassCastException cce) {
218                     // Expected exception; not an error
219                 }
220             } else {
221                 // Same chronology,
222                 ChronoZonedDateTime<?> result = czdt.with(adjuster, 1);
223                 assertEquals(result, czdt2, "DateTimeField adjustInto() failed to replace date");
224             }
225         }
226     }
227 
228     //-----------------------------------------------------------------------
229     // isBefore, isAfter, isEqual, INSTANT_COMPARATOR  test a Chrono against the other Chronos
230     //-----------------------------------------------------------------------
231     @SuppressWarnings("unused")
232     @Test(dataProvider="calendars")
test_zonedDateTime_comparisons(Chronology chrono)233     public void test_zonedDateTime_comparisons(Chronology chrono) {
234         List<ChronoZonedDateTime<?>> dates = new ArrayList<ChronoZonedDateTime<?>>();
235 
236         ChronoZonedDateTime<?> date = chrono.date(LocalDate.of(1900, 1, 1))
237                 .atTime(LocalTime.MIN)
238                 .atZone(ZoneOffset.UTC);
239 
240         // Insert dates in order, no duplicates
241         if (chrono != JapaneseChronology.INSTANCE) {
242             dates.add(date.minus(100, ChronoUnit.YEARS));
243         }
244         dates.add(date.minus(1, ChronoUnit.YEARS));
245         dates.add(date.minus(1, ChronoUnit.MONTHS));
246         dates.add(date.minus(1, ChronoUnit.WEEKS));
247         dates.add(date.minus(1, ChronoUnit.DAYS));
248         dates.add(date.minus(1, ChronoUnit.HOURS));
249         dates.add(date.minus(1, ChronoUnit.MINUTES));
250         dates.add(date.minus(1, ChronoUnit.SECONDS));
251         dates.add(date.minus(1, ChronoUnit.NANOS));
252         dates.add(date);
253         dates.add(date.plus(1, ChronoUnit.NANOS));
254         dates.add(date.plus(1, ChronoUnit.SECONDS));
255         dates.add(date.plus(1, ChronoUnit.MINUTES));
256         dates.add(date.plus(1, ChronoUnit.HOURS));
257         dates.add(date.plus(1, ChronoUnit.DAYS));
258         dates.add(date.plus(1, ChronoUnit.WEEKS));
259         dates.add(date.plus(1, ChronoUnit.MONTHS));
260         dates.add(date.plus(1, ChronoUnit.YEARS));
261         dates.add(date.plus(100, ChronoUnit.YEARS));
262 
263         // Check these dates against the corresponding dates for every calendar
264         for (Chronology[] clist : data_of_calendars()) {
265             List<ChronoZonedDateTime<?>> otherDates = new ArrayList<ChronoZonedDateTime<?>>();
266             Chronology chrono2 = IsoChronology.INSTANCE; //clist[0];
267             for (ChronoZonedDateTime<?> d : dates) {
268                 otherDates.add(chrono2.date(d).atTime(d.toLocalTime()).atZone(d.getZone()));
269             }
270 
271             // Now compare  the sequence of original dates with the sequence of converted dates
272             for (int i = 0; i < dates.size(); i++) {
273                 ChronoZonedDateTime<?> a = dates.get(i);
274                 for (int j = 0; j < otherDates.size(); j++) {
275                     ChronoZonedDateTime<?> b = otherDates.get(j);
276                     int cmp = ChronoZonedDateTime.timeLineOrder().compare(a, b);
277                     if (i < j) {
278                         assertTrue(cmp < 0, a + " compare " + b);
279                         assertEquals(a.isBefore(b), true, a + " isBefore " + b);
280                         assertEquals(a.isAfter(b), false, a + " ifAfter " + b);
281                         assertEquals(a.isEqual(b), false, a + " isEqual " + b);
282                     } else if (i > j) {
283                         assertTrue(cmp > 0, a + " compare " + b);
284                         assertEquals(a.isBefore(b), false, a + " isBefore " + b);
285                         assertEquals(a.isAfter(b), true, a + " ifAfter " + b);
286                         assertEquals(a.isEqual(b), false, a + " isEqual " + b);
287                     } else {
288                         assertTrue(cmp == 0, a + " compare " + b);
289                         assertEquals(a.isBefore(b), false, a + " isBefore " + b);
290                         assertEquals(a.isAfter(b), false, a + " ifAfter " + b);
291                         assertEquals(a.isEqual(b), true, a + " isEqual " + b);
292                     }
293                 }
294             }
295         }
296     }
297 
298     //-----------------------------------------------------------------------
299     // Test Serialization of ISO via chrono API
300     //-----------------------------------------------------------------------
301     @Test( dataProvider="calendars")
test_ChronoZonedDateTimeSerialization(Chronology chrono)302     public void test_ChronoZonedDateTimeSerialization(Chronology chrono) throws Exception {
303         ZonedDateTime ref = LocalDate.of(2000, 1, 5).atTime(12, 1, 2, 3).atZone(ZoneId.of("GMT+01:23"));
304         ChronoZonedDateTime<?> orginal = chrono.date(ref).atTime(ref.toLocalTime()).atZone(ref.getZone());
305         ByteArrayOutputStream baos = new ByteArrayOutputStream();
306         ObjectOutputStream out = new ObjectOutputStream(baos);
307         out.writeObject(orginal);
308         out.close();
309         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
310         ObjectInputStream in = new ObjectInputStream(bais);
311         ChronoZonedDateTime<?> ser = (ChronoZonedDateTime<?>) in.readObject();
312         assertEquals(ser, orginal, "deserialized date is wrong");
313     }
314 
315 
316     /**
317      * FixedAdjusted returns a fixed DateTime in all adjustments.
318      * Construct an adjuster with the DateTime that should be returned from adjustIntoAdjustment.
319      */
320     static class FixedAdjuster implements TemporalAdjuster, TemporalAmount {
321         private Temporal datetime;
322 
FixedAdjuster(Temporal datetime)323         FixedAdjuster(Temporal datetime) {
324             this.datetime = datetime;
325         }
326 
327         @Override
adjustInto(Temporal ignore)328         public Temporal adjustInto(Temporal ignore) {
329             return datetime;
330         }
331 
332         @Override
addTo(Temporal ignore)333         public Temporal addTo(Temporal ignore) {
334             return datetime;
335         }
336 
337         @Override
subtractFrom(Temporal ignore)338         public Temporal subtractFrom(Temporal ignore) {
339             return datetime;
340         }
341 
342         @Override
getUnits()343         public List<TemporalUnit> getUnits() {
344             throw new UnsupportedOperationException("Not supported yet.");
345         }
346 
347         @Override
get(TemporalUnit unit)348         public long get(TemporalUnit unit) {
349             throw new UnsupportedOperationException("Not supported yet.");
350         }
351     }
352 
353     /**
354      * FixedPeriodUnit returns a fixed DateTime in all adjustments.
355      * Construct an FixedPeriodUnit with the DateTime that should be returned from doPlus.
356      */
357     static class FixedPeriodUnit implements TemporalUnit {
358         private Temporal dateTime;
359 
FixedPeriodUnit(Temporal dateTime)360         FixedPeriodUnit(Temporal dateTime) {
361             this.dateTime = dateTime;
362         }
363 
364         @Override
toString()365         public String toString() {
366             return "FixedPeriodUnit";
367         }
368 
369         @Override
getDuration()370         public Duration getDuration() {
371             throw new UnsupportedOperationException("Not supported yet.");
372         }
373 
374         @Override
isDurationEstimated()375         public boolean isDurationEstimated() {
376             throw new UnsupportedOperationException("Not supported yet.");
377         }
378 
379         @Override
isDateBased()380         public boolean isDateBased() {
381             throw new UnsupportedOperationException("Not supported yet.");
382         }
383 
384         @Override
isTimeBased()385         public boolean isTimeBased() {
386             throw new UnsupportedOperationException("Not supported yet.");
387         }
388 
389         @Override
isSupportedBy(Temporal dateTime)390         public boolean isSupportedBy(Temporal dateTime) {
391             throw new UnsupportedOperationException("Not supported yet.");
392         }
393 
394         @SuppressWarnings("unchecked")
395         @Override
addTo(R dateTime, long periodToAdd)396         public <R extends Temporal> R addTo(R dateTime, long periodToAdd) {
397             return (R) this.dateTime;
398         }
399 
400         @Override
between(Temporal temporal1, Temporal temporal2)401         public long between(Temporal temporal1, Temporal temporal2) {
402             throw new UnsupportedOperationException("Not supported yet.");
403         }
404     }
405 
406     /**
407      * FixedDateTimeField returns a fixed DateTime in all adjustments.
408      * Construct an FixedDateTimeField with the DateTime that should be returned from adjustInto.
409      */
410     static class FixedDateTimeField implements TemporalField {
411         private Temporal dateTime;
FixedDateTimeField(Temporal dateTime)412         FixedDateTimeField(Temporal dateTime) {
413             this.dateTime = dateTime;
414         }
415 
416         @Override
toString()417         public String toString() {
418             return "FixedDateTimeField";
419         }
420 
421         @Override
getBaseUnit()422         public TemporalUnit getBaseUnit() {
423             throw new UnsupportedOperationException("Not supported yet.");
424         }
425 
426         @Override
getRangeUnit()427         public TemporalUnit getRangeUnit() {
428             throw new UnsupportedOperationException("Not supported yet.");
429         }
430 
431         @Override
range()432         public ValueRange range() {
433             throw new UnsupportedOperationException("Not supported yet.");
434         }
435 
436         @Override
isDateBased()437         public boolean isDateBased() {
438             throw new UnsupportedOperationException("Not supported yet.");
439         }
440 
441         @Override
isTimeBased()442         public boolean isTimeBased() {
443             throw new UnsupportedOperationException("Not supported yet.");
444         }
445 
446         @Override
isSupportedBy(TemporalAccessor dateTime)447         public boolean isSupportedBy(TemporalAccessor dateTime) {
448             throw new UnsupportedOperationException("Not supported yet.");
449         }
450 
451         @Override
rangeRefinedBy(TemporalAccessor dateTime)452         public ValueRange rangeRefinedBy(TemporalAccessor dateTime) {
453             throw new UnsupportedOperationException("Not supported yet.");
454         }
455 
456         @Override
getFrom(TemporalAccessor dateTime)457         public long getFrom(TemporalAccessor dateTime) {
458             throw new UnsupportedOperationException("Not supported yet.");
459         }
460 
461         @SuppressWarnings("unchecked")
462         @Override
adjustInto(R dateTime, long newValue)463         public <R extends Temporal> R adjustInto(R dateTime, long newValue) {
464             return (R) this.dateTime;
465         }
466 
467         @Override
getDisplayName(Locale locale)468         public String getDisplayName(Locale locale) {
469             throw new UnsupportedOperationException("Not supported yet.");
470         }
471 
472         @Override
resolve(Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle)473         public TemporalAccessor resolve(Map<TemporalField, Long> fieldValues,
474                         TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
475             return null;
476         }
477     }
478 }
479