OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [gcc/] [ada/] [g-calend.adb] - Blame information for rev 715

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 706 jeremybenn
------------------------------------------------------------------------------
2
--                                                                          --
3
--                         GNAT RUN-TIME COMPONENTS                         --
4
--                                                                          --
5
--                         G N A T . C A L E N D A R                        --
6
--                                                                          --
7
--                                 B o d y                                  --
8
--                                                                          --
9
--                     Copyright (C) 1999-2010, AdaCore                     --
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
 
32
package body GNAT.Calendar is
33
 
34
   use Ada.Calendar;
35
   use Interfaces;
36
 
37
   -----------------
38
   -- Day_In_Year --
39
   -----------------
40
 
41
   function Day_In_Year (Date : Time) return Day_In_Year_Number is
42
      Year     : Year_Number;
43
      Month    : Month_Number;
44
      Day      : Day_Number;
45
      Day_Secs : Day_Duration;
46
      pragma Unreferenced (Day_Secs);
47
   begin
48
      Split (Date, Year, Month, Day, Day_Secs);
49
      return Julian_Day (Year, Month, Day) - Julian_Day (Year, 1, 1) + 1;
50
   end Day_In_Year;
51
 
52
   -----------------
53
   -- Day_Of_Week --
54
   -----------------
55
 
56
   function Day_Of_Week (Date : Time) return Day_Name is
57
      Year     : Year_Number;
58
      Month    : Month_Number;
59
      Day      : Day_Number;
60
      Day_Secs : Day_Duration;
61
      pragma Unreferenced (Day_Secs);
62
   begin
63
      Split (Date, Year, Month, Day, Day_Secs);
64
      return Day_Name'Val ((Julian_Day (Year, Month, Day)) mod 7);
65
   end Day_Of_Week;
66
 
67
   ----------
68
   -- Hour --
69
   ----------
70
 
71
   function Hour (Date : Time) return Hour_Number is
72
      Year       : Year_Number;
73
      Month      : Month_Number;
74
      Day        : Day_Number;
75
      Hour       : Hour_Number;
76
      Minute     : Minute_Number;
77
      Second     : Second_Number;
78
      Sub_Second : Second_Duration;
79
      pragma Unreferenced (Year, Month, Day, Minute, Second, Sub_Second);
80
   begin
81
      Split (Date, Year, Month, Day, Hour, Minute, Second, Sub_Second);
82
      return Hour;
83
   end Hour;
84
 
85
   ----------------
86
   -- Julian_Day --
87
   ----------------
88
 
89
   --  Julian_Day is used to by Day_Of_Week and Day_In_Year. Note that this
90
   --  implementation is not expensive.
91
 
92
   function Julian_Day
93
     (Year  : Year_Number;
94
      Month : Month_Number;
95
      Day   : Day_Number) return Integer
96
   is
97
      Internal_Year  : Integer;
98
      Internal_Month : Integer;
99
      Internal_Day   : Integer;
100
      Julian_Date    : Integer;
101
      C              : Integer;
102
      Ya             : Integer;
103
 
104
   begin
105
      Internal_Year  := Integer (Year);
106
      Internal_Month := Integer (Month);
107
      Internal_Day   := Integer (Day);
108
 
109
      if Internal_Month > 2 then
110
         Internal_Month := Internal_Month - 3;
111
      else
112
         Internal_Month := Internal_Month + 9;
113
         Internal_Year  := Internal_Year - 1;
114
      end if;
115
 
116
      C  := Internal_Year / 100;
117
      Ya := Internal_Year - (100 * C);
118
 
119
      Julian_Date := (146_097 * C) / 4 +
120
        (1_461 * Ya) / 4 +
121
        (153 * Internal_Month + 2) / 5 +
122
        Internal_Day + 1_721_119;
123
 
124
      return Julian_Date;
125
   end Julian_Day;
126
 
127
   ------------
128
   -- Minute --
129
   ------------
130
 
131
   function Minute (Date : Time) return Minute_Number is
132
      Year       : Year_Number;
133
      Month      : Month_Number;
134
      Day        : Day_Number;
135
      Hour       : Hour_Number;
136
      Minute     : Minute_Number;
137
      Second     : Second_Number;
