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