]>
Commit | Line | Data |
---|---|---|
ccd6aacd VZ |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // Name: tests/datetime/datetime.cpp | |
3 | // Purpose: wxDateTime unit test | |
4 | // Author: Vadim Zeitlin | |
5 | // Created: 2004-06-23 (extracted from samples/console/console.cpp) | |
6 | // RCS-ID: $Id$ | |
7 | // Copyright: (c) 2004 Vadim Zeitlin <vadim@wxwindows.org> | |
8 | /////////////////////////////////////////////////////////////////////////////// | |
9 | ||
10 | // ---------------------------------------------------------------------------- | |
11 | // headers | |
12 | // ---------------------------------------------------------------------------- | |
13 | ||
8899b155 | 14 | #include "testprec.h" |
ccd6aacd VZ |
15 | |
16 | #ifdef __BORLANDC__ | |
17 | #pragma hdrstop | |
18 | #endif | |
19 | ||
20 | #ifndef WX_PRECOMP | |
21 | #endif // WX_PRECOMP | |
22 | ||
23 | #include "wx/datetime.h" | |
24 | ||
ccd6aacd VZ |
25 | // ---------------------------------------------------------------------------- |
26 | // broken down date representation used for testing | |
27 | // ---------------------------------------------------------------------------- | |
28 | ||
29 | struct Date | |
30 | { | |
31 | wxDateTime::wxDateTime_t day; | |
32 | wxDateTime::Month month; | |
33 | int year; | |
34 | wxDateTime::wxDateTime_t hour, min, sec; | |
35 | double jdn; | |
36 | wxDateTime::WeekDay wday; | |
37 | time_t gmticks, ticks; | |
38 | ||
39 | void Init(const wxDateTime::Tm& tm) | |
40 | { | |
41 | day = tm.mday; | |
42 | month = tm.mon; | |
43 | year = tm.year; | |
44 | hour = tm.hour; | |
45 | min = tm.min; | |
46 | sec = tm.sec; | |
47 | jdn = 0.0; | |
48 | gmticks = ticks = -1; | |
49 | } | |
50 | ||
51 | wxDateTime DT() const | |
52 | { return wxDateTime(day, month, year, hour, min, sec); } | |
53 | ||
54 | bool SameDay(const wxDateTime::Tm& tm) const | |
55 | { | |
56 | return day == tm.mday && month == tm.mon && year == tm.year; | |
57 | } | |
58 | ||
59 | wxString Format() const | |
60 | { | |
61 | wxString s; | |
62 | s.Printf(_T("%02d:%02d:%02d %10s %02d, %4d%s"), | |
63 | hour, min, sec, | |
64 | wxDateTime::GetMonthName(month).c_str(), | |
65 | day, | |
66 | abs(wxDateTime::ConvertYearToBC(year)), | |
67 | year > 0 ? _T("AD") : _T("BC")); | |
68 | return s; | |
69 | } | |
70 | ||
71 | wxString FormatDate() const | |
72 | { | |
73 | wxString s; | |
74 | s.Printf(_T("%02d-%s-%4d%s"), | |
75 | day, | |
76 | wxDateTime::GetMonthName(month, wxDateTime::Name_Abbr).c_str(), | |
77 | abs(wxDateTime::ConvertYearToBC(year)), | |
78 | year > 0 ? _T("AD") : _T("BC")); | |
79 | return s; | |
80 | } | |
81 | }; | |
82 | ||
83 | // ---------------------------------------------------------------------------- | |
84 | // test data | |
85 | // ---------------------------------------------------------------------------- | |
86 | ||
87 | static const Date testDates[] = | |
88 | { | |
89 | { 1, wxDateTime::Jan, 1970, 00, 00, 00, 2440587.5, wxDateTime::Thu, 0, -3600 }, | |
90 | { 7, wxDateTime::Feb, 2036, 00, 00, 00, 2464730.5, wxDateTime::Thu, -1, -1 }, | |
91 | { 8, wxDateTime::Feb, 2036, 00, 00, 00, 2464731.5, wxDateTime::Fri, -1, -1 }, | |
92 | { 1, wxDateTime::Jan, 2037, 00, 00, 00, 2465059.5, wxDateTime::Thu, -1, -1 }, | |
93 | { 1, wxDateTime::Jan, 2038, 00, 00, 00, 2465424.5, wxDateTime::Fri, -1, -1 }, | |
94 | { 21, wxDateTime::Jan, 2222, 00, 00, 00, 2532648.5, wxDateTime::Mon, -1, -1 }, | |
95 | { 29, wxDateTime::May, 1976, 12, 00, 00, 2442928.0, wxDateTime::Sat, 202219200, 202212000 }, | |
96 | { 29, wxDateTime::Feb, 1976, 00, 00, 00, 2442837.5, wxDateTime::Sun, 194400000, 194396400 }, | |
97 | { 1, wxDateTime::Jan, 1900, 12, 00, 00, 2415021.0, wxDateTime::Mon, -1, -1 }, | |
98 | { 1, wxDateTime::Jan, 1900, 00, 00, 00, 2415020.5, wxDateTime::Mon, -1, -1 }, | |
99 | { 15, wxDateTime::Oct, 1582, 00, 00, 00, 2299160.5, wxDateTime::Fri, -1, -1 }, | |
100 | { 4, wxDateTime::Oct, 1582, 00, 00, 00, 2299149.5, wxDateTime::Mon, -1, -1 }, | |
101 | { 1, wxDateTime::Mar, 1, 00, 00, 00, 1721484.5, wxDateTime::Thu, -1, -1 }, | |
102 | { 1, wxDateTime::Jan, 1, 00, 00, 00, 1721425.5, wxDateTime::Mon, -1, -1 }, | |
103 | { 31, wxDateTime::Dec, 0, 00, 00, 00, 1721424.5, wxDateTime::Sun, -1, -1 }, | |
104 | { 1, wxDateTime::Jan, 0, 00, 00, 00, 1721059.5, wxDateTime::Sat, -1, -1 }, | |
105 | { 12, wxDateTime::Aug, -1234, 00, 00, 00, 1270573.5, wxDateTime::Fri, -1, -1 }, | |
106 | { 12, wxDateTime::Aug, -4000, 00, 00, 00, 260313.5, wxDateTime::Sat, -1, -1 }, | |
107 | { 24, wxDateTime::Nov, -4713, 00, 00, 00, -0.5, wxDateTime::Mon, -1, -1 }, | |
108 | }; | |
109 | ||
110 | ||
111 | // ---------------------------------------------------------------------------- | |
112 | // test class | |
113 | // ---------------------------------------------------------------------------- | |
114 | ||
115 | class DateTimeTestCase : public CppUnit::TestCase | |
116 | { | |
117 | public: | |
118 | DateTimeTestCase() { } | |
119 | ||
120 | private: | |
121 | CPPUNIT_TEST_SUITE( DateTimeTestCase ); | |
122 | CPPUNIT_TEST( TestLeapYears ); | |
123 | CPPUNIT_TEST( TestTimeSet ); | |
124 | CPPUNIT_TEST( TestTimeJDN ); | |
125 | CPPUNIT_TEST( TestTimeWNumber ); | |
126 | CPPUNIT_TEST( TestTimeWDays ); | |
127 | CPPUNIT_TEST( TestTimeDST ); | |
128 | CPPUNIT_TEST( TestTimeFormat ); | |
129 | CPPUNIT_TEST( TestTimeTicks ); | |
130 | CPPUNIT_TEST( TestTimeParse ); | |
131 | CPPUNIT_TEST( TestTimeArithmetics ); | |
132 | CPPUNIT_TEST_SUITE_END(); | |
133 | ||
134 | void TestLeapYears(); | |
135 | void TestTimeSet(); | |
136 | void TestTimeJDN(); | |
137 | void TestTimeWNumber(); | |
138 | void TestTimeWDays(); | |
139 | void TestTimeDST(); | |
140 | void TestTimeFormat(); | |
141 | void TestTimeTicks(); | |
142 | void TestTimeParse(); | |
143 | void TestTimeArithmetics(); | |
144 | ||
145 | DECLARE_NO_COPY_CLASS(DateTimeTestCase) | |
146 | }; | |
147 | ||
148 | // register in the unnamed registry so that these tests are run by default | |
149 | CPPUNIT_TEST_SUITE_REGISTRATION( DateTimeTestCase ); | |
150 | ||
151 | // also include in it's own registry so that these tests can be run alone | |
152 | CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( DateTimeTestCase, "DateTimeTestCase" ); | |
153 | ||
154 | // ============================================================================ | |
155 | // implementation | |
156 | // ============================================================================ | |
157 | ||
158 | // test leap years detection | |
159 | void DateTimeTestCase::TestLeapYears() | |
160 | { | |
161 | static const struct LeapYearTestData | |
162 | { | |
163 | int year; | |
164 | bool isLeap; | |
165 | } years[] = | |
166 | { | |
167 | { 1900, false }, | |
168 | { 1990, false }, | |
169 | { 1976, true }, | |
170 | { 2000, true }, | |
171 | { 2030, false }, | |
172 | { 1984, true }, | |
173 | { 2100, false }, | |
174 | { 2400, true }, | |
175 | }; | |
176 | ||
177 | for ( size_t n = 0; n < WXSIZEOF(years); n++ ) | |
178 | { | |
179 | const LeapYearTestData& y = years[n]; | |
180 | ||
181 | CPPUNIT_ASSERT( wxDateTime::IsLeapYear(y.year) == y.isLeap ); | |
182 | } | |
183 | } | |
184 | ||
185 | // test constructing wxDateTime objects | |
186 | void DateTimeTestCase::TestTimeSet() | |
187 | { | |
188 | for ( size_t n = 0; n < WXSIZEOF(testDates); n++ ) | |
189 | { | |
190 | const Date& d1 = testDates[n]; | |
191 | wxDateTime dt = d1.DT(); | |
192 | ||
193 | Date d2; | |
194 | d2.Init(dt.GetTm()); | |
195 | ||
196 | wxString s1 = d1.Format(), | |
197 | s2 = d2.Format(); | |
198 | ||
199 | CPPUNIT_ASSERT( s1 == s2 ); | |
200 | } | |
201 | } | |
202 | ||
203 | // test conversions to JDN &c | |
204 | void DateTimeTestCase::TestTimeJDN() | |
205 | { | |
206 | for ( size_t n = 0; n < WXSIZEOF(testDates); n++ ) | |
207 | { | |
208 | const Date& d = testDates[n]; | |
209 | wxDateTime dt(d.day, d.month, d.year, d.hour, d.min, d.sec); | |
210 | double jdn = dt.GetJulianDayNumber(); | |
211 | ||
212 | CPPUNIT_ASSERT( jdn == d.jdn ); | |
e3559425 VZ |
213 | |
214 | dt.Set(jdn); | |
215 | CPPUNIT_ASSERT( dt.GetJulianDayNumber() == jdn ); | |
ccd6aacd VZ |
216 | } |
217 | } | |
218 | ||
219 | // test week days computation | |
220 | void DateTimeTestCase::TestTimeWDays() | |
221 | { | |
222 | // test GetWeekDay() | |
223 | size_t n; | |
224 | for ( n = 0; n < WXSIZEOF(testDates); n++ ) | |
225 | { | |
226 | const Date& d = testDates[n]; | |
227 | wxDateTime dt(d.day, d.month, d.year, d.hour, d.min, d.sec); | |
228 | ||
229 | wxDateTime::WeekDay wday = dt.GetWeekDay(); | |
230 | CPPUNIT_ASSERT( wday == d.wday ); | |
231 | } | |
232 | ||
233 | // test SetToWeekDay() | |
234 | struct WeekDateTestData | |
235 | { | |
236 | Date date; // the real date (precomputed) | |
237 | int nWeek; // its week index in the month | |
238 | wxDateTime::WeekDay wday; // the weekday | |
239 | wxDateTime::Month month; // the month | |
240 | int year; // and the year | |
241 | ||
242 | wxString Format() const | |
243 | { | |
244 | wxString s, which; | |
245 | switch ( nWeek < -1 ? -nWeek : nWeek ) | |
246 | { | |
247 | case 1: which = _T("first"); break; | |
248 | case 2: which = _T("second"); break; | |
249 | case 3: which = _T("third"); break; | |
250 | case 4: which = _T("fourth"); break; | |
251 | case 5: which = _T("fifth"); break; | |
252 | ||
253 | case -1: which = _T("last"); break; | |
254 | } | |
255 | ||
256 | if ( nWeek < -1 ) | |
257 | { | |
258 | which += _T(" from end"); | |
259 | } | |
260 | ||
261 | s.Printf(_T("The %s %s of %s in %d"), | |
262 | which.c_str(), | |
263 | wxDateTime::GetWeekDayName(wday).c_str(), | |
264 | wxDateTime::GetMonthName(month).c_str(), | |
265 | year); | |
266 | ||
267 | return s; | |
268 | } | |
269 | }; | |
270 | ||
271 | // the array data was generated by the following python program | |
272 | /* | |
273 | from DateTime import * | |
274 | from whrandom import * | |
275 | from string import * | |
276 | ||
277 | monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ] | |
278 | wdayNames = [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ] | |
279 | ||
280 | week = DateTimeDelta(7) | |
281 | ||
282 | for n in range(20): | |
283 | year = randint(1900, 2100) | |
284 | month = randint(1, 12) | |
285 | day = randint(1, 28) | |
286 | dt = DateTime(year, month, day) | |
287 | wday = dt.day_of_week | |
288 | ||
289 | countFromEnd = choice([-1, 1]) | |
290 | weekNum = 0; | |
291 | ||
292 | while dt.month is month: | |
293 | dt = dt - countFromEnd * week | |
294 | weekNum = weekNum + countFromEnd | |
295 | ||
296 | data = { 'day': rjust(`day`, 2), 'month': monthNames[month - 1], 'year': year, 'weekNum': rjust(`weekNum`, 2), 'wday': wdayNames[wday] } | |
297 | ||
298 | print "{ { %(day)s, wxDateTime::%(month)s, %(year)d }, %(weekNum)d, "\ | |
299 | "wxDateTime::%(wday)s, wxDateTime::%(month)s, %(year)d }," % data | |
300 | */ | |
301 | ||
302 | static const WeekDateTestData weekDatesTestData[] = | |
303 | { | |
304 | { { 20, wxDateTime::Mar, 2045 }, 3, wxDateTime::Mon, wxDateTime::Mar, 2045 }, | |
305 | { { 5, wxDateTime::Jun, 1985 }, -4, wxDateTime::Wed, wxDateTime::Jun, 1985 }, | |
306 | { { 12, wxDateTime::Nov, 1961 }, -3, wxDateTime::Sun, wxDateTime::Nov, 1961 }, | |
307 | { { 27, wxDateTime::Feb, 2093 }, -1, wxDateTime::Fri, wxDateTime::Feb, 2093 }, | |
308 | { { 4, wxDateTime::Jul, 2070 }, -4, wxDateTime::Fri, wxDateTime::Jul, 2070 }, | |
309 | { { 2, wxDateTime::Apr, 1906 }, -5, wxDateTime::Mon, wxDateTime::Apr, 1906 }, | |
310 | { { 19, wxDateTime::Jul, 2023 }, -2, wxDateTime::Wed, wxDateTime::Jul, 2023 }, | |
311 | { { 5, wxDateTime::May, 1958 }, -4, wxDateTime::Mon, wxDateTime::May, 1958 }, | |
312 | { { 11, wxDateTime::Aug, 1900 }, 2, wxDateTime::Sat, wxDateTime::Aug, 1900 }, | |
313 | { { 14, wxDateTime::Feb, 1945 }, 2, wxDateTime::Wed, wxDateTime::Feb, 1945 }, | |
314 | { { 25, wxDateTime::Jul, 1967 }, -1, wxDateTime::Tue, wxDateTime::Jul, 1967 }, | |
315 | { { 9, wxDateTime::May, 1916 }, -4, wxDateTime::Tue, wxDateTime::May, 1916 }, | |
316 | { { 20, wxDateTime::Jun, 1927 }, 3, wxDateTime::Mon, wxDateTime::Jun, 1927 }, | |
317 | { { 2, wxDateTime::Aug, 2000 }, 1, wxDateTime::Wed, wxDateTime::Aug, 2000 }, | |
318 | { { 20, wxDateTime::Apr, 2044 }, 3, wxDateTime::Wed, wxDateTime::Apr, 2044 }, | |
319 | { { 20, wxDateTime::Feb, 1932 }, -2, wxDateTime::Sat, wxDateTime::Feb, 1932 }, | |
320 | { { 25, wxDateTime::Jul, 2069 }, 4, wxDateTime::Thu, wxDateTime::Jul, 2069 }, | |
321 | { { 3, wxDateTime::Apr, 1925 }, 1, wxDateTime::Fri, wxDateTime::Apr, 1925 }, | |
322 | { { 21, wxDateTime::Mar, 2093 }, 3, wxDateTime::Sat, wxDateTime::Mar, 2093 }, | |
323 | { { 3, wxDateTime::Dec, 2074 }, -5, wxDateTime::Mon, wxDateTime::Dec, 2074 }, | |
1c5d27e2 | 324 | |
ccd6aacd VZ |
325 | }; |
326 | ||
ccd6aacd VZ |
327 | wxDateTime dt; |
328 | for ( n = 0; n < WXSIZEOF(weekDatesTestData); n++ ) | |
329 | { | |
330 | const WeekDateTestData& wd = weekDatesTestData[n]; | |
331 | ||
332 | dt.SetToWeekDay(wd.wday, wd.nWeek, wd.month, wd.year); | |
333 | ||
334 | const Date& d = wd.date; | |
335 | CPPUNIT_ASSERT( d.SameDay(dt.GetTm()) ); | |
336 | } | |
337 | } | |
338 | ||
339 | // test the computation of (ISO) week numbers | |
340 | void DateTimeTestCase::TestTimeWNumber() | |
341 | { | |
342 | struct WeekNumberTestData | |
343 | { | |
344 | Date date; // the date | |
345 | wxDateTime::wxDateTime_t week; // the week number in the year | |
346 | wxDateTime::wxDateTime_t wmon; // the week number in the month | |
347 | wxDateTime::wxDateTime_t wmon2; // same but week starts with Sun | |
348 | wxDateTime::wxDateTime_t dnum; // day number in the year | |
349 | }; | |
350 | ||
351 | // data generated with the following python script: | |
352 | /* | |
353 | from DateTime import * | |
354 | from whrandom import * | |
355 | from string import * | |
356 | ||
357 | monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ] | |
358 | wdayNames = [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ] | |
359 | ||
360 | def GetMonthWeek(dt): | |
361 | weekNumMonth = dt.iso_week[1] - DateTime(dt.year, dt.month, 1).iso_week[1] + 1 | |
362 | if weekNumMonth < 0: | |
363 | weekNumMonth = weekNumMonth + 53 | |
364 | return weekNumMonth | |
365 | ||
366 | def GetLastSundayBefore(dt): | |
367 | if dt.iso_week[2] == 7: | |
368 | return dt | |
369 | else: | |
370 | return dt - DateTimeDelta(dt.iso_week[2]) | |
371 | ||
372 | for n in range(20): | |
373 | year = randint(1900, 2100) | |
374 | month = randint(1, 12) | |
375 | day = randint(1, 28) | |
376 | dt = DateTime(year, month, day) | |
377 | dayNum = dt.day_of_year | |
378 | weekNum = dt.iso_week[1] | |
379 | weekNumMonth = GetMonthWeek(dt) | |
380 | ||
381 | weekNumMonth2 = 0 | |
382 | dtSunday = GetLastSundayBefore(dt) | |
383 | ||
384 | while dtSunday >= GetLastSundayBefore(DateTime(dt.year, dt.month, 1)): | |
385 | weekNumMonth2 = weekNumMonth2 + 1 | |
386 | dtSunday = dtSunday - DateTimeDelta(7) | |
387 | ||
388 | data = { 'day': rjust(`day`, 2), \ | |
389 | 'month': monthNames[month - 1], \ | |
390 | 'year': year, \ | |
391 | 'weekNum': rjust(`weekNum`, 2), \ | |
392 | 'weekNumMonth': weekNumMonth, \ | |
393 | 'weekNumMonth2': weekNumMonth2, \ | |
394 | 'dayNum': rjust(`dayNum`, 3) } | |
395 | ||
396 | print " { { %(day)s, "\ | |
397 | "wxDateTime::%(month)s, "\ | |
398 | "%(year)d }, "\ | |
399 | "%(weekNum)s, "\ | |
400 | "%(weekNumMonth)s, "\ | |
401 | "%(weekNumMonth2)s, "\ | |
402 | "%(dayNum)s }," % data | |
403 | ||
404 | */ | |
405 | static const WeekNumberTestData weekNumberTestDates[] = | |
406 | { | |
407 | { { 27, wxDateTime::Dec, 1966 }, 52, 5, 5, 361 }, | |
408 | { { 22, wxDateTime::Jul, 1926 }, 29, 4, 4, 203 }, | |
409 | { { 22, wxDateTime::Oct, 2076 }, 43, 4, 4, 296 }, | |
410 | { { 1, wxDateTime::Jul, 1967 }, 26, 1, 1, 182 }, | |
411 | { { 8, wxDateTime::Nov, 2004 }, 46, 2, 2, 313 }, | |
412 | { { 21, wxDateTime::Mar, 1920 }, 12, 3, 4, 81 }, | |
413 | { { 7, wxDateTime::Jan, 1965 }, 1, 2, 2, 7 }, | |
414 | { { 19, wxDateTime::Oct, 1999 }, 42, 4, 4, 292 }, | |
415 | { { 13, wxDateTime::Aug, 1955 }, 32, 2, 2, 225 }, | |
416 | { { 18, wxDateTime::Jul, 2087 }, 29, 3, 3, 199 }, | |
417 | { { 2, wxDateTime::Sep, 2028 }, 35, 1, 1, 246 }, | |
418 | { { 28, wxDateTime::Jul, 1945 }, 30, 5, 4, 209 }, | |
419 | { { 15, wxDateTime::Jun, 1901 }, 24, 3, 3, 166 }, | |
420 | { { 10, wxDateTime::Oct, 1939 }, 41, 3, 2, 283 }, | |
421 | { { 3, wxDateTime::Dec, 1965 }, 48, 1, 1, 337 }, | |
422 | { { 23, wxDateTime::Feb, 1940 }, 8, 4, 4, 54 }, | |
423 | { { 2, wxDateTime::Jan, 1987 }, 1, 1, 1, 2 }, | |
424 | { { 11, wxDateTime::Aug, 2079 }, 32, 2, 2, 223 }, | |
425 | { { 2, wxDateTime::Feb, 2063 }, 5, 1, 1, 33 }, | |
426 | { { 16, wxDateTime::Oct, 1942 }, 42, 3, 3, 289 }, | |
1c5d27e2 VZ |
427 | { { 30, wxDateTime::Dec, 2003 }, 1, 5, 5, 364 }, |
428 | { { 2, wxDateTime::Jan, 2004 }, 1, 1, 1, 2 }, | |
ccd6aacd VZ |
429 | }; |
430 | ||
431 | for ( size_t n = 0; n < WXSIZEOF(weekNumberTestDates); n++ ) | |
432 | { | |
433 | const WeekNumberTestData& wn = weekNumberTestDates[n]; | |
434 | const Date& d = wn.date; | |
435 | ||
436 | wxDateTime dt = d.DT(); | |
437 | ||
438 | wxDateTime::wxDateTime_t | |
439 | week = dt.GetWeekOfYear(wxDateTime::Monday_First), | |
440 | wmon = dt.GetWeekOfMonth(wxDateTime::Monday_First), | |
441 | wmon2 = dt.GetWeekOfMonth(wxDateTime::Sunday_First), | |
442 | dnum = dt.GetDayOfYear(); | |
443 | ||
444 | CPPUNIT_ASSERT( dnum == wn.dnum ); | |
445 | CPPUNIT_ASSERT( wmon == wn.wmon ); | |
446 | CPPUNIT_ASSERT( wmon2 == wn.wmon2 ); | |
447 | CPPUNIT_ASSERT( week == wn.week ); | |
448 | ||
4c27e2fa VZ |
449 | int year = d.year; |
450 | if ( week == 1 && d.month != wxDateTime::Jan ) | |
451 | { | |
452 | // this means we're in the first week of the next year | |
453 | year++; | |
454 | } | |
455 | ||
456 | wxDateTime | |
457 | dt2 = wxDateTime::SetToWeekOfYear(year, week, dt.GetWeekDay()); | |
ccd6aacd VZ |
458 | CPPUNIT_ASSERT( dt2 == dt ); |
459 | } | |
460 | } | |
461 | ||
462 | // test DST applicability | |
463 | void DateTimeTestCase::TestTimeDST() | |
464 | { | |
465 | // taken from http://www.energy.ca.gov/daylightsaving.html | |
466 | static const Date datesDST[2][2004 - 1900 + 1] = | |
467 | { | |
468 | { | |
469 | { 1, wxDateTime::Apr, 1990 }, | |
470 | { 7, wxDateTime::Apr, 1991 }, | |
471 | { 5, wxDateTime::Apr, 1992 }, | |
472 | { 4, wxDateTime::Apr, 1993 }, | |
473 | { 3, wxDateTime::Apr, 1994 }, | |
474 | { 2, wxDateTime::Apr, 1995 }, | |
475 | { 7, wxDateTime::Apr, 1996 }, | |
476 | { 6, wxDateTime::Apr, 1997 }, | |
477 | { 5, wxDateTime::Apr, 1998 }, | |
478 | { 4, wxDateTime::Apr, 1999 }, | |
479 | { 2, wxDateTime::Apr, 2000 }, | |
480 | { 1, wxDateTime::Apr, 2001 }, | |
481 | { 7, wxDateTime::Apr, 2002 }, | |
482 | { 6, wxDateTime::Apr, 2003 }, | |
483 | { 4, wxDateTime::Apr, 2004 }, | |
484 | }, | |
485 | { | |
486 | { 28, wxDateTime::Oct, 1990 }, | |
487 | { 27, wxDateTime::Oct, 1991 }, | |
488 | { 25, wxDateTime::Oct, 1992 }, | |
489 | { 31, wxDateTime::Oct, 1993 }, | |
490 | { 30, wxDateTime::Oct, 1994 }, | |
491 | { 29, wxDateTime::Oct, 1995 }, | |
492 | { 27, wxDateTime::Oct, 1996 }, | |
493 | { 26, wxDateTime::Oct, 1997 }, | |
494 | { 25, wxDateTime::Oct, 1998 }, | |
495 | { 31, wxDateTime::Oct, 1999 }, | |
496 | { 29, wxDateTime::Oct, 2000 }, | |
497 | { 28, wxDateTime::Oct, 2001 }, | |
498 | { 27, wxDateTime::Oct, 2002 }, | |
499 | { 26, wxDateTime::Oct, 2003 }, | |
500 | { 31, wxDateTime::Oct, 2004 }, | |
501 | } | |
502 | }; | |
503 | ||
504 | for ( int year = 1990; year < 2005; year++ ) | |
505 | { | |
506 | wxDateTime dtBegin = wxDateTime::GetBeginDST(year, wxDateTime::USA), | |
507 | dtEnd = wxDateTime::GetEndDST(year, wxDateTime::USA); | |
508 | ||
509 | size_t n = year - 1990; | |
510 | const Date& dBegin = datesDST[0][n]; | |
511 | const Date& dEnd = datesDST[1][n]; | |
512 | ||
513 | CPPUNIT_ASSERT( dBegin.SameDay(dtBegin.GetTm()) ); | |
514 | CPPUNIT_ASSERT( dEnd.SameDay(dtEnd.GetTm()) ); | |
515 | } | |
516 | } | |
517 | ||
518 | // test wxDateTime -> text conversion | |
519 | void DateTimeTestCase::TestTimeFormat() | |
520 | { | |
521 | // some information may be lost during conversion, so store what kind | |
522 | // of info should we recover after a round trip | |
523 | enum CompareKind | |
524 | { | |
525 | CompareNone, // don't try comparing | |
526 | CompareBoth, // dates and times should be identical | |
527 | CompareDate, // dates only | |
528 | CompareTime // time only | |
529 | }; | |
530 | ||
531 | static const struct | |
532 | { | |
533 | CompareKind compareKind; | |
534 | const wxChar *format; | |
535 | } formatTestFormats[] = | |
536 | { | |
537 | { CompareBoth, _T("---> %c") }, | |
538 | { CompareDate, _T("Date is %A, %d of %B, in year %Y") }, | |
539 | { CompareBoth, _T("Date is %x, time is %X") }, | |
540 | { CompareTime, _T("Time is %H:%M:%S or %I:%M:%S %p") }, | |
541 | { CompareNone, _T("The day of year: %j, the week of year: %W") }, | |
542 | { CompareDate, _T("ISO date without separators: %Y%m%d") }, | |
543 | }; | |
544 | ||
545 | static const Date formatTestDates[] = | |
546 | { | |
547 | { 29, wxDateTime::May, 1976, 18, 30, 00 }, | |
548 | { 31, wxDateTime::Dec, 1999, 23, 30, 00 }, | |
549 | #if 0 | |
550 | // this test can't work for other centuries because it uses two digit | |
551 | // years in formats, so don't even try it | |
552 | { 29, wxDateTime::May, 2076, 18, 30, 00 }, | |
553 | { 29, wxDateTime::Feb, 2400, 02, 15, 25 }, | |
554 | { 01, wxDateTime::Jan, -52, 03, 16, 47 }, | |
555 | #endif | |
556 | }; | |
557 | ||
558 | for ( size_t d = 0; d < WXSIZEOF(formatTestDates) + 1; d++ ) | |
559 | { | |
560 | wxDateTime dt = d == 0 ? wxDateTime::Now() : formatTestDates[d - 1].DT(); | |
561 | for ( size_t n = 0; n < WXSIZEOF(formatTestFormats); n++ ) | |
562 | { | |
563 | wxString s = dt.Format(formatTestFormats[n].format); | |
564 | ||
565 | // what can we recover? | |
566 | int kind = formatTestFormats[n].compareKind; | |
567 | ||
568 | // convert back | |
569 | wxDateTime dt2; | |
570 | const wxChar *result = dt2.ParseFormat(s, formatTestFormats[n].format); | |
571 | if ( !result ) | |
572 | { | |
573 | // converion failed - should it have? | |
574 | CPPUNIT_ASSERT( kind == CompareNone ); | |
575 | } | |
576 | else // conversion succeeded | |
577 | { | |
578 | // should have parsed the entire string | |
579 | CPPUNIT_ASSERT( !*result ); | |
580 | ||
581 | switch ( kind ) | |
582 | { | |
583 | case CompareBoth: | |
584 | CPPUNIT_ASSERT( dt2 == dt ); | |
585 | break; | |
586 | ||
587 | case CompareDate: | |
588 | CPPUNIT_ASSERT( dt.IsSameDate(dt2) ); | |
589 | break; | |
590 | ||
591 | case CompareTime: | |
592 | CPPUNIT_ASSERT( dt.IsSameTime(dt2) ); | |
593 | break; | |
594 | } | |
595 | } | |
596 | } | |
597 | } | |
598 | } | |
599 | ||
600 | void DateTimeTestCase::TestTimeTicks() | |
601 | { | |
602 | for ( size_t n = 0; n < WXSIZEOF(testDates); n++ ) | |
603 | { | |
604 | const Date& d = testDates[n]; | |
605 | if ( d.ticks == -1 ) | |
606 | continue; | |
607 | ||
608 | wxDateTime dt = d.DT(); | |
aa3698d5 RN |
609 | //RN: Translate according to test's time zone |
610 | //2nd param is to ignore DST - it's already factored | |
611 | //into Vadim's tests | |
612 | dt.MakeTimezone(wxDateTime::WEST, true); | |
ccd6aacd VZ |
613 | long ticks = (dt.GetValue() / 1000).ToLong(); |
614 | CPPUNIT_ASSERT( ticks == d.ticks ); | |
615 | ||
616 | dt = d.DT().ToTimezone(wxDateTime::GMT0); | |
617 | ticks = (dt.GetValue() / 1000).ToLong(); | |
618 | CPPUNIT_ASSERT( ticks == d.gmticks ); | |
619 | } | |
620 | } | |
621 | ||
622 | // test text -> wxDateTime conversion | |
623 | void DateTimeTestCase::TestTimeParse() | |
624 | { | |
625 | static const struct ParseTestData | |
626 | { | |
627 | const wxChar *format; | |
628 | Date date; | |
629 | bool good; | |
630 | } parseTestDates[] = | |
631 | { | |
632 | { _T("Sat, 18 Dec 1999 00:46:40 +0100"), { 18, wxDateTime::Dec, 1999, 00, 46, 40 }, true }, | |
633 | { _T("Wed, 1 Dec 1999 05:17:20 +0300"), { 1, wxDateTime::Dec, 1999, 03, 17, 20 }, true }, | |
634 | }; | |
635 | ||
636 | for ( size_t n = 0; n < WXSIZEOF(parseTestDates); n++ ) | |
637 | { | |
638 | const wxChar *format = parseTestDates[n].format; | |
639 | ||
640 | wxDateTime dt; | |
641 | if ( dt.ParseRfc822Date(format) ) | |
642 | { | |
643 | CPPUNIT_ASSERT( parseTestDates[n].good ); | |
644 | ||
645 | wxDateTime dtReal = parseTestDates[n].date.DT(); | |
aa3698d5 RN |
646 | //RN: We need this because the tests are based on |
647 | //a non-GMT time zone | |
648 | dtReal.MakeTimezone(wxDateTime::WEST, true); | |
ccd6aacd VZ |
649 | CPPUNIT_ASSERT( dt == dtReal ); |
650 | } | |
651 | else // failed to parse | |
652 | { | |
653 | CPPUNIT_ASSERT( !parseTestDates[n].good ); | |
654 | } | |
655 | } | |
656 | } | |
657 | ||
658 | void DateTimeTestCase::TestTimeArithmetics() | |
659 | { | |
660 | static const wxDateSpan testArithmData[] = | |
661 | { | |
662 | wxDateSpan::Day(), | |
663 | wxDateSpan::Week(), | |
664 | wxDateSpan::Month(), | |
665 | wxDateSpan::Year(), | |
666 | }; | |
667 | ||
668 | // the test will *not* work with arbitrary date! | |
669 | wxDateTime dt(2, wxDateTime::Dec, 1999), | |
670 | dt1, | |
671 | dt2; | |
672 | ||
673 | for ( size_t n = 0; n < WXSIZEOF(testArithmData); n++ ) | |
674 | { | |
675 | const wxDateSpan& span = testArithmData[n]; | |
676 | dt1 = dt + span; | |
677 | dt2 = dt - span; | |
678 | ||
679 | CPPUNIT_ASSERT( dt1 - span == dt ); | |
680 | CPPUNIT_ASSERT( dt2 + span == dt ); | |
681 | CPPUNIT_ASSERT( dt2 + 2*span == dt1 ); | |
682 | } | |
683 | } | |
684 |