138
      Sub_Second : Second_Duration;
139
      pragma Unreferenced (Year, Month, Day, Hour, Second, Sub_Second);
140
   begin
141
      Split (Date, Year, Month, Day, Hour, Minute, Second, Sub_Second);
142
      return Minute;
143
   end Minute;
144
 
145
   ------------
146
   -- Second --
147
   ------------
148
 
149
   function Second (Date : Time) return Second_Number is
150
      Year       : Year_Number;
151
      Month      : Month_Number;
152
      Day        : Day_Number;
153
      Hour       : Hour_Number;
154
      Minute     : Minute_Number;
155
      Second     : Second_Number;
156
      Sub_Second : Second_Duration;
157
      pragma Unreferenced (Year, Month, Day, Hour, Minute, Sub_Second);
158
   begin
159
      Split (Date, Year, Month, Day, Hour, Minute, Second, Sub_Second);
160
      return Second;
161
   end Second;
162
 
163
   -----------
164
   -- Split --
165
   -----------
166
 
167
   procedure Split
168
     (Date       : Time;
169
      Year       : out Year_Number;
170
      Month      : out Month_Number;
171
      Day        : out Day_Number;
172
      Hour       : out Hour_Number;
173
      Minute     : out Minute_Number;
174
      Second     : out Second_Number;
175
      Sub_Second : out Second_Duration)
176
   is
177
      Day_Secs : Day_Duration;
178
      Secs     : Natural;
179
 
180
   begin
181
      Split (Date, Year, Month, Day, Day_Secs);
182
 
183
      Secs       := (if Day_Secs = 0.0 then 0 else Natural (Day_Secs - 0.5));
184
      Sub_Second := Second_Duration (Day_Secs - Day_Duration (Secs));
185
      Hour       := Hour_Number (Secs / 3_600);
186
      Secs       := Secs mod 3_600;
187
      Minute     := Minute_Number (Secs / 60);
188
      Second     := Second_Number (Secs mod 60);
189
   end Split;
190
 
191
   ----------------
192
   -- Sub_Second --
193
   ----------------
194
 
195
   function Sub_Second (Date : Time) return Second_Duration is
196
      Year       : Year_Number;
197
      Month      : Month_Number;
198
      Day        : Day_Number;
199
      Hour       : Hour_Number;
200
      Minute     : Minute_Number;
201
      Second     : Second_Number;
202
      Sub_Second : Second_Duration;
203
      pragma Unreferenced (Year, Month, Day, Hour, Minute, Second);
204
   begin
205
      Split (Date, Year, Month, Day, Hour, Minute, Second, Sub_Second);
206
      return Sub_Second;
207
   end Sub_Second;
208
 
209
   -------------
210
   -- Time_Of --
211
   -------------
212
 
213
   function Time_Of
214
     (Year       : Year_Number;
215
      Month      : Month_Number;
216
      Day        : Day_Number;
217
      Hour       : Hour_Number;
218
      Minute     : Minute_Number;
219
      Second     : Second_Number;
220
      Sub_Second : Second_Duration := 0.0) return Time
221
   is
222
 
223
      Day_Secs : constant Day_Duration :=
224
                   Day_Duration (Hour   * 3_600) +
225
                   Day_Duration (Minute *    60) +
226
                   Day_Duration (Second)         +
227
                                 Sub_Second;
228
   begin
229
      return Time_Of (Year, Month, Day, Day_Secs);
230
   end Time_Of;
231
 
232
   -----------------
233
   -- To_Duration --
234
   -----------------
235
 
236
   function To_Duration (T : not null access timeval) return Duration is
237
 
238
      procedure timeval_to_duration
239
        (T    : not null access timeval;
240
         sec  : not null access C.long;
241
         usec : not null access C.long);
242
      pragma Import (C, timeval_to_duration, "__gnat_timeval_to_duration");
243
 
244
      Micro : constant := 10**6;
245
      sec   : aliased C.long;
246
      usec  : aliased C.long;
247
 
248
   begin
249
      timeval_to_duration (T, sec'Access, usec'Access);
250
      return Duration (sec) + Duration (usec) / Micro;
251
   end To_Duration;
252
 
253
   ----------------
