1 /* 2 * Copyright (c) 2012, 2016, 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) 2009-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.format.DateTimeFormatter.BASIC_ISO_DATE; 63 import static java.time.temporal.ChronoField.DAY_OF_MONTH; 64 import static java.time.temporal.ChronoField.HOUR_OF_DAY; 65 import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; 66 import static java.time.temporal.ChronoField.MONTH_OF_YEAR; 67 import static java.time.temporal.ChronoField.NANO_OF_SECOND; 68 import static java.time.temporal.ChronoField.OFFSET_SECONDS; 69 import static java.time.temporal.ChronoField.YEAR; 70 import static org.testng.Assert.assertEquals; 71 72 import java.text.ParsePosition; 73 import java.time.LocalDate; 74 import java.time.YearMonth; 75 import java.time.ZoneOffset; 76 import java.time.format.DateTimeFormatter; 77 import java.time.format.DateTimeFormatterBuilder; 78 import java.time.format.DateTimeParseException; 79 import java.time.format.SignStyle; 80 import java.time.format.TextStyle; 81 import java.time.temporal.Temporal; 82 import java.time.temporal.TemporalAccessor; 83 import java.util.HashMap; 84 import java.util.Locale; 85 import java.util.Map; 86 87 import org.testng.annotations.BeforeMethod; 88 import org.testng.annotations.DataProvider; 89 import org.testng.annotations.Test; 90 91 /** 92 * Test DateTimeFormatterBuilder. 93 */ 94 @Test 95 public class TCKDateTimeFormatterBuilder { 96 97 private DateTimeFormatterBuilder builder; 98 99 @BeforeMethod 100 public void setUp() { 101 builder = new DateTimeFormatterBuilder(); 102 } 103 104 //----------------------------------------------------------------------- 105 @Test 106 public void test_toFormatter_empty() throws Exception { 107 DateTimeFormatter f = builder.toFormatter(); 108 assertEquals(f.format(LocalDate.of(2012, 6, 30)), ""); 109 } 110 111 //----------------------------------------------------------------------- 112 @Test 113 public void test_parseDefaulting_entireDate() { 114 DateTimeFormatter f = builder 115 .parseDefaulting(YEAR, 2012).parseDefaulting(MONTH_OF_YEAR, 6) 116 .parseDefaulting(DAY_OF_MONTH, 30).toFormatter(); 117 LocalDate parsed = f.parse("", LocalDate::from); // blank string can be parsed 118 assertEquals(parsed, LocalDate.of(2012, 6, 30)); 119 } 120 121 @Test 122 public void test_parseDefaulting_yearOptionalMonthOptionalDay() { 123 DateTimeFormatter f = builder 124 .appendValue(YEAR) 125 .optionalStart().appendLiteral('-').appendValue(MONTH_OF_YEAR) 126 .optionalStart().appendLiteral('-').appendValue(DAY_OF_MONTH) 127 .optionalEnd().optionalEnd() 128 .parseDefaulting(MONTH_OF_YEAR, 1) 129 .parseDefaulting(DAY_OF_MONTH, 1).toFormatter(); 130 assertEquals(f.parse("2012", LocalDate::from), LocalDate.of(2012, 1, 1)); 131 assertEquals(f.parse("2012-6", LocalDate::from), LocalDate.of(2012, 6, 1)); 132 assertEquals(f.parse("2012-6-30", LocalDate::from), LocalDate.of(2012, 6, 30)); 133 } 134 135 @Test(expectedExceptions = NullPointerException.class) 136 public void test_parseDefaulting_null() { 137 builder.parseDefaulting(null, 1); 138 } 139 140 //----------------------------------------------------------------------- 141 @Test(expectedExceptions=NullPointerException.class) 142 public void test_appendValue_1arg_null() throws Exception { 143 builder.appendValue(null); 144 } 145 146 //----------------------------------------------------------------------- 147 @Test(expectedExceptions=NullPointerException.class) 148 public void test_appendValue_2arg_null() throws Exception { 149 builder.appendValue(null, 3); 150 } 151 152 @Test(expectedExceptions=IllegalArgumentException.class) 153 public void test_appendValue_2arg_widthTooSmall() throws Exception { 154 builder.appendValue(DAY_OF_MONTH, 0); 155 } 156 157 @Test(expectedExceptions=IllegalArgumentException.class) 158 public void test_appendValue_2arg_widthTooBig() throws Exception { 159 builder.appendValue(DAY_OF_MONTH, 20); 160 } 161 162 //----------------------------------------------------------------------- 163 @Test(expectedExceptions=NullPointerException.class) 164 public void test_appendValue_3arg_nullField() throws Exception { 165 builder.appendValue(null, 2, 3, SignStyle.NORMAL); 166 } 167 168 @Test(expectedExceptions=IllegalArgumentException.class) 169 public void test_appendValue_3arg_minWidthTooSmall() throws Exception { 170 builder.appendValue(DAY_OF_MONTH, 0, 2, SignStyle.NORMAL); 171 } 172 173 @Test(expectedExceptions=IllegalArgumentException.class) 174 public void test_appendValue_3arg_minWidthTooBig() throws Exception { 175 builder.appendValue(DAY_OF_MONTH, 20, 2, SignStyle.NORMAL); 176 } 177 178 @Test(expectedExceptions=IllegalArgumentException.class) 179 public void test_appendValue_3arg_maxWidthTooSmall() throws Exception { 180 builder.appendValue(DAY_OF_MONTH, 2, 0, SignStyle.NORMAL); 181 } 182 183 @Test(expectedExceptions=IllegalArgumentException.class) 184 public void test_appendValue_3arg_maxWidthTooBig() throws Exception { 185 builder.appendValue(DAY_OF_MONTH, 2, 20, SignStyle.NORMAL); 186 } 187 188 @Test(expectedExceptions=IllegalArgumentException.class) 189 public void test_appendValue_3arg_maxWidthMinWidth() throws Exception { 190 builder.appendValue(DAY_OF_MONTH, 4, 2, SignStyle.NORMAL); 191 } 192 193 @Test(expectedExceptions=NullPointerException.class) 194 public void test_appendValue_3arg_nullSignStyle() throws Exception { 195 builder.appendValue(DAY_OF_MONTH, 2, 3, null); 196 } 197 198 //----------------------------------------------------------------------- 199 @Test(expectedExceptions=NullPointerException.class) 200 public void test_appendValueReduced_int_nullField() throws Exception { 201 builder.appendValueReduced(null, 2, 2, 2000); 202 } 203 204 @Test(expectedExceptions=IllegalArgumentException.class) 205 public void test_appendValueReduced_int_minWidthTooSmall() throws Exception { 206 builder.appendValueReduced(YEAR, 0, 2, 2000); 207 } 208 209 @Test(expectedExceptions=IllegalArgumentException.class) 210 public void test_appendValueReduced_int_minWidthTooBig() throws Exception { 211 builder.appendValueReduced(YEAR, 11, 2, 2000); 212 } 213 214 @Test(expectedExceptions=IllegalArgumentException.class) 215 public void test_appendValueReduced_int_maxWidthTooSmall() throws Exception { 216 builder.appendValueReduced(YEAR, 2, 0, 2000); 217 } 218 219 @Test(expectedExceptions=IllegalArgumentException.class) 220 public void test_appendValueReduced_int_maxWidthTooBig() throws Exception { 221 builder.appendValueReduced(YEAR, 2, 11, 2000); 222 } 223 224 @Test(expectedExceptions=IllegalArgumentException.class) 225 public void test_appendValueReduced_int_maxWidthLessThanMin() throws Exception { 226 builder.appendValueReduced(YEAR, 2, 1, 2000); 227 } 228 229 //----------------------------------------------------------------------- 230 @Test(expectedExceptions=NullPointerException.class) 231 public void test_appendValueReduced_date_nullField() throws Exception { 232 builder.appendValueReduced(null, 2, 2, LocalDate.of(2000, 1, 1)); 233 } 234 235 @Test(expectedExceptions=NullPointerException.class) 236 public void test_appendValueReduced_date_nullDate() throws Exception { 237 builder.appendValueReduced(YEAR, 2, 2, null); 238 } 239 240 @Test(expectedExceptions=IllegalArgumentException.class) 241 public void test_appendValueReduced_date_minWidthTooSmall() throws Exception { 242 builder.appendValueReduced(YEAR, 0, 2, LocalDate.of(2000, 1, 1)); 243 } 244 245 @Test(expectedExceptions=IllegalArgumentException.class) 246 public void test_appendValueReduced_date_minWidthTooBig() throws Exception { 247 builder.appendValueReduced(YEAR, 11, 2, LocalDate.of(2000, 1, 1)); 248 } 249 250 @Test(expectedExceptions=IllegalArgumentException.class) 251 public void test_appendValueReduced_date_maxWidthTooSmall() throws Exception { 252 builder.appendValueReduced(YEAR, 2, 0, LocalDate.of(2000, 1, 1)); 253 } 254 255 @Test(expectedExceptions=IllegalArgumentException.class) 256 public void test_appendValueReduced_date_maxWidthTooBig() throws Exception { 257 builder.appendValueReduced(YEAR, 2, 11, LocalDate.of(2000, 1, 1)); 258 } 259 260 @Test(expectedExceptions=IllegalArgumentException.class) 261 public void test_appendValueReduced_date_maxWidthLessThanMin() throws Exception { 262 builder.appendValueReduced(YEAR, 2, 1, LocalDate.of(2000, 1, 1)); 263 } 264 265 //----------------------------------------------------------------------- 266 //----------------------------------------------------------------------- 267 //----------------------------------------------------------------------- 268 @Test(expectedExceptions=NullPointerException.class) 269 public void test_appendFraction_4arg_nullRule() throws Exception { 270 builder.appendFraction(null, 1, 9, false); 271 } 272 273 @Test(expectedExceptions=IllegalArgumentException.class) 274 public void test_appendFraction_4arg_invalidRuleNotFixedSet() throws Exception { 275 builder.appendFraction(DAY_OF_MONTH, 1, 9, false); 276 } 277 278 @Test(expectedExceptions=IllegalArgumentException.class) 279 public void test_appendFraction_4arg_minTooSmall() throws Exception { 280 builder.appendFraction(MINUTE_OF_HOUR, -1, 9, false); 281 } 282 283 @Test(expectedExceptions=IllegalArgumentException.class) 284 public void test_appendFraction_4arg_minTooBig() throws Exception { 285 builder.appendFraction(MINUTE_OF_HOUR, 10, 9, false); 286 } 287 288 @Test(expectedExceptions=IllegalArgumentException.class) 289 public void test_appendFraction_4arg_maxTooSmall() throws Exception { 290 builder.appendFraction(MINUTE_OF_HOUR, 0, -1, false); 291 } 292 293 @Test(expectedExceptions=IllegalArgumentException.class) 294 public void test_appendFraction_4arg_maxTooBig() throws Exception { 295 builder.appendFraction(MINUTE_OF_HOUR, 1, 10, false); 296 } 297 298 @Test(expectedExceptions=IllegalArgumentException.class) 299 public void test_appendFraction_4arg_maxWidthMinWidth() throws Exception { 300 builder.appendFraction(MINUTE_OF_HOUR, 9, 3, false); 301 } 302 303 //----------------------------------------------------------------------- 304 //----------------------------------------------------------------------- 305 //----------------------------------------------------------------------- 306 @Test(expectedExceptions=NullPointerException.class) 307 public void test_appendText_1arg_null() throws Exception { 308 builder.appendText(null); 309 } 310 311 //----------------------------------------------------------------------- 312 @Test(expectedExceptions=NullPointerException.class) 313 public void test_appendText_2arg_nullRule() throws Exception { 314 builder.appendText(null, TextStyle.SHORT); 315 } 316 317 @Test(expectedExceptions=NullPointerException.class) 318 public void test_appendText_2arg_nullStyle() throws Exception { 319 builder.appendText(MONTH_OF_YEAR, (TextStyle) null); 320 } 321 322 //----------------------------------------------------------------------- 323 @Test(expectedExceptions=NullPointerException.class) 324 public void test_appendTextMap_nullRule() throws Exception { 325 builder.appendText(null, new HashMap<>()); 326 } 327 328 @Test(expectedExceptions=NullPointerException.class) 329 public void test_appendTextMap_nullStyle() throws Exception { 330 builder.appendText(MONTH_OF_YEAR, (Map<Long, String>) null); 331 } 332 333 //----------------------------------------------------------------------- 334 //----------------------------------------------------------------------- 335 //----------------------------------------------------------------------- 336 @DataProvider(name="offsetPatterns") 337 Object[][] data_offsetPatterns() { 338 return new Object[][] { 339 {"+HH", 2, 0, 0, "+02"}, 340 {"+HH", -2, 0, 0, "-02"}, 341 {"+HH", 2, 30, 0, "+02"}, 342 {"+HH", 2, 0, 45, "+02"}, 343 {"+HH", 2, 30, 45, "+02"}, 344 345 {"+HHmm", 2, 0, 0, "+02"}, 346 {"+HHmm", -2, 0, 0, "-02"}, 347 {"+HHmm", 2, 30, 0, "+0230"}, 348 {"+HHmm", 2, 0, 45, "+02"}, 349 {"+HHmm", 2, 30, 45, "+0230"}, 350 351 {"+HH:mm", 2, 0, 0, "+02"}, 352 {"+HH:mm", -2, 0, 0, "-02"}, 353 {"+HH:mm", 2, 30, 0, "+02:30"}, 354 {"+HH:mm", 2, 0, 45, "+02"}, 355 {"+HH:mm", 2, 30, 45, "+02:30"}, 356 357 {"+HHMM", 2, 0, 0, "+0200"}, 358 {"+HHMM", -2, 0, 0, "-0200"}, 359 {"+HHMM", 2, 30, 0, "+0230"}, 360 {"+HHMM", 2, 0, 45, "+0200"}, 361 {"+HHMM", 2, 30, 45, "+0230"}, 362 363 {"+HH:MM", 2, 0, 0, "+02:00"}, 364 {"+HH:MM", -2, 0, 0, "-02:00"}, 365 {"+HH:MM", 2, 30, 0, "+02:30"}, 366 {"+HH:MM", 2, 0, 45, "+02:00"}, 367 {"+HH:MM", 2, 30, 45, "+02:30"}, 368 369 {"+HHMMss", 2, 0, 0, "+0200"}, 370 {"+HHMMss", -2, 0, 0, "-0200"}, 371 {"+HHMMss", 2, 30, 0, "+0230"}, 372 {"+HHMMss", 2, 0, 45, "+020045"}, 373 {"+HHMMss", 2, 30, 45, "+023045"}, 374 375 {"+HH:MM:ss", 2, 0, 0, "+02:00"}, 376 {"+HH:MM:ss", -2, 0, 0, "-02:00"}, 377 {"+HH:MM:ss", 2, 30, 0, "+02:30"}, 378 {"+HH:MM:ss", 2, 0, 45, "+02:00:45"}, 379 {"+HH:MM:ss", 2, 30, 45, "+02:30:45"}, 380 381 {"+HHMMSS", 2, 0, 0, "+020000"}, 382 {"+HHMMSS", -2, 0, 0, "-020000"}, 383 {"+HHMMSS", 2, 30, 0, "+023000"}, 384 {"+HHMMSS", 2, 0, 45, "+020045"}, 385 {"+HHMMSS", 2, 30, 45, "+023045"}, 386 387 {"+HH:MM:SS", 2, 0, 0, "+02:00:00"}, 388 {"+HH:MM:SS", -2, 0, 0, "-02:00:00"}, 389 {"+HH:MM:SS", 2, 30, 0, "+02:30:00"}, 390 {"+HH:MM:SS", 2, 0, 45, "+02:00:45"}, 391 {"+HH:MM:SS", 2, 30, 45, "+02:30:45"}, 392 393 {"+HHmmss", 2, 0, 0, "+02"}, 394 {"+HHmmss", -2, 0, 0, "-02"}, 395 {"+HHmmss", 2, 30, 0, "+0230"}, 396 {"+HHmmss", 2, 0, 45, "+020045"}, 397 {"+HHmmss", 2, 30, 45, "+023045"}, 398 399 {"+HH:mm:ss", 2, 0, 0, "+02"}, 400 {"+HH:mm:ss", -2, 0, 0, "-02"}, 401 {"+HH:mm:ss", 2, 30, 0, "+02:30"}, 402 {"+HH:mm:ss", 2, 0, 45, "+02:00:45"}, 403 {"+HH:mm:ss", 2, 30, 45, "+02:30:45"}, 404 405 406 }; 407 } 408 409 @Test(dataProvider="offsetPatterns") 410 public void test_appendOffset_format(String pattern, int h, int m, int s, String expected) throws Exception { 411 builder.appendOffset(pattern, "Z"); 412 DateTimeFormatter f = builder.toFormatter(); 413 ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(h, m, s); 414 assertEquals(f.format(offset), expected); 415 } 416 417 @Test(dataProvider="offsetPatterns") 418 public void test_appendOffset_parse(String pattern, int h, int m, int s, String expected) throws Exception { 419 builder.appendOffset(pattern, "Z"); 420 DateTimeFormatter f = builder.toFormatter(); 421 ZoneOffset parsed = f.parse(expected, ZoneOffset::from); 422 assertEquals(f.format(parsed), expected); 423 } 424 425 @DataProvider(name="badOffsetPatterns") 426 Object[][] data_badOffsetPatterns() { 427 return new Object[][] { 428 {"HH"}, 429 {"HHMM"}, 430 {"HH:MM"}, 431 {"HHMMss"}, 432 {"HH:MM:ss"}, 433 {"HHMMSS"}, 434 {"HH:MM:SS"}, 435 {"+H"}, 436 {"+HMM"}, 437 {"+HHM"}, 438 {"+A"}, 439 }; 440 } 441 442 @Test(dataProvider="badOffsetPatterns", expectedExceptions=IllegalArgumentException.class) 443 public void test_appendOffset_badPattern(String pattern) throws Exception { 444 builder.appendOffset(pattern, "Z"); 445 } 446 447 @Test(expectedExceptions=NullPointerException.class) 448 public void test_appendOffset_3arg_nullText() throws Exception { 449 builder.appendOffset("+HH:MM", null); 450 } 451 452 @Test(expectedExceptions=NullPointerException.class) 453 public void test_appendOffset_3arg_nullPattern() throws Exception { 454 builder.appendOffset(null, "Z"); 455 } 456 457 //----------------------------------------------------------------------- 458 //----------------------------------------------------------------------- 459 //----------------------------------------------------------------------- 460 @Test(expectedExceptions=NullPointerException.class) 461 public void test_appendZoneText_1arg_nullText() throws Exception { 462 builder.appendZoneText(null); 463 } 464 465 //----------------------------------------------------------------------- 466 //----------------------------------------------------------------------- 467 //----------------------------------------------------------------------- 468 @Test 469 public void test_padNext_1arg() { 470 builder.appendValue(MONTH_OF_YEAR).appendLiteral(':').padNext(2).appendValue(DAY_OF_MONTH); 471 assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2: 1"); 472 } 473 474 @Test(expectedExceptions=IllegalArgumentException.class) 475 public void test_padNext_1arg_invalidWidth() throws Exception { 476 builder.padNext(0); 477 } 478 479 //----------------------------------------------------------------------- 480 @Test 481 public void test_padNext_2arg_dash() throws Exception { 482 builder.appendValue(MONTH_OF_YEAR).appendLiteral(':').padNext(2, '-').appendValue(DAY_OF_MONTH); 483 assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2:-1"); 484 } 485 486 @Test(expectedExceptions=IllegalArgumentException.class) 487 public void test_padNext_2arg_invalidWidth() throws Exception { 488 builder.padNext(0, '-'); 489 } 490 491 //----------------------------------------------------------------------- 492 @Test 493 public void test_padOptional() throws Exception { 494 builder.appendValue(MONTH_OF_YEAR).appendLiteral(':') 495 .padNext(5).optionalStart().appendValue(DAY_OF_MONTH).optionalEnd() 496 .appendLiteral(':').appendValue(YEAR); 497 assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2: 1:2013"); 498 assertEquals(builder.toFormatter().format(YearMonth.of(2013, 2)), "2: :2013"); 499 } 500 501 //----------------------------------------------------------------------- 502 //----------------------------------------------------------------------- 503 //----------------------------------------------------------------------- 504 @Test(expectedExceptions=IllegalStateException.class) 505 public void test_optionalEnd_noStart() throws Exception { 506 builder.optionalEnd(); 507 } 508 509 //----------------------------------------------------------------------- 510 //----------------------------------------------------------------------- 511 //----------------------------------------------------------------------- 512 @DataProvider(name="validPatterns") 513 Object[][] dataValid() { 514 return new Object[][] { 515 {"'a'"}, 516 {"''"}, 517 {"'!'"}, 518 {"!"}, 519 {"'#'"}, 520 521 {"'hello_people,][)('"}, 522 {"'hi'"}, 523 {"'yyyy'"}, 524 {"''''"}, 525 {"'o''clock'"}, 526 527 {"G"}, 528 {"GG"}, 529 {"GGG"}, 530 {"GGGG"}, 531 {"GGGGG"}, 532 533 {"y"}, 534 {"yy"}, 535 {"yyy"}, 536 {"yyyy"}, 537 {"yyyyy"}, 538 539 {"M"}, 540 {"MM"}, 541 {"MMM"}, 542 {"MMMM"}, 543 {"MMMMM"}, 544 545 {"L"}, 546 {"LL"}, 547 {"LLL"}, 548 {"LLLL"}, 549 {"LLLLL"}, 550 551 {"D"}, 552 {"DD"}, 553 {"DDD"}, 554 555 {"d"}, 556 {"dd"}, 557 558 {"F"}, 559 560 {"Q"}, 561 {"QQ"}, 562 {"QQQ"}, 563 {"QQQQ"}, 564 {"QQQQQ"}, 565 566 {"q"}, 567 {"qq"}, 568 {"qqq"}, 569 {"qqqq"}, 570 {"qqqqq"}, 571 572 {"E"}, 573 {"EE"}, 574 {"EEE"}, 575 {"EEEE"}, 576 {"EEEEE"}, 577 578 {"e"}, 579 {"ee"}, 580 {"eee"}, 581 {"eeee"}, 582 {"eeeee"}, 583 584 {"c"}, 585 {"ccc"}, 586 {"cccc"}, 587 {"ccccc"}, 588 589 {"a"}, 590 591 {"H"}, 592 {"HH"}, 593 594 {"K"}, 595 {"KK"}, 596 597 {"k"}, 598 {"kk"}, 599 600 {"h"}, 601 {"hh"}, 602 603 {"m"}, 604 {"mm"}, 605 606 {"s"}, 607 {"ss"}, 608 609 {"S"}, 610 {"SS"}, 611 {"SSS"}, 612 {"SSSSSSSSS"}, 613 614 {"A"}, 615 {"AA"}, 616 {"AAA"}, 617 618 {"n"}, 619 {"nn"}, 620 {"nnn"}, 621 622 {"N"}, 623 {"NN"}, 624 {"NNN"}, 625 626 {"z"}, 627 {"zz"}, 628 {"zzz"}, 629 {"zzzz"}, 630 631 {"VV"}, 632 633 {"Z"}, 634 {"ZZ"}, 635 {"ZZZ"}, 636 637 {"X"}, 638 {"XX"}, 639 {"XXX"}, 640 {"XXXX"}, 641 {"XXXXX"}, 642 643 {"x"}, 644 {"xx"}, 645 {"xxx"}, 646 {"xxxx"}, 647 {"xxxxx"}, 648 649 {"ppH"}, 650 {"pppDD"}, 651 652 {"yyyy[-MM[-dd"}, 653 {"yyyy[-MM[-dd]]"}, 654 {"yyyy[-MM[]-dd]"}, 655 656 {"yyyy-MM-dd'T'HH:mm:ss.SSS"}, 657 658 {"e"}, 659 {"w"}, 660 {"ww"}, 661 {"W"}, 662 {"W"}, 663 664 {"g"}, 665 {"ggggg"}, 666 }; 667 } 668 669 @Test(dataProvider="validPatterns") 670 public void test_appendPattern_valid(String input) throws Exception { 671 builder.appendPattern(input); // test is for no error here 672 } 673 674 //----------------------------------------------------------------------- 675 @DataProvider(name="invalidPatterns") 676 Object[][] dataInvalid() { 677 return new Object[][] { 678 {"'"}, 679 {"'hello"}, 680 {"'hel''lo"}, 681 {"'hello''"}, 682 {"{"}, 683 {"}"}, 684 {"{}"}, 685 {"#"}, 686 {"]"}, 687 {"yyyy]"}, 688 {"yyyy]MM"}, 689 {"yyyy[MM]]"}, 690 691 {"aa"}, 692 {"aaa"}, 693 {"aaaa"}, 694 {"aaaaa"}, 695 {"aaaaaa"}, 696 {"MMMMMM"}, 697 {"QQQQQQ"}, 698 {"qqqqqq"}, 699 {"EEEEEE"}, 700 {"eeeeee"}, 701 {"cc"}, 702 {"cccccc"}, 703 {"ddd"}, 704 {"DDDD"}, 705 {"FF"}, 706 {"FFF"}, 707 {"hhh"}, 708 {"HHH"}, 709 {"kkk"}, 710 {"KKK"}, 711 {"mmm"}, 712 {"sss"}, 713 {"OO"}, 714 {"OOO"}, 715 {"OOOOO"}, 716 {"XXXXXX"}, 717 {"zzzzz"}, 718 {"ZZZZZZ"}, 719 720 {"RO"}, 721 722 {"p"}, 723 {"pp"}, 724 {"p:"}, 725 726 {"f"}, 727 {"ff"}, 728 {"f:"}, 729 {"fy"}, 730 {"fa"}, 731 {"fM"}, 732 733 {"www"}, 734 {"WW"}, 735 }; 736 } 737 738 @Test(dataProvider="invalidPatterns", expectedExceptions=IllegalArgumentException.class) 739 public void test_appendPattern_invalid(String input) throws Exception { 740 builder.appendPattern(input); // test is for error here 741 } 742 743 //----------------------------------------------------------------------- 744 @DataProvider(name="patternPrint") 745 Object[][] data_patternPrint() { 746 return new Object[][] { 747 {"Q", date(2012, 2, 10), "1"}, 748 {"QQ", date(2012, 2, 10), "01"}, 749 {"QQQ", date(2012, 2, 10), "Q1"}, 750 {"QQQQ", date(2012, 2, 10), "1st quarter"}, 751 {"QQQQQ", date(2012, 2, 10), "1"}, 752 }; 753 } 754 755 @Test(dataProvider="patternPrint") 756 public void test_appendPattern_patternPrint(String input, Temporal temporal, String expected) throws Exception { 757 DateTimeFormatter f = builder.appendPattern(input).toFormatter(Locale.UK); 758 String test = f.format(temporal); 759 assertEquals(test, expected); 760 } 761 762 private static Temporal date(int y, int m, int d) { 763 return LocalDate.of(y, m, d); 764 } 765 766 //----------------------------------------------------------------------- 767 @DataProvider(name="modJulianFieldPattern") 768 Object[][] data_modJuilanFieldPattern() { 769 return new Object[][] { 770 {"g", "1"}, 771 {"g", "123456"}, 772 {"gggggg", "123456"}, 773 }; 774 } 775 776 @Test(dataProvider="modJulianFieldPattern") 777 public void test_modJulianFieldPattern(String pattern, String input) throws Exception { 778 DateTimeFormatter.ofPattern(pattern).parse(input); 779 } 780 781 @DataProvider(name="modJulianFieldValues") 782 Object[][] data_modJuilanFieldValues() { 783 return new Object[][] { 784 {1970, 1, 1, "40587"}, 785 {1858, 11, 17, "0"}, 786 {1858, 11, 16, "-1"}, 787 }; 788 } 789 790 @Test(dataProvider="modJulianFieldValues") 791 public void test_modJulianFieldValues(int y, int m, int d, String expected) throws Exception { 792 DateTimeFormatter df = new DateTimeFormatterBuilder().appendPattern("g").toFormatter(); 793 assertEquals(LocalDate.of(y, m, d).format(df), expected); 794 } 795 796 //----------------------------------------------------------------------- 797 @DataProvider(name="dayOfYearFieldPattern") 798 Object[][] data_dayOfYearFieldPattern() { 799 return new Object[][] { 800 {"D", "1"}, 801 {"D", "123"}, 802 {"DD", "12"}, 803 {"DD", "123"}, 804 {"DDD", "123"}, 805 {"DDD", "12345"}, 806 }; 807 } 808 809 @Test(dataProvider="dayOfYearFieldPattern") 810 public void test_dayOfYearFieldPattern(String pattern, String input) throws Exception { 811 DateTimeFormatter.ofPattern(pattern).parse(input); 812 } 813 814 @DataProvider(name="dayOfYearFieldValues") 815 Object[][] data_dayOfYearFieldValues() { 816 return new Object[][] { 817 {2016, 1, 1, "D", "1"}, 818 {2016, 1, 31, "D", "31"}, 819 {2016, 1, 1, "DD", "01"}, 820 {2016, 1, 31, "DD", "31"}, 821 {2016, 4, 9, "DD", "100"}, 822 {2016, 1, 1, "DDD", "001"}, 823 {2016, 1, 31, "DDD", "031"}, 824 {2016, 4, 9, "DDD", "100"}, 825 }; 826 } 827 828 @Test(dataProvider="dayOfYearFieldValues") 829 public void test_dayOfYearFieldValues(int y, int m, int d, String pattern, String expected) throws Exception { 830 DateTimeFormatter df = new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(); 831 assertEquals(LocalDate.of(y, m, d).format(df), expected); 832 } 833 //----------------------------------------------------------------------- 834 @Test 835 public void test_adjacent_strict_firstFixedWidth() throws Exception { 836 // succeeds because both number elements are fixed width 837 DateTimeFormatter f = builder.appendValue(HOUR_OF_DAY, 2).appendValue(MINUTE_OF_HOUR, 2).appendLiteral('9').toFormatter(Locale.UK); 838 ParsePosition pp = new ParsePosition(0); 839 TemporalAccessor parsed = f.parseUnresolved("12309", pp); 840 assertEquals(pp.getErrorIndex(), -1); 841 assertEquals(pp.getIndex(), 5); 842 assertEquals(parsed.getLong(HOUR_OF_DAY), 12L); 843 assertEquals(parsed.getLong(MINUTE_OF_HOUR), 30L); 844 } 845 846 @Test 847 public void test_adjacent_strict_firstVariableWidth_success() throws Exception { 848 // succeeds greedily parsing variable width, then fixed width, to non-numeric Z 849 DateTimeFormatter f = builder.appendValue(HOUR_OF_DAY).appendValue(MINUTE_OF_HOUR, 2).appendLiteral('Z').toFormatter(Locale.UK); 850 ParsePosition pp = new ParsePosition(0); 851 TemporalAccessor parsed = f.parseUnresolved("12309Z", pp); 852 assertEquals(pp.getErrorIndex(), -1); 853 assertEquals(pp.getIndex(), 6); 854 assertEquals(parsed.getLong(HOUR_OF_DAY), 123L); 855 assertEquals(parsed.getLong(MINUTE_OF_HOUR), 9L); 856 } 857 858 @Test 859 public void test_adjacent_strict_firstVariableWidth_fails() throws Exception { 860 // fails because literal is a number and variable width parse greedily absorbs it 861 DateTimeFormatter f = builder.appendValue(HOUR_OF_DAY).appendValue(MINUTE_OF_HOUR, 2).appendLiteral('9').toFormatter(Locale.UK); 862 ParsePosition pp = new ParsePosition(0); 863 TemporalAccessor parsed = f.parseUnresolved("12309", pp); 864 assertEquals(pp.getErrorIndex(), 5); 865 assertEquals(parsed, null); 866 } 867 868 @Test 869 public void test_adjacent_lenient() throws Exception { 870 // succeeds because both number elements are fixed width even in lenient mode 871 DateTimeFormatter f = builder.parseLenient().appendValue(HOUR_OF_DAY, 2).appendValue(MINUTE_OF_HOUR, 2).appendLiteral('9').toFormatter(Locale.UK); 872 ParsePosition pp = new ParsePosition(0); 873 TemporalAccessor parsed = f.parseUnresolved("12309", pp); 874 assertEquals(pp.getErrorIndex(), -1); 875 assertEquals(pp.getIndex(), 5); 876 assertEquals(parsed.getLong(HOUR_OF_DAY), 12L); 877 assertEquals(parsed.getLong(MINUTE_OF_HOUR), 30L); 878 } 879 880 @Test 881 public void test_adjacent_lenient_firstVariableWidth_success() throws Exception { 882 // succeeds greedily parsing variable width, then fixed width, to non-numeric Z 883 DateTimeFormatter f = builder.parseLenient().appendValue(HOUR_OF_DAY).appendValue(MINUTE_OF_HOUR, 2).appendLiteral('Z').toFormatter(Locale.UK); 884 ParsePosition pp = new ParsePosition(0); 885 TemporalAccessor parsed = f.parseUnresolved("12309Z", pp); 886 assertEquals(pp.getErrorIndex(), -1); 887 assertEquals(pp.getIndex(), 6); 888 assertEquals(parsed.getLong(HOUR_OF_DAY), 123L); 889 assertEquals(parsed.getLong(MINUTE_OF_HOUR), 9L); 890 } 891 892 @Test 893 public void test_adjacent_lenient_firstVariableWidth_fails() throws Exception { 894 // fails because literal is a number and variable width parse greedily absorbs it 895 DateTimeFormatter f = builder.parseLenient().appendValue(HOUR_OF_DAY).appendValue(MINUTE_OF_HOUR, 2).appendLiteral('9').toFormatter(Locale.UK); 896 ParsePosition pp = new ParsePosition(0); 897 TemporalAccessor parsed = f.parseUnresolved("12309", pp); 898 assertEquals(pp.getErrorIndex(), 5); 899 assertEquals(parsed, null); 900 } 901 902 //----------------------------------------------------------------------- 903 @Test 904 public void test_adjacent_strict_fractionFollows() throws Exception { 905 // succeeds because hour/min are fixed width 906 DateTimeFormatter f = builder.appendValue(HOUR_OF_DAY, 2).appendValue(MINUTE_OF_HOUR, 2).appendFraction(NANO_OF_SECOND, 0, 3, false).toFormatter(Locale.UK); 907 ParsePosition pp = new ParsePosition(0); 908 TemporalAccessor parsed = f.parseUnresolved("1230567", pp); 909 assertEquals(pp.getErrorIndex(), -1); 910 assertEquals(pp.getIndex(), 7); 911 assertEquals(parsed.getLong(HOUR_OF_DAY), 12L); 912 assertEquals(parsed.getLong(MINUTE_OF_HOUR), 30L); 913 assertEquals(parsed.getLong(NANO_OF_SECOND), 567_000_000L); 914 } 915 916 @Test 917 public void test_adjacent_strict_fractionFollows_2digit() throws Exception { 918 // succeeds because hour/min are fixed width 919 DateTimeFormatter f = builder.appendValue(HOUR_OF_DAY, 2).appendValue(MINUTE_OF_HOUR, 2).appendFraction(NANO_OF_SECOND, 0, 3, false).toFormatter(Locale.UK); 920 ParsePosition pp = new ParsePosition(0); 921 TemporalAccessor parsed = f.parseUnresolved("123056", pp); 922 assertEquals(pp.getErrorIndex(), -1); 923 assertEquals(pp.getIndex(), 6); 924 assertEquals(parsed.getLong(HOUR_OF_DAY), 12L); 925 assertEquals(parsed.getLong(MINUTE_OF_HOUR), 30L); 926 assertEquals(parsed.getLong(NANO_OF_SECOND), 560_000_000L); 927 } 928 929 @Test 930 public void test_adjacent_strict_fractionFollows_0digit() throws Exception { 931 // succeeds because hour/min are fixed width 932 DateTimeFormatter f = builder.appendValue(HOUR_OF_DAY, 2).appendValue(MINUTE_OF_HOUR, 2).appendFraction(NANO_OF_SECOND, 0, 3, false).toFormatter(Locale.UK); 933 ParsePosition pp = new ParsePosition(0); 934 TemporalAccessor parsed = f.parseUnresolved("1230", pp); 935 assertEquals(pp.getErrorIndex(), -1); 936 assertEquals(pp.getIndex(), 4); 937 assertEquals(parsed.getLong(HOUR_OF_DAY), 12L); 938 assertEquals(parsed.getLong(MINUTE_OF_HOUR), 30L); 939 } 940 941 @Test 942 public void test_adjacent_lenient_fractionFollows() throws Exception { 943 // succeeds because hour/min are fixed width 944 DateTimeFormatter f = builder.parseLenient().appendValue(HOUR_OF_DAY, 2).appendValue(MINUTE_OF_HOUR, 2).appendFraction(NANO_OF_SECOND, 3, 3, false).toFormatter(Locale.UK); 945 ParsePosition pp = new ParsePosition(0); 946 TemporalAccessor parsed = f.parseUnresolved("1230567", pp); 947 assertEquals(pp.getErrorIndex(), -1); 948 assertEquals(pp.getIndex(), 7); 949 assertEquals(parsed.getLong(HOUR_OF_DAY), 12L); 950 assertEquals(parsed.getLong(MINUTE_OF_HOUR), 30L); 951 assertEquals(parsed.getLong(NANO_OF_SECOND), 567_000_000L); 952 } 953 954 @Test 955 public void test_adjacent_lenient_fractionFollows_2digit() throws Exception { 956 // succeeds because hour/min are fixed width 957 DateTimeFormatter f = builder.parseLenient().appendValue(HOUR_OF_DAY, 2).appendValue(MINUTE_OF_HOUR, 2).appendFraction(NANO_OF_SECOND, 3, 3, false).toFormatter(Locale.UK); 958 ParsePosition pp = new ParsePosition(0); 959 TemporalAccessor parsed = f.parseUnresolved("123056", pp); 960 assertEquals(pp.getErrorIndex(), -1); 961 assertEquals(pp.getIndex(), 6); 962 assertEquals(parsed.getLong(HOUR_OF_DAY), 12L); 963 assertEquals(parsed.getLong(MINUTE_OF_HOUR), 30L); 964 assertEquals(parsed.getLong(NANO_OF_SECOND), 560_000_000L); 965 } 966 967 @Test 968 public void test_adjacent_lenient_fractionFollows_0digit() throws Exception { 969 // succeeds because hour/min are fixed width 970 DateTimeFormatter f = builder.parseLenient().appendValue(HOUR_OF_DAY, 2).appendValue(MINUTE_OF_HOUR, 2).appendFraction(NANO_OF_SECOND, 3, 3, false).toFormatter(Locale.UK); 971 ParsePosition pp = new ParsePosition(0); 972 TemporalAccessor parsed = f.parseUnresolved("1230", pp); 973 assertEquals(pp.getErrorIndex(), -1); 974 assertEquals(pp.getIndex(), 4); 975 assertEquals(parsed.getLong(HOUR_OF_DAY), 12L); 976 assertEquals(parsed.getLong(MINUTE_OF_HOUR), 30L); 977 } 978 979 @DataProvider(name="lenientOffsetParseData") 980 Object[][] data_lenient_offset_parse() { 981 return new Object[][] { 982 {"+HH", "+01", 3600}, 983 {"+HH", "+0101", 3660}, 984 {"+HH", "+010101", 3661}, 985 {"+HH", "+01", 3600}, 986 {"+HH", "+01:01", 3660}, 987 {"+HH", "+01:01:01", 3661}, 988 {"+HHmm", "+01", 3600}, 989 {"+HHmm", "+0101", 3660}, 990 {"+HHmm", "+010101", 3661}, 991 {"+HH:mm", "+01", 3600}, 992 {"+HH:mm", "+01:01", 3660}, 993 {"+HH:mm", "+01:01:01", 3661}, 994 {"+HHMM", "+01", 3600}, 995 {"+HHMM", "+0101", 3660}, 996 {"+HHMM", "+010101", 3661}, 997 {"+HH:MM", "+01", 3600}, 998 {"+HH:MM", "+01:01", 3660}, 999 {"+HH:MM", "+01:01:01", 3661}, 1000 {"+HHMMss", "+01", 3600}, 1001 {"+HHMMss", "+0101", 3660}, 1002 {"+HHMMss", "+010101", 3661}, 1003 {"+HH:MM:ss", "+01", 3600}, 1004 {"+HH:MM:ss", "+01:01", 3660}, 1005 {"+HH:MM:ss", "+01:01:01", 3661}, 1006 {"+HHMMSS", "+01", 3600}, 1007 {"+HHMMSS", "+0101", 3660}, 1008 {"+HHMMSS", "+010101", 3661}, 1009 {"+HH:MM:SS", "+01", 3600}, 1010 {"+HH:MM:SS", "+01:01", 3660}, 1011 {"+HH:MM:SS", "+01:01:01", 3661}, 1012 {"+HHmmss", "+01", 3600}, 1013 {"+HHmmss", "+0101", 3660}, 1014 {"+HHmmss", "+010101", 3661}, 1015 {"+HH:mm:ss", "+01", 3600}, 1016 {"+HH:mm:ss", "+01:01", 3660}, 1017 {"+HH:mm:ss", "+01:01:01", 3661}, 1018 }; 1019 } 1020 1021 @Test(dataProvider="lenientOffsetParseData") 1022 public void test_lenient_offset_parse_1(String pattern, String offset, int offsetSeconds) { 1023 assertEquals(new DateTimeFormatterBuilder().parseLenient().appendOffset(pattern, "Z").toFormatter().parse(offset).get(OFFSET_SECONDS), 1024 offsetSeconds); 1025 } 1026 1027 @Test 1028 public void test_lenient_offset_parse_2() { 1029 assertEquals(new DateTimeFormatterBuilder().parseLenient().appendOffsetId().toFormatter().parse("+01").get(OFFSET_SECONDS), 1030 3600); 1031 } 1032 1033 @Test(expectedExceptions=DateTimeParseException.class) 1034 public void test_strict_appendOffsetId() { 1035 assertEquals(new DateTimeFormatterBuilder().appendOffsetId().toFormatter().parse("+01").get(OFFSET_SECONDS), 1036 3600); 1037 } 1038 1039 @Test(expectedExceptions=DateTimeParseException.class) 1040 public void test_strict_appendOffset_1() { 1041 assertEquals(new DateTimeFormatterBuilder().appendOffset("+HH:MM:ss", "Z").toFormatter().parse("+01").get(OFFSET_SECONDS), 1042 3600); 1043 } 1044 1045 @Test(expectedExceptions=DateTimeParseException.class) 1046 public void test_strict_appendOffset_2() { 1047 assertEquals(new DateTimeFormatterBuilder().appendOffset("+HHMMss", "Z").toFormatter().parse("+01").get(OFFSET_SECONDS), 1048 3600); 1049 } 1050 1051 @Test 1052 public void test_basic_iso_date() { 1053 assertEquals(BASIC_ISO_DATE.parse("20021231+01").get(OFFSET_SECONDS), 3600); 1054 assertEquals(BASIC_ISO_DATE.parse("20021231+0101").get(OFFSET_SECONDS), 3660); 1055 } 1056 1057 }