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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * This file is available under and governed by the GNU General Public
  26  * License version 2 only, as published by the Free Software Foundation.
  27  * However, the following notice accompanied the original version of this
  28  * file:
  29  *
  30  * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
  31  *
  32  * All rights reserved.
  33  *
  34  * Redistribution and use in source and binary forms, with or without
  35  * modification, are permitted provided that the following conditions are met:
  36  *
  37  *  * Redistributions of source code must retain the above copyright notice,
  38  *    this list of conditions and the following disclaimer.
  39  *
  40  *  * Redistributions in binary form must reproduce the above copyright notice,
  41  *    this list of conditions and the following disclaimer in the documentation
  42  *    and/or other materials provided with the distribution.
  43  *
  44  *  * Neither the name of JSR-310 nor the names of its contributors
  45  *    may be used to endorse or promote products derived from this software
  46  *    without specific prior written permission.
  47  *
  48  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  49  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  50  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  51  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  52  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  53  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  54  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  55  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  56  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  57  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  58  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  59  */
  60 package tck.java.time;
  61 
  62 import static java.time.temporal.ChronoField.OFFSET_SECONDS;
  63 import static org.testng.Assert.assertEquals;
  64 import static org.testng.Assert.assertSame;
  65 import static org.testng.Assert.assertTrue;
  66 import static org.testng.Assert.fail;
  67 
  68 import java.io.ByteArrayOutputStream;
  69 import java.io.DataOutputStream;
  70 import java.time.DateTimeException;
  71 import java.time.Duration;
  72 import java.time.Instant;
  73 import java.time.LocalDate;
  74 import java.time.LocalDateTime;
  75 import java.time.LocalTime;
  76 import java.time.ZoneOffset;
  77 import java.time.ZonedDateTime;
  78 import java.time.temporal.ChronoField;
  79 import java.time.temporal.JulianFields;
  80 import java.time.temporal.TemporalAccessor;
  81 import java.time.temporal.TemporalField;
  82 import java.time.temporal.TemporalQuery;
  83 import java.util.ArrayList;
  84 import java.util.Arrays;
  85 import java.util.List;
  86 
  87 import org.testng.annotations.DataProvider;
  88 import org.testng.annotations.Test;
  89 
  90 /**
  91  * Test ZoneOffset.
  92  */
  93 @Test
  94 public class TCKZoneOffset extends AbstractDateTimeTest {
  95 
  96     //-----------------------------------------------------------------------
  97     @Override
  98     protected List<TemporalAccessor> samples() {
  99         TemporalAccessor[] array = {ZoneOffset.ofHours(1), ZoneOffset.ofHoursMinutesSeconds(-5, -6, -30) };
 100         return Arrays.asList(array);
 101     }
 102 
 103     @Override
 104     protected List<TemporalField> validFields() {
 105         TemporalField[] array = {
 106             OFFSET_SECONDS,
 107         };
 108         return Arrays.asList(array);
 109     }
 110 
 111     @Override
 112     protected List<TemporalField> invalidFields() {
 113         List<TemporalField> list = new ArrayList<>(Arrays.<TemporalField>asList(ChronoField.values()));
 114         list.removeAll(validFields());
 115         list.add(JulianFields.JULIAN_DAY);
 116         list.add(JulianFields.MODIFIED_JULIAN_DAY);
 117         list.add(JulianFields.RATA_DIE);
 118         return list;
 119     }
 120 
 121     //-----------------------------------------------------------------------
 122     @Test
 123     public void test_serialization() throws Exception {
 124         assertSerializable(ZoneOffset.of("+01:30"));
 125     }
 126 
 127     @Test
 128     public void test_serialization_format_quarterPositive() throws Exception {
 129         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 130         try (DataOutputStream dos = new DataOutputStream(baos) ) {
 131             dos.writeByte(8);
 132             dos.writeByte(6);  // stored as quarter hours
 133         }
 134         byte[] bytes = baos.toByteArray();
 135         assertSerializedBySer(ZoneOffset.ofHoursMinutes(1, 30), bytes);
 136     }
 137 
 138     @Test
 139     public void test_serialization_format_quarterNegative() throws Exception {
 140         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 141         try (DataOutputStream dos = new DataOutputStream(baos) ) {
 142             dos.writeByte(8);
 143             dos.writeByte(-10);  // stored as quarter hours
 144         }
 145         byte[] bytes = baos.toByteArray();
 146         assertSerializedBySer(ZoneOffset.ofHoursMinutes(-2, -30), bytes);
 147     }
 148 
 149     @Test
 150     public void test_serialization_format_full() throws Exception {
 151         ByteArrayOutputStream baos = new ByteArrayOutputStream();
 152         try (DataOutputStream dos = new DataOutputStream(baos) ) {
 153             dos.writeByte(8);
 154             dos.writeByte(127);
 155             dos.writeInt(53265);
 156         }
 157         byte[] bytes = baos.toByteArray();
 158         assertSerializedBySer(ZoneOffset.ofTotalSeconds(53265), bytes);
 159     }
 160 
 161     //-----------------------------------------------------------------------
 162     // constants
 163     //-----------------------------------------------------------------------
 164     @Test
 165     public void test_constant_UTC() {
 166         ZoneOffset test = ZoneOffset.UTC;
 167         doTestOffset(test, 0, 0, 0);
 168     }
 169 
 170     @Test
 171     public void test_constant_MIN() {
 172         ZoneOffset test = ZoneOffset.MIN;
 173         doTestOffset(test, -18, 0, 0);
 174     }
 175 
 176     @Test
 177     public void test_constant_MAX() {
 178         ZoneOffset test = ZoneOffset.MAX;
 179         doTestOffset(test, 18, 0, 0);
 180     }
 181 
 182     //-----------------------------------------------------------------------
 183     // of(String)
 184     //-----------------------------------------------------------------------
 185     @Test
 186     public void test_factory_string_UTC() {
 187         String[] values = new String[] {
 188             "Z", "+0",
 189             "+00","+0000","+00:00","+000000","+00:00:00",
 190             "-00","-0000","-00:00","-000000","-00:00:00",
 191         };
 192         for (int i = 0; i < values.length; i++) {
 193             ZoneOffset test = ZoneOffset.of(values[i]);
 194             assertSame(test, ZoneOffset.UTC);
 195         }
 196     }
 197 
 198     @Test
 199     public void test_factory_string_invalid() {
 200         String[] values = new String[] {
 201             "","A","B","C","D","E","F","G","H","I","J","K","L","M",
 202             "N","O","P","Q","R","S","T","U","V","W","X","Y","ZZ",
 203             "0", "+0:00","+00:0","+0:0",
 204             "+000","+00000",
 205             "+0:00:00","+00:0:00","+00:00:0","+0:0:0","+0:0:00","+00:0:0","+0:00:0",
 206             "1", "+01_00","+01;00","+01@00","+01:AA",
 207             "+19","+19:00","+18:01","+18:00:01","+1801","+180001",
 208             "-0:00","-00:0","-0:0",
 209             "-000","-00000",
 210             "-0:00:00","-00:0:00","-00:00:0","-0:0:0","-0:0:00","-00:0:0","-0:00:0",
 211             "-19","-19:00","-18:01","-18:00:01","-1801","-180001",
 212             "-01_00","-01;00","-01@00","-01:AA",
 213             "@01:00",
 214         };
 215         for (int i = 0; i < values.length; i++) {
 216             try {
 217                 ZoneOffset.of(values[i]);
 218                 fail("Should have failed:" + values[i]);
 219             } catch (DateTimeException ex) {
 220                 // expected
 221             }
 222         }
 223     }
 224 
 225     @Test(expectedExceptions=NullPointerException.class)
 226     public void test_factory_string_null() {
 227         ZoneOffset.of((String) null);
 228     }
 229 
 230     //-----------------------------------------------------------------------
 231     @Test
 232     public void test_factory_string_singleDigitHours() {
 233         for (int i = -9; i <= 9; i++) {
 234             String str = (i < 0 ? "-" : "+") + Math.abs(i);
 235             ZoneOffset test = ZoneOffset.of(str);
 236             doTestOffset(test, i, 0, 0);
 237         }
 238     }
 239 
 240     @Test
 241     public void test_factory_string_hours() {
 242         for (int i = -18; i <= 18; i++) {
 243             String str = (i < 0 ? "-" : "+") + Integer.toString(Math.abs(i) + 100).substring(1);
 244             ZoneOffset test = ZoneOffset.of(str);
 245             doTestOffset(test, i, 0, 0);
 246         }
 247     }
 248 
 249     @Test
 250     public void test_factory_string_hours_minutes_noColon() {
 251         for (int i = -17; i <= 17; i++) {
 252             for (int j = -59; j <= 59; j++) {
 253                 if ((i < 0 && j <= 0) || (i > 0 && j >= 0) || i == 0) {
 254                     String str = (i < 0 || j < 0 ? "-" : "+") +
 255                         Integer.toString(Math.abs(i) + 100).substring(1) +
 256                         Integer.toString(Math.abs(j) + 100).substring(1);
 257                     ZoneOffset test = ZoneOffset.of(str);
 258                     doTestOffset(test, i, j, 0);
 259                 }
 260             }
 261         }
 262         ZoneOffset test1 = ZoneOffset.of("-1800");
 263         doTestOffset(test1, -18, 0, 0);
 264         ZoneOffset test2 = ZoneOffset.of("+1800");
 265         doTestOffset(test2, 18, 0, 0);
 266     }
 267 
 268     @Test
 269     public void test_factory_string_hours_minutes_colon() {
 270         for (int i = -17; i <= 17; i++) {
 271             for (int j = -59; j <= 59; j++) {
 272                 if ((i < 0 && j <= 0) || (i > 0 && j >= 0) || i == 0) {
 273                     String str = (i < 0 || j < 0 ? "-" : "+") +
 274                         Integer.toString(Math.abs(i) + 100).substring(1) + ":" +
 275                         Integer.toString(Math.abs(j) + 100).substring(1);
 276                     ZoneOffset test = ZoneOffset.of(str);
 277                     doTestOffset(test, i, j, 0);
 278                 }
 279             }
 280         }
 281         ZoneOffset test1 = ZoneOffset.of("-18:00");
 282         doTestOffset(test1, -18, 0, 0);
 283         ZoneOffset test2 = ZoneOffset.of("+18:00");
 284         doTestOffset(test2, 18, 0, 0);
 285     }
 286 
 287     @Test
 288     public void test_factory_string_hours_minutes_seconds_noColon() {
 289         for (int i = -17; i <= 17; i++) {
 290             for (int j = -59; j <= 59; j++) {
 291                 for (int k = -59; k <= 59; k++) {
 292                     if ((i < 0 && j <= 0 && k <= 0) || (i > 0 && j >= 0 && k >= 0) ||
 293                             (i == 0 && ((j < 0 && k <= 0) || (j > 0 && k >= 0) || j == 0))) {
 294                         String str = (i < 0 || j < 0 || k < 0 ? "-" : "+") +
 295                             Integer.toString(Math.abs(i) + 100).substring(1) +
 296                             Integer.toString(Math.abs(j) + 100).substring(1) +
 297                             Integer.toString(Math.abs(k) + 100).substring(1);
 298                         ZoneOffset test = ZoneOffset.of(str);
 299                         doTestOffset(test, i, j, k);
 300                     }
 301                 }
 302             }
 303         }
 304         ZoneOffset test1 = ZoneOffset.of("-180000");
 305         doTestOffset(test1, -18, 0, 0);
 306         ZoneOffset test2 = ZoneOffset.of("+180000");
 307         doTestOffset(test2, 18, 0, 0);
 308     }
 309 
 310     @Test
 311     public void test_factory_string_hours_minutes_seconds_colon() {
 312         for (int i = -17; i <= 17; i++) {
 313             for (int j = -59; j <= 59; j++) {
 314                 for (int k = -59; k <= 59; k++) {
 315                     if ((i < 0 && j <= 0 && k <= 0) || (i > 0 && j >= 0 && k >= 0) ||
 316                             (i == 0 && ((j < 0 && k <= 0) || (j > 0 && k >= 0) || j == 0))) {
 317                         String str = (i < 0 || j < 0 || k < 0 ? "-" : "+") +
 318                             Integer.toString(Math.abs(i) + 100).substring(1) + ":" +
 319                             Integer.toString(Math.abs(j) + 100).substring(1) + ":" +
 320                             Integer.toString(Math.abs(k) + 100).substring(1);
 321                         ZoneOffset test = ZoneOffset.of(str);
 322                         doTestOffset(test, i, j, k);
 323                     }
 324                 }
 325             }
 326         }
 327         ZoneOffset test1 = ZoneOffset.of("-18:00:00");
 328         doTestOffset(test1, -18, 0, 0);
 329         ZoneOffset test2 = ZoneOffset.of("+18:00:00");
 330         doTestOffset(test2, 18, 0, 0);
 331     }
 332 
 333     //-----------------------------------------------------------------------
 334     @Test
 335     public void test_factory_int_hours() {
 336         for (int i = -18; i <= 18; i++) {
 337             ZoneOffset test = ZoneOffset.ofHours(i);
 338             doTestOffset(test, i, 0, 0);
 339         }
 340     }
 341 
 342     @Test(expectedExceptions=DateTimeException.class)
 343     public void test_factory_int_hours_tooBig() {
 344         ZoneOffset.ofHours(19);
 345     }
 346 
 347     @Test(expectedExceptions=DateTimeException.class)
 348     public void test_factory_int_hours_tooSmall() {
 349         ZoneOffset.ofHours(-19);
 350     }
 351 
 352     //-----------------------------------------------------------------------
 353     @Test
 354     public void test_factory_int_hours_minutes() {
 355         for (int i = -17; i <= 17; i++) {
 356             for (int j = -59; j <= 59; j++) {
 357                 if ((i < 0 && j <= 0) || (i > 0 && j >= 0) || i == 0) {
 358                     ZoneOffset test = ZoneOffset.ofHoursMinutes(i, j);
 359                     doTestOffset(test, i, j, 0);
 360                 }
 361             }
 362         }
 363         ZoneOffset test1 = ZoneOffset.ofHoursMinutes(-18, 0);
 364         doTestOffset(test1, -18, 0, 0);
 365         ZoneOffset test2 = ZoneOffset.ofHoursMinutes(18, 0);
 366         doTestOffset(test2, 18, 0, 0);
 367     }
 368 
 369     @Test(expectedExceptions=DateTimeException.class)
 370     public void test_factory_int_hours_minutes_tooBig() {
 371         ZoneOffset.ofHoursMinutes(19, 0);
 372     }
 373 
 374     @Test(expectedExceptions=DateTimeException.class)
 375     public void test_factory_int_hours_minutes_tooSmall() {
 376         ZoneOffset.ofHoursMinutes(-19, 0);
 377     }
 378 
 379     //-----------------------------------------------------------------------
 380     @Test
 381     public void test_factory_int_hours_minutes_seconds() {
 382         for (int i = -17; i <= 17; i++) {
 383             for (int j = -59; j <= 59; j++) {
 384                 for (int k = -59; k <= 59; k++) {
 385                     if ((i < 0 && j <= 0 && k <= 0) || (i > 0 && j >= 0 && k >= 0) ||
 386                             (i == 0 && ((j < 0 && k <= 0) || (j > 0 && k >= 0) || j == 0))) {
 387                         ZoneOffset test = ZoneOffset.ofHoursMinutesSeconds(i, j, k);
 388                         doTestOffset(test, i, j, k);
 389                     }
 390                 }
 391             }
 392         }
 393         ZoneOffset test1 = ZoneOffset.ofHoursMinutesSeconds(-18, 0, 0);
 394         doTestOffset(test1, -18, 0, 0);
 395         ZoneOffset test2 = ZoneOffset.ofHoursMinutesSeconds(18, 0, 0);
 396         doTestOffset(test2, 18, 0, 0);
 397     }
 398 
 399     @Test(expectedExceptions=DateTimeException.class)
 400     public void test_factory_int_hours_minutes_seconds_plusHoursMinusMinutes() {
 401         ZoneOffset.ofHoursMinutesSeconds(1, -1, 0);
 402     }
 403 
 404     @Test(expectedExceptions=DateTimeException.class)
 405     public void test_factory_int_hours_minutes_seconds_plusHoursMinusSeconds() {
 406         ZoneOffset.ofHoursMinutesSeconds(1, 0, -1);
 407     }
 408 
 409     @Test(expectedExceptions=DateTimeException.class)
 410     public void test_factory_int_hours_minutes_seconds_minusHoursPlusMinutes() {
 411         ZoneOffset.ofHoursMinutesSeconds(-1, 1, 0);
 412     }
 413 
 414     @Test(expectedExceptions=DateTimeException.class)
 415     public void test_factory_int_hours_minutes_seconds_minusHoursPlusSeconds() {
 416         ZoneOffset.ofHoursMinutesSeconds(-1, 0, 1);
 417     }
 418 
 419     @Test(expectedExceptions=DateTimeException.class)
 420     public void test_factory_int_hours_minutes_seconds_zeroHoursMinusMinutesPlusSeconds() {
 421         ZoneOffset.ofHoursMinutesSeconds(0, -1, 1);
 422     }
 423 
 424     @Test(expectedExceptions=DateTimeException.class)
 425     public void test_factory_int_hours_minutes_seconds_zeroHoursPlusMinutesMinusSeconds() {
 426         ZoneOffset.ofHoursMinutesSeconds(0, 1, -1);
 427     }
 428 
 429     @Test(expectedExceptions=DateTimeException.class)
 430     public void test_factory_int_hours_minutes_seconds_minutesTooLarge() {
 431         ZoneOffset.ofHoursMinutesSeconds(0, 60, 0);
 432     }
 433 
 434     @Test(expectedExceptions=DateTimeException.class)
 435     public void test_factory_int_hours_minutes_seconds_minutesTooSmall() {
 436         ZoneOffset.ofHoursMinutesSeconds(0, -60, 0);
 437     }
 438 
 439     @Test(expectedExceptions=DateTimeException.class)
 440     public void test_factory_int_hours_minutes_seconds_secondsTooLarge() {
 441         ZoneOffset.ofHoursMinutesSeconds(0, 0, 60);
 442     }
 443 
 444     @Test(expectedExceptions=DateTimeException.class)
 445     public void test_factory_int_hours_minutes_seconds_secondsTooSmall() {
 446         ZoneOffset.ofHoursMinutesSeconds(0, 0, 60);
 447     }
 448 
 449     @Test(expectedExceptions=DateTimeException.class)
 450     public void test_factory_int_hours_minutes_seconds_hoursTooBig() {
 451         ZoneOffset.ofHoursMinutesSeconds(19, 0, 0);
 452     }
 453 
 454     @Test(expectedExceptions=DateTimeException.class)
 455     public void test_factory_int_hours_minutes_seconds_hoursTooSmall() {
 456         ZoneOffset.ofHoursMinutesSeconds(-19, 0, 0);
 457     }
 458 
 459     //-----------------------------------------------------------------------
 460     @Test
 461     public void test_factory_ofTotalSeconds() {
 462         assertEquals(ZoneOffset.ofTotalSeconds(60 * 60 + 1), ZoneOffset.ofHoursMinutesSeconds(1, 0, 1));
 463         assertEquals(ZoneOffset.ofTotalSeconds(18 * 60 * 60), ZoneOffset.ofHours(18));
 464         assertEquals(ZoneOffset.ofTotalSeconds(-18 * 60 * 60), ZoneOffset.ofHours(-18));
 465     }
 466 
 467     @Test(expectedExceptions=DateTimeException.class)
 468     public void test_factory_ofTotalSeconds_tooLarge() {
 469         ZoneOffset.ofTotalSeconds(18 * 60 * 60 + 1);
 470     }
 471 
 472     @Test(expectedExceptions=DateTimeException.class)
 473     public void test_factory_ofTotalSeconds_tooSmall() {
 474         ZoneOffset.ofTotalSeconds(-18 * 60 * 60 - 1);
 475     }
 476 
 477     //-----------------------------------------------------------------------
 478     // from()
 479     //-----------------------------------------------------------------------
 480     @Test
 481     public void test_factory_CalendricalObject() {
 482         assertEquals(ZoneOffset.from(ZonedDateTime.of(LocalDateTime.of(LocalDate.of(2007, 7, 15),
 483                 LocalTime.of(17, 30)), ZoneOffset.ofHours(2))), ZoneOffset.ofHours(2));
 484     }
 485 
 486     @Test(expectedExceptions=DateTimeException.class)
 487     public void test_factory_CalendricalObject_invalid_noDerive() {
 488         ZoneOffset.from(LocalTime.of(12, 30));
 489     }
 490 
 491     @Test(expectedExceptions=NullPointerException.class)
 492     public void test_factory_CalendricalObject_null() {
 493         ZoneOffset.from((TemporalAccessor) null);
 494     }
 495 
 496     //-----------------------------------------------------------------------
 497     // getTotalSeconds()
 498     //-----------------------------------------------------------------------
 499     @Test
 500     public void test_getTotalSeconds() {
 501         ZoneOffset offset = ZoneOffset.ofTotalSeconds(60 * 60 + 1);
 502         assertEquals(offset.getTotalSeconds(), 60 * 60 + 1);
 503     }
 504 
 505     //-----------------------------------------------------------------------
 506     // getId()
 507     //-----------------------------------------------------------------------
 508     @Test
 509     public void test_getId() {
 510         ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(1, 0, 0);
 511         assertEquals(offset.getId(), "+01:00");
 512         offset = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3);
 513         assertEquals(offset.getId(), "+01:02:03");
 514         offset = ZoneOffset.UTC;
 515         assertEquals(offset.getId(), "Z");
 516     }
 517 
 518     //-----------------------------------------------------------------------
 519     // getRules()
 520     //-----------------------------------------------------------------------
 521     @Test
 522     public void test_getRules() {
 523         ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3);
 524         assertEquals(offset.getRules().isFixedOffset(), true);
 525         assertEquals(offset.getRules().getOffset((Instant) null), offset);
 526         assertEquals(offset.getRules().getDaylightSavings((Instant) null), Duration.ZERO);
 527         assertEquals(offset.getRules().getStandardOffset((Instant) null), offset);
 528         assertEquals(offset.getRules().nextTransition((Instant) null), null);
 529         assertEquals(offset.getRules().previousTransition((Instant) null), null);
 530 
 531         assertEquals(offset.getRules().isValidOffset((LocalDateTime) null, offset), true);
 532         assertEquals(offset.getRules().isValidOffset((LocalDateTime) null, ZoneOffset.UTC), false);
 533         assertEquals(offset.getRules().isValidOffset((LocalDateTime) null, null), false);
 534         assertEquals(offset.getRules().getOffset((LocalDateTime) null), offset);
 535         assertEquals(offset.getRules().getValidOffsets((LocalDateTime) null), Arrays.asList(offset));
 536         assertEquals(offset.getRules().getTransition((LocalDateTime) null), null);
 537         assertEquals(offset.getRules().getTransitions().size(), 0);
 538         assertEquals(offset.getRules().getTransitionRules().size(), 0);
 539     }
 540 
 541     //-----------------------------------------------------------------------
 542     // get(TemporalField)
 543     //-----------------------------------------------------------------------
 544     @Test
 545     public void test_get_TemporalField() {
 546         assertEquals(ZoneOffset.UTC.get(OFFSET_SECONDS), 0);
 547         assertEquals(ZoneOffset.ofHours(-2).get(OFFSET_SECONDS), -7200);
 548         assertEquals(ZoneOffset.ofHoursMinutesSeconds(0, 1, 5).get(OFFSET_SECONDS), 65);
 549     }
 550 
 551     @Test
 552     public void test_getLong_TemporalField() {
 553         assertEquals(ZoneOffset.UTC.getLong(OFFSET_SECONDS), 0);
 554         assertEquals(ZoneOffset.ofHours(-2).getLong(OFFSET_SECONDS), -7200);
 555         assertEquals(ZoneOffset.ofHoursMinutesSeconds(0, 1, 5).getLong(OFFSET_SECONDS), 65);
 556     }
 557 
 558     //-----------------------------------------------------------------------
 559     // query(TemporalQuery)
 560     //-----------------------------------------------------------------------
 561     @DataProvider(name="query")
 562     Object[][] data_query() {
 563         return new Object[][] {
 564                 {ZoneOffset.UTC, TemporalQuery.chronology(), null},
 565                 {ZoneOffset.UTC, TemporalQuery.zoneId(), null},
 566                 {ZoneOffset.UTC, TemporalQuery.precision(), null},
 567                 {ZoneOffset.UTC, TemporalQuery.zone(), ZoneOffset.UTC},
 568                 {ZoneOffset.UTC, TemporalQuery.offset(), ZoneOffset.UTC},
 569                 {ZoneOffset.UTC, TemporalQuery.localDate(), null},
 570                 {ZoneOffset.UTC, TemporalQuery.localTime(), null},
 571         };
 572     }
 573 
 574     @Test(dataProvider="query")
 575     public <T> void test_query(TemporalAccessor temporal, TemporalQuery<T> query, T expected) {
 576         assertEquals(temporal.query(query), expected);
 577     }
 578 
 579     @Test(dataProvider="query")
 580     public <T> void test_queryFrom(TemporalAccessor temporal, TemporalQuery<T> query, T expected) {
 581         assertEquals(query.queryFrom(temporal), expected);
 582     }
 583 
 584     @Test(expectedExceptions=NullPointerException.class)
 585     public void test_query_null() {
 586         ZoneOffset.UTC.query(null);
 587     }
 588 
 589     //-----------------------------------------------------------------------
 590     // compareTo()
 591     //-----------------------------------------------------------------------
 592     @Test
 593     public void test_compareTo() {
 594         ZoneOffset offset1 = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3);
 595         ZoneOffset offset2 = ZoneOffset.ofHoursMinutesSeconds(2, 3, 4);
 596         assertTrue(offset1.compareTo(offset2) > 0);
 597         assertTrue(offset2.compareTo(offset1) < 0);
 598         assertTrue(offset1.compareTo(offset1) == 0);
 599         assertTrue(offset2.compareTo(offset2) == 0);
 600     }
 601 
 602     //-----------------------------------------------------------------------
 603     // equals() / hashCode()
 604     //-----------------------------------------------------------------------
 605     @Test
 606     public void test_equals() {
 607         ZoneOffset offset1 = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3);
 608         ZoneOffset offset2 = ZoneOffset.ofHoursMinutesSeconds(2, 3, 4);
 609         ZoneOffset offset2b = ZoneOffset.ofHoursMinutesSeconds(2, 3, 4);
 610         assertEquals(offset1.equals(offset2), false);
 611         assertEquals(offset2.equals(offset1), false);
 612 
 613         assertEquals(offset1.equals(offset1), true);
 614         assertEquals(offset2.equals(offset2), true);
 615         assertEquals(offset2.equals(offset2b), true);
 616 
 617         assertEquals(offset1.hashCode() == offset1.hashCode(), true);
 618         assertEquals(offset2.hashCode() == offset2.hashCode(), true);
 619         assertEquals(offset2.hashCode() == offset2b.hashCode(), true);
 620     }
 621 
 622     //-----------------------------------------------------------------------
 623     // toString()
 624     //-----------------------------------------------------------------------
 625     @Test
 626     public void test_toString() {
 627         ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(1, 0, 0);
 628         assertEquals(offset.toString(), "+01:00");
 629         offset = ZoneOffset.ofHoursMinutesSeconds(1, 2, 3);
 630         assertEquals(offset.toString(), "+01:02:03");
 631         offset = ZoneOffset.UTC;
 632         assertEquals(offset.toString(), "Z");
 633     }
 634 
 635     //-----------------------------------------------------------------------
 636     //-----------------------------------------------------------------------
 637     //-----------------------------------------------------------------------
 638     private void doTestOffset(ZoneOffset offset, int hours, int minutes, int seconds) {
 639         assertEquals(offset.getTotalSeconds(), hours * 60 * 60 + minutes * 60 + seconds);
 640         final String id;
 641         if (hours == 0 && minutes == 0 && seconds == 0) {
 642             id = "Z";
 643         } else {
 644             String str = (hours < 0 || minutes < 0 || seconds < 0) ? "-" : "+";
 645             str += Integer.toString(Math.abs(hours) + 100).substring(1);
 646             str += ":";
 647             str += Integer.toString(Math.abs(minutes) + 100).substring(1);
 648             if (seconds != 0) {
 649                 str += ":";
 650                 str += Integer.toString(Math.abs(seconds) + 100).substring(1);
 651             }
 652             id = str;
 653         }
 654         assertEquals(offset.getId(), id);
 655         assertEquals(offset, ZoneOffset.ofHoursMinutesSeconds(hours, minutes, seconds));
 656         if (seconds == 0) {
 657             assertEquals(offset, ZoneOffset.ofHoursMinutes(hours, minutes));
 658             if (minutes == 0) {
 659                 assertEquals(offset, ZoneOffset.ofHours(hours));
 660             }
 661         }
 662         assertEquals(ZoneOffset.of(id), offset);
 663         assertEquals(offset.toString(), id);
 664     }
 665 
 666 }