254
   -- To_Timeval --
255
   ----------------
256
 
257
   function To_Timeval (D : Duration) return timeval is
258
 
259
      procedure duration_to_timeval
260
        (Sec  : C.long;
261
         Usec : C.long;
262
         T : not null access timeval);
263
      pragma Import (C, duration_to_timeval, "__gnat_duration_to_timeval");
264
 
265
      Micro  : constant := 10**6;
266
      Result : aliased timeval;
267
      sec    : C.long;
268
      usec   : C.long;
269
 
270
   begin
271
      if D = 0.0 then
272
         sec  := 0;
273
         usec := 0;
274
      else
275
         sec  := C.long (D - 0.5);
276
         usec := C.long ((D - Duration (sec)) * Micro - 0.5);
277
      end if;
278
 
279
      duration_to_timeval (sec, usec, Result'Access);
280
 
281
      return Result;
282
   end To_Timeval;
283
 
284
   ------------------
285
   -- Week_In_Year --
286
   ------------------
287
 
288
   function Week_In_Year (Date : Time) return Week_In_Year_Number is
289
      Year : Year_Number;
290
      Week : Week_In_Year_Number;
291
      pragma Unreferenced (Year);
292
   begin
293
      Year_Week_In_Year (Date, Year, Week);
294
      return Week;
295
   end Week_In_Year;
296
 
297
   -----------------------
298
   -- Year_Week_In_Year --
299
   -----------------------
300
 
301
   procedure Year_Week_In_Year
302
     (Date : Time;
303
      Year : out Year_Number;
304
      Week : out Week_In_Year_Number)
305
   is
306
      Month      : Month_Number;
307
      Day        : Day_Number;
308
      Hour       : Hour_Number;
309
      Minute     : Minute_Number;
310
      Second     : Second_Number;
311
      Sub_Second : Second_Duration;
312
      Jan_1      : Day_Name;
313
      Shift      : Week_In_Year_Number;
314
      Start_Week : Week_In_Year_Number;
315
 
316
      pragma Unreferenced (Hour, Minute, Second, Sub_Second);
317
 
318
      function Is_Leap (Year : Year_Number) return Boolean;
319
      --  Return True if Year denotes a leap year. Leap centennial years are
320
      --  properly handled.
321
 
322
      function Jan_1_Day_Of_Week
323
        (Jan_1     : Day_Name;
324
         Year      : Year_Number;
325
         Last_Year : Boolean := False;
326
         Next_Year : Boolean := False) return Day_Name;
327
      --  Given the weekday of January 1 in Year, determine the weekday on
328
      --  which January 1 fell last year or will fall next year as set by
329
      --  the two flags. This routine does not call Time_Of or Split.
330
 
331
      function Last_Year_Has_53_Weeks
332
        (Jan_1 : Day_Name;
333
         Year  : Year_Number) return Boolean;
334
      --  Given the weekday of January 1 in Year, determine whether last year
335
      --  has 53 weeks. A False value implies that the year has 52 weeks.
336
 
337
      -------------
338
      -- Is_Leap --
339
      -------------
340
 
341
      function Is_Leap (Year : Year_Number) return Boolean is
342
      begin
343
         if Year mod 400 = 0 then
344
            return True;
345
         elsif Year mod 100 = 0 then
346
            return False;
347
         else
348
            return Year mod 4 = 0;
349
         end if;
350
      end Is_Leap;
351
 
352
      -----------------------
353
      -- Jan_1_Day_Of_Week --
354
      -----------------------
355
 
356
      function Jan_1_Day_Of_Week
357
        (Jan_1     : Day_Name;
358
         Year      : Year_Number;
359
         Last_Year : Boolean := False;
360
         Next_Year : Boolean := False) return Day_Name
361
      is
362
         Shift : Integer := 0;
363
 
364
      begin
365
         if Last_Year then
366
            Shift := (if Is_Leap (Year - 1) then -2 else -1);
367
         elsif Next_Year then
368
            Shift := (if Is_Leap (Year) then 2 else 1);
369
         end if;
370
 
371
         return Day_Name'Val ((Day_Name'Pos (Jan_1) + Shift) mod 7);
372
      end Jan_1_Day_Of_Week;
