1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- G N A T . C A L E N D A R . T I M E _ I O --
9 -- Copyright (C) 1999-2020, AdaCore --
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. --
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. --
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/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 with Ada.Calendar; use Ada.Calendar;
33 with Ada.Characters.Handling;
34 with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
39 package body GNAT.Calendar.Time_IO is
55 function Month_Name_To_Number
56 (Str : String) return Ada.Calendar.Month_Number;
57 -- Converts a string that contains an abbreviated month name to a month
58 -- number. Constraint_Error is raised if Str is not a valid month name.
59 -- Comparison is case insensitive
61 type Padding_Mode is (None, Zero, Space);
63 type Sec_Number is mod 2 ** 64;
64 -- Type used to compute the number of seconds since 01/01/1970. A 32 bit
65 -- number will cover only a period of 136 years. This means that for date
66 -- past 2106 the computation is not possible. A 64 bits number should be
67 -- enough for a very large period of time.
69 -----------------------
70 -- Local Subprograms --
71 -----------------------
73 function Am_Pm (H : Natural) return String;
74 -- Return AM or PM depending on the hour H
76 function Hour_12 (H : Natural) return Positive;
77 -- Convert a 1-24h format to a 0-12 hour format
79 function Image (Str : String; Length : Natural := 0) return String;
80 -- Return Str capitalized and cut to length number of characters. If
81 -- length is 0, then no cut operation is performed.
85 Padding : Padding_Mode := Zero;
86 Length : Natural := 0) return String;
87 -- Return image of N. This number is eventually padded with zeros or spaces
88 -- depending of the length required. If length is 0 then no padding occurs.
92 Padding : Padding_Mode := Zero;
93 Length : Natural := 0) return String;
94 -- As above with N provided in Integer format
96 procedure Parse_ISO_8861_UTC
98 Time : out Ada.Calendar.Time;
99 Success : out Boolean);
100 -- Subsidiary of function Value. It parses the string Date, interpreted as
101 -- an ISO 8861 time representation, and returns corresponding Time value.
102 -- Success is set to False when the string is not a supported ISO 8861
103 -- date. The following regular expression defines the supported format:
105 -- (yyyymmdd | yyyy'-'mm'-'dd)'T'(hhmmss | hh':'mm':'ss)
106 -- [ ('Z' | ('.' | ',') s{s} | ('+'|'-')hh':'mm) ]
108 -- Trailing characters (in particular spaces) are not allowed.
112 -- 2017-04-14T14:47:06 20170414T14:47:06 20170414T144706
113 -- 2017-04-14T14:47:06,12 20170414T14:47:06.12
114 -- 2017-04-14T19:47:06+05 20170414T09:00:06-05:47
120 function Am_Pm (H : Natural) return String is
122 if H = 0 or else H > 12 then
133 function Hour_12 (H : Natural) return Positive is
150 Length : Natural := 0) return String
152 use Ada.Characters.Handling;
153 Local : constant String :=
154 To_Upper (Str (Str'First)) &
155 To_Lower (Str (Str'First + 1 .. Str'Last));
160 return Local (1 .. Length);
170 Padding : Padding_Mode := Zero;
171 Length : Natural := 0) return String
174 return Image (Sec_Number (N), Padding, Length);
179 Padding : Padding_Mode := Zero;
180 Length : Natural := 0) return String
182 function Pad_Char return String;
188 function Pad_Char return String is
191 when None => return "";
192 when Zero => return "00";
193 when Space => return " ";
197 -- Local Declarations
199 NI : constant String := Sec_Number'Image (N);
200 NIP : constant String := Pad_Char & NI (2 .. NI'Last);
202 -- Start of processing for Image
205 if Length = 0 or else Padding = None then
206 return NI (2 .. NI'Last);
208 return NIP (NIP'Last - Length + 1 .. NIP'Last);
217 (Date : Ada.Calendar.Time;
218 Picture : Picture_String) return String
220 Padding : Padding_Mode := Zero;
221 -- Padding is set for one directive
223 Result : Unbounded_String;
226 Month : Month_Number;
229 Minute : Minute_Number;
230 Second : Second_Number;
231 Sub_Second : Second_Duration;
236 -- Get current time in split format
238 Split (Date, Year, Month, Day, Hour, Minute, Second, Sub_Second);
240 -- Null picture string is error
243 raise Picture_Error with "null picture string";
246 -- Loop through characters of picture string, building result
248 Result := Null_Unbounded_String;
250 while P <= Picture'Last loop
252 -- A directive has the following format "%[-_]."
254 if Picture (P) = '%' then
257 if P = Picture'Last then
258 raise Picture_Error with "picture string ends with '%";
261 -- Check for GNU extension to change the padding
263 if Picture (P + 1) = '-' then
267 elsif Picture (P + 1) = '_' then
272 if P = Picture'Last then
273 raise Picture_Error with "picture string ends with '- or '_";
276 case Picture (P + 1) is
281 Result := Result & '%';
286 Result := Result & ASCII.LF;
291 Result := Result & ASCII.HT;
296 Result := Result & Image (Hour, Padding, 2);
301 Result := Result & Image (Hour_12 (Hour), Padding, 2);
306 Result := Result & Image (Hour, Space, 2);
311 Result := Result & Image (Hour_12 (Hour), Space, 2);
316 Result := Result & Image (Minute, Padding, 2);
321 Result := Result & Am_Pm (Hour);
323 -- Time, 12-hour (hh:mm:ss [AP]M)
327 Image (Hour_12 (Hour), Padding, Length => 2) & ':' &
328 Image (Minute, Padding, Length => 2) & ':' &
329 Image (Second, Padding, Length => 2) & ' ' &
332 -- Seconds since 1970-01-01 00:00:00 UTC
333 -- (a nonstandard extension)
337 -- Compute the number of seconds using Ada.Calendar.Time
338 -- values rather than Julian days to account for Daylight
341 Neg : Boolean := False;
342 Sec : Duration := Date - Time_Of (1970, 1, 1, 0.0);
345 -- Avoid rounding errors and perform special processing
346 -- for dates earlier than the Unix Epoc.
352 Sec := abs (Sec + 0.5);
355 -- Prepend a minus sign to the result since Sec_Number
356 -- cannot handle negative numbers.
360 Result & "-" & Image (Sec_Number (Sec), None);
362 Result := Result & Image (Sec_Number (Sec), None);
369 Result := Result & Image (Second, Padding, Length => 2);
371 -- Milliseconds (3 digits)
372 -- Microseconds (6 digits)
373 -- Nanoseconds (9 digits)
375 when 'i' | 'e' | 'o' =>
377 Sub_Sec : constant Long_Integer :=
378 Long_Integer (Sub_Second * 1_000_000_000);
380 Img1 : constant String := Sub_Sec'Img;
381 Img2 : constant String :=
382 "00000000" & Img1 (Img1'First + 1 .. Img1'Last);
383 Nanos : constant String :=
384 Img2 (Img2'Last - 8 .. Img2'Last);
387 case Picture (P + 1) is
390 Nanos (Nanos'First .. Nanos'First + 2);
394 Nanos (Nanos'First .. Nanos'First + 5);
397 Result := Result & Nanos;
404 -- Time, 24-hour (hh:mm:ss)
408 Image (Hour, Padding, Length => 2) & ':' &
409 Image (Minute, Padding, Length => 2) & ':' &
410 Image (Second, Padding, Length => 2);
412 -- Locale's abbreviated weekday name (Sun..Sat)
416 Image (Day_Name'Image (Day_Of_Week (Date)), 3);
418 -- Locale's full weekday name, variable length
419 -- (Sunday..Saturday)
423 Image (Day_Name'Image (Day_Of_Week (Date)));
425 -- Locale's abbreviated month name (Jan..Dec)
429 Image (Month_Name'Image (Month_Name'Val (Month - 1)), 3);
431 -- Locale's full month name, variable length
432 -- (January..December).
436 Image (Month_Name'Image (Month_Name'Val (Month - 1)));
438 -- Locale's date and time (Sat Nov 04 12:02:33 EST 1989)
443 Result := Result & Image (Date, "%a %b %d %T %Y");
445 Result := Result & Image (Date, "%a %b %_d %_T %Y");
447 Result := Result & Image (Date, "%a %b %-d %-T %Y");
450 -- Day of month (01..31)
453 Result := Result & Image (Day, Padding, 2);
459 Image (Month, Padding, 2) & '/' &
460 Image (Day, Padding, 2) & '/' &
461 Image (Year, Padding, 2);
463 -- Day of year (001..366)
466 Result := Result & Image (Day_In_Year (Date), Padding, 3);
471 Result := Result & Image (Month, Padding, 2);
473 -- Week number of year with Sunday as first day of week
478 Offset : constant Natural :=
479 (Julian_Day (Year, 1, 1) + 1) mod 7;
481 Week : constant Natural :=
482 1 + ((Day_In_Year (Date) - 1) + Offset) / 7;
485 Result := Result & Image (Week, Padding, 2);
488 -- Day of week (0..6) with 0 corresponding to Sunday
492 DOW : constant Natural range 0 .. 6 :=
493 (if Day_Of_Week (Date) = Sunday
495 else Day_Name'Pos (Day_Of_Week (Date)));
497 Result := Result & Image (DOW, Length => 1);
500 -- Week number of year with Monday as first day of week
504 Result := Result & Image (Week_In_Year (Date), Padding, 2);
506 -- Last two digits of year (00..99)
510 Y : constant Natural := Year - (Year / 100) * 100;
512 Result := Result & Image (Y, Padding, 2);
518 Result := Result & Image (Year, None, 4);
521 raise Picture_Error with
522 "unknown format character in picture string";
525 -- Skip past % and format character
529 -- Character other than % is copied into the result
532 Result := Result & Picture (P);
537 return To_String (Result);
540 --------------------------
541 -- Month_Name_To_Number --
542 --------------------------
544 function Month_Name_To_Number
545 (Str : String) return Ada.Calendar.Month_Number
547 subtype String3 is String (1 .. 3);
548 Abbrev_Upper_Month_Names :
549 constant array (Ada.Calendar.Month_Number) of String3 :=
550 ("JAN", "FEB", "MAR", "APR", "MAY", "JUN",
551 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC");
552 -- Short version of the month names, used when parsing date strings
557 GNAT.Case_Util.To_Upper (S);
559 for J in Abbrev_Upper_Month_Names'Range loop
560 if Abbrev_Upper_Month_Names (J) = S then
565 return Abbrev_Upper_Month_Names'First;
566 end Month_Name_To_Number;
568 ------------------------
569 -- Parse_ISO_8861_UTC --
570 ------------------------
572 procedure Parse_ISO_8861_UTC
574 Time : out Ada.Calendar.Time;
575 Success : out Boolean)
577 Index : Positive := Date'First;
578 -- The current character scan index. After a call to Advance, Index
579 -- points to the next character.
581 End_Of_Source_Reached : exception;
582 -- An exception used to signal that the scan pointer has reached the
583 -- end of the source string.
585 Wrong_Syntax : exception;
586 -- An exception used to signal that the scan pointer has reached an
587 -- unexpected character in the source string.
590 pragma Inline (Advance);
591 -- Past the current character of Date
593 procedure Advance_Digits (Num_Digits : Positive);
594 pragma Inline (Advance_Digits);
595 -- Past the given number of digit characters
597 function Scan_Day return Day_Number;
598 pragma Inline (Scan_Day);
599 -- Scan the two digits of a day number and return its value
601 function Scan_Hour return Hour_Number;
602 pragma Inline (Scan_Hour);
603 -- Scan the two digits of an hour number and return its value
605 function Scan_Minute return Minute_Number;
606 pragma Inline (Scan_Minute);
607 -- Scan the two digits of a minute number and return its value
609 function Scan_Month return Month_Number;
610 pragma Inline (Scan_Month);
611 -- Scan the two digits of a month number and return its value
613 function Scan_Second return Second_Number;
614 pragma Inline (Scan_Second);
615 -- Scan the two digits of a second number and return its value
617 function Scan_Separator (Expected_Symbol : Character) return Boolean;
618 pragma Inline (Scan_Separator);
619 -- If the current symbol matches the Expected_Symbol then advance the
620 -- scanner index and return True; otherwise do nothing and return False
622 procedure Scan_Separator (Required : Boolean; Separator : Character);
623 pragma Inline (Scan_Separator);
624 -- If Required then check that the current character matches Separator
625 -- and advance the scanner index; if not Required then do nothing.
627 function Scan_Subsecond return Second_Duration;
628 pragma Inline (Scan_Subsecond);
629 -- Scan all the digits of a subsecond number and return its value
631 function Scan_Year return Year_Number;
632 pragma Inline (Scan_Year);
633 -- Scan the four digits of a year number and return its value
635 function Symbol return Character;
636 pragma Inline (Symbol);
637 -- Return the current character being scanned
645 -- Signal the end of the source string. This stops a complex scan by
646 -- bottoming up any recursive calls till control reaches routine Scan
647 -- which handles the exception. Certain scanning scenarios may handle
648 -- this exception on their own.
650 if Index > Date'Last then
651 raise End_Of_Source_Reached;
653 -- Advance the scan pointer as long as there are characters to scan,
654 -- in other words, the scan pointer has not passed the end of the
666 procedure Advance_Digits (Num_Digits : Positive) is
668 for J in 1 .. Num_Digits loop
669 if Symbol not in '0' .. '9' then
673 Advance; -- past digit
681 function Scan_Day return Day_Number is
682 From : constant Positive := Index;
684 Advance_Digits (Num_Digits => 2);
685 return Day_Number'Value (Date (From .. Index - 1));
692 function Scan_Hour return Hour_Number is
693 From : constant Positive := Index;
695 Advance_Digits (Num_Digits => 2);
696 return Hour_Number'Value (Date (From .. Index - 1));
703 function Scan_Minute return Minute_Number is
704 From : constant Positive := Index;
706 Advance_Digits (Num_Digits => 2);
707 return Minute_Number'Value (Date (From .. Index - 1));
714 function Scan_Month return Month_Number is
715 From : constant Positive := Index;
717 Advance_Digits (Num_Digits => 2);
718 return Month_Number'Value (Date (From .. Index - 1));
725 function Scan_Second return Second_Number is
726 From : constant Positive := Index;
728 Advance_Digits (Num_Digits => 2);
729 return Second_Number'Value (Date (From .. Index - 1));
736 function Scan_Separator (Expected_Symbol : Character) return Boolean is
738 if Symbol = Expected_Symbol then
750 procedure Scan_Separator (Required : Boolean; Separator : Character) is
753 if Symbol /= Separator then
757 Advance; -- Past the separator
765 function Scan_Subsecond return Second_Duration is
766 From : constant Positive := Index;
768 Advance_Digits (Num_Digits => 1);
770 while Symbol in '0' .. '9'
771 and then Index < Date'Length
776 if Symbol not in '0' .. '9' then
781 return Second_Duration'Value ("0." & Date (From .. Index - 1));
788 function Scan_Year return Year_Number is
789 From : constant Positive := Index;
791 Advance_Digits (Num_Digits => 4);
792 return Year_Number'Value (Date (From .. Index - 1));
799 function Symbol return Character is
801 -- Signal the end of the source string. This stops a complex scan by
802 -- bottoming up any recursive calls till control reaches routine Scan
803 -- which handles the exception. Certain scanning scenarios may handle
804 -- this exception on their own.
806 if Index > Date'Last then
807 raise End_Of_Source_Reached;
816 Date_Separator : constant Character := '-';
817 Hour_Separator : constant Character := ':';
820 Month : Month_Number;
822 Hour : Hour_Number := 0;
823 Minute : Minute_Number := 0;
824 Second : Second_Number := 0;
825 Subsec : Second_Duration := 0.0;
827 Local_Hour : Hour_Number := 0;
828 Local_Minute : Minute_Number := 0;
829 Local_Sign : Character := ' ';
830 Local_Disp : Duration;
832 Sep_Required : Boolean := False;
833 -- True if a separator is seen (and therefore required after it!)
839 Sep_Required := Scan_Separator (Date_Separator);
842 Scan_Separator (Sep_Required, Date_Separator);
846 if Index < Date'Last and then Symbol = 'T' then
852 Sep_Required := Scan_Separator (Hour_Separator);
854 Minute := Scan_Minute;
855 Scan_Separator (Sep_Required, Hour_Separator);
857 Second := Scan_Second;
859 -- [('Z' | ('.' | ',') s{s} | ('+'|'-')hh:mm)]
861 if Index <= Date'Last then
863 -- Suffix 'Z' just confirms that this is an UTC time. No further
869 -- A decimal fraction shall have at least one digit, and has as
870 -- many digits as supported by the underlying implementation.
871 -- The valid decimal separators are those specified in ISO 31-0,
872 -- i.e. the comma [,] or full stop [.]. Of these, the comma is
873 -- the preferred separator of ISO-8861.
875 elsif Symbol = ',' or else Symbol = '.' then
876 Advance; -- past decimal separator
877 Subsec := Scan_Subsecond;
879 -- Difference between local time and UTC: It shall be expressed
880 -- as positive (i.e. with the leading plus sign [+]) if the local
881 -- time is ahead of or equal to UTC of day and as negative (i.e.
882 -- with the leading minus sign [-]) if it is behind UTC of day.
883 -- The minutes time element of the difference may only be omitted
884 -- if the difference between the time scales is exactly an
885 -- integral number of hours.
887 elsif Symbol = '+' or else Symbol = '-' then
888 Local_Sign := Symbol;
890 Local_Hour := Scan_Hour;
894 if Index < Date'Last and then Symbol = Hour_Separator then
896 Local_Minute := Scan_Minute;
899 -- Compute local displacement
901 Local_Disp := Local_Hour * 3600.0 + Local_Minute * 60.0;
908 -- Sanity checks. The check on Index ensures that there are no trailing
911 if Index /= Date'Length + 1
912 or else not Year'Valid
913 or else not Month'Valid
914 or else not Day'Valid
915 or else not Hour'Valid
916 or else not Minute'Valid
917 or else not Second'Valid
918 or else not Subsec'Valid
919 or else not Local_Hour'Valid
920 or else not Local_Minute'Valid
925 -- Compute time without local displacement
927 if Local_Sign = ' ' then
928 Time := Time_Of (Year, Month, Day, Hour, Minute, Second, Subsec);
930 -- Compute time with positive local displacement
932 elsif Local_Sign = '+' then
934 Time_Of (Year, Month, Day, Hour, Minute, Second, Subsec) -
937 -- Compute time with negative local displacement
939 elsif Local_Sign = '-' then
941 Time_Of (Year, Month, Day, Hour, Minute, Second, Subsec) +
945 -- Notify that the input string was successfully parsed
950 when End_Of_Source_Reached
954 Time_Of (Year_Number'First, Month_Number'First, Day_Number'First);
956 end Parse_ISO_8861_UTC;
962 function Value (Date : String) return Ada.Calendar.Time is
963 D : String (1 .. 21);
964 D_Length : constant Natural := Date'Length;
967 Month : Month_Number;
970 Minute : Minute_Number;
971 Second : Second_Number;
973 procedure Extract_Date
974 (Year : out Year_Number;
975 Month : out Month_Number;
976 Day : out Day_Number;
977 Time_Start : out Natural);
978 -- Try and extract a date value from string D. Time_Start is set to the
979 -- first character that could be the start of time data.
981 procedure Extract_Time
983 Hour : out Hour_Number;
984 Minute : out Minute_Number;
985 Second : out Second_Number;
986 Check_Space : Boolean := False);
987 -- Try and extract a time value from string D starting from position
988 -- Index. Set Check_Space to True to check whether the character at
989 -- Index - 1 is a space. Raise Constraint_Error if the portion of D
990 -- corresponding to the date is not well formatted.
996 procedure Extract_Date
997 (Year : out Year_Number;
998 Month : out Month_Number;
999 Day : out Day_Number;
1000 Time_Start : out Natural)
1003 if D (3) = '-' or else D (3) = '/' then
1004 if D_Length = 8 or else D_Length = 17 then
1006 -- Formats are "yy*mm*dd" or "yy*mm*dd hh:mm:ss"
1008 if D (6) /= D (3) then
1009 raise Constraint_Error;
1012 Year := Year_Number'Value ("20" & D (1 .. 2));
1013 Month := Month_Number'Value (D (4 .. 5));
1014 Day := Day_Number'Value (D (7 .. 8));
1017 elsif D_Length = 10 or else D_Length = 19 then
1019 -- Formats are "mm*dd*yyyy" or "mm*dd*yyyy hh:mm:ss"
1021 if D (6) /= D (3) then
1022 raise Constraint_Error;
1025 Year := Year_Number'Value (D (7 .. 10));
1026 Month := Month_Number'Value (D (1 .. 2));
1027 Day := Day_Number'Value (D (4 .. 5));
1030 elsif D_Length = 11 or else D_Length = 20 then
1032 -- Formats are "dd*mmm*yyyy" or "dd*mmm*yyyy hh:mm:ss"
1034 if D (7) /= D (3) then
1035 raise Constraint_Error;
1038 Year := Year_Number'Value (D (8 .. 11));
1039 Month := Month_Name_To_Number (D (4 .. 6));
1040 Day := Day_Number'Value (D (1 .. 2));
1044 raise Constraint_Error;
1047 elsif D (3) = ' ' then
1048 if D_Length = 11 or else D_Length = 20 then
1050 -- Possible formats are "dd mmm yyyy", "dd mmm yyyy hh:mm:ss"
1052 if D (7) /= ' ' then
1053 raise Constraint_Error;
1056 Year := Year_Number'Value (D (8 .. 11));
1057 Month := Month_Name_To_Number (D (4 .. 6));
1058 Day := Day_Number'Value (D (1 .. 2));
1062 raise Constraint_Error;
1066 if D_Length = 8 or else D_Length = 17 then
1068 -- Possible formats are "yyyymmdd" or "yyyymmdd hh:mm:ss"
1070 Year := Year_Number'Value (D (1 .. 4));
1071 Month := Month_Number'Value (D (5 .. 6));
1072 Day := Day_Number'Value (D (7 .. 8));
1075 elsif D_Length = 10 or else D_Length = 19 then
1077 -- Possible formats are "yyyy*mm*dd" or "yyyy*mm*dd hh:mm:ss"
1079 if (D (5) /= '-' and then D (5) /= '/')
1080 or else D (8) /= D (5)
1082 raise Constraint_Error;
1085 Year := Year_Number'Value (D (1 .. 4));
1086 Month := Month_Number'Value (D (6 .. 7));
1087 Day := Day_Number'Value (D (9 .. 10));
1090 elsif D_Length = 11 or else D_Length = 20 then
1092 -- Possible formats are "yyyy*mmm*dd"
1094 if (D (5) /= '-' and then D (5) /= '/')
1095 or else D (9) /= D (5)
1097 raise Constraint_Error;
1100 Year := Year_Number'Value (D (1 .. 4));
1101 Month := Month_Name_To_Number (D (6 .. 8));
1102 Day := Day_Number'Value (D (10 .. 11));
1105 elsif D_Length = 12 or else D_Length = 21 then
1107 -- Formats are "mmm dd, yyyy" or "mmm dd, yyyy hh:mm:ss"
1110 or else D (7) /= ','
1111 or else D (8) /= ' '
1113 raise Constraint_Error;
1116 Year := Year_Number'Value (D (9 .. 12));
1117 Month := Month_Name_To_Number (D (1 .. 3));
1118 Day := Day_Number'Value (D (5 .. 6));
1122 raise Constraint_Error;
1131 procedure Extract_Time
1133 Hour : out Hour_Number;
1134 Minute : out Minute_Number;
1135 Second : out Second_Number;
1136 Check_Space : Boolean := False)
1139 -- If no time was specified in the string (do not allow trailing
1140 -- character either)
1142 if Index = D_Length + 2 then
1148 -- Not enough characters left ?
1150 if Index /= D_Length - 7 then
1151 raise Constraint_Error;
1154 if Check_Space and then D (Index - 1) /= ' ' then
1155 raise Constraint_Error;
1158 if D (Index + 2) /= ':' or else D (Index + 5) /= ':' then
1159 raise Constraint_Error;
1162 Hour := Hour_Number'Value (D (Index .. Index + 1));
1163 Minute := Minute_Number'Value (D (Index + 3 .. Index + 4));
1164 Second := Second_Number'Value (D (Index + 6 .. Index + 7));
1168 -- Local Declarations
1171 Time_Start : Natural := 1;
1172 Time : Ada.Calendar.Time;
1174 -- Start of processing for Value
1177 -- Let's try parsing Date as a supported ISO-8861 format. If we do not
1178 -- succeed, then retry using all the other GNAT supported formats.
1180 Parse_ISO_8861_UTC (Date, Time, Success);
1189 and then D_Length /= 10
1190 and then D_Length /= 11
1191 and then D_Length /= 12
1192 and then D_Length /= 17
1193 and then D_Length /= 19
1194 and then D_Length /= 20
1195 and then D_Length /= 21
1197 raise Constraint_Error;
1200 -- After the correct length has been determined, it is safe to create
1201 -- a local string copy in order to avoid String'First N arithmetic.
1203 D (1 .. D_Length) := Date;
1205 if D_Length /= 8 or else D (3) /= ':' then
1206 Extract_Date (Year, Month, Day, Time_Start);
1207 Extract_Time (Time_Start, Hour, Minute, Second, Check_Space => True);
1211 Discard : Second_Duration;
1213 Split (Clock, Year, Month, Day, Hour, Minute, Second,
1214 Sub_Second => Discard);
1217 Extract_Time (1, Hour, Minute, Second, Check_Space => False);
1223 or else not Month'Valid
1224 or else not Day'Valid
1225 or else not Hour'Valid
1226 or else not Minute'Valid
1227 or else not Second'Valid
1229 raise Constraint_Error;
1232 return Time_Of (Year, Month, Day, Hour, Minute, Second);
1239 procedure Put_Time (Date : Ada.Calendar.Time; Picture : Picture_String) is
1241 Ada.Text_IO.Put (Image (Date, Picture));
1244 end GNAT.Calendar.Time_IO;