Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

root/trunk/phobos/std/gregorian.d

Revision 1487, 9.4 kB (checked in by andrei, 15 years ago)

added

Line 
1 // Written in the D programming language.
2
3 /**
4 Macros:
5 WIKI = Phobos/StdGregorian
6
7 Copyright: Copyright Andrei Alexandrescu 2008 - 2009.
8 License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
9 Authors:   $(WEB erdani.org, Andrei Alexandrescu)
10
11          Copyright Andrei Alexandrescu 2010-.
12 Distributed under the Boost Software License, Version 1.0.
13    (See accompanying file LICENSE_1_0.txt or copy at
14          http://www.boost.org/LICENSE_1_0.txt)
15 */
16 module std.gregorian;
17
18 import std.typecons;
19 import core.sys.posix.time;
20 import std.conv;
21 version(unittest) import std.stdio;
22
23 unittest
24 {
25     auto d = Date(2010, May, 1);
26     auto d1 = d;
27     assert(d.year == 2010);
28     assert(d.month == May);
29     assert(d.day == 1);
30     assert(d.dayOfWeek == 6);
31     assert(d.dayOfYear == 121);
32     assert(Date(2010, Jan, 5).dayOfYear == 5);
33 }
34
35 unittest
36 {
37     auto d1 = Date(negInfin);
38     auto d2 = Date(posInfin);
39     auto d3 = Date(notADateTime);
40     auto d4 = Date(maxDateTime);
41     auto d5 = Date(minDateTime);
42 }
43
44 unittest
45 {
46     auto d1 = fromString("2002-1-25");
47     auto d2 = fromUndelimitedString("20020125");
48 }
49
50 unittest
51 {
52     auto d1 = dayClockLocalDay();
53     auto d2 = dayClockUniversalDay();
54 }
55
56 alias ushort GregYear;
57 alias ushort GregMonth;
58 alias ushort GregDay;
59 alias uint GregDayOfWeek;
60 alias uint GregDayOfYear;
61
62 enum { Jan = 1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec }
63
64 // Special constants
65 struct Special { ulong value; }
66 static immutable
67     notADateTime = Special(0),
68     negInfin = Special(1),
69     posInfin = Special(2),
70     minDateTime = Special(3),
71     maxDateTime = Special(4),
72     notSpecial = Special(5);
73
74 struct Date
75 {
76     this(uint year, uint month, uint day)
77     {
78         immutable
79             a = cast(ushort)((14-month)/12),
80             y = cast(ushort)(year + 4800 - a),
81             m = cast(ushort)(month + 12*a - 3);
82         days_ = day + ((153*m + 2)/5) + 365*y + (y/4)
83             - (y/100) + (y/400) - 32045;
84     }
85
86     this(Special s)
87     {
88     }
89
90     // Accessors
91     @property GregYear year() const
92     {
93         immutable
94             a = days_ + 32044,
95             b = (4*a + 3)/146097,
96             c = a-((146097*b)/4),
97             d = (4*c + 3)/1461,
98             e = c - (1461*d)/4,
99             m = (5*e + 2)/153;
100         //auto day = cast(ushort) (e - ((153*m + 2)/5) + 1);
101         //auto month = cast(ushort) (m + 3 - 12 * (m/10));
102         immutable year = cast(ushort) (100*b + d - 4800 + (m/10));
103
104         return year;
105     }
106
107     @property GregMonth month() const
108     {
109         immutable
110             a = days_ + 32044,
111             b = (4*a + 3)/146097,
112             c = a-((146097*b)/4),
113             d = (4*c + 3)/1461,
114             e = c - (1461*d)/4,
115             m = (5*e + 2)/153;
116         //auto day = cast(ushort) (e - ((153*m + 2)/5) + 1);
117         immutable month = cast(ushort) (m + 3 - 12 * (m/10));
118         //auto year = cast(ushort) (100*b + d - 4800 + (m/10));
119
120         return month;
121     }
122
123     @property GregDay day() const
124     {
125         immutable
126             a = days_ + 32044,
127             b = (4*a + 3)/146097,
128             c = a-((146097*b)/4),
129             d = (4*c + 3)/1461,
130             e = c - (1461*d)/4,
131             m = (5*e + 2)/153,
132             day = cast(ushort) (e - ((153*m + 2)/5) + 1);
133         //auto month = cast(ushort) (m + 3 - 12 * (m/10));
134         //auto year = cast(ushort) (100*b + d - 4800 + (m/10));
135
136         return day;
137     }
138
139     @property Tuple!(GregYear, GregMonth, GregDay)
140     yearMonthDay() const
141     {
142         immutable
143             a = days_ + 32044,
144             b = (4*a + 3)/146097,
145             c = a-((146097*b)/4),
146             d = (4*c + 3)/1461,
147             e = c - (1461*d)/4,
148             m = (5*e + 2)/153;
149         auto day = cast(ushort) (e - ((153*m + 2)/5) + 1);
150         auto month = cast(ushort) (m + 3 - 12 * (m/10));
151         auto year = cast(ushort) (100*b + d - 4800 + (m/10));
152
153         return tuple(year, month, day);
154     }
155
156     @property GregDayOfWeek dayOfWeek() const
157     {
158         immutable
159             ymd = yearMonthDay,
160             a = cast(ushort) ((14-ymd._1)/12),
161             y = cast(ushort) (ymd._0 - a),
162             m = cast(ushort) (ymd._1 + 12*a - 2),
163             d = cast(ushort) ((ymd._2 + y + (y/4) - (y/100) +
164                             (y/400) + (31*m)/12) % 7);
165         return d;
166     }
167
168     @property GregDayOfYear dayOfYear() const
169     {
170         const start_of_year = Date(year(), 1, 1);
171         auto doy = cast(ushort) ((this - start_of_year).days() + 1);
172         return cast(GregDayOfYear) doy;
173     }
174
175     @property Date endOfMonth() const
176     {
177         assert(0);
178     }
179
180     @property bool isInfinity() const
181     {
182         return isNegInfinity || isPosInfinity;
183     }
184
185     @property bool isNegInfinity() const
186     {
187         return days_ == negInfin.value;
188     }
189
190     @property bool isPosInfinity() const
191     {
192         return days_ == posInfin.value;
193     }
194
195     @property bool isNotADate() const
196     {
197         return days_ == notADateTime.value;
198     }
199
200     @property bool isSpecial() const
201     {
202         return isNotADate || isInfinity;
203     }
204
205     @property Special asSpecial() const
206     {
207         return days_ < notSpecial.value
208             ? Special(days_)
209             : notSpecial;
210     }
211
212     @property long modJulianDay() const
213     {
214         auto ymd = yearMonthDay();
215         return julianDay(ymd) - 2400001; //prerounded
216     }
217
218     static @property long julianDay(Tuple!(ushort, ushort, ushort) ymd)
219     {
220         immutable
221             a = cast(ushort) ((14-ymd._1)/12),
222             y = cast(ushort) (ymd._0 + 4800 - a),
223             m = cast(ushort) (ymd._1 + 12*a - 3),
224             d = ymd._2 + ((153*m + 2)/5) + 365*y + (y/4) - (y/100)
225             + (y/400) - 32045;
226         return d;
227     }
228
229     static bool isLeapYear(uint year)
230     {
231         //divisible by 4, not if divisible by 100, but true if
232         //divisible by 400
233         return (!(year % 4)) && ((year % 100) || (!(year % 400)));
234     }
235
236     @property int weekNumber() const
237     {
238         auto
239             ymd = yearMonthDay,
240             julianbegin = julianDay(tuple(cast(ushort)ymd._0,
241                             cast(ushort)1, cast(ushort)1)),
242             juliantoday = julianDay(ymd);
243         long day = (julianbegin + 3) % 7;
244         ulong week = (juliantoday + day - julianbegin + 4)/7;
245
246         if ((week >= 1) && (week <= 52))
247         {
248             return cast(int) week;
249         }
250
251         if ((week == 53))
252         {
253             if((day==6) ||(day == 5 && isLeapYear(ymd._0)))
254             {
255                 return cast(int) week; //under these circumstances week == 53.
256             }
257             else
258             {
259                 return 1; //monday - wednesday is in week 1 of next year
260             }
261         }
262
263         //if the week is not in current year recalculate using the
264         //previous year as the beginning year
265         else
266             if (week == 0)
267             {
268                 julianbegin = julianDay(
269                     tuple(cast(ushort) (ymd._0 - 1), cast(ushort) 1,
270                             cast(ushort) 1));
271                 juliantoday = julianDay(ymd);
272                 day = (julianbegin + 3) % 7;
273                 week = (juliantoday + day - julianbegin + 4)/7;
274                 return cast(int) week;
275             }
276         return cast(int) week;  //not reachable -- well except if day == 5 and
277                       //is_leap_year != true
278     }
279
280     @property uint endOfMonthDay() const
281     {
282         switch (month) {
283             case 2:
284                 if (isLeapYear(year)) {
285                     return 29;
286                 } else {
287                     return 28;
288                 };
289             case 4:
290             case 6:
291             case 9:
292             case 11:
293                 return 30;
294             default:
295                 return 31;
296         }
297     }
298
299     @property string toSimpleString() const
300     {
301         auto ymd = yearMonthDay;
302         return text(ymd._0, '-', ymd._1, '-', ymd._2);
303     }
304
305     @property string toIsoString() const
306     {
307         assert(0);
308     }
309
310     @property string toIsoExtendedString() const
311     {
312         assert(0);
313     }
314
315     bool opEquals(ref const Date rhs) const
316     {
317         return days_ == rhs.days_;
318     }
319
320     int opCmp(in Date rhs) const
321     {
322         return days_ < rhs.days_ ? -1 : days_ > rhs.days_ ? 1 : 0;
323     }
324
325     // Date opBinary(string op)(const Date d) const
326     // if (op == "-")
327     // {
328     // }
329
330     Days opBinary(string op)(const Date d) const
331     if (op == "-")
332     {
333         if (!isSpecial && !d.isSpecial)
334         {
335             return Days(days_ - d.days_);
336         }
337         else
338         {
339             assert(0);
340         }
341     }
342
343     tm toTm()
344     {
345         assert(0);
346     }
347
348     private ulong days_;
349 }
350
351 struct Days
352 {
353     private long days_;
354     this(long d) { days_ = d; }
355     this(Special s) { }
356     @property long days() const { return days_; }
357     @property bool isNegative() const { return days_ < 0; }
358     @property static Days unit() { return Days(1); }
359     @property bool isSpecial()
360     {
361         assert(0);
362     }
363     bool opEquals(ref const Days rhs) const
364     {
365         return days_ == rhs.days_;
366     }
367
368     int opCmp(in Days rhs) const
369     {
370         return days_ < rhs.days_ ? -1 : days_ > rhs.days_ ? 1 : 0;
371     }
372
373     Days opBinary(string op)(Days d) const
374     if (op == "+" || op == "-")
375     {
376     }
377 }
378
379 Date fromString(in char[] s)
380 {
381     Date result;
382     return result;
383 }
384
385 Date fromUndelimitedString(in char[] s)
386 {
387     Date result;
388     return result;
389 }
390
391 Date dayClockLocalDay()
392 {
393     Date result;
394     return result;
395 }
396
397 Date dayClockUniversalDay()
398 {
399     Date result;
400     return result;
401 }
402
403 Date dateFromTm(tm)
404 {
405     assert(0);
406 }
Note: See TracBrowser for help on using the browser.