373
 
374
      ----------------------------
375
      -- Last_Year_Has_53_Weeks --
376
      ----------------------------
377
 
378
      function Last_Year_Has_53_Weeks
379
        (Jan_1 : Day_Name;
380
         Year  : Year_Number) return Boolean
381
      is
382
         Last_Jan_1 : constant Day_Name :=
383
                        Jan_1_Day_Of_Week (Jan_1, Year, Last_Year => True);
384
 
385
      begin
386
         --  These two cases are illustrated in the table below
387
 
388
         return
389
           Last_Jan_1 = Thursday
390
             or else (Last_Jan_1 = Wednesday and then Is_Leap (Year - 1));
391
      end Last_Year_Has_53_Weeks;
392
 
393
   --  Start of processing for Week_In_Year
394
 
395
   begin
396
      Split (Date, Year, Month, Day, Hour, Minute, Second, Sub_Second);
397
 
398
      --  According to ISO 8601, the first week of year Y is the week that
399
      --  contains the first Thursday in year Y. The following table contains
400
      --  all possible combinations of years and weekdays along with examples.
401
 
402
      --    +-------+------+-------+---------+
403
      --    | Jan 1 | Leap | Weeks | Example |
404
      --    +-------+------+-------+---------+
405
      --    |  Mon  |  No  |  52   |  2007   |
406
      --    +-------+------+-------+---------+
407
      --    |  Mon  | Yes  |  52   |  1996   |
408
      --    +-------+------+-------+---------+
409
      --    |  Tue  |  No  |  52   |  2002   |
410
      --    +-------+------+-------+---------+
411
      --    |  Tue  | Yes  |  52   |  1980   |
412
      --    +-------+------+-------+---------+
413
      --    |  Wed  |  No  |  52   |  2003   |
414
      --    +-------+------#########---------+
415
      --    |  Wed  | Yes  #  53   #  1992   |
416
      --    +-------+------#-------#---------+
417
      --    |  Thu  |  No  #  53   #  1998   |
418
      --    +-------+------#-------#---------+
419
      --    |  Thu  | Yes  #  53   #  2004   |
420
      --    +-------+------#########---------+
421
      --    |  Fri  |  No  |  52   |  1999   |
422
      --    +-------+------+-------+---------+
423
      --    |  Fri  | Yes  |  52   |  1988   |
424
      --    +-------+------+-------+---------+
425
      --    |  Sat  |  No  |  52   |  1994   |
426
      --    +-------+------+-------+---------+
427
      --    |  Sat  | Yes  |  52   |  1972   |
428
      --    +-------+------+-------+---------+
429
      --    |  Sun  |  No  |  52   |  1995   |
430
      --    +-------+------+-------+---------+
431
      --    |  Sun  | Yes  |  52   |  1956   |
432
      --    +-------+------+-------+---------+
433
 
434
      --  A small optimization, the input date is January 1. Note that this
435
      --  is a key day since it determines the number of weeks and is used
436
      --  when special casing the first week of January and the last week of
437
      --  December.
438
 
439
      Jan_1 := Day_Of_Week (if Day = 1 and then Month = 1
440
                            then Date
441
                            else (Time_Of (Year, 1, 1, 0.0)));
442
 
443
      --  Special cases for January
444
 
445
      if Month = 1 then
446
 
447
         --  Special case 1: January 1, 2 and 3. These three days may belong
448
         --  to last year's last week which can be week number 52 or 53.
449
 
450
         --    +-----+-----+-----+=====+-----+-----+-----+
451
         --    | Mon | Tue | Wed # Thu # Fri | Sat | Sun |
452
         --    +-----+-----+-----+-----+-----+-----+-----+
453
         --    | 26  | 27  | 28  # 29  # 30  | 31  |  1  |
454
         --    +-----+-----+-----+-----+-----+-----+-----+
455
         --    | 27  | 28  | 29  # 30  # 31  |  1  |  2  |
456
         --    +-----+-----+-----+-----+-----+-----+-----+
457
         --    | 28  | 29  | 30  # 31  #  1  |  2  |  3  |
458
         --    +-----+-----+-----+=====+-----+-----+-----+
459
 
460
         if (Day = 1 and then Jan_1 in Friday .. Sunday)
