github.com/go-chrono/chrono@v0.0.0-20240102183611-532f0d0d7c34/format_test.go (about) 1 package chrono_test 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 "testing" 8 9 "github.com/go-chrono/chrono" 10 ) 11 12 func TestLocalDate_Parse_supported_specifiers(t *testing.T) { 13 setupCenturyParsing() 14 defer tearDownCenturyParsing() 15 16 for _, tt := range dateSpecifiers { 17 t.Run(fmt.Sprintf("%s (%v)", tt.specifier, tt.textToParse), func(t *testing.T) { 18 var date chrono.LocalDate 19 if err := date.Parse(tt.specifier, tt.textToParse); err != nil { 20 t.Errorf("failed to parse date: %v", err) 21 } 22 23 tt.checkParse(t, date) 24 }) 25 } 26 27 for _, tt := range timeSpecifiers { 28 t.Run(tt.specifier, func(t *testing.T) { 29 func() { 30 defer func() { 31 if r := recover(); r == nil { 32 t.Error("expecting panic that didn't occur") 33 } 34 }() 35 36 var date chrono.LocalDate 37 date.Format(tt.specifier) 38 }() 39 }) 40 } 41 } 42 43 func TestLocalTime_Parse_supported_specifiers(t *testing.T) { 44 setupCenturyParsing() 45 defer tearDownCenturyParsing() 46 47 for _, tt := range dateSpecifiers { 48 t.Run(fmt.Sprintf("%s (%v)", tt.specifier, tt.textToParse), func(t *testing.T) { 49 func() { 50 defer func() { 51 if r := recover(); r == nil { 52 t.Error("expecting panic that didn't occur") 53 } 54 }() 55 56 var time chrono.LocalTime 57 time.Format(tt.specifier) 58 }() 59 }) 60 } 61 62 for _, tt := range timeSpecifiers { 63 t.Run(tt.specifier, func(t *testing.T) { 64 var time chrono.LocalTime 65 if err := time.Parse(tt.specifier, tt.text); err != nil { 66 t.Errorf("failed to parse time: %v", err) 67 } 68 69 tt.checkParse(t, time) 70 }) 71 } 72 } 73 74 func TestLocalDateTime_Parse_supported_specifiers(t *testing.T) { 75 setupCenturyParsing() 76 defer tearDownCenturyParsing() 77 78 for _, tt := range dateSpecifiers { 79 t.Run(fmt.Sprintf("%s (%v)", tt.specifier, tt.textToParse), func(t *testing.T) { 80 var dt chrono.LocalDateTime 81 if err := dt.Parse(tt.specifier, tt.textToParse); err != nil { 82 t.Errorf("failed to parse date: %v", err) 83 } 84 85 date, _ := dt.Split() 86 tt.checkParse(t, date) 87 }) 88 } 89 90 for _, tt := range timeSpecifiers { 91 t.Run(tt.specifier, func(t *testing.T) { 92 var dt chrono.LocalDateTime 93 if err := dt.Parse(tt.specifier, tt.text); err != nil { 94 t.Errorf("failed to parse time: %v", err) 95 } 96 97 _, time := dt.Split() 98 tt.checkParse(t, time) 99 }) 100 } 101 } 102 103 func TestOffsetTime_Parse_suported_specifiers(t *testing.T) { 104 setupCenturyParsing() 105 defer tearDownCenturyParsing() 106 107 for _, tt := range dateSpecifiers { 108 t.Run(fmt.Sprintf("%s (%v)", tt.specifier, tt.textToParse), func(t *testing.T) { 109 func() { 110 defer func() { 111 if r := recover(); r == nil { 112 t.Error("expecting panic that didn't occur") 113 } 114 }() 115 116 var time chrono.OffsetTime 117 time.Format(tt.specifier) 118 }() 119 }) 120 } 121 122 for _, tt := range timeSpecifiers { 123 t.Run(tt.specifier, func(t *testing.T) { 124 var time chrono.OffsetTime 125 if err := time.Parse(tt.specifier, tt.text); err != nil { 126 t.Errorf("failed to parse time: %v", err) 127 } 128 129 tt.checkParse(t, time) 130 }) 131 } 132 133 for _, tt := range offsetTimeSpecifiersUTC { 134 t.Run(tt.specifier, func(t *testing.T) { 135 var time chrono.OffsetTime 136 if err := time.Parse(tt.specifier, tt.text); err != nil { 137 t.Errorf("failed to parse time: %v", err) 138 } 139 140 tt.checkParse(t, time) 141 }) 142 } 143 } 144 145 func TestOffsetDateTime_Parse_supported_specifiers(t *testing.T) { 146 setupCenturyParsing() 147 defer tearDownCenturyParsing() 148 149 for _, tt := range dateSpecifiers { 150 t.Run(fmt.Sprintf("%s (%v)", tt.specifier, tt.textToParse), func(t *testing.T) { 151 var dt chrono.OffsetDateTime 152 if err := dt.Parse(tt.specifier, tt.textToParse); err != nil { 153 t.Errorf("failed to parse date: %v", err) 154 } 155 156 date, _ := dt.Split() 157 tt.checkParse(t, date) 158 }) 159 } 160 161 for _, tt := range timeSpecifiers { 162 t.Run(tt.specifier, func(t *testing.T) { 163 var dt chrono.OffsetDateTime 164 if err := dt.Parse(tt.specifier, tt.text); err != nil { 165 t.Errorf("failed to parse time: %v", err) 166 } 167 168 _, time := dt.Split() 169 tt.checkParse(t, time) 170 }) 171 } 172 173 for _, tt := range offsetTimeSpecifiersUTC { 174 t.Run(tt.specifier, func(t *testing.T) { 175 var dt chrono.OffsetDateTime 176 if err := dt.Parse(tt.specifier, tt.text); err != nil { 177 t.Errorf("failed to parse time: %v", err) 178 } 179 180 _, time := dt.Split() 181 tt.checkParse(t, time) 182 }) 183 } 184 } 185 186 func TestLocalDate_Format_supported_specifiers(t *testing.T) { 187 for _, tt := range dateSpecifiers { 188 t.Run(fmt.Sprintf("%s (%v)", tt.specifier, tt.textToParse), func(t *testing.T) { 189 if formatted := chrono.LocalDateOf(formatYear, formatMonth, formatDay).Format(tt.specifier); formatted != tt.expectedFormatted { 190 t.Errorf("date.Format(%s) = %s, want %q", tt.specifier, formatted, tt.expectedFormatted) 191 } 192 }) 193 } 194 195 for _, tt := range timeSpecifiers { 196 t.Run(tt.specifier, func(t *testing.T) { 197 func() { 198 defer func() { 199 if r := recover(); r == nil { 200 t.Error("expecting panic that didn't occur") 201 } 202 }() 203 204 chrono.LocalDateOf(formatYear, formatMonth, formatDay).Format(tt.specifier) 205 }() 206 }) 207 } 208 } 209 210 func TestLocalTime_Format_supported_specifiers(t *testing.T) { 211 for _, tt := range dateSpecifiers { 212 t.Run(fmt.Sprintf("%s (%v)", tt.specifier, tt.textToParse), func(t *testing.T) { 213 func() { 214 defer func() { 215 if r := recover(); r == nil { 216 t.Error("expecting panic that didn't occur") 217 } 218 }() 219 220 chrono.LocalTimeOf(formatHour, formatMin, formatSec, formatNanos).Format(tt.specifier) 221 }() 222 }) 223 } 224 225 for _, tt := range timeSpecifiers { 226 t.Run(tt.specifier, func(t *testing.T) { 227 if formatted := chrono.LocalTimeOf(formatHour, formatMin, formatSec, formatNanos).Format(tt.specifier); formatted != tt.text { 228 t.Errorf("time.Format(%s) = %s, want %q", tt.specifier, formatted, tt.text) 229 } 230 }) 231 } 232 } 233 234 func TestLocalDateTime_Format_supported_specifiers(t *testing.T) { 235 for _, tt := range dateSpecifiers { 236 t.Run(fmt.Sprintf("%s (%v)", tt.specifier, tt.textToParse), func(t *testing.T) { 237 if formatted := chrono.LocalDateTimeOf(formatYear, formatMonth, formatDay, formatHour, formatMin, formatSec, formatNanos). 238 Format(tt.specifier); formatted != tt.expectedFormatted { 239 t.Errorf("datetime.Format(%s) = %s, want %q", tt.specifier, formatted, tt.expectedFormatted) 240 } 241 }) 242 } 243 244 for _, tt := range timeSpecifiers { 245 t.Run(tt.specifier, func(t *testing.T) { 246 if formatted := chrono.LocalDateTimeOf(formatYear, formatMonth, formatDay, formatHour, formatMin, formatSec, formatNanos). 247 Format(tt.specifier); formatted != tt.text { 248 t.Errorf("datetime.Format(%s) = %s, want %q", tt.specifier, formatted, tt.text) 249 } 250 }) 251 } 252 } 253 254 func TestOffsetTime_Format_supported_specifiers(t *testing.T) { 255 for _, tt := range dateSpecifiers { 256 t.Run(fmt.Sprintf("%s (%v)", tt.specifier, tt.textToParse), func(t *testing.T) { 257 func() { 258 defer func() { 259 if r := recover(); r == nil { 260 t.Error("expecting panic that didn't occur") 261 } 262 }() 263 264 chrono.OffsetTimeOf(formatHour, formatMin, formatSec, formatNanos, 265 formatOffsetHours, formatOffsetMins).Format(tt.specifier) 266 }() 267 }) 268 } 269 270 for _, tt := range timeSpecifiers { 271 t.Run(tt.specifier, func(t *testing.T) { 272 if formatted := chrono.OffsetTimeOf(formatHour, formatMin, formatSec, formatNanos, 273 formatOffsetHours, formatOffsetMins).Format(tt.specifier); formatted != tt.text { 274 t.Errorf("time.Format(%s) = %s, want %q", tt.specifier, formatted, tt.text) 275 } 276 }) 277 } 278 279 for _, tt := range offsetTimeSpecifiersUTC { 280 t.Run(tt.specifier, func(t *testing.T) { 281 if formatted := chrono.OffsetTimeOf(formatHour, formatMin, formatSec, formatNanos, 282 formatOffsetHours, formatOffsetMins).Format(tt.specifier); formatted != tt.expectedFormatted { 283 t.Errorf("time.Format(%s) = %s, want %q", tt.specifier, formatted, tt.expectedFormatted) 284 } 285 }) 286 } 287 } 288 289 func TestOffsetDateTime_Format_supported_specifiers(t *testing.T) { 290 for _, tt := range dateSpecifiers { 291 t.Run(fmt.Sprintf("%s (%v)", tt.specifier, tt.textToParse), func(t *testing.T) { 292 if formatted := chrono.OffsetDateTimeOf(formatYear, formatMonth, formatDay, formatHour, formatMin, formatSec, formatNanos, 293 formatOffsetHours, formatOffsetMins).Format(tt.specifier); formatted != tt.expectedFormatted { 294 t.Errorf("datetime.Format(%s) = %s, want %q", tt.specifier, formatted, tt.expectedFormatted) 295 } 296 }) 297 } 298 299 for _, tt := range timeSpecifiers { 300 t.Run(tt.specifier, func(t *testing.T) { 301 if formatted := chrono.OffsetDateTimeOf(formatYear, formatMonth, formatDay, formatHour, formatMin, formatSec, formatNanos, 302 formatOffsetHours, formatOffsetMins).Format(tt.specifier); formatted != tt.text { 303 t.Errorf("datetime.Format(%s) = %s, want %q", tt.specifier, formatted, tt.text) 304 } 305 }) 306 } 307 308 for _, tt := range offsetTimeSpecifiersUTC { 309 t.Run(tt.specifier, func(t *testing.T) { 310 if formatted := chrono.OffsetDateTimeOf(formatYear, formatMonth, formatDay, formatHour, formatMin, formatSec, formatNanos, 311 formatOffsetHours, formatOffsetMins).Format(tt.specifier); formatted != tt.expectedFormatted { 312 t.Errorf("datetime.Format(%s) = %s, want %q", tt.specifier, formatted, tt.expectedFormatted) 313 } 314 }) 315 } 316 } 317 318 func TestOffsetTime_Parse_offset_formats(t *testing.T) { 319 for _, tt := range offsetTimeSpecifiers { 320 t.Run(fmt.Sprintf("%s-%s", tt.specifier, tt.text), func(t *testing.T) { 321 var time chrono.OffsetTime 322 if err := time.Parse(tt.specifier, tt.text); !tt.expectErr && err != nil { 323 t.Errorf("failed to parse time: %v", err) 324 } else if err == nil && tt.expectErr { 325 t.Errorf("expecting error") 326 } 327 328 if v := time.Offset(); v != chrono.Offset(tt.expected) { 329 t.Errorf("time.Offset() = %d, want %d", v, tt.expected) 330 } 331 }) 332 } 333 } 334 335 func TestOffsetDateTime_Parse_offset_formats(t *testing.T) { 336 for _, tt := range offsetTimeSpecifiers { 337 t.Run(fmt.Sprintf("%s-%s", tt.specifier, tt.text), func(t *testing.T) { 338 var dt chrono.OffsetDateTime 339 if err := dt.Parse(tt.specifier, tt.text); !tt.expectErr && err != nil { 340 t.Errorf("failed to parse time: %v", err) 341 } else if err == nil && tt.expectErr { 342 t.Errorf("expecting error") 343 } 344 345 if v := dt.Offset(); v != chrono.Offset(tt.expected) { 346 t.Errorf("dt.Offset() = %d, want %d", v, tt.expected) 347 } 348 }) 349 } 350 } 351 352 func TestOffsetTime_Format_offset_formats(t *testing.T) { 353 for _, tt := range offsetTimeSpecifiers { 354 t.Run(fmt.Sprintf("%s-%s", tt.specifier, tt.text), func(t *testing.T) { 355 time := chrono.OfTimeOffset(chrono.LocalTimeOf(formatHour, formatMin, formatSec, formatNanos), chrono.Offset(tt.expected)) 356 if formatted := time.Format(tt.specifier); formatted != tt.expectedFormatted { 357 t.Errorf("time = %s, time.Format(%s) = %s, want %q", time, tt.specifier, formatted, tt.expectedFormatted) 358 } 359 }) 360 } 361 } 362 363 func TestOffsetDateTime_Format_offset_formats(t *testing.T) { 364 for _, tt := range offsetTimeSpecifiers { 365 t.Run(fmt.Sprintf("%s-%s", tt.specifier, tt.text), func(t *testing.T) { 366 dt := chrono.OfLocalDateTimeOffset( 367 chrono.LocalDateOf(formatYear, formatMonth, formatDay), 368 chrono.LocalTimeOf(formatHour, formatMin, formatSec, formatNanos), 369 tt.expected, 370 ) 371 372 if formatted := dt.Format(tt.specifier); formatted != tt.expectedFormatted { 373 t.Errorf("datetime.Format(%s) = %s, want %q", tt.specifier, formatted, tt.expectedFormatted) 374 } 375 }) 376 } 377 } 378 379 func Test_format_literals(t *testing.T) { 380 for _, tt := range []struct { 381 name string 382 value interface{ Format(string) string } 383 layout string 384 expected string 385 }{ 386 { 387 name: "date", 388 value: chrono.LocalDateOf(2020, chrono.March, 18), 389 layout: "str1 %Y str2 100%%foo", 390 expected: "str1 2020 str2 100%foo", 391 }, 392 { 393 name: "time", 394 value: chrono.LocalTimeOf(12, 30, 15, 0), 395 layout: "str1 %H str2 100%%foo", 396 expected: "str1 12 str2 100%foo", 397 }, 398 { 399 name: "datetime", 400 value: chrono.LocalDateTimeOf(2020, chrono.March, 18, 12, 30, 15, 0), 401 layout: "str1 %Y str2 100%%foo", 402 expected: "str1 2020 str2 100%foo", 403 }, 404 } { 405 t.Run(tt.name, func(t *testing.T) { 406 if actual := tt.value.Format(tt.layout); actual != tt.expected { 407 t.Errorf("datetime.Format(%s) = %s, want %q", tt.layout, actual, tt.expected) 408 } 409 }) 410 } 411 } 412 413 func Test_parse_cannot_parse_error(t *testing.T) { 414 for _, tt := range []struct { 415 name string 416 layout string 417 value string 418 expected string 419 }{ 420 {"none", "foo bar", "foo", "parsing time \"foo\" as \"foo bar\": cannot parse \"foo\" as \"foo bar\""}, 421 {"partial", "bar", "foo", "parsing time \"foo\" as \"bar\": cannot parse \"foo\" as \"bar\""}, 422 } { 423 t.Run(tt.name, func(t *testing.T) { 424 var date chrono.LocalDate 425 var time chrono.LocalTime 426 var datetime chrono.LocalDateTime 427 428 for _, v := range []interface { 429 Parse(layout, value string) error 430 }{ 431 &date, 432 &time, 433 &datetime, 434 } { 435 t.Run(reflect.TypeOf(v).Elem().Name(), func(t *testing.T) { 436 if err := v.Parse(tt.layout, tt.value); err == nil { 437 t.Errorf("expecting error but got nil") 438 } else if !strings.Contains(err.Error(), tt.expected) { 439 t.Errorf("expecting %q error but got %q", tt.expected, err.Error()) 440 } 441 }) 442 } 443 }) 444 } 445 } 446 447 func Test_parse_extra_text_error(t *testing.T) { 448 var date chrono.LocalDate 449 var time chrono.LocalTime 450 var datetime chrono.LocalDateTime 451 452 for _, v := range []interface { 453 Parse(layout, value string) error 454 }{ 455 &date, 456 &time, 457 &datetime, 458 } { 459 t.Run(reflect.TypeOf(v).Elem().Name(), func(t *testing.T) { 460 expected := "parsing time \"foo bar\": extra text: \" bar\"" 461 if err := v.Parse("foo", "foo bar"); err == nil { 462 t.Errorf("expecting error but got nil") 463 } else if !strings.Contains(err.Error(), expected) { 464 t.Errorf("expecting %q error but got %q", expected, err.Error()) 465 } 466 }) 467 } 468 } 469 470 func TestLocalDateTime_Parse_predefined_layouts(t *testing.T) { 471 for _, tt := range predefinedLayouts { 472 t.Run(tt.layout, func(t *testing.T) { 473 var datetime chrono.LocalDateTime 474 if err := datetime.Parse(tt.layout, tt.textToParse); err != nil { 475 t.Errorf("datetime.Parse(%s, %s) = %v, want nil", tt.layout, tt.textToParse, err) 476 } else if datetime.Compare(tt.datetime.Local()) != 0 { 477 t.Errorf("expecting %v, but got %v", tt.datetime, datetime) 478 } 479 }) 480 } 481 } 482 483 func TestLocalDate_Parse_default_values(t *testing.T) { 484 for _, tt := range []struct { 485 name string 486 layout string 487 value string 488 expected chrono.LocalDate 489 }{ 490 {"nothing", "", "", chrono.LocalDateOf(1970, chrono.January, 1)}, 491 {"only year", "%Y", "2020", chrono.LocalDateOf(2020, chrono.January, 1)}, 492 {"only month", "%m", "04", chrono.LocalDateOf(1970, chrono.April, 1)}, 493 {"only day", "%d", "22", chrono.LocalDateOf(1970, chrono.January, 22)}, 494 } { 495 t.Run(tt.name, func(t *testing.T) { 496 var date chrono.LocalDate 497 if err := date.Parse(tt.layout, tt.value); err != nil { 498 t.Errorf("date.Parse(%s, %s) = %v, want nil", tt.layout, tt.value, err) 499 } else if date != tt.expected { 500 t.Errorf("expecting %v, but got %v", tt.expected, date) 501 } 502 }) 503 } 504 } 505 506 func TestLocalDateTime_Format_predefined_layouts(t *testing.T) { 507 for _, tt := range predefinedLayouts { 508 t.Run(tt.layout, func(t *testing.T) { 509 if formatted := tt.datetime.Local().Format(tt.layout); formatted != tt.expectedFormattedLocal { 510 t.Errorf("datetime.Format(%s) = %s, want %q", tt.layout, formatted, tt.expectedFormattedLocal) 511 } 512 }) 513 } 514 } 515 516 func TestLocalTime_Format_12HourClock(t *testing.T) { 517 t.Run("am", func(t *testing.T) { 518 time := chrono.LocalTimeOf(10, 0, 0, 0) 519 if formatted := time.Format("%I %P"); formatted != "10 am" { 520 t.Errorf("got %q, want '10 am'", formatted) 521 } 522 }) 523 524 t.Run("AM", func(t *testing.T) { 525 time := chrono.LocalTimeOf(10, 0, 0, 0) 526 if formatted := time.Format("%I %p"); formatted != "10 AM" { 527 t.Errorf("got %q, want '10 AM'", formatted) 528 } 529 }) 530 531 t.Run("pm", func(t *testing.T) { 532 time := chrono.LocalTimeOf(22, 0, 0, 0) 533 if formatted := time.Format("%I %P"); formatted != "10 pm" { 534 t.Errorf("got %q, want '10 pm'", formatted) 535 } 536 }) 537 538 t.Run("PM", func(t *testing.T) { 539 time := chrono.LocalTimeOf(22, 0, 0, 0) 540 if formatted := time.Format("%I %p"); formatted != "10 PM" { 541 t.Errorf("got %q, want '10 PM'", formatted) 542 } 543 }) 544 545 t.Run("noon", func(t *testing.T) { 546 time := chrono.LocalTimeOf(12, 0, 0, 0) 547 if formatted := time.Format("%I %P"); formatted != "12 pm" { 548 t.Errorf("got %q, want '12 pm'", formatted) 549 } 550 }) 551 552 t.Run("midnight", func(t *testing.T) { 553 time := chrono.LocalTimeOf(0, 0, 0, 0) 554 if formatted := time.Format("%I %P"); formatted != "12 am" { 555 t.Errorf("got %q, want '12 am'", formatted) 556 } 557 }) 558 } 559 560 func TestLocalTime_Parse_12HourClock(t *testing.T) { 561 t.Run("am", func(t *testing.T) { 562 var time chrono.LocalTime 563 if err := time.Parse("%I %P", "10 am"); err != nil { 564 t.Errorf("failed to parse time: %v", err) 565 } 566 567 if hour, _, _ := time.Clock(); hour != 10 { 568 t.Errorf("got %d, want 10", hour) 569 } 570 }) 571 572 t.Run("AM", func(t *testing.T) { 573 var time chrono.LocalTime 574 if err := time.Parse("%I %p", "10 AM"); err != nil { 575 t.Errorf("failed to parse time: %v", err) 576 } 577 578 if hour, _, _ := time.Clock(); hour != 10 { 579 t.Errorf("got %d, want 10", hour) 580 } 581 }) 582 583 t.Run("pm", func(t *testing.T) { 584 var time chrono.LocalTime 585 if err := time.Parse("%I %P", "10 pm"); err != nil { 586 t.Errorf("failed to parse time: %v", err) 587 } 588 589 if hour, _, _ := time.Clock(); hour != 22 { 590 t.Errorf("got %d, want 22", hour) 591 } 592 }) 593 594 t.Run("PM", func(t *testing.T) { 595 var time chrono.LocalTime 596 if err := time.Parse("%I %p", "10 PM"); err != nil { 597 t.Errorf("failed to parse time: %v", err) 598 } 599 600 if hour, _, _ := time.Clock(); hour != 22 { 601 t.Errorf("got %d, want 22", hour) 602 } 603 }) 604 605 t.Run("noon", func(t *testing.T) { 606 var time chrono.LocalTime 607 if err := time.Parse("%I %P", "12 pm"); err != nil { 608 t.Errorf("failed to parse time: %v", err) 609 } 610 611 if hour, _, _ := time.Clock(); hour != 12 { 612 t.Errorf("got %d, want 12", hour) 613 } 614 }) 615 616 t.Run("midnight", func(t *testing.T) { 617 var time chrono.LocalTime 618 if err := time.Parse("%I %P", "12 am"); err != nil { 619 t.Errorf("failed to parse time: %v", err) 620 } 621 622 if hour, _, _ := time.Clock(); hour != 0 { 623 t.Errorf("got %d, want 0", hour) 624 } 625 }) 626 627 t.Run("invalid hour", func(t *testing.T) { 628 var time chrono.LocalTime 629 if err := time.Parse("%I %P", "14 am"); err == nil { 630 t.Errorf("expecting error but got nil") 631 } 632 }) 633 } 634 635 func TestLocalDate_Format_eras(t *testing.T) { 636 t.Run("CE", func(t *testing.T) { 637 date := chrono.LocalDateOf(2022, chrono.June, 18) 638 if formatted := date.Format("%EY %EC"); formatted != "2022 CE" { 639 t.Errorf("got %q, want '2022 CE'", formatted) 640 } 641 }) 642 643 t.Run("BCE", func(t *testing.T) { 644 date := chrono.LocalDateOf(-2021, chrono.June, 18) 645 if formatted := date.Format("%EY %EC"); formatted != "2022 BCE" { 646 t.Errorf("got %q, want '2022 BCE'", formatted) 647 } 648 }) 649 650 t.Run("zero", func(t *testing.T) { 651 date := chrono.LocalDateOf(0, chrono.June, 18) 652 if formatted := date.Format("%EY %EC"); formatted != "0001 BCE" { 653 t.Errorf("got %q, want '1 BCE'", formatted) 654 } 655 }) 656 } 657 658 func TestLocalDate_Parse_eras(t *testing.T) { 659 t.Run("CE", func(t *testing.T) { 660 var date chrono.LocalDate 661 if err := date.Parse("%EY %EC", "2022 CE"); err != nil { 662 t.Errorf("failed to parse date: %v", err) 663 } 664 665 if year, _, _ := date.Date(); year != 2022 { 666 t.Errorf("got %d, want 2022", year) 667 } 668 }) 669 670 t.Run("BCE", func(t *testing.T) { 671 var date chrono.LocalDate 672 if err := date.Parse("%EY %EC", "2022 BCE"); err != nil { 673 t.Errorf("failed to parse date: %v", err) 674 } 675 676 if year, _, _ := date.Date(); year != -2021 { 677 t.Errorf("got %d, want -2021", year) 678 } 679 }) 680 681 t.Run("zero", func(t *testing.T) { 682 var date chrono.LocalDate 683 if err := date.Parse("%EY %EC", "1 BCE"); err != nil { 684 t.Errorf("failed to parse date: %v", err) 685 } 686 687 if year, _, _ := date.Date(); year != 0 { 688 t.Errorf("got %d, want 0", year) 689 } 690 }) 691 } 692 693 func TestLocalDate_Parse_century(t *testing.T) { 694 var date chrono.LocalDate 695 if err := date.Parse("%C", "19"); err != nil { 696 t.Errorf("failed to parse date: %v", err) 697 } 698 699 if year, _, _ := date.Date(); year != 1900 { 700 t.Errorf("got %d, want 1900", year) 701 } 702 } 703 704 func TestLocalDate_Parse_century_withYear(t *testing.T) { 705 t.Run("valid", func(t *testing.T) { 706 var date chrono.LocalDate 707 if err := date.Parse("%C %Y", "19 1970"); err != nil { 708 t.Errorf("unexpected error %v", err) 709 } 710 711 if year, _, _ := date.Date(); year != 1970 { 712 t.Errorf("got %d, want 1970", year) 713 } 714 }) 715 716 t.Run("invalid", func(t *testing.T) { 717 var date chrono.LocalDate 718 if err := date.Parse("%C %Y", "18 1970"); err == nil { 719 t.Errorf("expecting error, got nil") 720 } else if err.Error() != "year century 18 does not agree with year 1970" { 721 t.Errorf("unexpected error text %q", err.Error()) 722 } 723 }) 724 } 725 726 func TestLocalDate_Parse_shortYear(t *testing.T) { 727 t.Run("1900s", func(t *testing.T) { 728 var date chrono.LocalDate 729 if err := date.Parse("%y", "80"); err != nil { 730 t.Errorf("failed to parse date: %v", err) 731 } 732 733 if year, _, _ := date.Date(); year != 1980 { 734 t.Errorf("got %d, want 1980", year) 735 } 736 }) 737 738 t.Run("2000s", func(t *testing.T) { 739 var date chrono.LocalDate 740 if err := date.Parse("%y", "10"); err != nil { 741 t.Errorf("failed to parse date: %v", err) 742 } 743 744 if year, _, _ := date.Date(); year != 2010 { 745 t.Errorf("got %d, want 2010", year) 746 } 747 }) 748 } 749 750 func TestLocalDate_Parse_shortYear_withYear(t *testing.T) { 751 t.Run("valid", func(t *testing.T) { 752 var date chrono.LocalDate 753 if err := date.Parse("%y %Y", "70 1970"); err != nil { 754 t.Errorf("unexpected error %v", err) 755 } 756 757 if year, _, _ := date.Date(); year != 1970 { 758 t.Errorf("got %d, want 1970", year) 759 } 760 }) 761 762 t.Run("invalid", func(t *testing.T) { 763 var date chrono.LocalDate 764 if err := date.Parse("%y %Y", "75 1970"); err == nil { 765 t.Errorf("expecting error, got nil") 766 } else if err.Error() != "short year 75 (1975) does not agree with year 1970" { 767 t.Errorf("unexpected error text %q", err.Error()) 768 } 769 }) 770 } 771 772 func TestLocalDate_Parse_century_shortYear(t *testing.T) { 773 var date chrono.LocalDate 774 if err := date.Parse("%C%y", "1970"); err != nil { 775 t.Errorf("unexpected error %v", err) 776 } 777 778 if year, _, _ := date.Date(); year != 1970 { 779 t.Errorf("got %d, want 1970", year) 780 } 781 } 782 783 func TestLocalDate_Parse_century_shortYear_withYear(t *testing.T) { 784 t.Run("valid", func(t *testing.T) { 785 var date chrono.LocalDate 786 if err := date.Parse("%C%y %Y", "1970 1970"); err != nil { 787 t.Errorf("unexpected error %v", err) 788 } 789 790 if year, _, _ := date.Date(); year != 1970 { 791 t.Errorf("got %d, want 1970", year) 792 } 793 }) 794 795 t.Run("invalid century", func(t *testing.T) { 796 var date chrono.LocalDate 797 if err := date.Parse("%C%y %Y", "1970 1870"); err == nil { 798 t.Errorf("expecting error, got nil") 799 } else if err.Error() != "year century 19 does not agree with year 1870" { 800 t.Errorf("unexpected error text %q", err.Error()) 801 } 802 }) 803 804 t.Run("invalid year", func(t *testing.T) { 805 var date chrono.LocalDate 806 if err := date.Parse("%C%y %Y", "1970 1971"); err == nil { 807 t.Errorf("expecting error, got nil") 808 } else if err.Error() != "short year 70 (1970) does not agree with year 1971" { 809 t.Errorf("unexpected error text %q", err.Error()) 810 } 811 }) 812 } 813 814 func TestLocalDate_Parse_invalidDayOfYear(t *testing.T) { 815 var date chrono.LocalDate 816 if err := date.Parse("%Y-%m-%d (day %j)", "2020-01-20 (day 21)"); err == nil { 817 t.Errorf("expecting error but got nil") 818 } 819 } 820 821 func TestLocalDate_Parse_invalidISOWeekYear(t *testing.T) { 822 var date chrono.LocalDate 823 if err := date.Parse("%Y-%m-%d (week %V)", "2020-01-20 (week 2)"); err == nil { 824 t.Errorf("expecting error but got nil") 825 } 826 } 827 828 func TestLocalDate_Parse_invalidDayOfWeek(t *testing.T) { 829 var date chrono.LocalDate 830 if err := date.Parse("%Y-%m-%d (weekday %A)", "2020-01-20 (weekday Thursday)"); err == nil { 831 t.Errorf("expecting error but got nil") 832 } 833 } 834 835 func TestLocalDate_Format_invalid_specifier(t *testing.T) { 836 for _, specifier := range []string{ 837 "%Z", 838 } { 839 t.Run(specifier, func(t *testing.T) { 840 defer func() { 841 if r := recover(); r == nil { 842 t.Error("expecting panic that didn't occur") 843 } 844 }() 845 846 var date chrono.LocalDate 847 _ = date.Format(specifier) 848 }) 849 } 850 } 851 852 func TestLocalDate_Parse_invalid_specifier(t *testing.T) { 853 for _, specifier := range []string{ 854 "%Z", 855 } { 856 t.Run(specifier, func(t *testing.T) { 857 var date chrono.LocalDate 858 if err := date.Parse(specifier, ""); err == nil { 859 t.Errorf("expecting error but got nil") 860 } 861 }) 862 } 863 }