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.format;
  61 
  62 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
  63 import static java.time.temporal.ChronoField.DAY_OF_WEEK;
  64 import static java.time.temporal.ChronoField.DAY_OF_YEAR;
  65 import static java.time.temporal.ChronoField.HOUR_OF_DAY;
  66 import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
  67 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
  68 import static java.time.temporal.ChronoField.NANO_OF_SECOND;
  69 import static java.time.temporal.ChronoField.OFFSET_SECONDS;
  70 import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
  71 import static java.time.temporal.ChronoField.YEAR;
  72 import static org.testng.Assert.assertEquals;
  73 import static org.testng.Assert.assertTrue;
  74 import static org.testng.Assert.fail;
  75 
  76 import java.text.ParsePosition;
  77 import java.time.DateTimeException;
  78 import java.time.LocalDate;
  79 import java.time.LocalDateTime;
  80 import java.time.Year;
  81 import java.time.YearMonth;
  82 import java.time.ZoneId;
  83 import java.time.ZoneOffset;
  84 import java.time.ZonedDateTime;
  85 import java.time.chrono.Chronology;
  86 import java.time.format.DateTimeFormatter;
  87 import java.time.format.DateTimeParseException;
  88 import java.time.temporal.IsoFields;
  89 import java.time.temporal.Queries;
  90 import java.time.temporal.TemporalAccessor;
  91 import java.time.temporal.TemporalField;
  92 import java.time.temporal.TemporalQuery;
  93 import java.util.HashMap;
  94 import java.util.Iterator;
  95 import java.util.Locale;
  96 import java.util.Map;
  97 
  98 import org.testng.annotations.BeforeMethod;
  99 import org.testng.annotations.DataProvider;
 100 import org.testng.annotations.Test;
 101 
 102 /**
 103  * Test DateTimeFormatter.
 104  */
 105 @Test
 106 public class TCKDateTimeFormatters {
 107 
 108     @BeforeMethod
 109     public void setUp() {
 110     }
 111 
 112     //-----------------------------------------------------------------------
 113     @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
 114     public void test_print_nullCalendrical() {
 115         DateTimeFormatter.ISO_DATE.format((TemporalAccessor) null);
 116     }
 117 
 118     //-----------------------------------------------------------------------
 119     //-----------------------------------------------------------------------
 120     //-----------------------------------------------------------------------
 121     @Test(groups={"tck"})
 122     public void test_pattern_String() {
 123         DateTimeFormatter test = DateTimeFormatter.ofPattern("d MMM yyyy");
 124         assertEquals(test.toString(), "Value(DayOfMonth)' 'Text(MonthOfYear,SHORT)' 'Value(Year,4,19,EXCEEDS_PAD)");
 125         assertEquals(test.getLocale(), Locale.getDefault());
 126     }
 127 
 128     @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
 129     public void test_pattern_String_invalid() {
 130         DateTimeFormatter.ofPattern("p");
 131     }
 132 
 133     @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
 134     public void test_pattern_String_null() {
 135         DateTimeFormatter.ofPattern(null);
 136     }
 137 
 138     //-----------------------------------------------------------------------
 139     //-----------------------------------------------------------------------
 140     //-----------------------------------------------------------------------
 141     @Test(groups={"tck"})
 142     public void test_pattern_StringLocale() {
 143         DateTimeFormatter test = DateTimeFormatter.ofPattern("d MMM yyyy", Locale.UK);
 144         assertEquals(test.toString(), "Value(DayOfMonth)' 'Text(MonthOfYear,SHORT)' 'Value(Year,4,19,EXCEEDS_PAD)");
 145         assertEquals(test.getLocale(), Locale.UK);
 146     }
 147 
 148     @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"})
 149     public void test_pattern_StringLocale_invalid() {
 150         DateTimeFormatter.ofPattern("p", Locale.UK);
 151     }
 152 
 153     @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
 154     public void test_pattern_StringLocale_nullPattern() {
 155         DateTimeFormatter.ofPattern(null, Locale.UK);
 156     }
 157 
 158     @Test(expectedExceptions=NullPointerException.class, groups={"tck"})
 159     public void test_pattern_StringLocale_nullLocale() {
 160         DateTimeFormatter.ofPattern("yyyy", null);
 161     }
 162 
 163     //-----------------------------------------------------------------------
 164     //-----------------------------------------------------------------------
 165     //-----------------------------------------------------------------------
 166     @DataProvider(name="sample_isoLocalDate")
 167     Object[][] provider_sample_isoLocalDate() {
 168         return new Object[][]{
 169                 {2008, null, null, null, null, null, DateTimeException.class},
 170                 {null, 6, null, null, null, null, DateTimeException.class},
 171                 {null, null, 30, null, null, null, DateTimeException.class},
 172                 {null, null, null, "+01:00", null, null, DateTimeException.class},
 173                 {null, null, null, null, "Europe/Paris", null, DateTimeException.class},
 174                 {2008, 6, null, null, null, null, DateTimeException.class},
 175                 {null, 6, 30, null, null, null, DateTimeException.class},
 176 
 177                 {2008, 6, 30, null, null,                   "2008-06-30", null},
 178                 {2008, 6, 30, "+01:00", null,               "2008-06-30", null},
 179                 {2008, 6, 30, "+01:00", "Europe/Paris",     "2008-06-30", null},
 180                 {2008, 6, 30, null, "Europe/Paris",         "2008-06-30", null},
 181 
 182                 {123456, 6, 30, null, null,                 "+123456-06-30", null},
 183         };
 184     }
 185 
 186     @Test(dataProvider="sample_isoLocalDate", groups={"tck"})
 187     public void test_print_isoLocalDate(
 188             Integer year, Integer month, Integer day, String offsetId, String zoneId,
 189             String expected, Class<?> expectedEx) {
 190         TemporalAccessor test = buildAccessor(year, month, day, null, null, null, null, offsetId, zoneId);
 191         if (expectedEx == null) {
 192             assertEquals(DateTimeFormatter.ISO_LOCAL_DATE.format(test), expected);
 193         } else {
 194             try {
 195                 DateTimeFormatter.ISO_LOCAL_DATE.format(test);
 196                 fail();
 197             } catch (Exception ex) {
 198                 assertTrue(expectedEx.isInstance(ex));
 199             }
 200         }
 201     }
 202 
 203     @Test(dataProvider="sample_isoLocalDate", groups={"tck"})
 204     public void test_parse_isoLocalDate(
 205             Integer year, Integer month, Integer day, String offsetId, String zoneId,
 206             String input, Class<?> invalid) {
 207         if (input != null) {
 208             Expected expected = createDate(year, month, day);
 209             // offset/zone not expected to be parsed
 210             assertParseMatch(DateTimeFormatter.ISO_LOCAL_DATE.parseUnresolved(input, new ParsePosition(0)), expected);
 211         }
 212     }
 213 
 214     @Test(groups={"tck"})
 215     public void test_parse_isoLocalDate_999999999() {
 216         Expected expected = createDate(999999999, 8, 6);
 217         assertParseMatch(DateTimeFormatter.ISO_LOCAL_DATE.parseUnresolved("+999999999-08-06", new ParsePosition(0)), expected);
 218         assertEquals(LocalDate.parse("+999999999-08-06"), LocalDate.of(999999999, 8, 6));
 219     }
 220 
 221     @Test(groups={"tck"})
 222     public void test_parse_isoLocalDate_1000000000() {
 223         Expected expected = createDate(1000000000, 8, 6);
 224         assertParseMatch(DateTimeFormatter.ISO_LOCAL_DATE.parseUnresolved("+1000000000-08-06", new ParsePosition(0)), expected);
 225     }
 226 
 227     @Test(expectedExceptions = DateTimeException.class, groups={"tck"})
 228     public void test_parse_isoLocalDate_1000000000_failedCreate() {
 229         LocalDate.parse("+1000000000-08-06");
 230     }
 231 
 232     @Test(groups={"tck"})
 233     public void test_parse_isoLocalDate_M999999999() {
 234         Expected expected = createDate(-999999999, 8, 6);
 235         assertParseMatch(DateTimeFormatter.ISO_LOCAL_DATE.parseUnresolved("-999999999-08-06", new ParsePosition(0)), expected);
 236         assertEquals(LocalDate.parse("-999999999-08-06"), LocalDate.of(-999999999, 8, 6));
 237     }
 238 
 239     @Test(groups={"tck"})
 240     public void test_parse_isoLocalDate_M1000000000() {
 241         Expected expected = createDate(-1000000000, 8, 6);
 242         assertParseMatch(DateTimeFormatter.ISO_LOCAL_DATE.parseUnresolved("-1000000000-08-06", new ParsePosition(0)), expected);
 243     }
 244 
 245     @Test(expectedExceptions = DateTimeException.class, groups={"tck"})
 246     public void test_parse_isoLocalDate_M1000000000_failedCreate() {
 247         LocalDate.parse("-1000000000-08-06");
 248     }
 249 
 250     //-----------------------------------------------------------------------
 251     //-----------------------------------------------------------------------
 252     //-----------------------------------------------------------------------
 253     @DataProvider(name="sample_isoOffsetDate")
 254     Object[][] provider_sample_isoOffsetDate() {
 255         return new Object[][]{
 256                 {2008, null, null, null, null, null, DateTimeException.class},
 257                 {null, 6, null, null, null, null, DateTimeException.class},
 258                 {null, null, 30, null, null, null, DateTimeException.class},
 259                 {null, null, null, "+01:00", null, null, DateTimeException.class},
 260                 {null, null, null, null, "Europe/Paris", null, DateTimeException.class},
 261                 {2008, 6, null, null, null, null, DateTimeException.class},
 262                 {null, 6, 30, null, null, null, DateTimeException.class},
 263 
 264                 {2008, 6, 30, null, null,                   null, DateTimeException.class},
 265                 {2008, 6, 30, "+01:00", null,               "2008-06-30+01:00", null},
 266                 {2008, 6, 30, "+01:00", "Europe/Paris",     "2008-06-30+01:00", null},
 267                 {2008, 6, 30, null, "Europe/Paris",         null, DateTimeException.class},
 268 
 269                 {123456, 6, 30, "+01:00", null,             "+123456-06-30+01:00", null},
 270         };
 271     }
 272 
 273     @Test(dataProvider="sample_isoOffsetDate", groups={"tck"})
 274     public void test_print_isoOffsetDate(
 275             Integer year, Integer month, Integer day, String offsetId, String zoneId,
 276             String expected, Class<?> expectedEx) {
 277         TemporalAccessor test = buildAccessor(year, month, day, null, null, null, null, offsetId, zoneId);
 278         if (expectedEx == null) {
 279             assertEquals(DateTimeFormatter.ISO_OFFSET_DATE.format(test), expected);
 280         } else {
 281             try {
 282                 DateTimeFormatter.ISO_OFFSET_DATE.format(test);
 283                 fail();
 284             } catch (Exception ex) {
 285                 assertTrue(expectedEx.isInstance(ex));
 286             }
 287         }
 288     }
 289 
 290     @Test(dataProvider="sample_isoOffsetDate", groups={"tck"})
 291     public void test_parse_isoOffsetDate(
 292             Integer year, Integer month, Integer day, String offsetId, String zoneId,
 293             String input, Class<?> invalid) {
 294         if (input != null) {
 295             Expected expected = createDate(year, month, day);
 296             buildCalendrical(expected, offsetId, null);  // zone not expected to be parsed
 297             assertParseMatch(DateTimeFormatter.ISO_OFFSET_DATE.parseUnresolved(input, new ParsePosition(0)), expected);
 298         }
 299     }
 300 
 301     //-----------------------------------------------------------------------
 302     //-----------------------------------------------------------------------
 303     //-----------------------------------------------------------------------
 304     @DataProvider(name="sample_isoDate")
 305     Object[][] provider_sample_isoDate() {
 306         return new Object[][]{
 307                 {2008, null, null, null, null, null, DateTimeException.class},
 308                 {null, 6, null, null, null, null, DateTimeException.class},
 309                 {null, null, 30, null, null, null, DateTimeException.class},
 310                 {null, null, null, "+01:00", null, null, DateTimeException.class},
 311                 {null, null, null, null, "Europe/Paris", null, DateTimeException.class},
 312                 {2008, 6, null, null, null, null, DateTimeException.class},
 313                 {null, 6, 30, null, null, null, DateTimeException.class},
 314 
 315                 {2008, 6, 30, null, null,                   "2008-06-30", null},
 316                 {2008, 6, 30, "+01:00", null,               "2008-06-30+01:00", null},
 317                 {2008, 6, 30, "+01:00", "Europe/Paris",     "2008-06-30+01:00", null},
 318                 {2008, 6, 30, null, "Europe/Paris",         "2008-06-30", null},
 319 
 320                 {123456, 6, 30, "+01:00", "Europe/Paris",   "+123456-06-30+01:00", null},
 321         };
 322     }
 323 
 324     @Test(dataProvider="sample_isoDate", groups={"tck"})
 325     public void test_print_isoDate(
 326             Integer year, Integer month, Integer day, String offsetId, String zoneId,
 327             String expected, Class<?> expectedEx) {
 328         TemporalAccessor test = buildAccessor(year, month, day, null, null, null, null, offsetId, zoneId);
 329         if (expectedEx == null) {
 330             assertEquals(DateTimeFormatter.ISO_DATE.format(test), expected);
 331         } else {
 332             try {
 333                 DateTimeFormatter.ISO_DATE.format(test);
 334                 fail();
 335             } catch (Exception ex) {
 336                 assertTrue(expectedEx.isInstance(ex));
 337             }
 338         }
 339     }
 340 
 341     @Test(dataProvider="sample_isoDate", groups={"tck"})
 342     public void test_parse_isoDate(
 343             Integer year, Integer month, Integer day, String offsetId, String zoneId,
 344             String input, Class<?> invalid) {
 345         if (input != null) {
 346             Expected expected = createDate(year, month, day);
 347             if (offsetId != null) {
 348                 expected.add(ZoneOffset.of(offsetId));
 349             }
 350             assertParseMatch(DateTimeFormatter.ISO_DATE.parseUnresolved(input, new ParsePosition(0)), expected);
 351         }
 352     }
 353 
 354     //-----------------------------------------------------------------------
 355     //-----------------------------------------------------------------------
 356     //-----------------------------------------------------------------------
 357     @DataProvider(name="sample_isoLocalTime")
 358     Object[][] provider_sample_isoLocalTime() {
 359         return new Object[][]{
 360                 {11, null, null, null, null, null, null, DateTimeException.class},
 361                 {null, 5, null, null, null, null, null, DateTimeException.class},
 362                 {null, null, 30, null, null, null, null, DateTimeException.class},
 363                 {null, null, null, 1, null, null, null, DateTimeException.class},
 364                 {null, null, null, null, "+01:00", null, null, DateTimeException.class},
 365                 {null, null, null, null, null, "Europe/Paris", null, DateTimeException.class},
 366 
 367                 {11, 5, null, null, null, null,     "11:05", null},
 368                 {11, 5, 30, null, null, null,       "11:05:30", null},
 369                 {11, 5, 30, 500000000, null, null,  "11:05:30.5", null},
 370                 {11, 5, 30, 1, null, null,          "11:05:30.000000001", null},
 371 
 372                 {11, 5, null, null, "+01:00", null,     "11:05", null},
 373                 {11, 5, 30, null, "+01:00", null,       "11:05:30", null},
 374                 {11, 5, 30, 500000000, "+01:00", null,  "11:05:30.5", null},
 375                 {11, 5, 30, 1, "+01:00", null,          "11:05:30.000000001", null},
 376 
 377                 {11, 5, null, null, "+01:00", "Europe/Paris",       "11:05", null},
 378                 {11, 5, 30, null, "+01:00", "Europe/Paris",         "11:05:30", null},
 379                 {11, 5, 30, 500000000, "+01:00", "Europe/Paris",    "11:05:30.5", null},
 380                 {11, 5, 30, 1, "+01:00", "Europe/Paris",            "11:05:30.000000001", null},
 381 
 382                 {11, 5, null, null, null, "Europe/Paris",       "11:05", null},
 383                 {11, 5, 30, null, null, "Europe/Paris",         "11:05:30", null},
 384                 {11, 5, 30, 500000000, null, "Europe/Paris",    "11:05:30.5", null},
 385                 {11, 5, 30, 1, null, "Europe/Paris",            "11:05:30.000000001", null},
 386         };
 387     }
 388 
 389     @Test(dataProvider="sample_isoLocalTime", groups={"tck"})
 390     public void test_print_isoLocalTime(
 391             Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
 392             String expected, Class<?> expectedEx) {
 393         TemporalAccessor test = buildAccessor(null, null, null, hour, min, sec, nano, offsetId, zoneId);
 394         if (expectedEx == null) {
 395             assertEquals(DateTimeFormatter.ISO_LOCAL_TIME.format(test), expected);
 396         } else {
 397             try {
 398                 DateTimeFormatter.ISO_LOCAL_TIME.format(test);
 399                 fail();
 400             } catch (Exception ex) {
 401                 assertTrue(expectedEx.isInstance(ex));
 402             }
 403         }
 404     }
 405 
 406     @Test(dataProvider="sample_isoLocalTime", groups={"tck"})
 407     public void test_parse_isoLocalTime(
 408             Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
 409             String input, Class<?> invalid) {
 410         if (input != null) {
 411             Expected expected = createTime(hour, min, sec, nano);
 412             // offset/zone not expected to be parsed
 413             assertParseMatch(DateTimeFormatter.ISO_LOCAL_TIME.parseUnresolved(input, new ParsePosition(0)), expected);
 414         }
 415     }
 416 
 417     //-----------------------------------------------------------------------
 418     //-----------------------------------------------------------------------
 419     //-----------------------------------------------------------------------
 420     @DataProvider(name="sample_isoOffsetTime")
 421     Object[][] provider_sample_isoOffsetTime() {
 422         return new Object[][]{
 423                 {11, null, null, null, null, null, null, DateTimeException.class},
 424                 {null, 5, null, null, null, null, null, DateTimeException.class},
 425                 {null, null, 30, null, null, null, null, DateTimeException.class},
 426                 {null, null, null, 1, null, null, null, DateTimeException.class},
 427                 {null, null, null, null, "+01:00", null, null, DateTimeException.class},
 428                 {null, null, null, null, null, "Europe/Paris", null, DateTimeException.class},
 429 
 430                 {11, 5, null, null, null, null,     null, DateTimeException.class},
 431                 {11, 5, 30, null, null, null,       null, DateTimeException.class},
 432                 {11, 5, 30, 500000000, null, null,  null, DateTimeException.class},
 433                 {11, 5, 30, 1, null, null,          null, DateTimeException.class},
 434 
 435                 {11, 5, null, null, "+01:00", null,     "11:05+01:00", null},
 436                 {11, 5, 30, null, "+01:00", null,       "11:05:30+01:00", null},
 437                 {11, 5, 30, 500000000, "+01:00", null,  "11:05:30.5+01:00", null},
 438                 {11, 5, 30, 1, "+01:00", null,          "11:05:30.000000001+01:00", null},
 439 
 440                 {11, 5, null, null, "+01:00", "Europe/Paris",       "11:05+01:00", null},
 441                 {11, 5, 30, null, "+01:00", "Europe/Paris",         "11:05:30+01:00", null},
 442                 {11, 5, 30, 500000000, "+01:00", "Europe/Paris",    "11:05:30.5+01:00", null},
 443                 {11, 5, 30, 1, "+01:00", "Europe/Paris",            "11:05:30.000000001+01:00", null},
 444 
 445                 {11, 5, null, null, null, "Europe/Paris",       null, DateTimeException.class},
 446                 {11, 5, 30, null, null, "Europe/Paris",         null, DateTimeException.class},
 447                 {11, 5, 30, 500000000, null, "Europe/Paris",    null, DateTimeException.class},
 448                 {11, 5, 30, 1, null, "Europe/Paris",            null, DateTimeException.class},
 449         };
 450     }
 451 
 452     @Test(dataProvider="sample_isoOffsetTime", groups={"tck"})
 453     public void test_print_isoOffsetTime(
 454             Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
 455             String expected, Class<?> expectedEx) {
 456         TemporalAccessor test = buildAccessor(null, null, null, hour, min, sec, nano, offsetId, zoneId);
 457         if (expectedEx == null) {
 458             assertEquals(DateTimeFormatter.ISO_OFFSET_TIME.format(test), expected);
 459         } else {
 460             try {
 461                 DateTimeFormatter.ISO_OFFSET_TIME.format(test);
 462                 fail();
 463             } catch (Exception ex) {
 464                 assertTrue(expectedEx.isInstance(ex));
 465             }
 466         }
 467     }
 468 
 469     @Test(dataProvider="sample_isoOffsetTime", groups={"tck"})
 470     public void test_parse_isoOffsetTime(
 471             Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
 472             String input, Class<?> invalid) {
 473         if (input != null) {
 474             Expected expected = createTime(hour, min, sec, nano);
 475             buildCalendrical(expected, offsetId, null);  // zoneId is not expected from parse
 476             assertParseMatch(DateTimeFormatter.ISO_OFFSET_TIME.parseUnresolved(input, new ParsePosition(0)), expected);
 477         }
 478     }
 479 
 480     //-----------------------------------------------------------------------
 481     //-----------------------------------------------------------------------
 482     //-----------------------------------------------------------------------
 483     @DataProvider(name="sample_isoTime")
 484     Object[][] provider_sample_isoTime() {
 485         return new Object[][]{
 486                 {11, null, null, null, null, null, null, DateTimeException.class},
 487                 {null, 5, null, null, null, null, null, DateTimeException.class},
 488                 {null, null, 30, null, null, null, null, DateTimeException.class},
 489                 {null, null, null, 1, null, null, null, DateTimeException.class},
 490                 {null, null, null, null, "+01:00", null, null, DateTimeException.class},
 491                 {null, null, null, null, null, "Europe/Paris", null, DateTimeException.class},
 492 
 493                 {11, 5, null, null, null, null,     "11:05", null},
 494                 {11, 5, 30, null, null, null,       "11:05:30", null},
 495                 {11, 5, 30, 500000000, null, null,  "11:05:30.5", null},
 496                 {11, 5, 30, 1, null, null,          "11:05:30.000000001", null},
 497 
 498                 {11, 5, null, null, "+01:00", null,     "11:05+01:00", null},
 499                 {11, 5, 30, null, "+01:00", null,       "11:05:30+01:00", null},
 500                 {11, 5, 30, 500000000, "+01:00", null,  "11:05:30.5+01:00", null},
 501                 {11, 5, 30, 1, "+01:00", null,          "11:05:30.000000001+01:00", null},
 502 
 503                 {11, 5, null, null, "+01:00", "Europe/Paris",       "11:05+01:00", null},
 504                 {11, 5, 30, null, "+01:00", "Europe/Paris",         "11:05:30+01:00", null},
 505                 {11, 5, 30, 500000000, "+01:00", "Europe/Paris",    "11:05:30.5+01:00", null},
 506                 {11, 5, 30, 1, "+01:00", "Europe/Paris",            "11:05:30.000000001+01:00", null},
 507 
 508                 {11, 5, null, null, null, "Europe/Paris",       "11:05", null},
 509                 {11, 5, 30, null, null, "Europe/Paris",         "11:05:30", null},
 510                 {11, 5, 30, 500000000, null, "Europe/Paris",    "11:05:30.5", null},
 511                 {11, 5, 30, 1, null, "Europe/Paris",            "11:05:30.000000001", null},
 512         };
 513     }
 514 
 515     @Test(dataProvider="sample_isoTime", groups={"tck"})
 516     public void test_print_isoTime(
 517             Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
 518             String expected, Class<?> expectedEx) {
 519         TemporalAccessor test = buildAccessor(null, null, null, hour, min, sec, nano, offsetId, zoneId);
 520         if (expectedEx == null) {
 521             assertEquals(DateTimeFormatter.ISO_TIME.format(test), expected);
 522         } else {
 523             try {
 524                 DateTimeFormatter.ISO_TIME.format(test);
 525                 fail();
 526             } catch (Exception ex) {
 527                 assertTrue(expectedEx.isInstance(ex));
 528             }
 529         }
 530     }
 531 
 532     @Test(dataProvider="sample_isoTime", groups={"tck"})
 533     public void test_parse_isoTime(
 534             Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
 535             String input, Class<?> invalid) {
 536         if (input != null) {
 537             Expected expected = createTime(hour, min, sec, nano);
 538             if (offsetId != null) {
 539                 expected.add(ZoneOffset.of(offsetId));
 540             }
 541             assertParseMatch(DateTimeFormatter.ISO_TIME.parseUnresolved(input, new ParsePosition(0)), expected);
 542         }
 543     }
 544 
 545     //-----------------------------------------------------------------------
 546     //-----------------------------------------------------------------------
 547     //-----------------------------------------------------------------------
 548     @DataProvider(name="sample_isoLocalDateTime")
 549     Object[][] provider_sample_isoLocalDateTime() {
 550         return new Object[][]{
 551                 {2008, null, null, null, null, null, null, null, null, null, DateTimeException.class},
 552                 {null, 6, null, null, null, null, null, null, null, null, DateTimeException.class},
 553                 {null, null, 30, null, null, null, null, null, null, null, DateTimeException.class},
 554                 {null, null, null, 11, null, null, null, null, null, null, DateTimeException.class},
 555                 {null, null, null, null, 5, null, null, null, null, null, DateTimeException.class},
 556                 {null, null, null, null, null, null, null, "+01:00", null, null, DateTimeException.class},
 557                 {null, null, null, null, null, null, null, null, "Europe/Paris", null, DateTimeException.class},
 558                 {2008, 6, 30, 11, null, null, null, null, null, null, DateTimeException.class},
 559                 {2008, 6, 30, null, 5, null, null, null, null, null, DateTimeException.class},
 560                 {2008, 6, null, 11, 5, null, null, null, null, null, DateTimeException.class},
 561                 {2008, null, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
 562                 {null, 6, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
 563 
 564                 {2008, 6, 30, 11, 5, null, null, null, null,                    "2008-06-30T11:05", null},
 565                 {2008, 6, 30, 11, 5, 30, null, null, null,                      "2008-06-30T11:05:30", null},
 566                 {2008, 6, 30, 11, 5, 30, 500000000, null, null,                 "2008-06-30T11:05:30.5", null},
 567                 {2008, 6, 30, 11, 5, 30, 1, null, null,                         "2008-06-30T11:05:30.000000001", null},
 568 
 569                 {2008, 6, 30, 11, 5, null, null, "+01:00", null,                "2008-06-30T11:05", null},
 570                 {2008, 6, 30, 11, 5, 30, null, "+01:00", null,                  "2008-06-30T11:05:30", null},
 571                 {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", null,             "2008-06-30T11:05:30.5", null},
 572                 {2008, 6, 30, 11, 5, 30, 1, "+01:00", null,                     "2008-06-30T11:05:30.000000001", null},
 573 
 574                 {2008, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris",      "2008-06-30T11:05", null},
 575                 {2008, 6, 30, 11, 5, 30, null, "+01:00", "Europe/Paris",        "2008-06-30T11:05:30", null},
 576                 {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "Europe/Paris",   "2008-06-30T11:05:30.5", null},
 577                 {2008, 6, 30, 11, 5, 30, 1, "+01:00", "Europe/Paris",           "2008-06-30T11:05:30.000000001", null},
 578 
 579                 {2008, 6, 30, 11, 5, null, null, null, "Europe/Paris",          "2008-06-30T11:05", null},
 580                 {2008, 6, 30, 11, 5, 30, null, null, "Europe/Paris",            "2008-06-30T11:05:30", null},
 581                 {2008, 6, 30, 11, 5, 30, 500000000, null, "Europe/Paris",       "2008-06-30T11:05:30.5", null},
 582                 {2008, 6, 30, 11, 5, 30, 1, null, "Europe/Paris",               "2008-06-30T11:05:30.000000001", null},
 583 
 584                 {123456, 6, 30, 11, 5, null, null, null, null,                  "+123456-06-30T11:05", null},
 585         };
 586     }
 587 
 588     @Test(dataProvider="sample_isoLocalDateTime", groups={"tck"})
 589     public void test_print_isoLocalDateTime(
 590             Integer year, Integer month, Integer day,
 591             Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
 592             String expected, Class<?> expectedEx) {
 593         TemporalAccessor test = buildAccessor(year, month, day, hour, min, sec, nano, offsetId, zoneId);
 594         if (expectedEx == null) {
 595             assertEquals(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(test), expected);
 596         } else {
 597             try {
 598                 DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(test);
 599                 fail();
 600             } catch (Exception ex) {
 601                 assertTrue(expectedEx.isInstance(ex));
 602             }
 603         }
 604     }
 605 
 606     @Test(dataProvider="sample_isoLocalDateTime", groups={"tck"})
 607     public void test_parse_isoLocalDateTime(
 608             Integer year, Integer month, Integer day,
 609             Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
 610             String input, Class<?> invalid) {
 611         if (input != null) {
 612             Expected expected = createDateTime(year, month, day, hour, min, sec, nano);
 613             assertParseMatch(DateTimeFormatter.ISO_LOCAL_DATE_TIME.parseUnresolved(input, new ParsePosition(0)), expected);
 614         }
 615     }
 616 
 617     //-----------------------------------------------------------------------
 618     //-----------------------------------------------------------------------
 619     //-----------------------------------------------------------------------
 620     @DataProvider(name="sample_isoOffsetDateTime")
 621     Object[][] provider_sample_isoOffsetDateTime() {
 622         return new Object[][]{
 623                 {2008, null, null, null, null, null, null, null, null, null, DateTimeException.class},
 624                 {null, 6, null, null, null, null, null, null, null, null, DateTimeException.class},
 625                 {null, null, 30, null, null, null, null, null, null, null, DateTimeException.class},
 626                 {null, null, null, 11, null, null, null, null, null, null, DateTimeException.class},
 627                 {null, null, null, null, 5, null, null, null, null, null, DateTimeException.class},
 628                 {null, null, null, null, null, null, null, "+01:00", null, null, DateTimeException.class},
 629                 {null, null, null, null, null, null, null, null, "Europe/Paris", null, DateTimeException.class},
 630                 {2008, 6, 30, 11, null, null, null, null, null, null, DateTimeException.class},
 631                 {2008, 6, 30, null, 5, null, null, null, null, null, DateTimeException.class},
 632                 {2008, 6, null, 11, 5, null, null, null, null, null, DateTimeException.class},
 633                 {2008, null, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
 634                 {null, 6, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
 635 
 636                 {2008, 6, 30, 11, 5, null, null, null, null,                    null, DateTimeException.class},
 637                 {2008, 6, 30, 11, 5, 30, null, null, null,                      null, DateTimeException.class},
 638                 {2008, 6, 30, 11, 5, 30, 500000000, null, null,                 null, DateTimeException.class},
 639                 {2008, 6, 30, 11, 5, 30, 1, null, null,                         null, DateTimeException.class},
 640 
 641                 {2008, 6, 30, 11, 5, null, null, "+01:00", null,                "2008-06-30T11:05+01:00", null},
 642                 {2008, 6, 30, 11, 5, 30, null, "+01:00", null,                  "2008-06-30T11:05:30+01:00", null},
 643                 {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", null,             "2008-06-30T11:05:30.5+01:00", null},
 644                 {2008, 6, 30, 11, 5, 30, 1, "+01:00", null,                     "2008-06-30T11:05:30.000000001+01:00", null},
 645 
 646                 {2008, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris",      "2008-06-30T11:05+01:00", null},
 647                 {2008, 6, 30, 11, 5, 30, null, "+01:00", "Europe/Paris",        "2008-06-30T11:05:30+01:00", null},
 648                 {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "Europe/Paris",   "2008-06-30T11:05:30.5+01:00", null},
 649                 {2008, 6, 30, 11, 5, 30, 1, "+01:00", "Europe/Paris",           "2008-06-30T11:05:30.000000001+01:00", null},
 650 
 651                 {2008, 6, 30, 11, 5, null, null, null, "Europe/Paris",          null, DateTimeException.class},
 652                 {2008, 6, 30, 11, 5, 30, null, null, "Europe/Paris",            null, DateTimeException.class},
 653                 {2008, 6, 30, 11, 5, 30, 500000000, null, "Europe/Paris",       null, DateTimeException.class},
 654                 {2008, 6, 30, 11, 5, 30, 1, null, "Europe/Paris",               null, DateTimeException.class},
 655 
 656                 {123456, 6, 30, 11, 5, null, null, "+01:00", null,              "+123456-06-30T11:05+01:00", null},
 657         };
 658     }
 659 
 660     @Test(dataProvider="sample_isoOffsetDateTime", groups={"tck"})
 661     public void test_print_isoOffsetDateTime(
 662             Integer year, Integer month, Integer day,
 663             Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
 664             String expected, Class<?> expectedEx) {
 665         TemporalAccessor test = buildAccessor(year, month, day, hour, min, sec, nano, offsetId, zoneId);
 666         if (expectedEx == null) {
 667             assertEquals(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(test), expected);
 668         } else {
 669             try {
 670                 DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(test);
 671                 fail();
 672             } catch (Exception ex) {
 673                 assertTrue(expectedEx.isInstance(ex));
 674             }
 675         }
 676     }
 677 
 678     @Test(dataProvider="sample_isoOffsetDateTime", groups={"tck"})
 679     public void test_parse_isoOffsetDateTime(
 680             Integer year, Integer month, Integer day,
 681             Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
 682             String input, Class<?> invalid) {
 683         if (input != null) {
 684             Expected expected = createDateTime(year, month, day, hour, min, sec, nano);
 685             buildCalendrical(expected, offsetId, null);  // zone not expected to be parsed
 686             assertParseMatch(DateTimeFormatter.ISO_OFFSET_DATE_TIME.parseUnresolved(input, new ParsePosition(0)), expected);
 687         }
 688     }
 689 
 690     //-----------------------------------------------------------------------
 691     //-----------------------------------------------------------------------
 692     //-----------------------------------------------------------------------
 693     @DataProvider(name="sample_isoZonedDateTime")
 694     Object[][] provider_sample_isoZonedDateTime() {
 695         return new Object[][]{
 696                 {2008, null, null, null, null, null, null, null, null, null, DateTimeException.class},
 697                 {null, 6, null, null, null, null, null, null, null, null, DateTimeException.class},
 698                 {null, null, 30, null, null, null, null, null, null, null, DateTimeException.class},
 699                 {null, null, null, 11, null, null, null, null, null, null, DateTimeException.class},
 700                 {null, null, null, null, 5, null, null, null, null, null, DateTimeException.class},
 701                 {null, null, null, null, null, null, null, "+01:00", null, null, DateTimeException.class},
 702                 {null, null, null, null, null, null, null, null, "Europe/Paris", null, DateTimeException.class},
 703                 {2008, 6, 30, 11, null, null, null, null, null, null, DateTimeException.class},
 704                 {2008, 6, 30, null, 5, null, null, null, null, null, DateTimeException.class},
 705                 {2008, 6, null, 11, 5, null, null, null, null, null, DateTimeException.class},
 706                 {2008, null, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
 707                 {null, 6, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
 708 
 709                 {2008, 6, 30, 11, 5, null, null, null, null,                    null, DateTimeException.class},
 710                 {2008, 6, 30, 11, 5, 30, null, null, null,                      null, DateTimeException.class},
 711                 {2008, 6, 30, 11, 5, 30, 500000000, null, null,                 null, DateTimeException.class},
 712                 {2008, 6, 30, 11, 5, 30, 1, null, null,                         null, DateTimeException.class},
 713 
 714                 // allow OffsetDateTime (no harm comes of this AFAICT)
 715                 {2008, 6, 30, 11, 5, null, null, "+01:00", null,                "2008-06-30T11:05+01:00", null},
 716                 {2008, 6, 30, 11, 5, 30, null, "+01:00", null,                  "2008-06-30T11:05:30+01:00", null},
 717                 {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", null,             "2008-06-30T11:05:30.5+01:00", null},
 718                 {2008, 6, 30, 11, 5, 30, 1, "+01:00", null,                     "2008-06-30T11:05:30.000000001+01:00", null},
 719 
 720                 // ZonedDateTime with ZoneId of ZoneOffset
 721                 {2008, 6, 30, 11, 5, null, null, "+01:00", "+01:00",            "2008-06-30T11:05+01:00", null},
 722                 {2008, 6, 30, 11, 5, 30, null, "+01:00", "+01:00",              "2008-06-30T11:05:30+01:00", null},
 723                 {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "+01:00",         "2008-06-30T11:05:30.5+01:00", null},
 724                 {2008, 6, 30, 11, 5, 30, 1, "+01:00", "+01:00",                 "2008-06-30T11:05:30.000000001+01:00", null},
 725 
 726                 // ZonedDateTime with ZoneId of ZoneRegion
 727                 {2008, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris",      "2008-06-30T11:05+01:00[Europe/Paris]", null},
 728                 {2008, 6, 30, 11, 5, 30, null, "+01:00", "Europe/Paris",        "2008-06-30T11:05:30+01:00[Europe/Paris]", null},
 729                 {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "Europe/Paris",   "2008-06-30T11:05:30.5+01:00[Europe/Paris]", null},
 730                 {2008, 6, 30, 11, 5, 30, 1, "+01:00", "Europe/Paris",           "2008-06-30T11:05:30.000000001+01:00[Europe/Paris]", null},
 731 
 732                 // offset required
 733                 {2008, 6, 30, 11, 5, null, null, null, "Europe/Paris",          null, DateTimeException.class},
 734                 {2008, 6, 30, 11, 5, 30, null, null, "Europe/Paris",            null, DateTimeException.class},
 735                 {2008, 6, 30, 11, 5, 30, 500000000, null, "Europe/Paris",       null, DateTimeException.class},
 736                 {2008, 6, 30, 11, 5, 30, 1, null, "Europe/Paris",               null, DateTimeException.class},
 737 
 738                 {123456, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris",    "+123456-06-30T11:05+01:00[Europe/Paris]", null},
 739         };
 740     }
 741 
 742     @Test(dataProvider="sample_isoZonedDateTime", groups={"tck"})
 743     public void test_print_isoZonedDateTime(
 744             Integer year, Integer month, Integer day,
 745             Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
 746             String expected, Class<?> expectedEx) {
 747         TemporalAccessor test = buildAccessor(year, month, day, hour, min, sec, nano, offsetId, zoneId);
 748         if (expectedEx == null) {
 749             assertEquals(DateTimeFormatter.ISO_ZONED_DATE_TIME.format(test), expected);
 750         } else {
 751             try {
 752                 DateTimeFormatter.ISO_ZONED_DATE_TIME.format(test);
 753                 fail(test.toString());
 754             } catch (Exception ex) {
 755                 assertTrue(expectedEx.isInstance(ex));
 756             }
 757         }
 758     }
 759 
 760     @Test(dataProvider="sample_isoZonedDateTime", groups={"tck"})
 761     public void test_parse_isoZonedDateTime(
 762             Integer year, Integer month, Integer day,
 763             Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
 764             String input, Class<?> invalid) {
 765         if (input != null) {
 766             Expected expected = createDateTime(year, month, day, hour, min, sec, nano);
 767             if (offsetId.equals(zoneId)) {
 768                 buildCalendrical(expected, offsetId, null);
 769             } else {
 770                 buildCalendrical(expected, offsetId, zoneId);
 771             }
 772             assertParseMatch(DateTimeFormatter.ISO_ZONED_DATE_TIME.parseUnresolved(input, new ParsePosition(0)), expected);
 773         }
 774     }
 775 
 776     //-----------------------------------------------------------------------
 777     //-----------------------------------------------------------------------
 778     //-----------------------------------------------------------------------
 779     @DataProvider(name="sample_isoDateTime")
 780     Object[][] provider_sample_isoDateTime() {
 781         return new Object[][]{
 782                 {2008, null, null, null, null, null, null, null, null, null, DateTimeException.class},
 783                 {null, 6, null, null, null, null, null, null, null, null, DateTimeException.class},
 784                 {null, null, 30, null, null, null, null, null, null, null, DateTimeException.class},
 785                 {null, null, null, 11, null, null, null, null, null, null, DateTimeException.class},
 786                 {null, null, null, null, 5, null, null, null, null, null, DateTimeException.class},
 787                 {null, null, null, null, null, null, null, "+01:00", null, null, DateTimeException.class},
 788                 {null, null, null, null, null, null, null, null, "Europe/Paris", null, DateTimeException.class},
 789                 {2008, 6, 30, 11, null, null, null, null, null, null, DateTimeException.class},
 790                 {2008, 6, 30, null, 5, null, null, null, null, null, DateTimeException.class},
 791                 {2008, 6, null, 11, 5, null, null, null, null, null, DateTimeException.class},
 792                 {2008, null, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
 793                 {null, 6, 30, 11, 5, null, null, null, null, null, DateTimeException.class},
 794 
 795                 {2008, 6, 30, 11, 5, null, null, null, null,                    "2008-06-30T11:05", null},
 796                 {2008, 6, 30, 11, 5, 30, null, null, null,                      "2008-06-30T11:05:30", null},
 797                 {2008, 6, 30, 11, 5, 30, 500000000, null, null,                 "2008-06-30T11:05:30.5", null},
 798                 {2008, 6, 30, 11, 5, 30, 1, null, null,                         "2008-06-30T11:05:30.000000001", null},
 799 
 800                 {2008, 6, 30, 11, 5, null, null, "+01:00", null,                "2008-06-30T11:05+01:00", null},
 801                 {2008, 6, 30, 11, 5, 30, null, "+01:00", null,                  "2008-06-30T11:05:30+01:00", null},
 802                 {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", null,             "2008-06-30T11:05:30.5+01:00", null},
 803                 {2008, 6, 30, 11, 5, 30, 1, "+01:00", null,                     "2008-06-30T11:05:30.000000001+01:00", null},
 804 
 805                 {2008, 6, 30, 11, 5, null, null, "+01:00", "Europe/Paris",      "2008-06-30T11:05+01:00[Europe/Paris]", null},
 806                 {2008, 6, 30, 11, 5, 30, null, "+01:00", "Europe/Paris",        "2008-06-30T11:05:30+01:00[Europe/Paris]", null},
 807                 {2008, 6, 30, 11, 5, 30, 500000000, "+01:00", "Europe/Paris",   "2008-06-30T11:05:30.5+01:00[Europe/Paris]", null},
 808                 {2008, 6, 30, 11, 5, 30, 1, "+01:00", "Europe/Paris",           "2008-06-30T11:05:30.000000001+01:00[Europe/Paris]", null},
 809 
 810                 {2008, 6, 30, 11, 5, null, null, null, "Europe/Paris",          "2008-06-30T11:05", null},
 811                 {2008, 6, 30, 11, 5, 30, null, null, "Europe/Paris",            "2008-06-30T11:05:30", null},
 812                 {2008, 6, 30, 11, 5, 30, 500000000, null, "Europe/Paris",       "2008-06-30T11:05:30.5", null},
 813                 {2008, 6, 30, 11, 5, 30, 1, null, "Europe/Paris",               "2008-06-30T11:05:30.000000001", null},
 814 
 815                 {123456, 6, 30, 11, 5, null, null, null, null,                  "+123456-06-30T11:05", null},
 816         };
 817     }
 818 
 819     @Test(dataProvider="sample_isoDateTime", groups={"tck"})
 820     public void test_print_isoDateTime(
 821             Integer year, Integer month, Integer day,
 822             Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
 823             String expected, Class<?> expectedEx) {
 824         TemporalAccessor test = buildAccessor(year, month, day, hour, min, sec, nano, offsetId, zoneId);
 825         if (expectedEx == null) {
 826             assertEquals(DateTimeFormatter.ISO_DATE_TIME.format(test), expected);
 827         } else {
 828             try {
 829                 DateTimeFormatter.ISO_DATE_TIME.format(test);
 830                 fail();
 831             } catch (Exception ex) {
 832                 assertTrue(expectedEx.isInstance(ex));
 833             }
 834         }
 835     }
 836 
 837     @Test(dataProvider="sample_isoDateTime", groups={"tck"})
 838     public void test_parse_isoDateTime(
 839             Integer year, Integer month, Integer day,
 840             Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId,
 841             String input, Class<?> invalid) {
 842         if (input != null) {
 843             Expected expected = createDateTime(year, month, day, hour, min, sec, nano);
 844             if (offsetId != null) {
 845                 expected.add(ZoneOffset.of(offsetId));
 846                 if (zoneId != null) {
 847                     expected.zone = ZoneId.of(zoneId);
 848                 }
 849             }
 850             assertParseMatch(DateTimeFormatter.ISO_DATE_TIME.parseUnresolved(input, new ParsePosition(0)), expected);
 851         }
 852     }
 853 
 854     //-----------------------------------------------------------------------
 855     //-----------------------------------------------------------------------
 856     //-----------------------------------------------------------------------
 857     @Test(groups={"tck"})
 858     public void test_print_isoOrdinalDate() {
 859         TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), null, null);
 860         assertEquals(DateTimeFormatter.ISO_ORDINAL_DATE.format(test), "2008-155");
 861     }
 862 
 863     @Test(groups={"tck"})
 864     public void test_print_isoOrdinalDate_offset() {
 865         TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), "Z", null);
 866         assertEquals(DateTimeFormatter.ISO_ORDINAL_DATE.format(test), "2008-155Z");
 867     }
 868 
 869     @Test(groups={"tck"})
 870     public void test_print_isoOrdinalDate_zoned() {
 871         TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), "+02:00", "Europe/Paris");
 872         assertEquals(DateTimeFormatter.ISO_ORDINAL_DATE.format(test), "2008-155+02:00");
 873     }
 874 
 875     @Test(groups={"tck"})
 876     public void test_print_isoOrdinalDate_zoned_largeYear() {
 877         TemporalAccessor test = buildAccessor(LocalDateTime.of(123456, 6, 3, 11, 5, 30), "Z", null);
 878         assertEquals(DateTimeFormatter.ISO_ORDINAL_DATE.format(test), "+123456-155Z");
 879     }
 880 
 881     @Test
 882     public void test_print_isoOrdinalDate_fields() {
 883         // mock for testing that does not fully comply with TemporalAccessor contract
 884         TemporalAccessor test = new TemporalAccessor() {
 885             @Override
 886             public boolean isSupported(TemporalField field) {
 887                 return field == YEAR || field == DAY_OF_YEAR;
 888             }
 889             @Override
 890             public long getLong(TemporalField field) {
 891                 if (field == YEAR) {
 892                     return 2008;
 893                 }
 894                 if (field == DAY_OF_YEAR) {
 895                     return 231;
 896                 }
 897                 throw new DateTimeException("Unsupported");
 898             }
 899         };
 900         assertEquals(DateTimeFormatter.ISO_ORDINAL_DATE.format(test), "2008-231");
 901     }
 902 
 903     @Test(expectedExceptions=DateTimeException.class)
 904     public void test_print_isoOrdinalDate_missingField() {
 905         TemporalAccessor test = Year.of(2008);
 906         DateTimeFormatter.ISO_ORDINAL_DATE.format(test);
 907     }
 908 
 909     //-----------------------------------------------------------------------
 910     @Test(groups={"tck"})
 911     public void test_parse_isoOrdinalDate() {
 912         Expected expected = new Expected(YEAR, 2008, DAY_OF_YEAR, 123);
 913         assertParseMatch(DateTimeFormatter.ISO_ORDINAL_DATE.parseUnresolved("2008-123", new ParsePosition(0)), expected);
 914     }
 915 
 916     @Test(groups={"tck"})
 917     public void test_parse_isoOrdinalDate_largeYear() {
 918         Expected expected = new Expected(YEAR, 123456, DAY_OF_YEAR, 123);
 919         assertParseMatch(DateTimeFormatter.ISO_ORDINAL_DATE.parseUnresolved("+123456-123", new ParsePosition(0)), expected);
 920     }
 921 
 922     //-----------------------------------------------------------------------
 923     //-----------------------------------------------------------------------
 924     //-----------------------------------------------------------------------
 925     @Test(groups={"tck"})
 926     public void test_print_basicIsoDate() {
 927         TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), null, null);
 928         assertEquals(DateTimeFormatter.BASIC_ISO_DATE.format(test), "20080603");
 929     }
 930 
 931     @Test(groups={"tck"})
 932     public void test_print_basicIsoDate_offset() {
 933         TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), "Z", null);
 934         assertEquals(DateTimeFormatter.BASIC_ISO_DATE.format(test), "20080603Z");
 935     }
 936 
 937     @Test(groups={"tck"})
 938     public void test_print_basicIsoDate_zoned() {
 939         TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), "+02:00", "Europe/Paris");
 940         assertEquals(DateTimeFormatter.BASIC_ISO_DATE.format(test), "20080603+0200");
 941     }
 942 
 943     @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
 944     public void test_print_basicIsoDate_largeYear() {
 945         TemporalAccessor test = buildAccessor(LocalDateTime.of(123456, 6, 3, 11, 5, 30), "Z", null);
 946         DateTimeFormatter.BASIC_ISO_DATE.format(test);
 947     }
 948 
 949     @Test(groups={"tck"})
 950     public void test_print_basicIsoDate_fields() {
 951         TemporalAccessor test = buildAccessor(LocalDate.of(2008, 6, 3), null, null);
 952         assertEquals(DateTimeFormatter.BASIC_ISO_DATE.format(test), "20080603");
 953     }
 954 
 955     @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
 956     public void test_print_basicIsoDate_missingField() {
 957         TemporalAccessor test = YearMonth.of(2008, 6);
 958         DateTimeFormatter.BASIC_ISO_DATE.format(test);
 959     }
 960 
 961     //-----------------------------------------------------------------------
 962     @Test(groups={"tck"})
 963     public void test_parse_basicIsoDate() {
 964         LocalDate expected = LocalDate.of(2008, 6, 3);
 965         assertEquals(DateTimeFormatter.BASIC_ISO_DATE.parse("20080603", LocalDate::from), expected);
 966     }
 967 
 968     @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"})
 969     public void test_parse_basicIsoDate_largeYear() {
 970         try {
 971             LocalDate expected = LocalDate.of(123456, 6, 3);
 972             assertEquals(DateTimeFormatter.BASIC_ISO_DATE.parse("+1234560603", LocalDate::from), expected);
 973         } catch (DateTimeParseException ex) {
 974             assertEquals(ex.getErrorIndex(), 0);
 975             assertEquals(ex.getParsedString(), "+1234560603");
 976             throw ex;
 977         }
 978     }
 979 
 980     //-----------------------------------------------------------------------
 981     //-----------------------------------------------------------------------
 982     //-----------------------------------------------------------------------
 983     @DataProvider(name="weekDate")
 984     Iterator<Object[]> weekDate() {
 985         return new Iterator<Object[]>() {
 986             private ZonedDateTime date = ZonedDateTime.of(LocalDateTime.of(2003, 12, 29, 11, 5, 30), ZoneId.of("Europe/Paris"));
 987             private ZonedDateTime endDate = date.withYear(2005).withMonth(1).withDayOfMonth(2);
 988             private int week = 1;
 989             private int day = 1;
 990 
 991             public boolean hasNext() {
 992                 return !date.isAfter(endDate);
 993             }
 994             public Object[] next() {
 995                 StringBuilder sb = new StringBuilder("2004-W");
 996                 if (week < 10) {
 997                     sb.append('0');
 998                 }
 999                 sb.append(week).append('-').append(day).append(date.getOffset());
1000                 Object[] ret = new Object[] {date, sb.toString()};
1001                 date = date.plusDays(1);
1002                 day += 1;
1003                 if (day == 8) {
1004                     day = 1;
1005                     week++;
1006                 }
1007                 return ret;
1008             }
1009             public void remove() {
1010                 throw new UnsupportedOperationException();
1011             }
1012         };
1013     }
1014 
1015     @Test(dataProvider="weekDate", groups={"tck"})
1016     public void test_print_isoWeekDate(TemporalAccessor test, String expected) {
1017         assertEquals(DateTimeFormatter.ISO_WEEK_DATE.format(test), expected);
1018     }
1019 
1020     @Test(groups={"tck"})
1021     public void test_print_isoWeekDate_zoned_largeYear() {
1022         TemporalAccessor test = buildAccessor(LocalDateTime.of(123456, 6, 3, 11, 5, 30), "Z", null);
1023         assertEquals(DateTimeFormatter.ISO_WEEK_DATE.format(test), "+123456-W23-2Z");
1024     }
1025 
1026     @Test(groups={"tck"})
1027     public void test_print_isoWeekDate_fields() {
1028         TemporalAccessor test = buildAccessor(LocalDate.of(2004, 1, 27), null, null);
1029         assertEquals(DateTimeFormatter.ISO_WEEK_DATE.format(test), "2004-W05-2");
1030     }
1031 
1032     @Test(expectedExceptions=DateTimeException.class, groups={"tck"})
1033     public void test_print_isoWeekDate_missingField() {
1034         TemporalAccessor test = YearMonth.of(2008, 6);
1035         DateTimeFormatter.ISO_WEEK_DATE.format(test);
1036     }
1037 
1038     //-----------------------------------------------------------------------
1039     @Test(groups={"tck"})
1040     public void test_parse_weekDate() {
1041         LocalDate expected = LocalDate.of(2004, 1, 28);
1042         assertEquals(DateTimeFormatter.ISO_WEEK_DATE.parse("2004-W05-3", LocalDate::from), expected);
1043     }
1044 
1045     @Test(groups={"tck"})
1046     public void test_parse_weekDate_largeYear() {
1047         TemporalAccessor parsed = DateTimeFormatter.ISO_WEEK_DATE.parseUnresolved("+123456-W04-5", new ParsePosition(0));
1048         assertEquals(parsed.getLong(IsoFields.WEEK_BASED_YEAR), 123456L);
1049         assertEquals(parsed.getLong(IsoFields.WEEK_OF_WEEK_BASED_YEAR), 4L);
1050         assertEquals(parsed.getLong(DAY_OF_WEEK), 5L);
1051     }
1052 
1053     //-----------------------------------------------------------------------
1054     //-----------------------------------------------------------------------
1055     //-----------------------------------------------------------------------
1056     @DataProvider(name="rfc")
1057     Object[][] data_rfc() {
1058         return new Object[][] {
1059             {LocalDateTime.of(2008, 6, 3, 11, 5, 30), "Z", "Tue, 3 Jun 2008 11:05:30 GMT"},
1060             {LocalDateTime.of(2008, 6, 30, 11, 5, 30), "Z", "Mon, 30 Jun 2008 11:05:30 GMT"},
1061             {LocalDateTime.of(2008, 6, 3, 11, 5, 30), "+02:00", "Tue, 3 Jun 2008 11:05:30 +0200"},
1062             {LocalDateTime.of(2008, 6, 30, 11, 5, 30), "-03:00", "Mon, 30 Jun 2008 11:05:30 -0300"},
1063         };
1064     }
1065 
1066     @Test(groups={"tck"}, dataProvider="rfc")
1067     public void test_print_rfc1123(LocalDateTime base, String offsetId, String expected) {
1068         TemporalAccessor test = buildAccessor(base, offsetId, null);
1069         assertEquals(DateTimeFormatter.RFC_1123_DATE_TIME.format(test), expected);
1070     }
1071 
1072     @Test(groups={"tck"}, dataProvider="rfc")
1073     public void test_print_rfc1123_french(LocalDateTime base, String offsetId, String expected) {
1074         TemporalAccessor test = buildAccessor(base, offsetId, null);
1075         assertEquals(DateTimeFormatter.RFC_1123_DATE_TIME.withLocale(Locale.FRENCH).format(test), expected);
1076     }
1077 
1078     @Test(groups={"tck"}, expectedExceptions=DateTimeException.class)
1079     public void test_print_rfc1123_missingField() {
1080         TemporalAccessor test = YearMonth.of(2008, 6);
1081         DateTimeFormatter.RFC_1123_DATE_TIME.format(test);
1082     }
1083 
1084     //-----------------------------------------------------------------------
1085     //-----------------------------------------------------------------------
1086     //-----------------------------------------------------------------------
1087     private Expected createDate(Integer year, Integer month, Integer day) {
1088         Expected test = new Expected();
1089         if (year != null) {
1090             test.fieldValues.put(YEAR, (long) year);
1091         }
1092         if (month != null) {
1093             test.fieldValues.put(MONTH_OF_YEAR, (long) month);
1094         }
1095         if (day != null) {
1096             test.fieldValues.put(DAY_OF_MONTH, (long) day);
1097         }
1098         return test;
1099     }
1100 
1101     private Expected createTime(Integer hour, Integer min, Integer sec, Integer nano) {
1102         Expected test = new Expected();
1103         if (hour != null) {
1104             test.fieldValues.put(HOUR_OF_DAY, (long) hour);
1105         }
1106         if (min != null) {
1107             test.fieldValues.put(MINUTE_OF_HOUR, (long) min);
1108         }
1109         if (sec != null) {
1110             test.fieldValues.put(SECOND_OF_MINUTE, (long) sec);
1111         }
1112         if (nano != null) {
1113             test.fieldValues.put(NANO_OF_SECOND, (long) nano);
1114         }
1115         return test;
1116     }
1117 
1118     private Expected createDateTime(
1119             Integer year, Integer month, Integer day,
1120             Integer hour, Integer min, Integer sec, Integer nano) {
1121         Expected test = new Expected();
1122         if (year != null) {
1123             test.fieldValues.put(YEAR, (long) year);
1124         }
1125         if (month != null) {
1126             test.fieldValues.put(MONTH_OF_YEAR, (long) month);
1127         }
1128         if (day != null) {
1129             test.fieldValues.put(DAY_OF_MONTH, (long) day);
1130         }
1131         if (hour != null) {
1132             test.fieldValues.put(HOUR_OF_DAY, (long) hour);
1133         }
1134         if (min != null) {
1135             test.fieldValues.put(MINUTE_OF_HOUR, (long) min);
1136         }
1137         if (sec != null) {
1138             test.fieldValues.put(SECOND_OF_MINUTE, (long) sec);
1139         }
1140         if (nano != null) {
1141             test.fieldValues.put(NANO_OF_SECOND, (long) nano);
1142         }
1143         return test;
1144     }
1145 
1146     private TemporalAccessor buildAccessor(
1147                     Integer year, Integer month, Integer day,
1148                     Integer hour, Integer min, Integer sec, Integer nano,
1149                     String offsetId, String zoneId) {
1150         MockAccessor mock = new MockAccessor();
1151         if (year != null) {
1152             mock.fields.put(YEAR, (long) year);
1153         }
1154         if (month != null) {
1155             mock.fields.put(MONTH_OF_YEAR, (long) month);
1156         }
1157         if (day != null) {
1158             mock.fields.put(DAY_OF_MONTH, (long) day);
1159         }
1160         if (hour != null) {
1161             mock.fields.put(HOUR_OF_DAY, (long) hour);
1162         }
1163         if (min != null) {
1164             mock.fields.put(MINUTE_OF_HOUR, (long) min);
1165         }
1166         if (sec != null) {
1167             mock.fields.put(SECOND_OF_MINUTE, (long) sec);
1168         }
1169         if (nano != null) {
1170             mock.fields.put(NANO_OF_SECOND, (long) nano);
1171         }
1172         mock.setOffset(offsetId);
1173         mock.setZone(zoneId);
1174         return mock;
1175     }
1176 
1177     private TemporalAccessor buildAccessor(LocalDateTime base, String offsetId, String zoneId) {
1178         MockAccessor mock = new MockAccessor();
1179         mock.setFields(base);
1180         mock.setOffset(offsetId);
1181         mock.setZone(zoneId);
1182         return mock;
1183     }
1184 
1185     private TemporalAccessor buildAccessor(LocalDate base, String offsetId, String zoneId) {
1186         MockAccessor mock = new MockAccessor();
1187         mock.setFields(base);
1188         mock.setOffset(offsetId);
1189         mock.setZone(zoneId);
1190         return mock;
1191     }
1192 
1193     private void buildCalendrical(Expected expected, String offsetId, String zoneId) {
1194         if (offsetId != null) {
1195             expected.add(ZoneOffset.of(offsetId));
1196         }
1197         if (zoneId != null) {
1198             expected.zone = ZoneId.of(zoneId);
1199         }
1200     }
1201 
1202     private void assertParseMatch(TemporalAccessor parsed, Expected expected) {
1203         for (TemporalField field : expected.fieldValues.keySet()) {
1204             assertEquals(parsed.isSupported(field), true);
1205             parsed.getLong(field);
1206         }
1207         assertEquals(parsed.query(Queries.chronology()), expected.chrono);
1208         assertEquals(parsed.query(Queries.zoneId()), expected.zone);
1209     }
1210 
1211     //-------------------------------------------------------------------------
1212         Map<TemporalField, Long> fields = new HashMap<>();
1213         ZoneId zoneId;
1214     static class MockAccessor implements TemporalAccessor {
1215         Map<TemporalField, Long> fields = new HashMap<>();
1216         ZoneId zoneId;
1217 
1218         void setFields(LocalDate dt) {
1219             if (dt != null) {
1220                 fields.put(YEAR, (long) dt.getYear());
1221                 fields.put(MONTH_OF_YEAR, (long) dt.getMonthValue());
1222                 fields.put(DAY_OF_MONTH, (long) dt.getDayOfMonth());
1223                 fields.put(DAY_OF_YEAR, (long) dt.getDayOfYear());
1224                 fields.put(DAY_OF_WEEK, (long) dt.getDayOfWeek().getValue());
1225                 fields.put(IsoFields.WEEK_BASED_YEAR, dt.getLong(IsoFields.WEEK_BASED_YEAR));
1226                 fields.put(IsoFields.WEEK_OF_WEEK_BASED_YEAR, dt.getLong(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
1227             }
1228         }
1229 
1230         void setFields(LocalDateTime dt) {
1231             if (dt != null) {
1232                 fields.put(YEAR, (long) dt.getYear());
1233                 fields.put(MONTH_OF_YEAR, (long) dt.getMonthValue());
1234                 fields.put(DAY_OF_MONTH, (long) dt.getDayOfMonth());
1235                 fields.put(DAY_OF_YEAR, (long) dt.getDayOfYear());
1236                 fields.put(DAY_OF_WEEK, (long) dt.getDayOfWeek().getValue());
1237                 fields.put(IsoFields.WEEK_BASED_YEAR, dt.getLong(IsoFields.WEEK_BASED_YEAR));
1238                 fields.put(IsoFields.WEEK_OF_WEEK_BASED_YEAR, dt.getLong(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
1239                 fields.put(HOUR_OF_DAY, (long) dt.getHour());
1240                 fields.put(MINUTE_OF_HOUR, (long) dt.getMinute());
1241                 fields.put(SECOND_OF_MINUTE, (long) dt.getSecond());
1242                 fields.put(NANO_OF_SECOND, (long) dt.getNano());
1243             }
1244         }
1245 
1246         void setOffset(String offsetId) {
1247             if (offsetId != null) {
1248                 this.fields.put(OFFSET_SECONDS, (long) ZoneOffset.of(offsetId).getTotalSeconds());
1249             }
1250         }
1251 
1252         void setZone(String zoneId) {
1253             if (zoneId != null) {
1254                 this.zoneId = ZoneId.of(zoneId);
1255             }
1256         }
1257 
1258         @Override
1259         public boolean isSupported(TemporalField field) {
1260             return fields.containsKey(field);
1261         }
1262 
1263         @Override
1264         public long getLong(TemporalField field) {
1265             try {
1266                 return fields.get(field);
1267             } catch (NullPointerException ex) {
1268                 throw new DateTimeException("Field missing: " + field);
1269             }
1270         }
1271 
1272         @SuppressWarnings("unchecked")
1273         @Override
1274         public <R> R query(TemporalQuery<R> query) {
1275             if (query == Queries.zoneId()) {
1276                 return (R) zoneId;
1277             }
1278             return TemporalAccessor.super.query(query);
1279         }
1280 
1281         @Override
1282         public String toString() {
1283             return fields + (zoneId != null ? " " + zoneId : "");
1284         }
1285     }
1286 
1287     //-----------------------------------------------------------------------
1288     static class Expected {
1289         Map<TemporalField, Long> fieldValues = new HashMap<>();
1290         ZoneId zone;
1291         Chronology chrono;
1292 
1293         Expected() {
1294         }
1295 
1296         Expected(TemporalField field1, long value1, TemporalField field2, long value2) {
1297             fieldValues.put(field1, value1);
1298             fieldValues.put(field2, value2);
1299         }
1300 
1301         void add(ZoneOffset offset) {
1302             fieldValues.put(OFFSET_SECONDS, (long) offset.getTotalSeconds());
1303         }
1304     }
1305 }