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.temporal; 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.util.ArrayList; 67 import java.util.List; 68 69 import java.time.Duration; 70 import java.time.LocalDate; 71 import java.time.LocalTime; 72 import java.time.ZoneId; 73 import java.time.ZoneOffset; 74 import java.time.ZonedDateTime; 75 import java.time.temporal.Chrono; 76 import java.time.temporal.ChronoUnit; 77 import java.time.temporal.ChronoZonedDateTime; 78 import java.time.temporal.SimplePeriod; 79 import java.time.temporal.Temporal; 80 import java.time.temporal.TemporalAccessor; 81 import java.time.format.DateTimeBuilder; 82 import java.time.temporal.TemporalAdder; 83 import java.time.temporal.TemporalAdjuster; 84 import java.time.temporal.TemporalField; 85 import java.time.temporal.TemporalSubtractor; 86 import java.time.temporal.ValueRange; 87 import java.time.temporal.ISOChrono; 88 import java.time.temporal.TemporalUnit; 89 import java.time.calendar.HijrahChrono; 90 import java.time.calendar.JapaneseChrono; 91 import java.time.calendar.MinguoChrono; 92 import java.time.calendar.ThaiBuddhistChrono; 93 94 import org.testng.Assert; 95 import org.testng.annotations.DataProvider; 96 import org.testng.annotations.Test; 97 98 /** 99 * Test assertions that must be true for all built-in chronologies. 100 */ 101 @Test 102 public class TestChronoZonedDateTime { 103 104 //----------------------------------------------------------------------- 105 // regular data factory for names and descriptions of available calendars 106 //----------------------------------------------------------------------- 107 @DataProvider(name = "calendars") 108 Chrono<?>[][] data_of_calendars() { 109 return new Chrono<?>[][]{ 110 {HijrahChrono.INSTANCE}, 111 {ISOChrono.INSTANCE}, 112 {JapaneseChrono.INSTANCE}, 113 {MinguoChrono.INSTANCE}, 114 {ThaiBuddhistChrono.INSTANCE}, 115 }; 116 } 117 118 @Test(groups={"tck"}, dataProvider="calendars") 119 public void test_badWithAdjusterChrono(Chrono<?> chrono) { 120 LocalDate refDate = LocalDate.of(1900, 1, 1); 121 ChronoZonedDateTime<?> czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); 122 for (Chrono<?>[] clist : data_of_calendars()) { 123 Chrono<?> chrono2 = clist[0]; 124 ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); 125 TemporalAdjuster adjuster = new FixedAdjuster(czdt2); 126 if (chrono != chrono2) { 127 try { 128 czdt.with(adjuster); 129 Assert.fail("WithAdjuster should have thrown a ClassCastException, " 130 + "required: " + czdt + ", supplied: " + czdt2); 131 } catch (ClassCastException cce) { 132 // Expected exception; not an error 133 } 134 } else { 135 ChronoZonedDateTime<?> result = czdt.with(adjuster); 136 assertEquals(result, czdt2, "WithAdjuster failed to replace date"); 137 } 138 } 139 } 140 141 @Test(groups={"tck"}, dataProvider="calendars") 142 public void test_badPlusAdjusterChrono(Chrono<?> chrono) { 143 LocalDate refDate = LocalDate.of(1900, 1, 1); 144 ChronoZonedDateTime<?> czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); 145 for (Chrono<?>[] clist : data_of_calendars()) { 146 Chrono<?> chrono2 = clist[0]; 147 ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); 148 TemporalAdder adjuster = new FixedAdjuster(czdt2); 149 if (chrono != chrono2) { 150 try { 151 czdt.plus(adjuster); 152 Assert.fail("WithAdjuster should have thrown a ClassCastException, " 153 + "required: " + czdt + ", supplied: " + czdt2); 154 } catch (ClassCastException cce) { 155 // Expected exception; not an error 156 } 157 } else { 158 // Same chronology, 159 ChronoZonedDateTime<?> result = czdt.plus(adjuster); 160 assertEquals(result, czdt2, "WithAdjuster failed to replace date time"); 161 } 162 } 163 } 164 165 @Test(groups={"tck"}, dataProvider="calendars") 166 public void test_badMinusAdjusterChrono(Chrono<?> chrono) { 167 LocalDate refDate = LocalDate.of(1900, 1, 1); 168 ChronoZonedDateTime<?> czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); 169 for (Chrono<?>[] clist : data_of_calendars()) { 170 Chrono<?> chrono2 = clist[0]; 171 ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); 172 TemporalSubtractor adjuster = new FixedAdjuster(czdt2); 173 if (chrono != chrono2) { 174 try { 175 czdt.minus(adjuster); 176 Assert.fail("WithAdjuster should have thrown a ClassCastException, " 177 + "required: " + czdt + ", supplied: " + czdt2); 178 } catch (ClassCastException cce) { 179 // Expected exception; not an error 180 } 181 } else { 182 // Same chronology, 183 ChronoZonedDateTime<?> result = czdt.minus(adjuster); 184 assertEquals(result, czdt2, "WithAdjuster failed to replace date"); 185 } 186 } 187 } 188 189 @Test(groups={"tck"}, dataProvider="calendars") 190 public void test_badPlusTemporalUnitChrono(Chrono<?> chrono) { 191 LocalDate refDate = LocalDate.of(1900, 1, 1); 192 ChronoZonedDateTime<?> czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); 193 for (Chrono<?>[] clist : data_of_calendars()) { 194 Chrono<?> chrono2 = clist[0]; 195 ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); 196 TemporalUnit adjuster = new FixedTemporalUnit(czdt2); 197 if (chrono != chrono2) { 198 try { 199 czdt.plus(1, adjuster); 200 Assert.fail("TemporalUnit.doPlus plus should have thrown a ClassCastException, " + czdt 201 + " can not be cast to " + czdt2); 202 } catch (ClassCastException cce) { 203 // Expected exception; not an error 204 } 205 } else { 206 // Same chronology, 207 ChronoZonedDateTime<?> result = czdt.plus(1, adjuster); 208 assertEquals(result, czdt2, "WithAdjuster failed to replace date"); 209 } 210 } 211 } 212 213 @Test(groups={"tck"}, dataProvider="calendars") 214 public void test_badMinusTemporalUnitChrono(Chrono<?> chrono) { 215 LocalDate refDate = LocalDate.of(1900, 1, 1); 216 ChronoZonedDateTime<?> czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); 217 for (Chrono<?>[] clist : data_of_calendars()) { 218 Chrono<?> chrono2 = clist[0]; 219 ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); 220 TemporalUnit adjuster = new FixedTemporalUnit(czdt2); 221 if (chrono != chrono2) { 222 try { 223 czdt.minus(1, adjuster); 224 Assert.fail("TemporalUnit.doPlus minus should have thrown a ClassCastException, " + czdt.getClass() 225 + " can not be cast to " + czdt2.getClass()); 226 } catch (ClassCastException cce) { 227 // Expected exception; not an error 228 } 229 } else { 230 // Same chronology, 231 ChronoZonedDateTime<?> result = czdt.minus(1, adjuster); 232 assertEquals(result, czdt2, "WithAdjuster failed to replace date"); 233 } 234 } 235 } 236 237 @Test(groups={"tck"}, dataProvider="calendars") 238 public void test_badTemporalFieldChrono(Chrono<?> chrono) { 239 LocalDate refDate = LocalDate.of(1900, 1, 1); 240 ChronoZonedDateTime<?> czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); 241 for (Chrono<?>[] clist : data_of_calendars()) { 242 Chrono<?> chrono2 = clist[0]; 243 ChronoZonedDateTime<?> czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); 244 TemporalField adjuster = new FixedTemporalField(czdt2); 245 if (chrono != chrono2) { 246 try { 247 czdt.with(adjuster, 1); 248 Assert.fail("TemporalField doWith() should have thrown a ClassCastException, " + czdt.getClass() 249 + " can not be cast to " + czdt2.getClass()); 250 } catch (ClassCastException cce) { 251 // Expected exception; not an error 252 } 253 } else { 254 // Same chronology, 255 ChronoZonedDateTime<?> result = czdt.with(adjuster, 1); 256 assertEquals(result, czdt2, "TemporalField doWith() failed to replace date"); 257 } 258 } 259 } 260 261 //----------------------------------------------------------------------- 262 // isBefore, isAfter, isEqual, INSTANT_COMPARATOR test a Chrono<?> against the other Chronos 263 //----------------------------------------------------------------------- 264 @Test(groups={"tck"}, dataProvider="calendars") 265 public void test_zonedDateTime_comparisons(Chrono<?> chrono) { 266 List<ChronoZonedDateTime<?>> dates = new ArrayList<>(); 267 268 ChronoZonedDateTime<?> date = chrono.date(LocalDate.of(1900, 1, 1)) 269 .atTime(LocalTime.MIN) 270 .atZone(ZoneOffset.UTC); 271 272 // Insert dates in order, no duplicates 273 dates.add(date.minus(100, ChronoUnit.YEARS)); 274 dates.add(date.minus(1, ChronoUnit.YEARS)); 275 dates.add(date.minus(1, ChronoUnit.MONTHS)); 276 dates.add(date.minus(1, ChronoUnit.WEEKS)); 277 dates.add(date.minus(1, ChronoUnit.DAYS)); 278 dates.add(date.minus(1, ChronoUnit.HOURS)); 279 dates.add(date.minus(1, ChronoUnit.MINUTES)); 280 dates.add(date.minus(1, ChronoUnit.SECONDS)); 281 dates.add(date.minus(1, ChronoUnit.NANOS)); 282 dates.add(date); 283 dates.add(date.plus(1, ChronoUnit.NANOS)); 284 dates.add(date.plus(1, ChronoUnit.SECONDS)); 285 dates.add(date.plus(1, ChronoUnit.MINUTES)); 286 dates.add(date.plus(1, ChronoUnit.HOURS)); 287 dates.add(date.plus(1, ChronoUnit.DAYS)); 288 dates.add(date.plus(1, ChronoUnit.WEEKS)); 289 dates.add(date.plus(1, ChronoUnit.MONTHS)); 290 dates.add(date.plus(1, ChronoUnit.YEARS)); 291 dates.add(date.plus(100, ChronoUnit.YEARS)); 292 293 // Check these dates against the corresponding dates for every calendar 294 for (Chrono<?>[] clist : data_of_calendars()) { 295 List<ChronoZonedDateTime<?>> otherDates = new ArrayList<>(); 296 Chrono<?> chrono2 = ISOChrono.INSTANCE; //clist[0]; 297 for (ChronoZonedDateTime<?> d : dates) { 298 otherDates.add(chrono2.date(d).atTime(d.getTime()).atZone(d.getZone())); 299 } 300 301 // Now compare the sequence of original dates with the sequence of converted dates 302 for (int i = 0; i < dates.size(); i++) { 303 ChronoZonedDateTime<?> a = dates.get(i); 304 for (int j = 0; j < otherDates.size(); j++) { 305 ChronoZonedDateTime<?> b = otherDates.get(j); 306 int cmp = ChronoZonedDateTime.INSTANT_COMPARATOR.compare(a, b); 307 if (i < j) { 308 assertTrue(cmp < 0, a + " compare " + b); 309 assertEquals(a.isBefore(b), true, a + " isBefore " + b); 310 assertEquals(a.isAfter(b), false, a + " ifAfter " + b); 311 assertEquals(a.isEqual(b), false, a + " isEqual " + b); 312 } else if (i > j) { 313 assertTrue(cmp > 0, a + " compare " + b); 314 assertEquals(a.isBefore(b), false, a + " isBefore " + b); 315 assertEquals(a.isAfter(b), true, a + " ifAfter " + b); 316 assertEquals(a.isEqual(b), false, a + " isEqual " + b); 317 } else { 318 assertTrue(cmp == 0, a + " compare " + b); 319 assertEquals(a.isBefore(b), false, a + " isBefore " + b); 320 assertEquals(a.isAfter(b), false, a + " ifAfter " + b); 321 assertEquals(a.isEqual(b), true, a + " isEqual " + b); 322 } 323 } 324 } 325 } 326 } 327 328 //----------------------------------------------------------------------- 329 // Test Serialization of ISO via chrono API 330 //----------------------------------------------------------------------- 331 @Test( groups={"tck"}, dataProvider="calendars") 332 public <C extends Chrono<C>> void test_ChronoZonedDateTimeSerialization(C chrono) throws Exception { 333 ZonedDateTime ref = LocalDate.of(2000, 1, 5).atTime(12, 1, 2, 3).atZone(ZoneId.of("GMT+01:23")); 334 ChronoZonedDateTime<C> orginal = chrono.date(ref).atTime(ref.getTime()).atZone(ref.getZone()); 335 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 336 ObjectOutputStream out = new ObjectOutputStream(baos); 337 out.writeObject(orginal); 338 out.close(); 339 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 340 ObjectInputStream in = new ObjectInputStream(bais); 341 @SuppressWarnings("unchecked") 342 ChronoZonedDateTime<C> ser = (ChronoZonedDateTime<C>) in.readObject(); 343 assertEquals(ser, orginal, "deserialized date is wrong"); 344 } 345 346 347 /** 348 * FixedAdjusted returns a fixed Temporal in all adjustments. 349 * Construct an adjuster with the Temporal that should be returned from adjust. 350 */ 351 static class FixedAdjuster implements TemporalAdjuster, TemporalAdder, TemporalSubtractor { 352 private Temporal datetime; 353 354 FixedAdjuster(Temporal datetime) { 355 this.datetime = datetime; 356 } 357 358 @Override 359 public Temporal adjustInto(Temporal ignore) { 360 return datetime; 361 } 362 363 @Override 364 public Temporal addTo(Temporal ignore) { 365 return datetime; 366 } 367 368 @Override 369 public Temporal subtractFrom(Temporal ignore) { 370 return datetime; 371 } 372 373 } 374 375 /** 376 * FixedTemporalUnit returns a fixed Temporal in all adjustments. 377 * Construct an FixedTemporalUnit with the Temporal that should be returned from doPlus. 378 */ 379 static class FixedTemporalUnit implements TemporalUnit { 380 private Temporal temporal; 381 382 FixedTemporalUnit(Temporal temporal) { 383 this.temporal = temporal; 384 } 385 386 @Override 387 public String getName() { 388 return "FixedTemporalUnit"; 389 } 390 391 @Override 392 public Duration getDuration() { 393 throw new UnsupportedOperationException("Not supported yet."); 394 } 395 396 @Override 397 public boolean isDurationEstimated() { 398 throw new UnsupportedOperationException("Not supported yet."); 399 } 400 401 @Override 402 public boolean isSupported(Temporal temporal) { 403 throw new UnsupportedOperationException("Not supported yet."); 404 } 405 406 @SuppressWarnings("unchecked") 407 @Override 408 public <R extends Temporal> R doPlus(R dateTime, long periodToAdd) { 409 return (R) this.temporal; 410 } 411 412 @Override 413 public <R extends Temporal> SimplePeriod between(R dateTime1, R dateTime2) { 414 throw new UnsupportedOperationException("Not supported yet."); 415 } 416 } 417 418 /** 419 * FixedTemporalField returns a fixed Temporal in all adjustments. 420 * Construct an FixedTemporalField with the Temporal that should be returned from doWith. 421 */ 422 static class FixedTemporalField implements TemporalField { 423 private Temporal temporal; 424 FixedTemporalField(Temporal temporal) { 425 this.temporal = temporal; 426 } 427 428 @Override 429 public String getName() { 430 return "FixedTemporalField"; 431 } 432 433 @Override 434 public TemporalUnit getBaseUnit() { 435 throw new UnsupportedOperationException("Not supported yet."); 436 } 437 438 @Override 439 public TemporalUnit getRangeUnit() { 440 throw new UnsupportedOperationException("Not supported yet."); 441 } 442 443 @Override 444 public ValueRange range() { 445 throw new UnsupportedOperationException("Not supported yet."); 446 } 447 448 @Override 449 public boolean doIsSupported(TemporalAccessor temporal) { 450 throw new UnsupportedOperationException("Not supported yet."); 451 } 452 453 @Override 454 public ValueRange doRange(TemporalAccessor temporal) { 455 throw new UnsupportedOperationException("Not supported yet."); 456 } 457 458 @Override 459 public long doGet(TemporalAccessor temporal) { 460 throw new UnsupportedOperationException("Not supported yet."); 461 } 462 463 @SuppressWarnings("unchecked") 464 @Override 465 public <R extends Temporal> R doWith(R temporal, long newValue) { 466 return (R) this.temporal; 467 } 468 469 @Override 470 public boolean resolve(DateTimeBuilder builder, long value) { 471 throw new UnsupportedOperationException("Not supported yet."); 472 } 473 474 } 475 }