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