1------------------------------------------------------------------------------ 2-- -- 3-- GNAT RUN-TIME COMPONENTS -- 4-- -- 5-- A D A . C A L E N D A R . F O R M A T T I N G -- 6-- -- 7-- B o d y -- 8-- -- 9-- Copyright (C) 2006-2018, Free Software Foundation, Inc. -- 10-- -- 11-- GNAT is free software; you can redistribute it and/or modify it under -- 12-- terms of the GNU General Public License as published by the Free Soft- -- 13-- ware Foundation; either version 3, or (at your option) any later ver- -- 14-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- 15-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- 16-- or FITNESS FOR A PARTICULAR PURPOSE. -- 17-- -- 18-- As a special exception under Section 7 of GPL version 3, you are granted -- 19-- additional permissions described in the GCC Runtime Library Exception, -- 20-- version 3.1, as published by the Free Software Foundation. -- 21-- -- 22-- You should have received a copy of the GNU General Public License and -- 23-- a copy of the GCC Runtime Library Exception along with this program; -- 24-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- 25-- <http://www.gnu.org/licenses/>. -- 26-- -- 27-- GNAT was originally developed by the GNAT team at New York University. -- 28-- Extensive contributions were provided by Ada Core Technologies Inc. -- 29-- -- 30------------------------------------------------------------------------------ 31 32with Ada.Calendar; use Ada.Calendar; 33with Ada.Calendar.Time_Zones; use Ada.Calendar.Time_Zones; 34 35package body Ada.Calendar.Formatting is 36 37 -------------------------- 38 -- Implementation Notes -- 39 -------------------------- 40 41 -- All operations in this package are target and time representation 42 -- independent, thus only one source file is needed for multiple targets. 43 44 procedure Check_Char (S : String; C : Character; Index : Integer); 45 -- Subsidiary to the two versions of Value. Determine whether the input 46 -- string S has character C at position Index. Raise Constraint_Error if 47 -- there is a mismatch. 48 49 procedure Check_Digit (S : String; Index : Integer); 50 -- Subsidiary to the two versions of Value. Determine whether the character 51 -- of string S at position Index is a digit. This catches invalid input 52 -- such as 1983-*1-j3 u5:n7:k9 which should be 1983-01-03 05:07:09. Raise 53 -- Constraint_Error if there is a mismatch. 54 55 ---------------- 56 -- Check_Char -- 57 ---------------- 58 59 procedure Check_Char (S : String; C : Character; Index : Integer) is 60 begin 61 if S (Index) /= C then 62 raise Constraint_Error; 63 end if; 64 end Check_Char; 65 66 ----------------- 67 -- Check_Digit -- 68 ----------------- 69 70 procedure Check_Digit (S : String; Index : Integer) is 71 begin 72 if S (Index) not in '0' .. '9' then 73 raise Constraint_Error; 74 end if; 75 end Check_Digit; 76 77 --------- 78 -- Day -- 79 --------- 80 81 function Day 82 (Date : Time; 83 Time_Zone : Time_Zones.Time_Offset := 0) return Day_Number 84 is 85 Y : Year_Number; 86 Mo : Month_Number; 87 D : Day_Number; 88 H : Hour_Number; 89 Mi : Minute_Number; 90 Se : Second_Number; 91 Ss : Second_Duration; 92 Le : Boolean; 93 94 pragma Unreferenced (Y, Mo, H, Mi); 95 96 begin 97 Split (Date, Y, Mo, D, H, Mi, Se, Ss, Le, Time_Zone); 98 return D; 99 end Day; 100 101 ----------------- 102 -- Day_Of_Week -- 103 ----------------- 104 105 function Day_Of_Week (Date : Time) return Day_Name is 106 begin 107 return Day_Name'Val (Formatting_Operations.Day_Of_Week (Date)); 108 end Day_Of_Week; 109 110 ---------- 111 -- Hour -- 112 ---------- 113 114 function Hour 115 (Date : Time; 116 Time_Zone : Time_Zones.Time_Offset := 0) return Hour_Number 117 is 118 Y : Year_Number; 119 Mo : Month_Number; 120 D : Day_Number; 121 H : Hour_Number; 122 Mi : Minute_Number; 123 Se : Second_Number; 124 Ss : Second_Duration; 125 Le : Boolean; 126 127 pragma Unreferenced (Y, Mo, D, Mi); 128 129 begin 130 Split (Date, Y, Mo, D, H, Mi, Se, Ss, Le, Time_Zone); 131 return H; 132 end Hour; 133 134 ----------- 135 -- Image -- 136 ----------- 137 138 function Image 139 (Elapsed_Time : Duration; 140 Include_Time_Fraction : Boolean := False) return String 141 is 142 To_Char : constant array (0 .. 9) of Character := "0123456789"; 143 Hour : Hour_Number; 144 Minute : Minute_Number; 145 Second : Second_Number; 146 Sub_Second : Duration; 147 SS_Nat : Natural; 148 149 -- Determine the two slice bounds for the result string depending on 150 -- whether the input is negative and whether fractions are requested. 151 152 First : constant Integer := (if Elapsed_Time < 0.0 then 1 else 2); 153 Last : constant Integer := (if Include_Time_Fraction then 12 else 9); 154 155 Result : String := "-00:00:00.00"; 156 157 begin 158 Split (abs (Elapsed_Time), Hour, Minute, Second, Sub_Second); 159 160 -- Hour processing, positions 2 and 3 161 162 Result (2) := To_Char (Hour / 10); 163 Result (3) := To_Char (Hour mod 10); 164 165 -- Minute processing, positions 5 and 6 166 167 Result (5) := To_Char (Minute / 10); 168 Result (6) := To_Char (Minute mod 10); 169 170 -- Second processing, positions 8 and 9 171 172 Result (8) := To_Char (Second / 10); 173 Result (9) := To_Char (Second mod 10); 174 175 -- Optional sub second processing, positions 11 and 12 176 177 if Include_Time_Fraction and then Sub_Second > 0.0 then 178 179 -- Prevent rounding up when converting to natural, avoiding the zero 180 -- case to prevent rounding down to a negative number. 181 182 SS_Nat := Natural (Duration'(Sub_Second * 100.0) - 0.5); 183 184 Result (11) := To_Char (SS_Nat / 10); 185 Result (12) := To_Char (SS_Nat mod 10); 186 end if; 187 188 return Result (First .. Last); 189 end Image; 190 191 ----------- 192 -- Image -- 193 ----------- 194 195 function Image 196 (Date : Time; 197 Include_Time_Fraction : Boolean := False; 198 Time_Zone : Time_Zones.Time_Offset := 0) return String 199 is 200 To_Char : constant array (0 .. 9) of Character := "0123456789"; 201 202 Year : Year_Number; 203 Month : Month_Number; 204 Day : Day_Number; 205 Hour : Hour_Number; 206 Minute : Minute_Number; 207 Second : Second_Number; 208 Sub_Second : Duration; 209 SS_Nat : Natural; 210 Leap_Second : Boolean; 211 212 -- The result length depends on whether fractions are requested. 213 214 Result : String := "0000-00-00 00:00:00.00"; 215 Last : constant Positive := 216 Result'Last - (if Include_Time_Fraction then 0 else 3); 217 218 begin 219 Split (Date, Year, Month, Day, 220 Hour, Minute, Second, Sub_Second, Leap_Second, Time_Zone); 221 222 -- Year processing, positions 1, 2, 3 and 4 223 224 Result (1) := To_Char (Year / 1000); 225 Result (2) := To_Char (Year / 100 mod 10); 226 Result (3) := To_Char (Year / 10 mod 10); 227 Result (4) := To_Char (Year mod 10); 228 229 -- Month processing, positions 6 and 7 230 231 Result (6) := To_Char (Month / 10); 232 Result (7) := To_Char (Month mod 10); 233 234 -- Day processing, positions 9 and 10 235 236 Result (9) := To_Char (Day / 10); 237 Result (10) := To_Char (Day mod 10); 238 239 Result (12) := To_Char (Hour / 10); 240 Result (13) := To_Char (Hour mod 10); 241 242 -- Minute processing, positions 15 and 16 243 244 Result (15) := To_Char (Minute / 10); 245 Result (16) := To_Char (Minute mod 10); 246 247 -- Second processing, positions 18 and 19 248 249 Result (18) := To_Char (Second / 10); 250 Result (19) := To_Char (Second mod 10); 251 252 -- Optional sub second processing, positions 21 and 22 253 254 if Include_Time_Fraction and then Sub_Second > 0.0 then 255 256 -- Prevent rounding up when converting to natural, avoiding the zero 257 -- case to prevent rounding down to a negative number. 258 259 SS_Nat := Natural (Duration'(Sub_Second * 100.0) - 0.5); 260 261 Result (21) := To_Char (SS_Nat / 10); 262 Result (22) := To_Char (SS_Nat mod 10); 263 end if; 264 265 return Result (Result'First .. Last); 266 end Image; 267 268 ------------ 269 -- Minute -- 270 ------------ 271 272 function Minute 273 (Date : Time; 274 Time_Zone : Time_Zones.Time_Offset := 0) return Minute_Number 275 is 276 Y : Year_Number; 277 Mo : Month_Number; 278 D : Day_Number; 279 H : Hour_Number; 280 Mi : Minute_Number; 281 Se : Second_Number; 282 Ss : Second_Duration; 283 Le : Boolean; 284 285 pragma Unreferenced (Y, Mo, D, H); 286 287 begin 288 Split (Date, Y, Mo, D, H, Mi, Se, Ss, Le, Time_Zone); 289 return Mi; 290 end Minute; 291 292 ----------- 293 -- Month -- 294 ----------- 295 296 function Month 297 (Date : Time; 298 Time_Zone : Time_Zones.Time_Offset := 0) return Month_Number 299 is 300 Y : Year_Number; 301 Mo : Month_Number; 302 D : Day_Number; 303 H : Hour_Number; 304 Mi : Minute_Number; 305 Se : Second_Number; 306 Ss : Second_Duration; 307 Le : Boolean; 308 309 pragma Unreferenced (Y, D, H, Mi); 310 311 begin 312 Split (Date, Y, Mo, D, H, Mi, Se, Ss, Le, Time_Zone); 313 return Mo; 314 end Month; 315 316 ------------ 317 -- Second -- 318 ------------ 319 320 function Second (Date : Time) return Second_Number is 321 Y : Year_Number; 322 Mo : Month_Number; 323 D : Day_Number; 324 H : Hour_Number; 325 Mi : Minute_Number; 326 Se : Second_Number; 327 Ss : Second_Duration; 328 Le : Boolean; 329 330 pragma Unreferenced (Y, Mo, D, H, Mi); 331 332 begin 333 Split (Date, Y, Mo, D, H, Mi, Se, Ss, Le); 334 return Se; 335 end Second; 336 337 ---------------- 338 -- Seconds_Of -- 339 ---------------- 340 341 function Seconds_Of 342 (Hour : Hour_Number; 343 Minute : Minute_Number; 344 Second : Second_Number := 0; 345 Sub_Second : Second_Duration := 0.0) return Day_Duration is 346 347 begin 348 -- Validity checks 349 350 if not Hour'Valid 351 or else not Minute'Valid 352 or else not Second'Valid 353 or else not Sub_Second'Valid 354 then 355 raise Constraint_Error; 356 end if; 357 358 return Day_Duration (Hour * 3_600) + 359 Day_Duration (Minute * 60) + 360 Day_Duration (Second) + 361 Sub_Second; 362 end Seconds_Of; 363 364 ----------- 365 -- Split -- 366 ----------- 367 368 procedure Split 369 (Seconds : Day_Duration; 370 Hour : out Hour_Number; 371 Minute : out Minute_Number; 372 Second : out Second_Number; 373 Sub_Second : out Second_Duration) 374 is 375 Secs : Natural; 376 377 begin 378 -- Validity checks 379 380 if not Seconds'Valid then 381 raise Constraint_Error; 382 end if; 383 384 Secs := (if Seconds = 0.0 then 0 else Natural (Seconds - 0.5)); 385 386 Sub_Second := Second_Duration (Seconds - Day_Duration (Secs)); 387 Hour := Hour_Number (Secs / 3_600); 388 Secs := Secs mod 3_600; 389 Minute := Minute_Number (Secs / 60); 390 Second := Second_Number (Secs mod 60); 391 392 -- Validity checks 393 394 if not Hour'Valid 395 or else not Minute'Valid 396 or else not Second'Valid 397 or else not Sub_Second'Valid 398 then 399 raise Time_Error; 400 end if; 401 end Split; 402 403 ----------- 404 -- Split -- 405 ----------- 406 407 procedure Split 408 (Date : Time; 409 Year : out Year_Number; 410 Month : out Month_Number; 411 Day : out Day_Number; 412 Seconds : out Day_Duration; 413 Leap_Second : out Boolean; 414 Time_Zone : Time_Zones.Time_Offset := 0) 415 is 416 H : Integer; 417 M : Integer; 418 Se : Integer; 419 Su : Duration; 420 Tz : constant Long_Integer := Long_Integer (Time_Zone); 421 422 begin 423 Formatting_Operations.Split 424 (Date => Date, 425 Year => Year, 426 Month => Month, 427 Day => Day, 428 Day_Secs => Seconds, 429 Hour => H, 430 Minute => M, 431 Second => Se, 432 Sub_Sec => Su, 433 Leap_Sec => Leap_Second, 434 Use_TZ => True, 435 Is_Historic => True, 436 Time_Zone => Tz); 437 438 -- Validity checks 439 440 if not Year'Valid 441 or else not Month'Valid 442 or else not Day'Valid 443 or else not Seconds'Valid 444 then 445 raise Time_Error; 446 end if; 447 end Split; 448 449 ----------- 450 -- Split -- 451 ----------- 452 453 procedure Split 454 (Date : Time; 455 Year : out Year_Number; 456 Month : out Month_Number; 457 Day : out Day_Number; 458 Hour : out Hour_Number; 459 Minute : out Minute_Number; 460 Second : out Second_Number; 461 Sub_Second : out Second_Duration; 462 Time_Zone : Time_Zones.Time_Offset := 0) 463 is 464 Dd : Day_Duration; 465 Le : Boolean; 466 Tz : constant Long_Integer := Long_Integer (Time_Zone); 467 468 begin 469 Formatting_Operations.Split 470 (Date => Date, 471 Year => Year, 472 Month => Month, 473 Day => Day, 474 Day_Secs => Dd, 475 Hour => Hour, 476 Minute => Minute, 477 Second => Second, 478 Sub_Sec => Sub_Second, 479 Leap_Sec => Le, 480 Use_TZ => True, 481 Is_Historic => True, 482 Time_Zone => Tz); 483 484 -- Validity checks 485 486 if not Year'Valid 487 or else not Month'Valid 488 or else not Day'Valid 489 or else not Hour'Valid 490 or else not Minute'Valid 491 or else not Second'Valid 492 or else not Sub_Second'Valid 493 then 494 raise Time_Error; 495 end if; 496 end Split; 497 498 ----------- 499 -- Split -- 500 ----------- 501 502 procedure Split 503 (Date : Time; 504 Year : out Year_Number; 505 Month : out Month_Number; 506 Day : out Day_Number; 507 Hour : out Hour_Number; 508 Minute : out Minute_Number; 509 Second : out Second_Number; 510 Sub_Second : out Second_Duration; 511 Leap_Second : out Boolean; 512 Time_Zone : Time_Zones.Time_Offset := 0) 513 is 514 Dd : Day_Duration; 515 Tz : constant Long_Integer := Long_Integer (Time_Zone); 516 517 begin 518 Formatting_Operations.Split 519 (Date => Date, 520 Year => Year, 521 Month => Month, 522 Day => Day, 523 Day_Secs => Dd, 524 Hour => Hour, 525 Minute => Minute, 526 Second => Second, 527 Sub_Sec => Sub_Second, 528 Leap_Sec => Leap_Second, 529 Use_TZ => True, 530 Is_Historic => True, 531 Time_Zone => Tz); 532 533 -- Validity checks 534 535 if not Year'Valid 536 or else not Month'Valid 537 or else not Day'Valid 538 or else not Hour'Valid 539 or else not Minute'Valid 540 or else not Second'Valid 541 or else not Sub_Second'Valid 542 then 543 raise Time_Error; 544 end if; 545 end Split; 546 547 ---------------- 548 -- Sub_Second -- 549 ---------------- 550 551 function Sub_Second (Date : Time) return Second_Duration is 552 Y : Year_Number; 553 Mo : Month_Number; 554 D : Day_Number; 555 H : Hour_Number; 556 Mi : Minute_Number; 557 Se : Second_Number; 558 Ss : Second_Duration; 559 Le : Boolean; 560 561 pragma Unreferenced (Y, Mo, D, H, Mi); 562 563 begin 564 Split (Date, Y, Mo, D, H, Mi, Se, Ss, Le); 565 return Ss; 566 end Sub_Second; 567 568 ------------- 569 -- Time_Of -- 570 ------------- 571 572 function Time_Of 573 (Year : Year_Number; 574 Month : Month_Number; 575 Day : Day_Number; 576 Seconds : Day_Duration := 0.0; 577 Leap_Second : Boolean := False; 578 Time_Zone : Time_Zones.Time_Offset := 0) return Time 579 is 580 Adj_Year : Year_Number := Year; 581 Adj_Month : Month_Number := Month; 582 Adj_Day : Day_Number := Day; 583 584 H : constant Integer := 1; 585 M : constant Integer := 1; 586 Se : constant Integer := 1; 587 Ss : constant Duration := 0.1; 588 Tz : constant Long_Integer := Long_Integer (Time_Zone); 589 590 begin 591 -- Validity checks 592 593 if not Year'Valid 594 or else not Month'Valid 595 or else not Day'Valid 596 or else not Seconds'Valid 597 or else not Time_Zone'Valid 598 then 599 raise Constraint_Error; 600 end if; 601 602 -- A Seconds value of 86_400 denotes a new day. This case requires an 603 -- adjustment to the input values. 604 605 if Seconds = 86_400.0 then 606 if Day < Days_In_Month (Month) 607 or else (Is_Leap (Year) 608 and then Month = 2) 609 then 610 Adj_Day := Day + 1; 611 else 612 Adj_Day := 1; 613 614 if Month < 12 then 615 Adj_Month := Month + 1; 616 else 617 Adj_Month := 1; 618 Adj_Year := Year + 1; 619 end if; 620 end if; 621 end if; 622 623 return 624 Formatting_Operations.Time_Of 625 (Year => Adj_Year, 626 Month => Adj_Month, 627 Day => Adj_Day, 628 Day_Secs => Seconds, 629 Hour => H, 630 Minute => M, 631 Second => Se, 632 Sub_Sec => Ss, 633 Leap_Sec => Leap_Second, 634 Use_Day_Secs => True, 635 Use_TZ => True, 636 Is_Historic => True, 637 Time_Zone => Tz); 638 end Time_Of; 639 640 ------------- 641 -- Time_Of -- 642 ------------- 643 644 function Time_Of 645 (Year : Year_Number; 646 Month : Month_Number; 647 Day : Day_Number; 648 Hour : Hour_Number; 649 Minute : Minute_Number; 650 Second : Second_Number; 651 Sub_Second : Second_Duration := 0.0; 652 Leap_Second : Boolean := False; 653 Time_Zone : Time_Zones.Time_Offset := 0) return Time 654 is 655 Dd : constant Day_Duration := Day_Duration'First; 656 Tz : constant Long_Integer := Long_Integer (Time_Zone); 657 658 begin 659 -- Validity checks 660 661 if not Year'Valid 662 or else not Month'Valid 663 or else not Day'Valid 664 or else not Hour'Valid 665 or else not Minute'Valid 666 or else not Second'Valid 667 or else not Sub_Second'Valid 668 or else not Time_Zone'Valid 669 then 670 raise Constraint_Error; 671 end if; 672 673 return 674 Formatting_Operations.Time_Of 675 (Year => Year, 676 Month => Month, 677 Day => Day, 678 Day_Secs => Dd, 679 Hour => Hour, 680 Minute => Minute, 681 Second => Second, 682 Sub_Sec => Sub_Second, 683 Leap_Sec => Leap_Second, 684 Use_Day_Secs => False, 685 Use_TZ => True, 686 Is_Historic => True, 687 Time_Zone => Tz); 688 end Time_Of; 689 690 ----------- 691 -- Value -- 692 ----------- 693 694 function Value 695 (Date : String; 696 Time_Zone : Time_Zones.Time_Offset := 0) return Time 697 is 698 D : String (1 .. 22); 699 Year : Year_Number; 700 Month : Month_Number; 701 Day : Day_Number; 702 Hour : Hour_Number; 703 Minute : Minute_Number; 704 Second : Second_Number; 705 Sub_Second : Second_Duration := 0.0; 706 707 begin 708 -- Validity checks 709 710 if not Time_Zone'Valid then 711 raise Constraint_Error; 712 end if; 713 714 -- Length checks 715 716 if Date'Length /= 19 717 and then Date'Length /= 22 718 then 719 raise Constraint_Error; 720 end if; 721 722 -- After the correct length has been determined, it is safe to copy the 723 -- Date in order to avoid Date'First + N indexing. 724 725 D (1 .. Date'Length) := Date; 726 727 -- Format checks 728 729 Check_Char (D, '-', 5); 730 Check_Char (D, '-', 8); 731 Check_Char (D, ' ', 11); 732 Check_Char (D, ':', 14); 733 Check_Char (D, ':', 17); 734 735 if Date'Length = 22 then 736 Check_Char (D, '.', 20); 737 end if; 738 739 -- Leading zero checks 740 741 Check_Digit (D, 6); 742 Check_Digit (D, 9); 743 Check_Digit (D, 12); 744 Check_Digit (D, 15); 745 Check_Digit (D, 18); 746 747 if Date'Length = 22 then 748 Check_Digit (D, 21); 749 end if; 750 751 -- Value extraction 752 753 Year := Year_Number (Year_Number'Value (D (1 .. 4))); 754 Month := Month_Number (Month_Number'Value (D (6 .. 7))); 755 Day := Day_Number (Day_Number'Value (D (9 .. 10))); 756 Hour := Hour_Number (Hour_Number'Value (D (12 .. 13))); 757 Minute := Minute_Number (Minute_Number'Value (D (15 .. 16))); 758 Second := Second_Number (Second_Number'Value (D (18 .. 19))); 759 760 -- Optional part 761 762 if Date'Length = 22 then 763 Sub_Second := Second_Duration (Second_Duration'Value (D (20 .. 22))); 764 end if; 765 766 -- Sanity checks 767 768 if not Year'Valid 769 or else not Month'Valid 770 or else not Day'Valid 771 or else not Hour'Valid 772 or else not Minute'Valid 773 or else not Second'Valid 774 or else not Sub_Second'Valid 775 then 776 raise Constraint_Error; 777 end if; 778 779 return Time_Of (Year, Month, Day, 780 Hour, Minute, Second, Sub_Second, False, Time_Zone); 781 782 exception 783 when others => raise Constraint_Error; 784 end Value; 785 786 ----------- 787 -- Value -- 788 ----------- 789 790 function Value (Elapsed_Time : String) return Duration is 791 D : String (1 .. 11); 792 Hour : Hour_Number; 793 Minute : Minute_Number; 794 Second : Second_Number; 795 Sub_Second : Second_Duration := 0.0; 796 797 begin 798 -- Length checks 799 800 if Elapsed_Time'Length /= 8 801 and then Elapsed_Time'Length /= 11 802 then 803 raise Constraint_Error; 804 end if; 805 806 -- After the correct length has been determined, it is safe to copy the 807 -- Elapsed_Time in order to avoid Date'First + N indexing. 808 809 D (1 .. Elapsed_Time'Length) := Elapsed_Time; 810 811 -- Format checks 812 813 Check_Char (D, ':', 3); 814 Check_Char (D, ':', 6); 815 816 if Elapsed_Time'Length = 11 then 817 Check_Char (D, '.', 9); 818 end if; 819 820 -- Leading zero checks 821 822 Check_Digit (D, 1); 823 Check_Digit (D, 4); 824 Check_Digit (D, 7); 825 826 if Elapsed_Time'Length = 11 then 827 Check_Digit (D, 10); 828 end if; 829 830 -- Value extraction 831 832 Hour := Hour_Number (Hour_Number'Value (D (1 .. 2))); 833 Minute := Minute_Number (Minute_Number'Value (D (4 .. 5))); 834 Second := Second_Number (Second_Number'Value (D (7 .. 8))); 835 836 -- Optional part 837 838 if Elapsed_Time'Length = 11 then 839 Sub_Second := Second_Duration (Second_Duration'Value (D (9 .. 11))); 840 end if; 841 842 -- Sanity checks 843 844 if not Hour'Valid 845 or else not Minute'Valid 846 or else not Second'Valid 847 or else not Sub_Second'Valid 848 then 849 raise Constraint_Error; 850 end if; 851 852 return Seconds_Of (Hour, Minute, Second, Sub_Second); 853 854 exception 855 when others => raise Constraint_Error; 856 end Value; 857 858 ---------- 859 -- Year -- 860 ---------- 861 862 function Year 863 (Date : Time; 864 Time_Zone : Time_Zones.Time_Offset := 0) return Year_Number 865 is 866 Y : Year_Number; 867 Mo : Month_Number; 868 D : Day_Number; 869 H : Hour_Number; 870 Mi : Minute_Number; 871 Se : Second_Number; 872 Ss : Second_Duration; 873 Le : Boolean; 874 875 pragma Unreferenced (Mo, D, H, Mi); 876 877 begin 878 Split (Date, Y, Mo, D, H, Mi, Se, Ss, Le, Time_Zone); 879 return Y; 880 end Year; 881 882end Ada.Calendar.Formatting; 883