461
               or else
462
            (Day = 2 and then Jan_1 in Friday .. Saturday)
463
               or else
464
            (Day = 3 and then Jan_1 = Friday)
465
         then
466
            Week := (if Last_Year_Has_53_Weeks (Jan_1, Year) then 53 else 52);
467
 
468
            --  January 1, 2 and 3 belong to the previous year
469
 
470
            Year := Year - 1;
471
            return;
472
 
473
         --  Special case 2: January 1, 2, 3, 4, 5, 6 and 7 of the first week
474
 
475
         --    +-----+-----+-----+=====+-----+-----+-----+
476
         --    | Mon | Tue | Wed # Thu # Fri | Sat | Sun |
477
         --    +-----+-----+-----+-----+-----+-----+-----+
478
         --    | 29  | 30  | 31  #  1  #  2  |  3  |  4  |
479
         --    +-----+-----+-----+-----+-----+-----+-----+
480
         --    | 30  | 31  |  1  #  2  #  3  |  4  |  5  |
481
         --    +-----+-----+-----+-----+-----+-----+-----+
482
         --    | 31  |  1  |  2  #  3  #  4  |  5  |  6  |
483
         --    +-----+-----+-----+-----+-----+-----+-----+
484
         --    |  1  |  2  |  3  #  4  #  5  |  6  |  7  |
485
         --    +-----+-----+-----+=====+-----+-----+-----+
486
 
487
         elsif (Day <= 4 and then Jan_1 in Monday .. Thursday)
488
                  or else
489
               (Day = 5  and then Jan_1 in Monday .. Wednesday)
490
                  or else
491
               (Day = 6  and then Jan_1 in Monday ..  Tuesday)
492
                  or else
493
               (Day = 7  and then Jan_1 = Monday)
494
         then
495
            Week := 1;
496
            return;
497
         end if;
498
 
499
      --  Month other than 1
500
 
501
      --  Special case 3: December 29, 30 and 31. These days may belong to
502
      --  next year's first week.
503
 
504
      --    +-----+-----+-----+=====+-----+-----+-----+
505
      --    | Mon | Tue | Wed # Thu # Fri | Sat | Sun |
506
      --    +-----+-----+-----+-----+-----+-----+-----+
507
      --    | 29  | 30  | 31  #  1  #  2  |  3  |  4  |
508
      --    +-----+-----+-----+-----+-----+-----+-----+
509
      --    | 30  | 31  |  1  #  2  #  3  |  4  |  5  |
510
      --    +-----+-----+-----+-----+-----+-----+-----+
511
      --    | 31  |  1  |  2  #  3  #  4  |  5  |  6  |
512
      --    +-----+-----+-----+=====+-----+-----+-----+
513
 
514
      elsif Month = 12 and then Day > 28 then
515
         declare
516
            Next_Jan_1 : constant Day_Name :=
517
                           Jan_1_Day_Of_Week (Jan_1, Year, Next_Year => True);
518
         begin
519
            if (Day = 29 and then Next_Jan_1 = Thursday)
520
                  or else
521
               (Day = 30 and then Next_Jan_1 in Wednesday .. Thursday)
522
                  or else
523
               (Day = 31 and then Next_Jan_1 in Tuesday .. Thursday)
524
            then
525
               Year := Year + 1;
526
               Week := 1;
527
               return;
528
            end if;
529
         end;
530
      end if;
531
 
532
      --  Determine the week from which to start counting. If January 1 does
533
      --  not belong to the first week of the input year, then the next week
534
      --  is the first week.
535
 
536
      Start_Week := (if Jan_1 in Friday .. Sunday then 1 else 2);
537
 
538
      --  At this point all special combinations have been accounted for and
539
      --  the proper start week has been found. Since January 1 may not fall
540
      --  on a Monday, shift 7 - Day_Name'Pos (Jan_1). This action ensures an
541
      --  origin which falls on Monday.
542
 
543
      Shift := 7 - Day_Name'Pos (Jan_1);
544
      Week  := Start_Week + (Day_In_Year (Date) - Shift - 1) / 7;
545
   end Year_Week_In_Year;
546
 
547
end GNAT.Calendar;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.