Add class configuration
[libacl.git] / src / date.cpp
1 /**************************************************************************
2 **  (c) Copyright 1999, Andromeda Technology & Automation
3 ***************************************************************************
4 ** MODULE INFORMATION *
5 ***********************
6 **      FILE NAME      : date.cpp
7 **      SYSTEM NAME    : AXE - Andromeda X-windows Encapsulation
8 **      VERSION NUMBER : $Revision: 1.3 $
9 **
10 **  DESCRIPTION      :  
11 **
12 **  EXPORTED OBJECTS : 
13 **  LOCAL    OBJECTS : 
14 **  MODULES  USED    :
15 ***************************************************************************
16 **  ADMINISTRATIVE INFORMATION *
17 ********************************
18 **      ORIGINAL AUTHOR : Arjen Baart - arjen@andromeda.nl
19 **      CREATION DATE   : Feb 06, 1998
20 **      LAST UPDATE     : Oct 16, 1999
21 **************************************************************************/
22
23 /*****************************
24    $Log: date.cpp,v $
25    Revision 1.3  2002-09-28 06:58:45  arjen
26    Bugfix: conversion of an empty string to a date or hour object
27    now makes the values of such an object 0 (null) instead of giving
28    a segmentation fault.
29    The class UTC combines the date and hour classes. The most basic
30    functions of the UTC class are now implemented.
31    These include constructors and conversion to and from String objects.
32    New functions: date::proper(), hour::proper() and UTC::proper().
33    Return true if the object holds a proper clock time and/or calendar
34    date; false if at least one value is out of range.
35
36    Revision 1.2  2002/09/02 06:18:20  arjen
37    Fixed some date and time conversion functions
38
39    Revision 1.1  2002/07/25 08:01:26  arjen
40    First checkin, AXE release 0.2
41
42 *****************************/
43
44 #include <iostream> 
45 #include <time.h>
46 #include "date.h"
47 #include "parsedate.h"
48
49 static unsigned short mon[] =
50 {
51    0,
52    31, 28, 31, 30,
53    31, 30, 31, 31,
54    30, 31, 30, 31
55 };
56
57 static const char * abr_month_name[] =
58 {
59    "xxx",
60    "Jan", "Feb", "Mar", "Apr",
61    "May", "Jun", "Jul", "Aug",
62    "Sep", "Oct", "Nov", "Dec"
63 };
64
65 date::date(String s)
66 {
67    struct parseddate *pd;
68
69    if (~s == 0)
70    {
71       year   = 0;
72       month  = 0;
73       day    = 0;
74    }
75    else
76    {
77       pd = parsedate(s);
78       year = pd->year;
79       month = pd->month;
80       day   = pd->day;
81    }
82 }
83
84 int date::Leap(void)
85 {
86    int leap;
87
88    leap = 0;
89    if (year % 4 == 0)
90       leap++;          // leapyear
91    if (year % 100 == 0)
92       leap--;          // But not every century
93    if (year % 400 == 0)
94       leap++;          // except every 4th century
95
96    return leap;
97 }
98
99 unsigned date::DaysInMonth(void)
100 {
101    unsigned days;
102    
103    if (month < 1 || month > 12)
104    {
105       days = 0;
106    }
107    else
108    {
109       days = mon[month];
110    
111       if (month == 2 && Leap())    //  Februari
112       {
113          days++;
114       }                                                 
115    }
116    
117    return days;
118 }
119  
120 String date::MonthName(void)
121 {
122    if (month <= 12)
123    {
124       return String(abr_month_name[month]);
125    }
126    else
127    {
128       return String("xxx");
129    }
130 }
131
132 unsigned date::YearDay(void)
133 {
134    unsigned days = 0;
135
136    if (proper())
137    {
138       for (unsigned m = 1; m < month; m++)
139       {
140          days += date(1, m, year).DaysInMonth();
141       }
142       days += day;
143    }
144
145    return days;
146 }
147
148 date date::add(date D)
149 {
150    year += D.year;
151    month += D.month;
152    while (month > 12)
153    {
154       year++;
155       month -= 12;
156    }
157    day += D.day;
158    while (day > DaysInMonth())
159    {
160       day -= DaysInMonth();
161       month++;
162       if (month > 12)
163       {
164          year++;
165          month -= 12;
166       }
167    }
168
169    return *this;
170 }
171
172 date date::add(unsigned long days)
173 {
174    //  Calculate the date <days> days in the future
175
176    days += day;
177    while (days > DaysInMonth())
178    {
179       days -= DaysInMonth();
180       month++;
181       if (month > 12)
182       {
183          year++;
184          month -= 12;
185       }
186    }
187    day = days;
188
189    return *this;
190 }
191
192 date date::subtract(unsigned long days)
193 {
194    //  Calculate the date <days> days in the past
195
196    while (days != 0)
197    {
198       if (days < day)
199       {
200          day -= days;
201          days = 0;
202       }
203       else
204       {
205          month--;
206          if (month == 0)
207          {
208             year--;
209             month = 12;
210          }
211          days -= day;
212          day = DaysInMonth();
213       }
214    }
215
216    return *this;
217 }
218
219 bool date::proper()
220 {
221    return  year != -1 && year != 0 &&
222            month > 0  && month <= 12 &&
223            day   > 0  && day <= DaysInMonth();
224 }
225
226 date operator+(date d1, date d2)
227 {
228    d1.add(d2);
229    return d1;
230 }
231
232 date operator+(unsigned long l, date d)
233 {
234    d.add(l);
235    return d;
236 }
237
238 date operator+(date d, unsigned long l)
239 {
240    d.add(l);
241    return d;
242 }
243
244 date operator-(unsigned long l, date d)
245 {
246    d.subtract(l);
247    return d;
248 }
249
250 date operator-(date d, unsigned long l)
251 {
252    d.subtract(l);
253    return d;
254 }
255
256 date today(bool local)
257 {
258    long      clock;
259    struct tm   *tp;
260
261    time(&clock);
262    if (local)
263    {
264       tp = localtime(&clock);
265    }
266    else
267    {
268       tp = gmtime(&clock);
269    }
270    
271    return date(tp->tm_mday, tp->tm_mon+1, tp->tm_year+1900);
272 }
273
274 /*=========================================================================
275 **  NAME           : date::julian
276 **  SYNOPSIS       :
277 **  PARAMETERS     :
278 **  RETURN VALUE   :
279 **
280 **  DESCRIPTION    :  Return the number of days since the base date of the
281 **                    Julian Calendar.
282 **
283 **  VARS USED      :
284 **  VARS CHANGED   :
285 **  FUNCTIONS USED :
286 **  SEE ALSO       :
287 **  LAST MODIFIED  :
288 **  SEE ALSO       :
289 **  LAST MODIFIED  :
290 **=========================================================================
291 */
292
293 long date::julian(void)
294 {
295    long cent;
296    int  yr, mn, dy;
297
298    yr = year;
299    mn = month;
300    dy = day;
301
302    if (mn > 2)
303       mn -= 3;
304    else
305    {
306       mn += 9;
307       yr -= 1;
308    }
309
310    cent = yr / 100;
311    yr   %= 100;
312
313    return  (146097 * cent >> 2) + (1461 * yr >> 2) +
314            (153 * mn + 2) / 5 + dy + 1721119;
315
316 }
317
318 long operator-(date &d1, date &d2)
319 {
320    return d1.julian() - d2.julian();
321 }
322
323 std::ostream &operator<<(std::ostream &s, const date &d)
324 {
325    s.width(2);
326    s.fill('0');
327
328    s << int(d.day) << "-";
329    s.width(2);
330    s.fill('0');
331    s << int(d.month) << "-";
332    s << d.year;
333
334    return s;
335 }
336
337 std::istream &operator>>(std::istream &s, date &d)
338 {
339    char c;
340    int  D, M, Y;
341
342    s >> D >> c >> M >> c >> Y;
343
344    d.day = D;
345    d.month = M;
346    if (Y < 100)
347    {
348       if (Y < 70)
349          Y += 2000;
350       else
351          Y += 1900;
352    }
353    d.year = Y;
354
355    return s;
356 }
357
358 String date::format(const char *fmt)
359 {
360    String  s;
361    char    buf[40];
362    struct  tm  t;
363
364    t.tm_year = year - 1900;
365    t.tm_mon  = month - 1;
366    t.tm_mday = day;
367
368    strftime(buf, 40, fmt, &t);
369    s = buf;
370
371    return s;
372 }
373