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