* MAINTAINERS: (Write After Approval): Add myself.
[official-gcc.git] / gcc / ada / 4wcalend.adb
blobd49fada2ad5a56dd74db78286a3098505cd47cb5
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 -- --
10 -- Copyright (C) 1997-2001 Free Software Foundation, Inc. --
11 -- --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
22 -- --
23 -- As a special exception, if other files instantiate generics from this --
24 -- unit, or you link this unit with other files to produce an executable, --
25 -- this unit does not by itself cause the resulting executable to be --
26 -- covered by the GNU General Public License. This exception does not --
27 -- however invalidate any other reasons why the executable file might be --
28 -- covered by the GNU Public License. --
29 -- --
30 -- GNAT was originally developed by the GNAT team at New York University. --
31 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
32 -- --
33 ------------------------------------------------------------------------------
35 -- This is the Windows NT/95 version.
37 with System.OS_Primitives;
38 -- used for Clock
40 with System.OS_Interface;
42 package body Ada.Calendar is
44 use System.OS_Interface;
46 ------------------------------
47 -- Use of Pragma Unsuppress --
48 ------------------------------
50 -- This implementation of Calendar takes advantage of the permission in
51 -- Ada 95 of using arithmetic overflow checks to check for out of bounds
52 -- time values. This means that we must catch the constraint error that
53 -- results from arithmetic overflow, so we use pragma Unsuppress to make
54 -- sure that overflow is enabled, using software overflow checking if
55 -- necessary. That way, compiling Calendar with options to suppress this
56 -- checking will not affect its correctness.
58 ------------------------
59 -- Local Declarations --
60 ------------------------
62 Ada_Year_Min : constant := 1901;
63 Ada_Year_Max : constant := 2099;
65 -- Win32 time constants
67 epoch_1970 : constant := 16#19D_B1DE_D53E_8000#; -- win32 UTC epoch
68 system_time_ns : constant := 100; -- 100 ns per tick
69 Sec_Unit : constant := 10#1#E9;
71 ---------
72 -- "+" --
73 ---------
75 function "+" (Left : Time; Right : Duration) return Time is
76 pragma Unsuppress (Overflow_Check);
77 begin
78 return (Left + Time (Right));
80 exception
81 when Constraint_Error =>
82 raise Time_Error;
83 end "+";
85 function "+" (Left : Duration; Right : Time) return Time is
86 pragma Unsuppress (Overflow_Check);
87 begin
88 return (Time (Left) + Right);
90 exception
91 when Constraint_Error =>
92 raise Time_Error;
93 end "+";
95 ---------
96 -- "-" --
97 ---------
99 function "-" (Left : Time; Right : Duration) return Time is
100 pragma Unsuppress (Overflow_Check);
101 begin
102 return Left - Time (Right);
104 exception
105 when Constraint_Error =>
106 raise Time_Error;
107 end "-";
109 function "-" (Left : Time; Right : Time) return Duration is
110 pragma Unsuppress (Overflow_Check);
111 begin
112 return Duration (Left) - Duration (Right);
114 exception
115 when Constraint_Error =>
116 raise Time_Error;
117 end "-";
119 ---------
120 -- "<" --
121 ---------
123 function "<" (Left, Right : Time) return Boolean is
124 begin
125 return Duration (Left) < Duration (Right);
126 end "<";
128 ----------
129 -- "<=" --
130 ----------
132 function "<=" (Left, Right : Time) return Boolean is
133 begin
134 return Duration (Left) <= Duration (Right);
135 end "<=";
137 ---------
138 -- ">" --
139 ---------
141 function ">" (Left, Right : Time) return Boolean is
142 begin
143 return Duration (Left) > Duration (Right);
144 end ">";
146 ----------
147 -- ">=" --
148 ----------
150 function ">=" (Left, Right : Time) return Boolean is
151 begin
152 return Duration (Left) >= Duration (Right);
153 end ">=";
155 -----------
156 -- Clock --
157 -----------
159 -- The Ada.Calendar.Clock function gets the time from the soft links
160 -- interface which will call the appropriate function depending wether
161 -- tasking is involved or not.
163 function Clock return Time is
164 begin
165 return Time (System.OS_Primitives.Clock);
166 end Clock;
168 ---------
169 -- Day --
170 ---------
172 function Day (Date : Time) return Day_Number is
173 DY : Year_Number;
174 DM : Month_Number;
175 DD : Day_Number;
176 DS : Day_Duration;
178 begin
179 Split (Date, DY, DM, DD, DS);
180 return DD;
181 end Day;
183 -----------
184 -- Month --
185 -----------
187 function Month (Date : Time) return Month_Number is
188 DY : Year_Number;
189 DM : Month_Number;
190 DD : Day_Number;
191 DS : Day_Duration;
193 begin
194 Split (Date, DY, DM, DD, DS);
195 return DM;
196 end Month;
198 -------------
199 -- Seconds --
200 -------------
202 function Seconds (Date : Time) return Day_Duration is
203 DY : Year_Number;
204 DM : Month_Number;
205 DD : Day_Number;
206 DS : Day_Duration;
208 begin
209 Split (Date, DY, DM, DD, DS);
210 return DS;
211 end Seconds;
213 -----------
214 -- Split --
215 -----------
217 procedure Split
218 (Date : Time;
219 Year : out Year_Number;
220 Month : out Month_Number;
221 Day : out Day_Number;
222 Seconds : out Day_Duration)
225 Date_Int : aliased Long_Long_Integer;
226 Date_Loc : aliased Long_Long_Integer;
227 Timbuf : aliased SYSTEMTIME;
228 Int_Date : Long_Long_Integer;
229 Sub_Seconds : Duration;
231 begin
232 -- We take the sub-seconds (decimal part) of Date and this is added
233 -- to compute the Seconds. This way we keep the precision of the
234 -- high-precision clock that was lost with the Win32 API calls
235 -- below.
237 if Date < 0.0 then
239 -- this is a Date before Epoch (January 1st, 1970)
241 Sub_Seconds := Duration (Date) -
242 Duration (Long_Long_Integer (Date + Duration'(0.5)));
244 Int_Date := Long_Long_Integer (Date - Sub_Seconds);
246 -- For Date = -86400.1 we are 2 days before Epoch at 0.1 seconds
247 -- from day 1 before Epoch. It means that it is 23h 59m 59.9s.
248 -- here we adjust for that.
250 if Sub_Seconds < 0.0 then
251 Int_Date := Int_Date - 1;
252 Sub_Seconds := 1.0 + Sub_Seconds;
253 end if;
255 else
257 -- this is a Date after Epoch (January 1st, 1970)
259 Sub_Seconds := Duration (Date) -
260 Duration (Long_Long_Integer (Date - Duration'(0.5)));
262 Int_Date := Long_Long_Integer (Date - Sub_Seconds);
264 end if;
266 -- Date_Int is the number of seconds from Epoch.
268 Date_Int := Long_Long_Integer
269 (Int_Date * Sec_Unit / system_time_ns) + epoch_1970;
271 if not FileTimeToLocalFileTime (Date_Int'Access, Date_Loc'Access) then
272 raise Time_Error;
273 end if;
275 if not FileTimeToSystemTime (Date_Loc'Access, Timbuf'Access) then
276 raise Time_Error;
277 end if;
279 if Timbuf.wYear not in Ada_Year_Min .. Ada_Year_Max then
280 raise Time_Error;
281 end if;
283 Seconds :=
284 Duration (Timbuf.wHour) * 3_600.0 +
285 Duration (Timbuf.wMinute) * 60.0 +
286 Duration (Timbuf.wSecond) +
287 Sub_Seconds;
289 Day := Integer (Timbuf.wDay);
290 Month := Integer (Timbuf.wMonth);
291 Year := Integer (Timbuf.wYear);
292 end Split;
294 -------------
295 -- Time_Of --
296 -------------
298 function Time_Of
299 (Year : Year_Number;
300 Month : Month_Number;
301 Day : Day_Number;
302 Seconds : Day_Duration := 0.0)
303 return Time
306 Timbuf : aliased SYSTEMTIME;
307 Now : aliased Long_Long_Integer;
308 Loc : aliased Long_Long_Integer;
309 Int_Secs : Integer;
310 Secs : Integer;
311 Add_One_Day : Boolean := False;
312 Date : Time;
314 begin
315 -- The following checks are redundant with respect to the constraint
316 -- error checks that should normally be made on parameters, but we
317 -- decide to raise Constraint_Error in any case if bad values come
318 -- in (as a result of checks being off in the caller, or for other
319 -- erroneous or bounded error cases).
321 if not Year 'Valid
322 or else not Month 'Valid
323 or else not Day 'Valid
324 or else not Seconds'Valid
325 then
326 raise Constraint_Error;
327 end if;
329 if Seconds = 0.0 then
330 Int_Secs := 0;
331 else
332 Int_Secs := Integer (Seconds - 0.5);
333 end if;
335 -- Timbuf.wMillisec is to keep the msec. We can't use that because the
336 -- high-resolution clock has a precision of 1 Microsecond.
337 -- Anyway the sub-seconds part is not needed to compute the number
338 -- of seconds in UTC.
340 if Int_Secs = 86_400 then
341 Secs := 0;
342 Add_One_Day := True;
343 else
344 Secs := Int_Secs;
345 end if;
347 Timbuf.wMilliseconds := 0;
348 Timbuf.wSecond := WORD (Secs mod 60);
349 Timbuf.wMinute := WORD ((Secs / 60) mod 60);
350 Timbuf.wHour := WORD (Secs / 3600);
351 Timbuf.wDay := WORD (Day);
352 Timbuf.wMonth := WORD (Month);
353 Timbuf.wYear := WORD (Year);
355 if not SystemTimeToFileTime (Timbuf'Access, Loc'Access) then
356 raise Time_Error;
357 end if;
359 if not LocalFileTimeToFileTime (Loc'Access, Now'Access) then
360 raise Time_Error;
361 end if;
363 -- Here we have the UTC now translate UTC to Epoch time (UNIX style
364 -- time based on 1 january 1970) and add there the sub-seconds part.
366 declare
367 Sub_Sec : Duration := Seconds - Duration (Int_Secs);
368 begin
369 Date := Time ((Now - epoch_1970) * system_time_ns / Sec_Unit) +
370 Sub_Sec;
371 end;
373 if Add_One_Day then
374 Date := Date + Duration (86400.0);
375 end if;
377 return Date;
378 end Time_Of;
380 ----------
381 -- Year --
382 ----------
384 function Year (Date : Time) return Year_Number is
385 DY : Year_Number;
386 DM : Month_Number;
387 DD : Day_Number;
388 DS : Day_Duration;
390 begin
391 Split (Date, DY, DM, DD, DS);
392 return DY;
393 end Year;
395 end Ada.Calendar;