]> git.saurik.com Git - wxWidgets.git/blob - src/common/datetime.cpp
Various small fixes and tweaks
[wxWidgets.git] / src / common / datetime.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: wx/datetime.h
3 // Purpose: implementation of time/date related classes
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 11.05.99
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "datetime.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/string.h"
33 #include "wx/intl.h"
34 #include "wx/log.h"
35 #endif // WX_PRECOMP
36
37 #define wxDEFINE_TIME_CONSTANTS
38
39 #include "wx/datetime.h"
40
41 // ----------------------------------------------------------------------------
42 // constants
43 // ----------------------------------------------------------------------------
44
45 // the number of days in month in Julian/Gregorian calendar: the first line is
46 // for normal years, the second one is for the leap ones
47 static wxDateTime::wxDateTime_t gs_daysInMonth[2][12] =
48 {
49 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
50 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
51 };
52
53 // ----------------------------------------------------------------------------
54 // private functions
55 // ----------------------------------------------------------------------------
56
57 static wxString CallStrftime(const wxChar *format, const tm* tm)
58 {
59 wxChar buf[1024];
60 if ( !wxStrftime(buf, WXSIZEOF(buf), format, tm) )
61 {
62 // is ti really possible that 1024 is too short?
63 wxFAIL_MSG(_T("strftime() failed"));
64 }
65
66 return wxString(buf);
67 }
68
69 // ============================================================================
70 // implementation of wxDateTime
71 // ============================================================================
72
73 // ----------------------------------------------------------------------------
74 // static data
75 // ----------------------------------------------------------------------------
76
77 wxDateTime::Country wxDateTime::ms_country = wxDateTime::Country_Unknown;
78 wxDateTime wxDateTime::ms_InvDateTime;
79
80 // ----------------------------------------------------------------------------
81 // struct Tm
82 // ----------------------------------------------------------------------------
83
84 wxDateTime::Tm::Tm()
85 {
86 year = (wxDateTime_t)wxDateTime::Inv_Year;
87 mon = wxDateTime::Inv_Month;
88 mday = 0;
89 hour = min = sec = 0;
90 wday = wxDateTime::Inv_WeekDay;
91 }
92
93 wxDateTime::Tm::Tm(const struct tm& tm)
94 {
95 sec = tm.tm_sec;
96 min = tm.tm_min;
97 hour = tm.tm_hour;
98 mday = tm.tm_mday;
99 mon = tm.tm_mon;
100 year = 1900 + tm.tm_year;
101 wday = tm.tm_wday;
102 yday = tm.tm_yday;
103 }
104
105 bool wxDateTime::Tm::IsValid() const
106 {
107 // we allow for the leap seconds, although we don't use them (yet)
108 return (year != wxDateTime::Inv_Year) && (mon < 12) &&
109 (mday < gs_daysInMonth[IsLeapYear(year)][mon]) &&
110 (hour < 24) && (min < 60) && (sec < 62);
111 }
112
113 void wxDateTime::Tm::ComputeWeekDay()
114 {
115 wxFAIL_MSG(_T("TODO"));
116 }
117
118 // ----------------------------------------------------------------------------
119 // static functions
120 // ----------------------------------------------------------------------------
121
122 /* static */
123 bool wxDateTime::IsLeapYear(int year, wxDateTime::Calendar cal)
124 {
125 if ( cal == Gregorian )
126 {
127 // in Gregorian calendar leap years are those divisible by 4 except
128 // those divisible by 100 unless they're also divisible by 400
129 // (in some countries, like Russia and Greece, additional corrections
130 // exist, but they won't manifest themselves until 2700)
131 return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
132 }
133 else if ( cal == Julian )
134 {
135 // in Julian calendar the rule is simpler
136 return year % 4 == 0;
137 }
138 else
139 {
140 wxFAIL_MSG(_T("unknown calendar"));
141
142 return FALSE;
143 }
144 }
145
146 /* static */
147 void wxDateTime::SetCountry(wxDateTime::Country country)
148 {
149 ms_country = country;
150 }
151
152 /* static */
153 int wxDateTime::ConvertYearToBC(int year)
154 {
155 // year 0 is BC 1
156 return year > 0 ? year : year - 1;
157 }
158
159 /* static */
160 int wxDateTime::GetCurrentYear(wxDateTime::Calendar cal)
161 {
162 switch ( cal )
163 {
164 case Gregorian:
165 return Now().GetYear();
166
167 case Julian:
168 wxFAIL_MSG(_T("TODO"));
169 break;
170
171 default:
172 wxFAIL_MSG(_T("unsupported calendar"));
173 break;
174 }
175
176 return Inv_Year;
177 }
178
179 /* static */
180 wxDateTime::Month wxDateTime::GetCurrentMonth(wxDateTime::Calendar cal)
181 {
182 switch ( cal )
183 {
184 case Gregorian:
185 return Now().GetMonth();
186 break;
187
188 case Julian:
189 wxFAIL_MSG(_T("TODO"));
190 break;
191
192 default:
193 wxFAIL_MSG(_T("unsupported calendar"));
194 break;
195 }
196
197 return Inv_Month;
198 }
199
200 /* static */
201 wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(wxDateTime::Month month,
202 int year,
203 wxDateTime::Calendar cal)
204 {
205 wxCHECK_MSG( month < 12, 0, _T("invalid month") );
206
207 if ( cal == Gregorian || cal == Julian )
208 {
209 if ( year == Inv_Year )
210 {
211 // take the current year if none given
212 year = GetCurrentYear();
213 }
214
215 return gs_daysInMonth[IsLeapYear(year)][month];
216 }
217 else
218 {
219 wxFAIL_MSG(_T("unsupported calendar"));
220
221 return 0;
222 }
223 }
224
225 /* static */
226 wxString wxDateTime::GetMonthName(wxDateTime::Month month, bool abbr)
227 {
228 wxCHECK_MSG( month != Inv_Month, _T(""), _T("invalid month") );
229
230 tm tm = { 0, 0, 0, 1, month, 76 }; // any year will do
231
232 return CallStrftime(abbr ? _T("%b") : _T("%B"), &tm);
233 }
234
235 /* static */
236 wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday, bool abbr)
237 {
238 wxCHECK_MSG( wday != Inv_WeekDay, _T(""), _T("invalid weekday") );
239
240 // take some arbitrary Sunday
241 tm tm = { 0, 0, 0, 28, Nov, 99 };
242
243 // and offset it by the number of days needed to get
244 tm.tm_mday += wday;
245
246 return CallStrftime(abbr ? _T("%a") : _T("%A"), &tm);
247 }
248
249 // ----------------------------------------------------------------------------
250 // constructors and assignment operators
251 // ----------------------------------------------------------------------------
252
253 wxDateTime& wxDateTime::Set(const struct tm& tm1)
254 {
255 wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
256
257 tm tm2(tm1);
258 time_t timet = mktime(&tm2);
259 if ( timet == (time_t)(-1) )
260 {
261 wxFAIL_MSG(_T("Invalid time"));
262
263 return ms_InvDateTime;
264 }
265 else
266 {
267 return Set(timet);
268 }
269 }
270
271 wxDateTime& wxDateTime::Set(wxDateTime_t hour,
272 wxDateTime_t minute,
273 wxDateTime_t second,
274 wxDateTime_t millisec)
275 {
276 wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
277
278 // we allow seconds to be 61 to account for the leap seconds, even if we
279 // don't use them really
280 wxCHECK_MSG( hour < 24 && second < 62 && minute < 60 && millisec < 1000,
281 ms_InvDateTime,
282 _T("Invalid time in wxDateTime::Set()") );
283
284 // get the current date from system
285 time_t timet = GetTimeNow();
286 struct tm *tm = localtime(&timet);
287
288 // adjust the time
289 tm->tm_hour = hour;
290 tm->tm_min = minute;
291 tm->tm_sec = second;
292
293 (void)Set(*tm);
294
295 // and finally adjust milliseconds
296 return SetMillisecond(millisec);
297 }
298
299 wxDateTime& wxDateTime::Set(wxDateTime_t day,
300 Month month,
301 int year,
302 wxDateTime_t hour,
303 wxDateTime_t minute,
304 wxDateTime_t second,
305 wxDateTime_t millisec)
306 {
307 wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
308
309 wxCHECK_MSG( hour < 24 && second < 62 && minute < 60 && millisec < 1000,
310 ms_InvDateTime,
311 _T("Invalid time in wxDateTime::Set()") );
312
313 if ( year == Inv_Year )
314 year = GetCurrentYear();
315 if ( month == Inv_Month )
316 month = GetCurrentMonth();
317
318 wxCHECK_MSG( day < GetNumberOfDays(month, year), ms_InvDateTime,
319 _T("Invalid date in wxDateTime::Set()") );
320
321 // the range of time_t type (inclusive)
322 static const int yearMinInRange = 1970;
323 static const int yearMaxInRange = 2037;
324
325 // test only the year instead of testing for the exact end of the Unix
326 // time_t range - it doesn't bring anything to do more precise checks
327 if ( year >= yearMaxInRange && year <= yearMaxInRange )
328 {
329 // use the standard library version if the date is in range - this is
330 // probably more efficient than our code
331 struct tm tm;
332 tm.tm_year = year - 1900;
333 tm.tm_mon = month;
334 tm.tm_mday = day;
335 tm.tm_hour = hour;
336 tm.tm_min = minute;
337 tm.tm_sec = second;
338
339 (void)Set(tm);
340
341 // and finally adjust milliseconds
342 return SetMillisecond(millisec);
343 }
344 else
345 {
346 // do time calculations ourselves: we want to calculate the number of
347 // milliseconds between the given date and the epoch (necessarily
348 // negative)
349 wxFAIL_MSG(_T("TODO"));
350 }
351
352 return *this;
353 }
354
355 // ----------------------------------------------------------------------------
356 // time_t <-> broken down time conversions
357 // ----------------------------------------------------------------------------
358
359 wxDateTime::Tm wxDateTime::GetTm() const
360 {
361 wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
362
363 time_t time = GetTicks();
364 if ( time != (time_t)-1 )
365 {
366 // use C RTL functions
367 tm *tm = localtime(&time);
368
369 // should never happen
370 wxCHECK_MSG( tm, Tm(), _T("localtime() failed") );
371
372 return Tm(*tm);
373 }
374 else
375 {
376 wxFAIL_MSG(_T("TODO"));
377
378 return Tm();
379 }
380 }
381
382 wxDateTime& wxDateTime::SetYear(int year)
383 {
384 wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
385
386 Tm tm(GetTm());
387 tm.year = year;
388 Set(tm);
389
390 return *this;
391 }
392
393 wxDateTime& wxDateTime::SetMonth(Month month)
394 {
395 wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
396
397 Tm tm(GetTm());
398 tm.mon = month;
399 Set(tm);
400
401 return *this;
402 }
403
404 wxDateTime& wxDateTime::SetDay(wxDateTime_t mday)
405 {
406 wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
407
408 Tm tm(GetTm());
409 tm.mday = mday;
410 Set(tm);
411
412 return *this;
413 }
414
415 wxDateTime& wxDateTime::SetHour(wxDateTime_t hour)
416 {
417 wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
418
419 Tm tm(GetTm());
420 tm.hour = hour;
421 Set(tm);
422
423 return *this;
424 }
425
426 wxDateTime& wxDateTime::SetMinute(wxDateTime_t min)
427 {
428 wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
429
430 Tm tm(GetTm());
431 tm.min = min;
432 Set(tm);
433
434 return *this;
435 }
436
437 wxDateTime& wxDateTime::SetSecond(wxDateTime_t sec)
438 {
439 wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
440
441 Tm tm(GetTm());
442 tm.sec = sec;
443 Set(tm);
444
445 return *this;
446 }
447
448 wxDateTime& wxDateTime::SetMillisecond(wxDateTime_t millisecond)
449 {
450 wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") );
451
452 // we don't need to use GetTm() for this one
453 m_time -= m_time % 1000l;
454 m_time += millisecond;
455
456 return *this;
457 }
458
459 // ----------------------------------------------------------------------------
460 // wxDateTime arithmetics
461 // ----------------------------------------------------------------------------
462
463 wxDateTime& wxDateTime::Add(const wxDateSpan& diff)
464 {
465 Tm tm(GetTm());
466
467 tm.year += diff.GetYears();
468 tm.mon += diff.GetMonths();
469 tm.mday += diff.GetTotalDays();
470
471 Set(tm);
472
473 return *this;
474 }
475
476 // ----------------------------------------------------------------------------
477 // wxDateTime to/from text representations
478 // ----------------------------------------------------------------------------
479
480 wxString wxDateTime::Format(const wxChar *format) const
481 {
482 time_t time = GetTicks();
483 if ( time != (time_t)-1 )
484 {
485 // use strftime()
486 tm *tm = localtime(&time);
487
488 // should never happen
489 wxCHECK_MSG( tm, _T(""), _T("localtime() failed") );
490
491 return CallStrftime(format, tm);
492 }
493 else
494 {
495 wxFAIL_MSG(_T("TODO"));
496
497 return _T("");
498 }
499 }