1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- A D A . C A L E N D A R . F O R M A T T I N G --
9 -- Copyright (C) 2006-2007, Free Software Foundation, Inc. --
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 2, 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. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING. If not, write --
19 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
20 -- MA 02111-1307, USA. --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 ------------------------------------------------------------------------------
34 with Ada.Calendar; use Ada.Calendar;
35 with Ada.Calendar.Time_Zones; use Ada.Calendar.Time_Zones;
37 pragma Warnings (Off); -- temp till we fix out param warnings ???
39 package body Ada.Calendar.Formatting is
41 --------------------------
42 -- Implementation Notes --
43 --------------------------
45 -- All operations in this package are target and time representation
46 -- independent, thus only one source file is needed for multiple targets.
48 procedure Check_Char (S : String; C : Character; Index : Integer);
49 -- Subsidiary to the two versions of Value. Determine whether the
50 -- input strint S has character C at position Index. Raise
51 -- Constraint_Error if there is a mismatch.
53 procedure Check_Digit (S : String; Index : Integer);
54 -- Subsidiary to the two versions of Value. Determine whether the
55 -- character of string S at position Index is a digit. This catches
56 -- invalid input such as 1983-*1-j3 u5:n7:k9 which should be
57 -- 1983-01-03 05:07:09. Raise Constraint_Error if there is a mismatch.
63 procedure Check_Char (S : String; C : Character; Index : Integer) is
65 if S (Index) /= C then
66 raise Constraint_Error;
74 procedure Check_Digit (S : String; Index : Integer) is
76 if S (Index) not in '0' .. '9' then
77 raise Constraint_Error;
87 Time_Zone : Time_Zones.Time_Offset := 0) return Day_Number
98 pragma Unreferenced (Y, Mo, H, Mi);
101 Split (Date, Y, Mo, D, H, Mi, Se, Ss, Le, Time_Zone);
109 function Day_Of_Week (Date : Time) return Day_Name is
111 return Day_Name'Val (Formatting_Operations.Day_Of_Week (Date));
120 Time_Zone : Time_Zones.Time_Offset := 0) return Hour_Number
128 Ss : Second_Duration;
131 pragma Unreferenced (Y, Mo, D, Mi);
134 Split (Date, Y, Mo, D, H, Mi, Se, Ss, Le, Time_Zone);
143 (Elapsed_Time : Duration;
144 Include_Time_Fraction : Boolean := False) return String
147 Minute : Minute_Number;
148 Second : Second_Number;
149 Sub_Second : Duration;
155 Result : String := "-00:00:00.00";
158 Split (abs (Elapsed_Time), Hour, Minute, Second, Sub_Second);
160 -- Determine the two slice bounds for the result string depending on
161 -- whether the input is negative and whether fractions are requested.
163 if Elapsed_Time < 0.0 then
169 if Include_Time_Fraction then
175 -- Prevent rounding when converting to natural
177 Sub_Second := Sub_Second * 100.0 - 0.5;
178 SS_Nat := Natural (Sub_Second);
181 Hour_Str : constant String := Hour_Number'Image (Hour);
182 Minute_Str : constant String := Minute_Number'Image (Minute);
183 Second_Str : constant String := Second_Number'Image (Second);
184 SS_Str : constant String := Natural'Image (SS_Nat);
187 -- Hour processing, positions 2 and 3
190 Result (3) := Hour_Str (2);
192 Result (2) := Hour_Str (2);
193 Result (3) := Hour_Str (3);
196 -- Minute processing, positions 5 and 6
199 Result (6) := Minute_Str (2);
201 Result (5) := Minute_Str (2);
202 Result (6) := Minute_Str (3);
205 -- Second processing, positions 8 and 9
208 Result (9) := Second_Str (2);
210 Result (8) := Second_Str (2);
211 Result (9) := Second_Str (3);
214 -- Optional sub second processing, positions 11 and 12
216 if Include_Time_Fraction then
218 Result (12) := SS_Str (2);
220 Result (11) := SS_Str (2);
221 Result (12) := SS_Str (3);
225 return Result (Low .. High);
235 Include_Time_Fraction : Boolean := False;
236 Time_Zone : Time_Zones.Time_Offset := 0) return String
239 Month : Month_Number;
242 Minute : Minute_Number;
243 Second : Second_Number;
244 Sub_Second : Duration;
246 Leap_Second : Boolean;
248 Result : String := "0000-00-00 00:00:00.00";
251 Split (Date, Year, Month, Day,
252 Hour, Minute, Second, Sub_Second, Leap_Second, Time_Zone);
254 -- Prevent rounding when converting to natural
256 Sub_Second := Sub_Second * 100.0 - 0.5;
257 SS_Nat := Natural (Sub_Second);
260 Year_Str : constant String := Year_Number'Image (Year);
261 Month_Str : constant String := Month_Number'Image (Month);
262 Day_Str : constant String := Day_Number'Image (Day);
263 Hour_Str : constant String := Hour_Number'Image (Hour);
264 Minute_Str : constant String := Minute_Number'Image (Minute);
265 Second_Str : constant String := Second_Number'Image (Second);
266 SS_Str : constant String := Natural'Image (SS_Nat);
269 -- Year processing, positions 1, 2, 3 and 4
271 Result (1) := Year_Str (2);
272 Result (2) := Year_Str (3);
273 Result (3) := Year_Str (4);
274 Result (4) := Year_Str (5);
276 -- Month processing, positions 6 and 7
279 Result (7) := Month_Str (2);
281 Result (6) := Month_Str (2);
282 Result (7) := Month_Str (3);
285 -- Day processing, positions 9 and 10
288 Result (10) := Day_Str (2);
290 Result (9) := Day_Str (2);
291 Result (10) := Day_Str (3);
294 -- Hour processing, positions 12 and 13
297 Result (13) := Hour_Str (2);
299 Result (12) := Hour_Str (2);
300 Result (13) := Hour_Str (3);
303 -- Minute processing, positions 15 and 16
306 Result (16) := Minute_Str (2);
308 Result (15) := Minute_Str (2);
309 Result (16) := Minute_Str (3);
312 -- Second processing, positions 18 and 19
315 Result (19) := Second_Str (2);
317 Result (18) := Second_Str (2);
318 Result (19) := Second_Str (3);
321 -- Optional sub second processing, positions 21 and 22
323 if Include_Time_Fraction then
325 Result (22) := SS_Str (2);
327 Result (21) := SS_Str (2);
328 Result (22) := SS_Str (3);
333 return Result (1 .. 19);
344 Time_Zone : Time_Zones.Time_Offset := 0) return Minute_Number
352 Ss : Second_Duration;
355 pragma Unreferenced (Y, Mo, D, H);
358 Split (Date, Y, Mo, D, H, Mi, Se, Ss, Le, Time_Zone);
368 Time_Zone : Time_Zones.Time_Offset := 0) return Month_Number
376 Ss : Second_Duration;
379 pragma Unreferenced (Y, D, H, Mi);
382 Split (Date, Y, Mo, D, H, Mi, Se, Ss, Le, Time_Zone);
390 function Second (Date : Time) return Second_Number is
397 Ss : Second_Duration;
400 pragma Unreferenced (Y, Mo, D, H, Mi);
403 Split (Date, Y, Mo, D, H, Mi, Se, Ss, Le);
413 Minute : Minute_Number;
414 Second : Second_Number := 0;
415 Sub_Second : Second_Duration := 0.0) return Day_Duration is
421 or else not Minute'Valid
422 or else not Second'Valid
423 or else not Sub_Second'Valid
425 raise Constraint_Error;
428 return Day_Duration (Hour * 3_600) +
429 Day_Duration (Minute * 60) +
430 Day_Duration (Second) +
439 (Seconds : Day_Duration;
440 Hour : out Hour_Number;
441 Minute : out Minute_Number;
442 Second : out Second_Number;
443 Sub_Second : out Second_Duration)
450 if not Seconds'Valid then
451 raise Constraint_Error;
454 if Seconds = 0.0 then
457 Secs := Natural (Seconds - 0.5);
460 Sub_Second := Second_Duration (Seconds - Day_Duration (Secs));
461 Hour := Hour_Number (Secs / 3_600);
462 Secs := Secs mod 3_600;
463 Minute := Minute_Number (Secs / 60);
464 Second := Second_Number (Secs mod 60);
469 or else not Minute'Valid
470 or else not Second'Valid
471 or else not Sub_Second'Valid
483 Year : out Year_Number;
484 Month : out Month_Number;
485 Day : out Day_Number;
486 Seconds : out Day_Duration;
487 Leap_Second : out Boolean;
488 Time_Zone : Time_Zones.Time_Offset := 0)
494 Tz : constant Long_Integer := Long_Integer (Time_Zone);
497 Formatting_Operations.Split
507 Leap_Sec => Leap_Second,
514 or else not Month'Valid
515 or else not Day'Valid
516 or else not Seconds'Valid
528 Year : out Year_Number;
529 Month : out Month_Number;
530 Day : out Day_Number;
531 Hour : out Hour_Number;
532 Minute : out Minute_Number;
533 Second : out Second_Number;
534 Sub_Second : out Second_Duration;
535 Time_Zone : Time_Zones.Time_Offset := 0)
539 Tz : constant Long_Integer := Long_Integer (Time_Zone);
542 Formatting_Operations.Split
551 Sub_Sec => Sub_Second,
559 or else not Month'Valid
560 or else not Day'Valid
561 or else not Hour'Valid
562 or else not Minute'Valid
563 or else not Second'Valid
564 or else not Sub_Second'Valid
576 Year : out Year_Number;
577 Month : out Month_Number;
578 Day : out Day_Number;
579 Hour : out Hour_Number;
580 Minute : out Minute_Number;
581 Second : out Second_Number;
582 Sub_Second : out Second_Duration;
583 Leap_Second : out Boolean;
584 Time_Zone : Time_Zones.Time_Offset := 0)
587 Tz : constant Long_Integer := Long_Integer (Time_Zone);
590 Formatting_Operations.Split
599 Sub_Sec => Sub_Second,
600 Leap_Sec => Leap_Second,
607 or else not Month'Valid
608 or else not Day'Valid
609 or else not Hour'Valid
610 or else not Minute'Valid
611 or else not Second'Valid
612 or else not Sub_Second'Valid
622 function Sub_Second (Date : Time) return Second_Duration is
629 Ss : Second_Duration;
632 pragma Unreferenced (Y, Mo, D, H, Mi);
635 Split (Date, Y, Mo, D, H, Mi, Se, Ss, Le);
645 Month : Month_Number;
647 Seconds : Day_Duration := 0.0;
648 Leap_Second : Boolean := False;
649 Time_Zone : Time_Zones.Time_Offset := 0) return Time
651 Adj_Year : Year_Number := Year;
652 Adj_Month : Month_Number := Month;
653 Adj_Day : Day_Number := Day;
655 H : constant Integer := 1;
656 M : constant Integer := 1;
657 Se : constant Integer := 1;
658 Ss : constant Duration := 0.1;
659 Tz : constant Long_Integer := Long_Integer (Time_Zone);
665 or else not Month'Valid
666 or else not Day'Valid
667 or else not Seconds'Valid
668 or else not Time_Zone'Valid
670 raise Constraint_Error;
673 -- A Seconds value of 86_400 denotes a new day. This case requires an
674 -- adjustment to the input values.
676 if Seconds = 86_400.0 then
677 if Day < Days_In_Month (Month)
678 or else (Is_Leap (Year)
686 Adj_Month := Month + 1;
689 Adj_Year := Year + 1;
695 Formatting_Operations.Time_Of
704 Leap_Sec => Leap_Second,
705 Use_Day_Secs => True,
716 Month : Month_Number;
719 Minute : Minute_Number;
720 Second : Second_Number;
721 Sub_Second : Second_Duration := 0.0;
722 Leap_Second : Boolean := False;
723 Time_Zone : Time_Zones.Time_Offset := 0) return Time
725 Dd : constant Day_Duration := Day_Duration'First;
726 Tz : constant Long_Integer := Long_Integer (Time_Zone);
732 or else not Month'Valid
733 or else not Day'Valid
734 or else not Hour'Valid
735 or else not Minute'Valid
736 or else not Second'Valid
737 or else not Sub_Second'Valid
738 or else not Time_Zone'Valid
740 raise Constraint_Error;
744 Formatting_Operations.Time_Of
752 Sub_Sec => Sub_Second,
753 Leap_Sec => Leap_Second,
754 Use_Day_Secs => False,
765 Time_Zone : Time_Zones.Time_Offset := 0) return Time
767 D : String (1 .. 22);
769 Month : Month_Number;
772 Minute : Minute_Number;
773 Second : Second_Number;
774 Sub_Second : Second_Duration := 0.0;
779 if not Time_Zone'Valid then
780 raise Constraint_Error;
786 and then Date'Length /= 22
788 raise Constraint_Error;
791 -- After the correct length has been determined, it is safe to
792 -- copy the Date in order to avoid Date'First + N indexing.
794 D (1 .. Date'Length) := Date;
798 Check_Char (D, '-', 5);
799 Check_Char (D, '-', 8);
800 Check_Char (D, ' ', 11);
801 Check_Char (D, ':', 14);
802 Check_Char (D, ':', 17);
804 if Date'Length = 22 then
805 Check_Char (D, '.', 20);
808 -- Leading zero checks
816 if Date'Length = 22 then
822 Year := Year_Number (Year_Number'Value (D (1 .. 4)));
823 Month := Month_Number (Month_Number'Value (D (6 .. 7)));
824 Day := Day_Number (Day_Number'Value (D (9 .. 10)));
825 Hour := Hour_Number (Hour_Number'Value (D (12 .. 13)));
826 Minute := Minute_Number (Minute_Number'Value (D (15 .. 16)));
827 Second := Second_Number (Second_Number'Value (D (18 .. 19)));
831 if Date'Length = 22 then
832 Sub_Second := Second_Duration (Second_Duration'Value (D (20 .. 22)));
838 or else not Month'Valid
839 or else not Day'Valid
840 or else not Hour'Valid
841 or else not Minute'Valid
842 or else not Second'Valid
843 or else not Sub_Second'Valid
845 raise Constraint_Error;
848 return Time_Of (Year, Month, Day,
849 Hour, Minute, Second, Sub_Second, False, Time_Zone);
852 when others => raise Constraint_Error;
859 function Value (Elapsed_Time : String) return Duration is
860 D : String (1 .. 11);
862 Minute : Minute_Number;
863 Second : Second_Number;
864 Sub_Second : Second_Duration := 0.0;
869 if Elapsed_Time'Length /= 8
870 and then Elapsed_Time'Length /= 11
872 raise Constraint_Error;
875 -- After the correct length has been determined, it is safe to
876 -- copy the Elapsed_Time in order to avoid Date'First + N indexing.
878 D (1 .. Elapsed_Time'Length) := Elapsed_Time;
882 Check_Char (D, ':', 3);
883 Check_Char (D, ':', 6);
885 if Elapsed_Time'Length = 11 then
886 Check_Char (D, '.', 9);
889 -- Leading zero checks
895 if Elapsed_Time'Length = 11 then
901 Hour := Hour_Number (Hour_Number'Value (D (1 .. 2)));
902 Minute := Minute_Number (Minute_Number'Value (D (4 .. 5)));
903 Second := Second_Number (Second_Number'Value (D (7 .. 8)));
907 if Elapsed_Time'Length = 11 then
908 Sub_Second := Second_Duration (Second_Duration'Value (D (9 .. 11)));
914 or else not Minute'Valid
915 or else not Second'Valid
916 or else not Sub_Second'Valid
918 raise Constraint_Error;
921 return Seconds_Of (Hour, Minute, Second, Sub_Second);
924 when others => raise Constraint_Error;
933 Time_Zone : Time_Zones.Time_Offset := 0) return Year_Number
941 Ss : Second_Duration;
944 pragma Unreferenced (Mo, D, H, Mi);
947 Split (Date, Y, Mo, D, H, Mi, Se, Ss, Le, Time_Zone);
951 end Ada.Calendar.Formatting;