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) 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 test.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.MINUTE_OF_HOUR; 65 import static java.time.temporal.ChronoField.MONTH_OF_YEAR; 66 import static java.time.temporal.ChronoField.YEAR; 67 import static org.testng.Assert.assertEquals; 68 import static org.testng.Assert.assertNotNull; 69 70 import java.text.ParsePosition; 71 import java.time.LocalDate; 72 import java.time.YearMonth; 73 import java.time.ZoneOffset; 74 import java.time.chrono.Chronology; 75 import java.time.chrono.IsoChronology; 76 import java.time.chrono.JapaneseChronology; 77 import java.time.chrono.MinguoChronology; 78 import java.time.format.DateTimeFormatter; 79 import java.time.format.DateTimeFormatterBuilder; 80 import java.time.format.FormatStyle; 81 import java.time.format.SignStyle; 82 import java.time.format.TextStyle; 83 import java.time.temporal.Temporal; 84 import java.time.temporal.TemporalAccessor; 85 import java.util.HashMap; 86 import java.util.Locale; 87 import java.util.Map; 88 89 import org.testng.annotations.BeforeMethod; 90 import org.testng.annotations.DataProvider; 91 import org.testng.annotations.Test; 92 93 /** 94 * Test DateTimeFormatterBuilder. 95 */ 96 @Test 97 public class TestDateTimeFormatterBuilder { 98 99 private DateTimeFormatterBuilder builder; 100 101 @BeforeMethod setUp()102 public void setUp() { 103 builder = new DateTimeFormatterBuilder(); 104 } 105 106 //----------------------------------------------------------------------- 107 @Test test_toFormatter_empty()108 public void test_toFormatter_empty() throws Exception { 109 DateTimeFormatter f = builder.toFormatter(); 110 assertEquals(f.toString(), ""); 111 } 112 113 //----------------------------------------------------------------------- 114 @Test test_parseCaseSensitive()115 public void test_parseCaseSensitive() throws Exception { 116 builder.parseCaseSensitive(); 117 DateTimeFormatter f = builder.toFormatter(); 118 assertEquals(f.toString(), "ParseCaseSensitive(true)"); 119 } 120 121 @Test test_parseCaseInsensitive()122 public void test_parseCaseInsensitive() throws Exception { 123 builder.parseCaseInsensitive(); 124 DateTimeFormatter f = builder.toFormatter(); 125 assertEquals(f.toString(), "ParseCaseSensitive(false)"); 126 } 127 128 //----------------------------------------------------------------------- 129 @Test test_parseStrict()130 public void test_parseStrict() throws Exception { 131 builder.parseStrict(); 132 DateTimeFormatter f = builder.toFormatter(); 133 assertEquals(f.toString(), "ParseStrict(true)"); 134 } 135 136 @Test test_parseLenient()137 public void test_parseLenient() throws Exception { 138 builder.parseLenient(); 139 DateTimeFormatter f = builder.toFormatter(); 140 assertEquals(f.toString(), "ParseStrict(false)"); 141 } 142 143 //----------------------------------------------------------------------- 144 @Test test_appendValue_1arg()145 public void test_appendValue_1arg() throws Exception { 146 builder.appendValue(DAY_OF_MONTH); 147 DateTimeFormatter f = builder.toFormatter(); 148 assertEquals(f.toString(), "Value(DayOfMonth)"); 149 } 150 151 @Test(expectedExceptions=NullPointerException.class) test_appendValue_1arg_null()152 public void test_appendValue_1arg_null() throws Exception { 153 builder.appendValue(null); 154 } 155 156 //----------------------------------------------------------------------- 157 @Test test_appendValue_2arg()158 public void test_appendValue_2arg() throws Exception { 159 builder.appendValue(DAY_OF_MONTH, 3); 160 DateTimeFormatter f = builder.toFormatter(); 161 assertEquals(f.toString(), "Value(DayOfMonth,3)"); 162 } 163 164 @Test(expectedExceptions=NullPointerException.class) test_appendValue_2arg_null()165 public void test_appendValue_2arg_null() throws Exception { 166 builder.appendValue(null, 3); 167 } 168 169 @Test(expectedExceptions=IllegalArgumentException.class) test_appendValue_2arg_widthTooSmall()170 public void test_appendValue_2arg_widthTooSmall() throws Exception { 171 builder.appendValue(DAY_OF_MONTH, 0); 172 } 173 174 @Test(expectedExceptions=IllegalArgumentException.class) test_appendValue_2arg_widthTooBig()175 public void test_appendValue_2arg_widthTooBig() throws Exception { 176 builder.appendValue(DAY_OF_MONTH, 20); 177 } 178 179 //----------------------------------------------------------------------- 180 @Test test_appendValue_3arg()181 public void test_appendValue_3arg() throws Exception { 182 builder.appendValue(DAY_OF_MONTH, 2, 3, SignStyle.NORMAL); 183 DateTimeFormatter f = builder.toFormatter(); 184 assertEquals(f.toString(), "Value(DayOfMonth,2,3,NORMAL)"); 185 } 186 187 @Test(expectedExceptions=NullPointerException.class) test_appendValue_3arg_nullField()188 public void test_appendValue_3arg_nullField() throws Exception { 189 builder.appendValue(null, 2, 3, SignStyle.NORMAL); 190 } 191 192 @Test(expectedExceptions=IllegalArgumentException.class) test_appendValue_3arg_minWidthTooSmall()193 public void test_appendValue_3arg_minWidthTooSmall() throws Exception { 194 builder.appendValue(DAY_OF_MONTH, 0, 2, SignStyle.NORMAL); 195 } 196 197 @Test(expectedExceptions=IllegalArgumentException.class) test_appendValue_3arg_minWidthTooBig()198 public void test_appendValue_3arg_minWidthTooBig() throws Exception { 199 builder.appendValue(DAY_OF_MONTH, 20, 2, SignStyle.NORMAL); 200 } 201 202 @Test(expectedExceptions=IllegalArgumentException.class) test_appendValue_3arg_maxWidthTooSmall()203 public void test_appendValue_3arg_maxWidthTooSmall() throws Exception { 204 builder.appendValue(DAY_OF_MONTH, 2, 0, SignStyle.NORMAL); 205 } 206 207 @Test(expectedExceptions=IllegalArgumentException.class) test_appendValue_3arg_maxWidthTooBig()208 public void test_appendValue_3arg_maxWidthTooBig() throws Exception { 209 builder.appendValue(DAY_OF_MONTH, 2, 20, SignStyle.NORMAL); 210 } 211 212 @Test(expectedExceptions=IllegalArgumentException.class) test_appendValue_3arg_maxWidthMinWidth()213 public void test_appendValue_3arg_maxWidthMinWidth() throws Exception { 214 builder.appendValue(DAY_OF_MONTH, 4, 2, SignStyle.NORMAL); 215 } 216 217 @Test(expectedExceptions=NullPointerException.class) test_appendValue_3arg_nullSignStyle()218 public void test_appendValue_3arg_nullSignStyle() throws Exception { 219 builder.appendValue(DAY_OF_MONTH, 2, 3, null); 220 } 221 222 //----------------------------------------------------------------------- 223 @Test test_appendValue_subsequent2_parse3()224 public void test_appendValue_subsequent2_parse3() throws Exception { 225 builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2); 226 DateTimeFormatter f = builder.toFormatter(); 227 assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)"); 228 TemporalAccessor parsed = f.parseUnresolved("123", new ParsePosition(0)); 229 assertEquals(parsed.getLong(MONTH_OF_YEAR), 1L); 230 assertEquals(parsed.getLong(DAY_OF_MONTH), 23L); 231 } 232 233 @Test test_appendValue_subsequent2_parse4()234 public void test_appendValue_subsequent2_parse4() throws Exception { 235 builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2); 236 DateTimeFormatter f = builder.toFormatter(); 237 assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)"); 238 TemporalAccessor parsed = f.parseUnresolved("0123", new ParsePosition(0)); 239 assertEquals(parsed.getLong(MONTH_OF_YEAR), 1L); 240 assertEquals(parsed.getLong(DAY_OF_MONTH), 23L); 241 } 242 243 @Test test_appendValue_subsequent2_parse5()244 public void test_appendValue_subsequent2_parse5() throws Exception { 245 builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2).appendLiteral('4'); 246 DateTimeFormatter f = builder.toFormatter(); 247 assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)'4'"); 248 TemporalAccessor parsed = f.parseUnresolved("01234", new ParsePosition(0)); 249 assertEquals(parsed.getLong(MONTH_OF_YEAR), 1L); 250 assertEquals(parsed.getLong(DAY_OF_MONTH), 23L); 251 } 252 253 @Test test_appendValue_subsequent3_parse6()254 public void test_appendValue_subsequent3_parse6() throws Exception { 255 builder 256 .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) 257 .appendValue(MONTH_OF_YEAR, 2) 258 .appendValue(DAY_OF_MONTH, 2); 259 DateTimeFormatter f = builder.toFormatter(); 260 assertEquals(f.toString(), "Value(Year,4,10,EXCEEDS_PAD)Value(MonthOfYear,2)Value(DayOfMonth,2)"); 261 TemporalAccessor parsed = f.parseUnresolved("20090630", new ParsePosition(0)); 262 assertEquals(parsed.getLong(YEAR), 2009L); 263 assertEquals(parsed.getLong(MONTH_OF_YEAR), 6L); 264 assertEquals(parsed.getLong(DAY_OF_MONTH), 30L); 265 } 266 267 //----------------------------------------------------------------------- 268 @Test(expectedExceptions=NullPointerException.class) test_appendValueReduced_null()269 public void test_appendValueReduced_null() throws Exception { 270 builder.appendValueReduced(null, 2, 2, 2000); 271 } 272 273 @Test test_appendValueReduced()274 public void test_appendValueReduced() throws Exception { 275 builder.appendValueReduced(YEAR, 2, 2, 2000); 276 DateTimeFormatter f = builder.toFormatter(); 277 assertEquals(f.toString(), "ReducedValue(Year,2,2,2000)"); 278 TemporalAccessor parsed = f.parseUnresolved("12", new ParsePosition(0)); 279 assertEquals(parsed.getLong(YEAR), 2012L); 280 } 281 282 @Test test_appendValueReduced_subsequent_parse()283 public void test_appendValueReduced_subsequent_parse() throws Exception { 284 builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValueReduced(YEAR, 2, 2, 2000); 285 DateTimeFormatter f = builder.toFormatter(); 286 assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)ReducedValue(Year,2,2,2000)"); 287 ParsePosition ppos = new ParsePosition(0); 288 TemporalAccessor parsed = f.parseUnresolved("123", ppos); 289 assertNotNull(parsed, "Parse failed: " + ppos.toString()); 290 assertEquals(parsed.getLong(MONTH_OF_YEAR), 1L); 291 assertEquals(parsed.getLong(YEAR), 2023L); 292 } 293 294 //----------------------------------------------------------------------- 295 //----------------------------------------------------------------------- 296 //----------------------------------------------------------------------- 297 @Test test_appendFraction_4arg()298 public void test_appendFraction_4arg() throws Exception { 299 builder.appendFraction(MINUTE_OF_HOUR, 1, 9, false); 300 DateTimeFormatter f = builder.toFormatter(); 301 assertEquals(f.toString(), "Fraction(MinuteOfHour,1,9)"); 302 } 303 304 @Test(expectedExceptions=NullPointerException.class) test_appendFraction_4arg_nullRule()305 public void test_appendFraction_4arg_nullRule() throws Exception { 306 builder.appendFraction(null, 1, 9, false); 307 } 308 309 @Test(expectedExceptions=IllegalArgumentException.class) test_appendFraction_4arg_invalidRuleNotFixedSet()310 public void test_appendFraction_4arg_invalidRuleNotFixedSet() throws Exception { 311 builder.appendFraction(DAY_OF_MONTH, 1, 9, false); 312 } 313 314 @Test(expectedExceptions=IllegalArgumentException.class) test_appendFraction_4arg_minTooSmall()315 public void test_appendFraction_4arg_minTooSmall() throws Exception { 316 builder.appendFraction(MINUTE_OF_HOUR, -1, 9, false); 317 } 318 319 @Test(expectedExceptions=IllegalArgumentException.class) test_appendFraction_4arg_minTooBig()320 public void test_appendFraction_4arg_minTooBig() throws Exception { 321 builder.appendFraction(MINUTE_OF_HOUR, 10, 9, false); 322 } 323 324 @Test(expectedExceptions=IllegalArgumentException.class) test_appendFraction_4arg_maxTooSmall()325 public void test_appendFraction_4arg_maxTooSmall() throws Exception { 326 builder.appendFraction(MINUTE_OF_HOUR, 0, -1, false); 327 } 328 329 @Test(expectedExceptions=IllegalArgumentException.class) test_appendFraction_4arg_maxTooBig()330 public void test_appendFraction_4arg_maxTooBig() throws Exception { 331 builder.appendFraction(MINUTE_OF_HOUR, 1, 10, false); 332 } 333 334 @Test(expectedExceptions=IllegalArgumentException.class) test_appendFraction_4arg_maxWidthMinWidth()335 public void test_appendFraction_4arg_maxWidthMinWidth() throws Exception { 336 builder.appendFraction(MINUTE_OF_HOUR, 9, 3, false); 337 } 338 339 //----------------------------------------------------------------------- 340 //----------------------------------------------------------------------- 341 //----------------------------------------------------------------------- 342 @Test test_appendText_1arg()343 public void test_appendText_1arg() throws Exception { 344 builder.appendText(MONTH_OF_YEAR); 345 DateTimeFormatter f = builder.toFormatter(); 346 assertEquals(f.toString(), "Text(MonthOfYear)"); 347 } 348 349 @Test(expectedExceptions=NullPointerException.class) test_appendText_1arg_null()350 public void test_appendText_1arg_null() throws Exception { 351 builder.appendText(null); 352 } 353 354 //----------------------------------------------------------------------- 355 @Test test_appendText_2arg()356 public void test_appendText_2arg() throws Exception { 357 builder.appendText(MONTH_OF_YEAR, TextStyle.SHORT); 358 DateTimeFormatter f = builder.toFormatter(); 359 assertEquals(f.toString(), "Text(MonthOfYear,SHORT)"); 360 } 361 362 @Test(expectedExceptions=NullPointerException.class) test_appendText_2arg_nullRule()363 public void test_appendText_2arg_nullRule() throws Exception { 364 builder.appendText(null, TextStyle.SHORT); 365 } 366 367 @Test(expectedExceptions=NullPointerException.class) test_appendText_2arg_nullStyle()368 public void test_appendText_2arg_nullStyle() throws Exception { 369 builder.appendText(MONTH_OF_YEAR, (TextStyle) null); 370 } 371 372 //----------------------------------------------------------------------- 373 @Test test_appendTextMap()374 public void test_appendTextMap() throws Exception { 375 Map<Long, String> map = new HashMap<>(); 376 map.put(1L, "JNY"); 377 map.put(2L, "FBY"); 378 map.put(3L, "MCH"); 379 map.put(4L, "APL"); 380 map.put(5L, "MAY"); 381 map.put(6L, "JUN"); 382 map.put(7L, "JLY"); 383 map.put(8L, "AGT"); 384 map.put(9L, "SPT"); 385 map.put(10L, "OBR"); 386 map.put(11L, "NVR"); 387 map.put(12L, "DBR"); 388 builder.appendText(MONTH_OF_YEAR, map); 389 DateTimeFormatter f = builder.toFormatter(); 390 assertEquals(f.toString(), "Text(MonthOfYear)"); // TODO: toString should be different? 391 } 392 393 @Test(expectedExceptions=NullPointerException.class) test_appendTextMap_nullRule()394 public void test_appendTextMap_nullRule() throws Exception { 395 builder.appendText(null, new HashMap<Long, String>()); 396 } 397 398 @Test(expectedExceptions=NullPointerException.class) test_appendTextMap_nullStyle()399 public void test_appendTextMap_nullStyle() throws Exception { 400 builder.appendText(MONTH_OF_YEAR, (Map<Long, String>) null); 401 } 402 403 //----------------------------------------------------------------------- 404 //----------------------------------------------------------------------- 405 //----------------------------------------------------------------------- 406 @Test test_appendOffsetId()407 public void test_appendOffsetId() throws Exception { 408 builder.appendOffsetId(); 409 DateTimeFormatter f = builder.toFormatter(); 410 assertEquals(f.toString(), "Offset(+HH:MM:ss,'Z')"); 411 } 412 413 @DataProvider(name="offsetPatterns") data_offsetPatterns()414 Object[][] data_offsetPatterns() { 415 return new Object[][] { 416 {"+HH", 2, 0, 0, "+02"}, 417 {"+HH", -2, 0, 0, "-02"}, 418 {"+HH", 2, 30, 0, "+02"}, 419 {"+HH", 2, 0, 45, "+02"}, 420 {"+HH", 2, 30, 45, "+02"}, 421 422 {"+HHMM", 2, 0, 0, "+0200"}, 423 {"+HHMM", -2, 0, 0, "-0200"}, 424 {"+HHMM", 2, 30, 0, "+0230"}, 425 {"+HHMM", 2, 0, 45, "+0200"}, 426 {"+HHMM", 2, 30, 45, "+0230"}, 427 428 {"+HH:MM", 2, 0, 0, "+02:00"}, 429 {"+HH:MM", -2, 0, 0, "-02:00"}, 430 {"+HH:MM", 2, 30, 0, "+02:30"}, 431 {"+HH:MM", 2, 0, 45, "+02:00"}, 432 {"+HH:MM", 2, 30, 45, "+02:30"}, 433 434 {"+HHMMss", 2, 0, 0, "+0200"}, 435 {"+HHMMss", -2, 0, 0, "-0200"}, 436 {"+HHMMss", 2, 30, 0, "+0230"}, 437 {"+HHMMss", 2, 0, 45, "+020045"}, 438 {"+HHMMss", 2, 30, 45, "+023045"}, 439 440 {"+HH:MM:ss", 2, 0, 0, "+02:00"}, 441 {"+HH:MM:ss", -2, 0, 0, "-02:00"}, 442 {"+HH:MM:ss", 2, 30, 0, "+02:30"}, 443 {"+HH:MM:ss", 2, 0, 45, "+02:00:45"}, 444 {"+HH:MM:ss", 2, 30, 45, "+02:30:45"}, 445 446 {"+HHMMSS", 2, 0, 0, "+020000"}, 447 {"+HHMMSS", -2, 0, 0, "-020000"}, 448 {"+HHMMSS", 2, 30, 0, "+023000"}, 449 {"+HHMMSS", 2, 0, 45, "+020045"}, 450 {"+HHMMSS", 2, 30, 45, "+023045"}, 451 452 {"+HH:MM:SS", 2, 0, 0, "+02:00:00"}, 453 {"+HH:MM:SS", -2, 0, 0, "-02:00:00"}, 454 {"+HH:MM:SS", 2, 30, 0, "+02:30:00"}, 455 {"+HH:MM:SS", 2, 0, 45, "+02:00:45"}, 456 {"+HH:MM:SS", 2, 30, 45, "+02:30:45"}, 457 }; 458 } 459 460 @Test(dataProvider="offsetPatterns") test_appendOffset_format(String pattern, int h, int m, int s, String expected)461 public void test_appendOffset_format(String pattern, int h, int m, int s, String expected) throws Exception { 462 builder.appendOffset(pattern, "Z"); 463 DateTimeFormatter f = builder.toFormatter(); 464 ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(h, m, s); 465 assertEquals(f.format(offset), expected); 466 } 467 468 @Test(dataProvider="offsetPatterns") test_appendOffset_parse(String pattern, int h, int m, int s, String expected)469 public void test_appendOffset_parse(String pattern, int h, int m, int s, String expected) throws Exception { 470 builder.appendOffset(pattern, "Z"); 471 DateTimeFormatter f = builder.toFormatter(); 472 ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(h, m, s); 473 ZoneOffset parsed = f.parse(expected, ZoneOffset::from); 474 assertEquals(f.format(parsed), expected); 475 } 476 477 @DataProvider(name="badOffsetPatterns") data_badOffsetPatterns()478 Object[][] data_badOffsetPatterns() { 479 return new Object[][] { 480 {"HH"}, 481 {"HHMM"}, 482 {"HH:MM"}, 483 {"HHMMss"}, 484 {"HH:MM:ss"}, 485 {"HHMMSS"}, 486 {"HH:MM:SS"}, 487 {"+H"}, 488 {"+HMM"}, 489 {"+HHM"}, 490 {"+A"}, 491 }; 492 } 493 494 @Test(dataProvider="badOffsetPatterns", expectedExceptions=IllegalArgumentException.class) test_appendOffset_badPattern(String pattern)495 public void test_appendOffset_badPattern(String pattern) throws Exception { 496 builder.appendOffset(pattern, "Z"); 497 } 498 499 @Test(expectedExceptions=NullPointerException.class) test_appendOffset_3arg_nullText()500 public void test_appendOffset_3arg_nullText() throws Exception { 501 builder.appendOffset("+HH:MM", null); 502 } 503 504 @Test(expectedExceptions=NullPointerException.class) test_appendOffset_3arg_nullPattern()505 public void test_appendOffset_3arg_nullPattern() throws Exception { 506 builder.appendOffset(null, "Z"); 507 } 508 509 //----------------------------------------------------------------------- 510 //----------------------------------------------------------------------- 511 //----------------------------------------------------------------------- 512 @Test test_appendZoneId()513 public void test_appendZoneId() throws Exception { 514 builder.appendZoneId(); 515 DateTimeFormatter f = builder.toFormatter(); 516 assertEquals(f.toString(), "ZoneId()"); 517 } 518 519 @Test test_appendZoneText_1arg()520 public void test_appendZoneText_1arg() throws Exception { 521 builder.appendZoneText(TextStyle.FULL); 522 DateTimeFormatter f = builder.toFormatter(); 523 assertEquals(f.toString(), "ZoneText(FULL)"); 524 } 525 526 @Test(expectedExceptions=NullPointerException.class) test_appendZoneText_1arg_nullText()527 public void test_appendZoneText_1arg_nullText() throws Exception { 528 builder.appendZoneText(null); 529 } 530 531 //----------------------------------------------------------------------- 532 //----------------------------------------------------------------------- 533 //----------------------------------------------------------------------- 534 @Test test_padNext_1arg()535 public void test_padNext_1arg() { 536 builder.appendValue(MONTH_OF_YEAR).appendLiteral(':').padNext(2).appendValue(DAY_OF_MONTH); 537 assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2: 1"); 538 } 539 540 @Test(expectedExceptions=IllegalArgumentException.class) test_padNext_1arg_invalidWidth()541 public void test_padNext_1arg_invalidWidth() throws Exception { 542 builder.padNext(0); 543 } 544 545 //----------------------------------------------------------------------- 546 @Test test_padNext_2arg_dash()547 public void test_padNext_2arg_dash() throws Exception { 548 builder.appendValue(MONTH_OF_YEAR).appendLiteral(':').padNext(2, '-').appendValue(DAY_OF_MONTH); 549 assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2:-1"); 550 } 551 552 @Test(expectedExceptions=IllegalArgumentException.class) test_padNext_2arg_invalidWidth()553 public void test_padNext_2arg_invalidWidth() throws Exception { 554 builder.padNext(0, '-'); 555 } 556 557 //----------------------------------------------------------------------- 558 @Test test_padOptional()559 public void test_padOptional() throws Exception { 560 builder.appendValue(MONTH_OF_YEAR).appendLiteral(':') 561 .padNext(5).optionalStart().appendValue(DAY_OF_MONTH).optionalEnd() 562 .appendLiteral(':').appendValue(YEAR); 563 assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2: 1:2013"); 564 assertEquals(builder.toFormatter().format(YearMonth.of(2013, 2)), "2: :2013"); 565 } 566 567 //----------------------------------------------------------------------- 568 //----------------------------------------------------------------------- 569 //----------------------------------------------------------------------- 570 @Test test_optionalStart_noEnd()571 public void test_optionalStart_noEnd() throws Exception { 572 builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).appendValue(DAY_OF_WEEK); 573 DateTimeFormatter f = builder.toFormatter(); 574 assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)Value(DayOfWeek)]"); 575 } 576 577 @Test test_optionalStart2_noEnd()578 public void test_optionalStart2_noEnd() throws Exception { 579 builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).optionalStart().appendValue(DAY_OF_WEEK); 580 DateTimeFormatter f = builder.toFormatter(); 581 assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)[Value(DayOfWeek)]]"); 582 } 583 584 @Test test_optionalStart_doubleStart()585 public void test_optionalStart_doubleStart() throws Exception { 586 builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH); 587 DateTimeFormatter f = builder.toFormatter(); 588 assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]"); 589 } 590 591 //----------------------------------------------------------------------- 592 @Test test_optionalEnd()593 public void test_optionalEnd() throws Exception { 594 builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).optionalEnd().appendValue(DAY_OF_WEEK); 595 DateTimeFormatter f = builder.toFormatter(); 596 assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)]Value(DayOfWeek)"); 597 } 598 599 @Test test_optionalEnd2()600 public void test_optionalEnd2() throws Exception { 601 builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH) 602 .optionalStart().appendValue(DAY_OF_WEEK).optionalEnd().appendValue(DAY_OF_MONTH).optionalEnd(); 603 DateTimeFormatter f = builder.toFormatter(); 604 assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)[Value(DayOfWeek)]Value(DayOfMonth)]"); 605 } 606 607 @Test test_optionalEnd_doubleStartSingleEnd()608 public void test_optionalEnd_doubleStartSingleEnd() throws Exception { 609 builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH).optionalEnd(); 610 DateTimeFormatter f = builder.toFormatter(); 611 assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]"); 612 } 613 614 @Test test_optionalEnd_doubleStartDoubleEnd()615 public void test_optionalEnd_doubleStartDoubleEnd() throws Exception { 616 builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH).optionalEnd().optionalEnd(); 617 DateTimeFormatter f = builder.toFormatter(); 618 assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]"); 619 } 620 621 @Test test_optionalStartEnd_immediateStartEnd()622 public void test_optionalStartEnd_immediateStartEnd() throws Exception { 623 builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalEnd().appendValue(DAY_OF_MONTH); 624 DateTimeFormatter f = builder.toFormatter(); 625 assertEquals(f.toString(), "Value(MonthOfYear)Value(DayOfMonth)"); 626 } 627 628 @Test(expectedExceptions=IllegalStateException.class) test_optionalEnd_noStart()629 public void test_optionalEnd_noStart() throws Exception { 630 builder.optionalEnd(); 631 } 632 633 //----------------------------------------------------------------------- 634 //----------------------------------------------------------------------- 635 //----------------------------------------------------------------------- 636 @DataProvider(name="validPatterns") dataValid()637 Object[][] dataValid() { 638 return new Object[][] { 639 {"'a'", "'a'"}, 640 {"''", "''"}, 641 {"'!'", "'!'"}, 642 {"!", "'!'"}, 643 644 {"'hello_people,][)('", "'hello_people,][)('"}, 645 {"'hi'", "'hi'"}, 646 {"'yyyy'", "'yyyy'"}, 647 {"''''", "''"}, 648 {"'o''clock'", "'o''clock'"}, 649 650 {"G", "Text(Era,SHORT)"}, 651 {"GG", "Text(Era,SHORT)"}, 652 {"GGG", "Text(Era,SHORT)"}, 653 {"GGGG", "Text(Era)"}, 654 {"GGGGG", "Text(Era,NARROW)"}, 655 656 {"u", "Value(Year)"}, 657 {"uu", "ReducedValue(Year,2,2,2000-01-01)"}, 658 {"uuu", "Value(Year,3,19,NORMAL)"}, 659 {"uuuu", "Value(Year,4,19,EXCEEDS_PAD)"}, 660 {"uuuuu", "Value(Year,5,19,EXCEEDS_PAD)"}, 661 662 {"y", "Value(YearOfEra)"}, 663 {"yy", "ReducedValue(YearOfEra,2,2,2000-01-01)"}, 664 {"yyy", "Value(YearOfEra,3,19,NORMAL)"}, 665 {"yyyy", "Value(YearOfEra,4,19,EXCEEDS_PAD)"}, 666 {"yyyyy", "Value(YearOfEra,5,19,EXCEEDS_PAD)"}, 667 668 {"Y", "Localized(WeekBasedYear)"}, 669 {"YY", "Localized(ReducedValue(WeekBasedYear,2,2,2000-01-01))"}, 670 {"YYY", "Localized(WeekBasedYear,3,19,NORMAL)"}, 671 {"YYYY", "Localized(WeekBasedYear,4,19,EXCEEDS_PAD)"}, 672 {"YYYYY", "Localized(WeekBasedYear,5,19,EXCEEDS_PAD)"}, 673 674 {"M", "Value(MonthOfYear)"}, 675 {"MM", "Value(MonthOfYear,2)"}, 676 {"MMM", "Text(MonthOfYear,SHORT)"}, 677 {"MMMM", "Text(MonthOfYear)"}, 678 {"MMMMM", "Text(MonthOfYear,NARROW)"}, 679 680 {"L", "Value(MonthOfYear)"}, 681 {"LL", "Value(MonthOfYear,2)"}, 682 {"LLL", "Text(MonthOfYear,SHORT_STANDALONE)"}, 683 {"LLLL", "Text(MonthOfYear,FULL_STANDALONE)"}, 684 {"LLLLL", "Text(MonthOfYear,NARROW_STANDALONE)"}, 685 686 {"D", "Value(DayOfYear)"}, 687 {"DD", "Value(DayOfYear,2)"}, 688 {"DDD", "Value(DayOfYear,3)"}, 689 690 {"d", "Value(DayOfMonth)"}, 691 {"dd", "Value(DayOfMonth,2)"}, 692 693 {"F", "Value(AlignedDayOfWeekInMonth)"}, 694 695 {"Q", "Value(QuarterOfYear)"}, 696 {"QQ", "Value(QuarterOfYear,2)"}, 697 {"QQQ", "Text(QuarterOfYear,SHORT)"}, 698 {"QQQQ", "Text(QuarterOfYear)"}, 699 {"QQQQQ", "Text(QuarterOfYear,NARROW)"}, 700 701 {"q", "Value(QuarterOfYear)"}, 702 {"qq", "Value(QuarterOfYear,2)"}, 703 {"qqq", "Text(QuarterOfYear,SHORT_STANDALONE)"}, 704 {"qqqq", "Text(QuarterOfYear,FULL_STANDALONE)"}, 705 {"qqqqq", "Text(QuarterOfYear,NARROW_STANDALONE)"}, 706 707 {"E", "Text(DayOfWeek,SHORT)"}, 708 {"EE", "Text(DayOfWeek,SHORT)"}, 709 {"EEE", "Text(DayOfWeek,SHORT)"}, 710 {"EEEE", "Text(DayOfWeek)"}, 711 {"EEEEE", "Text(DayOfWeek,NARROW)"}, 712 713 {"e", "Localized(DayOfWeek,1)"}, 714 {"ee", "Localized(DayOfWeek,2)"}, 715 {"eee", "Text(DayOfWeek,SHORT)"}, 716 {"eeee", "Text(DayOfWeek)"}, 717 {"eeeee", "Text(DayOfWeek,NARROW)"}, 718 719 {"c", "Localized(DayOfWeek,1)"}, 720 {"ccc", "Text(DayOfWeek,SHORT_STANDALONE)"}, 721 {"cccc", "Text(DayOfWeek,FULL_STANDALONE)"}, 722 {"ccccc", "Text(DayOfWeek,NARROW_STANDALONE)"}, 723 724 {"a", "Text(AmPmOfDay,SHORT)"}, 725 726 {"H", "Value(HourOfDay)"}, 727 {"HH", "Value(HourOfDay,2)"}, 728 729 {"K", "Value(HourOfAmPm)"}, 730 {"KK", "Value(HourOfAmPm,2)"}, 731 732 {"k", "Value(ClockHourOfDay)"}, 733 {"kk", "Value(ClockHourOfDay,2)"}, 734 735 {"h", "Value(ClockHourOfAmPm)"}, 736 {"hh", "Value(ClockHourOfAmPm,2)"}, 737 738 {"m", "Value(MinuteOfHour)"}, 739 {"mm", "Value(MinuteOfHour,2)"}, 740 741 {"s", "Value(SecondOfMinute)"}, 742 {"ss", "Value(SecondOfMinute,2)"}, 743 744 {"S", "Fraction(NanoOfSecond,1,1)"}, 745 {"SS", "Fraction(NanoOfSecond,2,2)"}, 746 {"SSS", "Fraction(NanoOfSecond,3,3)"}, 747 {"SSSSSSSSS", "Fraction(NanoOfSecond,9,9)"}, 748 749 {"A", "Value(MilliOfDay)"}, 750 {"AA", "Value(MilliOfDay,2)"}, 751 {"AAA", "Value(MilliOfDay,3)"}, 752 753 {"n", "Value(NanoOfSecond)"}, 754 {"nn", "Value(NanoOfSecond,2)"}, 755 {"nnn", "Value(NanoOfSecond,3)"}, 756 757 {"N", "Value(NanoOfDay)"}, 758 {"NN", "Value(NanoOfDay,2)"}, 759 {"NNN", "Value(NanoOfDay,3)"}, 760 761 {"z", "ZoneText(SHORT)"}, 762 {"zz", "ZoneText(SHORT)"}, 763 {"zzz", "ZoneText(SHORT)"}, 764 {"zzzz", "ZoneText(FULL)"}, 765 766 {"VV", "ZoneId()"}, 767 768 {"Z", "Offset(+HHMM,'+0000')"}, // SimpleDateFormat 769 {"ZZ", "Offset(+HHMM,'+0000')"}, // SimpleDateFormat 770 {"ZZZ", "Offset(+HHMM,'+0000')"}, // SimpleDateFormat 771 772 {"X", "Offset(+HHmm,'Z')"}, // LDML/almost SimpleDateFormat 773 {"XX", "Offset(+HHMM,'Z')"}, // LDML/SimpleDateFormat 774 {"XXX", "Offset(+HH:MM,'Z')"}, // LDML/SimpleDateFormat 775 {"XXXX", "Offset(+HHMMss,'Z')"}, // LDML 776 {"XXXXX", "Offset(+HH:MM:ss,'Z')"}, // LDML 777 778 {"x", "Offset(+HHmm,'+00')"}, // LDML 779 {"xx", "Offset(+HHMM,'+0000')"}, // LDML 780 {"xxx", "Offset(+HH:MM,'+00:00')"}, // LDML 781 {"xxxx", "Offset(+HHMMss,'+0000')"}, // LDML 782 {"xxxxx", "Offset(+HH:MM:ss,'+00:00')"}, // LDML 783 784 {"ppH", "Pad(Value(HourOfDay),2)"}, 785 {"pppDD", "Pad(Value(DayOfYear,2),3)"}, 786 787 {"yyyy[-MM[-dd", "Value(YearOfEra,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)['-'Value(DayOfMonth,2)]]"}, 788 {"yyyy[-MM[-dd]]", "Value(YearOfEra,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)['-'Value(DayOfMonth,2)]]"}, 789 {"yyyy[-MM[]-dd]", "Value(YearOfEra,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)]"}, 790 791 {"yyyy-MM-dd'T'HH:mm:ss.SSS", "Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)" + 792 "'T'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)'.'Fraction(NanoOfSecond,3,3)"}, 793 794 {"w", "Localized(WeekOfWeekBasedYear,1)"}, 795 {"ww", "Localized(WeekOfWeekBasedYear,2)"}, 796 {"W", "Localized(WeekOfMonth,1)"}, 797 }; 798 } 799 800 @Test(dataProvider="validPatterns") test_appendPattern_valid(String input, String expected)801 public void test_appendPattern_valid(String input, String expected) throws Exception { 802 builder.appendPattern(input); 803 DateTimeFormatter f = builder.toFormatter(); 804 assertEquals(f.toString(), expected); 805 } 806 807 //----------------------------------------------------------------------- 808 @DataProvider(name="invalidPatterns") dataInvalid()809 Object[][] dataInvalid() { 810 return new Object[][] { 811 {"'"}, 812 {"'hello"}, 813 {"'hel''lo"}, 814 {"'hello''"}, 815 {"{"}, 816 {"}"}, 817 {"{}"}, 818 {"]"}, 819 {"yyyy]"}, 820 {"yyyy]MM"}, 821 {"yyyy[MM]]"}, 822 823 {"aa"}, 824 {"aaa"}, 825 {"aaaa"}, 826 {"aaaaa"}, 827 {"aaaaaa"}, 828 {"MMMMMM"}, 829 {"LLLLLL"}, 830 {"QQQQQQ"}, 831 {"qqqqqq"}, 832 {"EEEEEE"}, 833 {"eeeeee"}, 834 {"cc"}, 835 {"cccccc"}, 836 {"ddd"}, 837 {"DDDD"}, 838 {"FF"}, 839 {"FFF"}, 840 {"hhh"}, 841 {"HHH"}, 842 {"kkk"}, 843 {"KKK"}, 844 {"mmm"}, 845 {"sss"}, 846 {"OO"}, 847 {"OOO"}, 848 {"OOOOO"}, 849 {"XXXXXX"}, 850 {"ZZZZZZ"}, 851 {"zzzzz"}, 852 {"V"}, 853 {"VVV"}, 854 {"VVVV"}, 855 {"VVVVV"}, 856 857 {"RO"}, 858 859 {"p"}, 860 {"pp"}, 861 {"p:"}, 862 863 {"f"}, 864 {"ff"}, 865 {"f:"}, 866 {"fy"}, 867 {"fa"}, 868 {"fM"}, 869 870 {"www"}, 871 {"WW"}, 872 }; 873 } 874 875 @Test(dataProvider="invalidPatterns", expectedExceptions=IllegalArgumentException.class) test_appendPattern_invalid(String input)876 public void test_appendPattern_invalid(String input) throws Exception { 877 try { 878 builder.appendPattern(input); 879 } catch (IllegalArgumentException ex) { 880 throw ex; 881 } 882 } 883 884 //----------------------------------------------------------------------- 885 @DataProvider(name="patternPrint") data_patternPrint()886 Object[][] data_patternPrint() { 887 return new Object[][] { 888 {"Q", date(2012, 2, 10), "1"}, 889 {"QQ", date(2012, 2, 10), "01"}, 890 {"QQQ", date(2012, 2, 10), "Q1"}, 891 {"QQQQ", date(2012, 2, 10), "1st quarter"}, 892 {"QQQQQ", date(2012, 2, 10), "1"}, 893 }; 894 } 895 896 @Test(dataProvider="patternPrint") test_appendPattern_patternPrint(String input, Temporal temporal, String expected)897 public void test_appendPattern_patternPrint(String input, Temporal temporal, String expected) throws Exception { 898 DateTimeFormatter f = builder.appendPattern(input).toFormatter(Locale.UK); 899 String test = f.format(temporal); 900 assertEquals(test, expected); 901 } 902 903 //----------------------------------------------------------------------- 904 @DataProvider(name="localePatterns") localizedDateTimePatterns()905 Object[][] localizedDateTimePatterns() { 906 // Android-changed: Adapt for changes since old CLDR version this tests were written for. 907 return new Object[][] { 908 {FormatStyle.FULL, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.US, "EEEE, MMMM d, y 'at' h:mm:ss a zzzz"}, 909 {FormatStyle.LONG, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.US, "MMMM d, y 'at' h:mm:ss a z"}, 910 {FormatStyle.MEDIUM, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.US, "MMM d, y, h:mm:ss a"}, 911 {FormatStyle.SHORT, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.US, "M/d/yy, h:mm a"}, 912 {FormatStyle.FULL, null, IsoChronology.INSTANCE, Locale.US, "EEEE, MMMM d, y"}, 913 {FormatStyle.LONG, null, IsoChronology.INSTANCE, Locale.US, "MMMM d, y"}, 914 {FormatStyle.MEDIUM, null, IsoChronology.INSTANCE, Locale.US, "MMM d, y"}, 915 {FormatStyle.SHORT, null, IsoChronology.INSTANCE, Locale.US, "M/d/yy"}, 916 {null, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.US, "h:mm:ss a zzzz"}, 917 {null, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.US, "h:mm:ss a z"}, 918 {null, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.US, "h:mm:ss a"}, 919 {null, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.US, "h:mm a"}, 920 921 // French Locale and ISO Chronology 922 {FormatStyle.FULL, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.FRENCH, "EEEE d MMMM y 'à' HH:mm:ss zzzz"}, 923 {FormatStyle.LONG, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.FRENCH, "d MMMM y 'à' HH:mm:ss z"}, 924 // Android-changed: Since ICU 68, medium format uses ',' instead of 'à', to separate the date and time in French. 925 // {FormatStyle.MEDIUM, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.FRENCH, "d MMM y 'à' HH:mm:ss"}, 926 {FormatStyle.MEDIUM, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.FRENCH, "d MMM y, HH:mm:ss"}, 927 {FormatStyle.SHORT, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.FRENCH, "dd/MM/y HH:mm"}, 928 {FormatStyle.FULL, null, IsoChronology.INSTANCE, Locale.FRENCH, "EEEE d MMMM y"}, 929 {FormatStyle.LONG, null, IsoChronology.INSTANCE, Locale.FRENCH, "d MMMM y"}, 930 {FormatStyle.MEDIUM, null, IsoChronology.INSTANCE, Locale.FRENCH, "d MMM y"}, 931 {FormatStyle.SHORT, null, IsoChronology.INSTANCE, Locale.FRENCH, "dd/MM/y"}, 932 {null, FormatStyle.FULL, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm:ss zzzz"}, 933 {null, FormatStyle.LONG, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm:ss z"}, 934 {null, FormatStyle.MEDIUM, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm:ss"}, 935 {null, FormatStyle.SHORT, IsoChronology.INSTANCE, Locale.FRENCH, "HH:mm"}, 936 937 // Japanese Locale and JapaneseChronology 938 {FormatStyle.FULL, FormatStyle.FULL, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5EEEE H\u6642mm\u5206ss\u79d2 zzzz"}, 939 {FormatStyle.LONG, FormatStyle.LONG, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5 H:mm:ss z"}, 940 {FormatStyle.MEDIUM, FormatStyle.MEDIUM, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5 H:mm:ss"}, 941 {FormatStyle.SHORT, FormatStyle.SHORT, JapaneseChronology.INSTANCE, Locale.JAPANESE, "GGGGGy/M/d H:mm"}, 942 {FormatStyle.FULL, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5EEEE"}, 943 {FormatStyle.LONG, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5"}, 944 {FormatStyle.MEDIUM, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "Gy\u5e74M\u6708d\u65e5"}, 945 {FormatStyle.SHORT, null, JapaneseChronology.INSTANCE, Locale.JAPANESE, "GGGGGy/M/d"}, 946 {null, FormatStyle.FULL, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H\u6642mm\u5206ss\u79d2 zzzz"}, 947 {null, FormatStyle.LONG, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H:mm:ss z"}, 948 {null, FormatStyle.MEDIUM, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H:mm:ss"}, 949 {null, FormatStyle.SHORT, JapaneseChronology.INSTANCE, Locale.JAPANESE, "H:mm"}, 950 951 // Chinese Local and Chronology 952 {FormatStyle.FULL, FormatStyle.FULL, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5EEEE zzzz ah:mm:ss"}, 953 {FormatStyle.LONG, FormatStyle.LONG, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5 z ah:mm:ss"}, 954 {FormatStyle.MEDIUM, FormatStyle.MEDIUM, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5 ah:mm:ss"}, 955 // Android-changed: Since ICU 68, use single 'y' to represent year in short form like other format styles 956 // {FormatStyle.SHORT, FormatStyle.SHORT, MinguoChronology.INSTANCE, Locale.CHINESE, "Gyy/M/d ah:mm"}, 957 {FormatStyle.SHORT, FormatStyle.SHORT, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy/M/d ah:mm"}, 958 {FormatStyle.FULL, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5EEEE"}, 959 {FormatStyle.LONG, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5"}, 960 {FormatStyle.MEDIUM, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy\u5e74M\u6708d\u65e5"}, 961 // Android-changed: Since ICU 68, use single 'y' to represent year in short form like other format styles 962 // {FormatStyle.SHORT, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gyy/M/d"}, 963 {FormatStyle.SHORT, null, MinguoChronology.INSTANCE, Locale.CHINESE, "Gy/M/d"}, 964 {null, FormatStyle.FULL, MinguoChronology.INSTANCE, Locale.CHINESE, "zzzz ah:mm:ss"}, 965 {null, FormatStyle.LONG, MinguoChronology.INSTANCE, Locale.CHINESE, "z ah:mm:ss"}, 966 {null, FormatStyle.MEDIUM, MinguoChronology.INSTANCE, Locale.CHINESE, "ah:mm:ss"}, 967 {null, FormatStyle.SHORT, MinguoChronology.INSTANCE, Locale.CHINESE, "ah:mm"}, 968 }; 969 } 970 971 @Test(dataProvider="localePatterns") test_getLocalizedDateTimePattern(FormatStyle dateStyle, FormatStyle timeStyle, Chronology chrono, Locale locale, String expected)972 public void test_getLocalizedDateTimePattern(FormatStyle dateStyle, FormatStyle timeStyle, 973 Chronology chrono, Locale locale, String expected) { 974 String actual = DateTimeFormatterBuilder.getLocalizedDateTimePattern(dateStyle, timeStyle, chrono, locale); 975 assertEquals(actual, expected, "Pattern " + convertNonAscii(actual)); 976 } 977 978 @Test(expectedExceptions=java.lang.IllegalArgumentException.class) test_getLocalizedDateTimePatternIAE()979 public void test_getLocalizedDateTimePatternIAE() { 980 DateTimeFormatterBuilder.getLocalizedDateTimePattern(null, null, IsoChronology.INSTANCE, Locale.US); 981 } 982 983 @Test(expectedExceptions=java.lang.NullPointerException.class) test_getLocalizedChronoNPE()984 public void test_getLocalizedChronoNPE() { 985 DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.SHORT, FormatStyle.SHORT, null, Locale.US); 986 } 987 988 @Test(expectedExceptions=java.lang.NullPointerException.class) test_getLocalizedLocaleNPE()989 public void test_getLocalizedLocaleNPE() { 990 DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.SHORT, FormatStyle.SHORT, IsoChronology.INSTANCE, null); 991 } 992 993 /** 994 * Returns a string that includes non-ascii characters after expanding 995 * the non-ascii characters to their Java language \\uxxxx form. 996 * @param input an input string 997 * @return the encoded string. 998 */ convertNonAscii(String input)999 private String convertNonAscii(String input) { 1000 StringBuilder sb = new StringBuilder(input.length() * 6); 1001 for (int i = 0; i < input.length(); i++) { 1002 char ch = input.charAt(i); 1003 if (ch < 255) { 1004 sb.append(ch); 1005 } else { 1006 sb.append("\\u"); 1007 sb.append(Integer.toHexString(ch)); 1008 } 1009 } 1010 return sb.toString(); 1011 } 1012 date(int y, int m, int d)1013 private static Temporal date(int y, int m, int d) { 1014 return LocalDate.of(y, m, d); 1015 } 1016 1017 } 1018