Daily bump.
[official-gcc.git] / gcc / ada / 4wcalend.adb
blob501c602a16f311c82ff4534424821be027b62569
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME COMPONENTS --
4 -- --
5 -- A D A . C A L E N D A R --
6 -- --
7 -- B o d y --
8 -- --
9 -- $Revision: 1.1 $
10 -- --
11 -- Copyright (C) 1997-2001 Free Software Foundation, Inc. --
12 -- --
13 -- GNAT is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNAT; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
23 -- --
24 -- As a special exception, if other files instantiate generics from this --
25 -- unit, or you link this unit with other files to produce an executable, --
26 -- this unit does not by itself cause the resulting executable to be --
27 -- covered by the GNU General Public License. This exception does not --
28 -- however invalidate any other reasons why the executable file might be --
29 -- covered by the GNU Public License. --
30 -- --
31 -- GNAT was originally developed by the GNAT team at New York University. --
32 -- Extensive contributions were provided by Ada Core Technologies Inc. --
33 -- --
34 ------------------------------------------------------------------------------
36 -- This is the Windows NT/95 version.
38 with System.OS_Primitives;
39 -- used for Clock
41 with System.OS_Interface;
43 package body Ada.Calendar is
45 use System.OS_Interface;
47 ------------------------------
48 -- Use of Pragma Unsuppress --
49 ------------------------------
51 -- This implementation of Calendar takes advantage of the permission in
52 -- Ada 95 of using arithmetic overflow checks to check for out of bounds
53 -- time values. This means that we must catch the constraint error that
54 -- results from arithmetic overflow, so we use pragma Unsuppress to make
55 -- sure that overflow is enabled, using software overflow checking if
56 -- necessary. That way, compiling Calendar with options to suppress this
57 -- checking will not affect its correctness.
59 ------------------------
60 -- Local Declarations --
61 ------------------------
63 Ada_Year_Min : constant := 1901;
64 Ada_Year_Max : constant := 2099;
66 -- Win32 time constants
68 epoch_1970 : constant := 16#19D_B1DE_D53E_8000#; -- win32 UTC epoch
69 system_time_ns : constant := 100; -- 100 ns per tick
70 Sec_Unit : constant := 10#1#E9;
72 ---------
73 -- "+" --
74 ---------
76 function "+" (Left : Time; Right : Duration) return Time is
77 pragma Unsuppress (Overflow_Check);
78 begin
79 return (Left + Time (Right));
81 exception
82 when Constraint_Error =>
83 raise Time_Error;
84 end "+";
86 function "+" (Left : Duration; Right : Time) return Time is
87 pragma Unsuppress (Overflow_Check);
88 begin
89 return (Time (Left) + Right);
91 exception
92 when Constraint_Error =>
93 raise Time_Error;
94 end "+";
96 ---------
97 -- "-" --
98 ---------
100 function "-" (Left : Time; Right : Duration) return Time is
101 pragma Unsuppress (Overflow_Check);
102 begin
103 return Left - Time (Right);
105 exception
106 when Constraint_Error =>
107 raise Time_Error;
108 end "-";
110 function "-" (Left : Time; Right : Time) return Duration is
111 pragma Unsuppress (Overflow_Check);
112 begin
113 return Duration (Left) - Duration (Right);
115 exception
116 when Constraint_Error =>
117 raise Time_Error;
118 end "-";
120 ---------
121 -- "<" --
122 ---------
124 function "<" (Left, Right : Time) return Boolean is
125 begin
126 return Duration (Left) < Duration (Right);
127 end "<";
129 ----------
130 -- "<=" --
131 ----------
133 function "<=" (Left, Right : Time) return Boolean is
134 begin
135 return Duration (Left) <= Duration (Right);
136 end "<=";
138 ---------
139 -- ">" --
140 ---------
142 function ">" (Left, Right : Time) return Boolean is
143 begin
144 return Duration (Left) > Duration (Right);
145 end ">";
147 ----------
148 -- ">=" --
149 ----------
151 function ">=" (Left, Right : Time) return Boolean is
152 begin
153 return Duration (Left) >= Duration (Right);
154 end ">=";
156 -----------
157 -- Clock --
158 -----------
160 -- The Ada.Calendar.Clock function gets the time from the soft links
161 -- interface which will call the appropriate function depending wether
162 -- tasking is involved or not.
164 function Clock return Time is
165 begin
166 return Time (System.OS_Primitives.Clock);
167 end Clock;
169 ---------
170 -- Day --
171 ---------
173 function Day (Date : Time) return Day_Number is
174 DY : Year_Number;
175 DM : Month_Number;
176 DD : Day_Number;
177 DS : Day_Duration;
179 begin
180 Split (Date, DY, DM, DD, DS);
181 return DD;
182 end Day;
184 -----------
185 -- Month --
186 -----------
188 function Month (Date : Time) return Month_Number is
189 DY : Year_Number;
190 DM : Month_Number;
191 DD : Day_Number;
192 DS : Day_Duration;
194 begin
195 Split (Date, DY, DM, DD, DS);
196 return DM;
197 end Month;
199 -------------
200 -- Seconds --
201 -------------
203 function Seconds (Date : Time) return Day_Duration is
204 DY : Year_Number;
205 DM : Month_Number;
206 DD : Day_Number;
207 DS : Day_Duration;
209 begin
210 Split (Date, DY, DM, DD, DS);
211 return DS;
212 end Seconds;
214 -----------
215 -- Split --
216 -----------
218 procedure Split
219 (Date : Time;
220 Year : out Year_Number;
221 Month : out Month_Number;
222 Day : out Day_Number;
223 Seconds : out Day_Duration)
226 Date_Int : aliased Long_Long_Integer;
227 Date_Loc : aliased Long_Long_Integer;
228 Timbuf : aliased SYSTEMTIME;
229 Int_Date : Long_Long_Integer;
230 Sub_Seconds : Duration;
232 begin
233 -- We take the sub-seconds (decimal part) of Date and this is added
234 -- to compute the Seconds. This way we keep the precision of the
235 -- high-precision clock that was lost with the Win32 API calls
236 -- below.
238 if Date < 0.0 then
240 -- this is a Date before Epoch (January 1st, 1970)
242 Sub_Seconds := Duration (Date) -
243 Duration (Long_Long_Integer (Date + Duration'(0.5)));
245 Int_Date := Long_Long_Integer (Date - Sub_Seconds);
247 -- For Date = -86400.1 we are 2 days before Epoch at 0.1 seconds
248 -- from day 1 before Epoch. It means that it is 23h 59m 59.9s.
249 -- here we adjust for that.
251 if Sub_Seconds < 0.0 then
252 Int_Date := Int_Date - 1;
253 Sub_Seconds := 1.0 + Sub_Seconds;
254 end if;
256 else
258 -- this is a Date after Epoch (January 1st, 1970)
260 Sub_Seconds := Duration (Date) -
261 Duration (Long_Long_Integer (Date - Duration'(0.5)));
263 Int_Date := Long_Long_Integer (Date - Sub_Seconds);
265 end if;
267 -- Date_Int is the number of seconds from Epoch.
269 Date_Int := Long_Long_Integer
270 (Int_Date * Sec_Unit / system_time_ns) + epoch_1970;
272 if not FileTimeToLocalFileTime (Date_Int'Access, Date_Loc'Access) then
273 raise Time_Error;
274 end if;
276 if not FileTimeToSystemTime (Date_Loc'Access, Timbuf'Access) then
277 raise Time_Error;
278 end if;
280 if Timbuf.wYear not in Ada_Year_Min .. Ada_Year_Max then
281 raise Time_Error;
282 end if;
284 Seconds :=
285 Duration (Timbuf.wHour) * 3_600.0 +
286 Duration (Timbuf.wMinute) * 60.0 +
287 Duration (Timbuf.wSecond) +
288 Sub_Seconds;
290 Day := Integer (Timbuf.wDay);
291 Month := Integer (Timbuf.wMonth);
292 Year := Integer (Timbuf.wYear);
293 end Split;
295 -------------
296 -- Time_Of --
297 -------------
299 function Time_Of
300 (Year : Year_Number;
301 Month : Month_Number;
302 Day : Day_Number;
303 Seconds : Day_Duration := 0.0)
304 return Time
307 Timbuf : aliased SYSTEMTIME;
308 Now : aliased Long_Long_Integer;
309 Loc : aliased Long_Long_Integer;
310 Int_Secs : Integer;
311 Secs : Integer;
312 Add_One_Day : Boolean := False;
313 Date : Time;
315 begin
316 -- The following checks are redundant with respect to the constraint
317 -- error checks that should normally be made on parameters, but we
318 -- decide to raise Constraint_Error in any case if bad values come
319 -- in (as a result of checks being off in the caller, or for other
320 -- erroneous or bounded error cases).
322 if not Year 'Valid
323 or else not Month 'Valid
324 or else not Day 'Valid
325 or else not Seconds'Valid
326 then
327 raise Constraint_Error;
328 end if;
330 if Seconds = 0.0 then
331 Int_Secs := 0;
332 else
333 Int_Secs := Integer (Seconds - 0.5);
334 end if;
336 -- Timbuf.wMillisec is to keep the msec. We can't use that because the
337 -- high-resolution clock has a precision of 1 Microsecond.
338 -- Anyway the sub-seconds part is not needed to compute the number
339 -- of seconds in UTC.
341 if Int_Secs = 86_400 then
342 Secs := 0;
343 Add_One_Day := True;
344 else
345 Secs := Int_Secs;
346 end if;
348 Timbuf.wMilliseconds := 0;
349 Timbuf.wSecond := WORD (Secs mod 60);
350 Timbuf.wMinute := WORD ((Secs / 60) mod 60);
351 Timbuf.wHour := WORD (Secs / 3600);
352 Timbuf.wDay := WORD (Day);
353 Timbuf.wMonth := WORD (Month);
354 Timbuf.wYear := WORD (Year);
356 if not SystemTimeToFileTime (Timbuf'Access, Loc'Access) then
357 raise Time_Error;
358 end if;
360 if not LocalFileTimeToFileTime (Loc'Access, Now'Access) then
361 raise Time_Error;
362 end if;
364 -- Here we have the UTC now translate UTC to Epoch time (UNIX style
365 -- time based on 1 january 1970) and add there the sub-seconds part.
367 declare
368 Sub_Sec : Duration := Seconds - Duration (Int_Secs);
369 begin
370 Date := Time ((Now - epoch_1970) * system_time_ns / Sec_Unit) +
371 Sub_Sec;
372 end;
374 if Add_One_Day then
375 Date := Date + Duration (86400.0);
376 end if;
378 return Date;
379 end Time_Of;
381 ----------
382 -- Year --
383 ----------
385 function Year (Date : Time) return Year_Number is
386 DY : Year_Number;
387 DM : Month_Number;
388 DD : Day_Number;
389 DS : Day_Duration;
391 begin
392 Split (Date, DY, DM, DD, DS);
393 return DY;
394 end Year;
396 end Ada.Calendar;