]>
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) | |
ccd6aacd VZ |
6 | // Copyright: (c) 2004 Vadim Zeitlin <vadim@wxwindows.org> |
7 | /////////////////////////////////////////////////////////////////////////////// | |
8 | ||
9 | // ---------------------------------------------------------------------------- | |
10 | // headers | |
11 | // ---------------------------------------------------------------------------- | |
12 | ||
8899b155 | 13 | #include "testprec.h" |
ccd6aacd VZ |
14 | |
15 | #ifdef __BORLANDC__ | |
16 | #pragma hdrstop | |
17 | #endif | |
18 | ||
86d19346 VZ |
19 | #if wxUSE_DATETIME |
20 | ||
ccd6aacd | 21 | #ifndef WX_PRECOMP |
86d19346 | 22 | #include "wx/time.h" // wxGetTimeZone() |
ccd6aacd VZ |
23 | #endif // WX_PRECOMP |
24 | ||
1789c1c6 | 25 | #include "wx/wxcrt.h" // for wxStrstr() |
8605eb1a | 26 | |
a5f22686 | 27 | #include "testdate.h" |
b2eabfe8 | 28 | |
a480d0ab VZ |
29 | // to test Today() meaningfully we must be able to change the system date which |
30 | // is not usually the case, but if we're under Win32 we can try it -- define | |
31 | // the macro below to do it | |
32 | //#define CHANGE_SYSTEM_DATE | |
33 | ||
34 | #ifndef __WINDOWS__ | |
35 | #undef CHANGE_SYSTEM_DATE | |
36 | #endif | |
37 | ||
38 | #ifdef CHANGE_SYSTEM_DATE | |
39 | ||
40 | class DateChanger | |
41 | { | |
42 | public: | |
43 | DateChanger(int year, int month, int day, int hour, int min, int sec) | |
44 | { | |
45 | SYSTEMTIME st; | |
46 | st.wDay = day; | |
47 | st.wMonth = month; | |
48 | st.wYear = year; | |
49 | st.wHour = hour; | |
50 | st.wMinute = min; | |
51 | st.wSecond = sec; | |
52 | st.wMilliseconds = 0; | |
53 | ||
54 | ::GetSystemTime(&m_savedTime); | |
55 | ::GetTimeZoneInformation(&m_tzi); | |
56 | ||
57 | m_changed = ::SetSystemTime(&st) != 0; | |
58 | } | |
59 | ||
60 | ~DateChanger() | |
61 | { | |
62 | if ( m_changed ) | |
63 | { | |
64 | ::SetSystemTime(&m_savedTime); | |
65 | ::SetTimeZoneInformation(&m_tzi); | |
66 | } | |
67 | } | |
68 | ||
69 | private: | |
70 | SYSTEMTIME m_savedTime; | |
71 | TIME_ZONE_INFORMATION m_tzi; | |
72 | bool m_changed; | |
73 | }; | |
74 | ||
75 | #endif // CHANGE_SYSTEM_DATE | |
76 | ||
66f22f4a VZ |
77 | // helper function translating week day/month names from English to the current |
78 | // locale | |
79 | static wxString TranslateDate(const wxString& str) | |
80 | { | |
81 | // small optimization: if there are no alphabetic characters in the string, | |
82 | // there is nothing to translate | |
83 | wxString::const_iterator i, end = str.end(); | |
84 | for ( i = str.begin(); i != end; ++i ) | |
85 | { | |
86 | if ( isalpha(*i) ) | |
87 | break; | |
88 | } | |
89 | ||
90 | if ( i == end ) | |
91 | return str; | |
92 | ||
93 | wxString trans(str); | |
94 | ||
66f22f4a VZ |
95 | for ( wxDateTime::WeekDay wd = wxDateTime::Sun; |
96 | wd < wxDateTime::Inv_WeekDay; | |
97 | wxNextWDay(wd) ) | |
98 | { | |
99 | trans.Replace | |
100 | ( | |
e538985e | 101 | wxDateTime::GetEnglishWeekDayName(wd, wxDateTime::Name_Abbr), |
66f22f4a VZ |
102 | wxDateTime::GetWeekDayName(wd, wxDateTime::Name_Abbr) |
103 | ); | |
104 | } | |
105 | ||
66f22f4a VZ |
106 | for ( wxDateTime::Month mon = wxDateTime::Jan; |
107 | mon < wxDateTime::Inv_Month; | |
108 | wxNextMonth(mon) ) | |
109 | { | |
110 | trans.Replace | |
111 | ( | |
e538985e | 112 | wxDateTime::GetEnglishMonthName(mon, wxDateTime::Name_Abbr), |
66f22f4a VZ |
113 | wxDateTime::GetMonthName(mon, wxDateTime::Name_Abbr) |
114 | ); | |
115 | } | |
116 | ||
117 | return trans; | |
118 | } | |
119 | ||
ccd6aacd VZ |
120 | // ---------------------------------------------------------------------------- |
121 | // broken down date representation used for testing | |
122 | // ---------------------------------------------------------------------------- | |
123 | ||
124 | struct Date | |
125 | { | |
126 | wxDateTime::wxDateTime_t day; | |
127 | wxDateTime::Month month; | |
128 | int year; | |
129 | wxDateTime::wxDateTime_t hour, min, sec; | |
130 | double jdn; | |
131 | wxDateTime::WeekDay wday; | |
a669640b | 132 | time_t gmticks; |
1bf29a7a | 133 | |
ccd6aacd VZ |
134 | void Init(const wxDateTime::Tm& tm) |
135 | { | |
136 | day = tm.mday; | |
137 | month = tm.mon; | |
138 | year = tm.year; | |
139 | hour = tm.hour; | |
140 | min = tm.min; | |
141 | sec = tm.sec; | |
142 | jdn = 0.0; | |
a669640b | 143 | gmticks = -1; |
ccd6aacd VZ |
144 | } |
145 | ||
146 | wxDateTime DT() const | |
147 | { return wxDateTime(day, month, year, hour, min, sec); } | |
148 | ||
149 | bool SameDay(const wxDateTime::Tm& tm) const | |
150 | { | |
151 | return day == tm.mday && month == tm.mon && year == tm.year; | |
152 | } | |
153 | ||
154 | wxString Format() const | |
155 | { | |
156 | wxString s; | |
9a83f860 | 157 | s.Printf(wxT("%02d:%02d:%02d %10s %02d, %4d%s"), |
ccd6aacd VZ |
158 | hour, min, sec, |
159 | wxDateTime::GetMonthName(month).c_str(), | |
160 | day, | |
161 | abs(wxDateTime::ConvertYearToBC(year)), | |
9a83f860 | 162 | year > 0 ? wxT("AD") : wxT("BC")); |
ccd6aacd VZ |
163 | return s; |
164 | } | |
165 | ||
166 | wxString FormatDate() const | |
167 | { | |
168 | wxString s; | |
9a83f860 | 169 | s.Printf(wxT("%02d-%s-%4d%s"), |
ccd6aacd VZ |
170 | day, |
171 | wxDateTime::GetMonthName(month, wxDateTime::Name_Abbr).c_str(), | |
172 | abs(wxDateTime::ConvertYearToBC(year)), | |
9a83f860 | 173 | year > 0 ? wxT("AD") : wxT("BC")); |
ccd6aacd VZ |
174 | return s; |
175 | } | |
176 | }; | |
177 | ||
178 | // ---------------------------------------------------------------------------- | |
179 | // test data | |
180 | // ---------------------------------------------------------------------------- | |
181 | ||
182 | static const Date testDates[] = | |
183 | { | |
a669640b VZ |
184 | { 1, wxDateTime::Jan, 1970, 00, 00, 00, 2440587.5, wxDateTime::Thu, 0 }, |
185 | { 7, wxDateTime::Feb, 2036, 00, 00, 00, 2464730.5, wxDateTime::Thu, -1 }, | |
186 | { 8, wxDateTime::Feb, 2036, 00, 00, 00, 2464731.5, wxDateTime::Fri, -1 }, | |
187 | { 1, wxDateTime::Jan, 2037, 00, 00, 00, 2465059.5, wxDateTime::Thu, -1 }, | |
188 | { 1, wxDateTime::Jan, 2038, 00, 00, 00, 2465424.5, wxDateTime::Fri, -1 }, | |
189 | { 21, wxDateTime::Jan, 2222, 00, 00, 00, 2532648.5, wxDateTime::Mon, -1 }, | |
190 | { 29, wxDateTime::May, 1976, 12, 00, 00, 2442928.0, wxDateTime::Sat, 202219200 }, | |
191 | { 29, wxDateTime::Feb, 1976, 00, 00, 00, 2442837.5, wxDateTime::Sun, 194400000 }, | |
192 | { 1, wxDateTime::Jan, 1900, 12, 00, 00, 2415021.0, wxDateTime::Mon, -1 }, | |
193 | { 1, wxDateTime::Jan, 1900, 00, 00, 00, 2415020.5, wxDateTime::Mon, -1 }, | |
194 | { 15, wxDateTime::Oct, 1582, 00, 00, 00, 2299160.5, wxDateTime::Fri, -1 }, | |
195 | { 4, wxDateTime::Oct, 1582, 00, 00, 00, 2299149.5, wxDateTime::Mon, -1 }, | |
196 | { 1, wxDateTime::Mar, 1, 00, 00, 00, 1721484.5, wxDateTime::Thu, -1 }, | |
197 | { 1, wxDateTime::Jan, 1, 00, 00, 00, 1721425.5, wxDateTime::Mon, -1 }, | |
198 | { 31, wxDateTime::Dec, 0, 00, 00, 00, 1721424.5, wxDateTime::Sun, -1 }, | |
199 | { 1, wxDateTime::Jan, 0, 00, 00, 00, 1721059.5, wxDateTime::Sat, -1 }, | |
200 | { 12, wxDateTime::Aug, -1234, 00, 00, 00, 1270573.5, wxDateTime::Fri, -1 }, | |
201 | { 12, wxDateTime::Aug, -4000, 00, 00, 00, 260313.5, wxDateTime::Sat, -1 }, | |
202 | { 24, wxDateTime::Nov, -4713, 00, 00, 00, -0.5, wxDateTime::Mon, -1 }, | |
ccd6aacd VZ |
203 | }; |
204 | ||
205 | ||
206 | // ---------------------------------------------------------------------------- | |
207 | // test class | |
208 | // ---------------------------------------------------------------------------- | |
209 | ||
210 | class DateTimeTestCase : public CppUnit::TestCase | |
211 | { | |
212 | public: | |
213 | DateTimeTestCase() { } | |
214 | ||
215 | private: | |
216 | CPPUNIT_TEST_SUITE( DateTimeTestCase ); | |
217 | CPPUNIT_TEST( TestLeapYears ); | |
218 | CPPUNIT_TEST( TestTimeSet ); | |
219 | CPPUNIT_TEST( TestTimeJDN ); | |
220 | CPPUNIT_TEST( TestTimeWNumber ); | |
221 | CPPUNIT_TEST( TestTimeWDays ); | |
222 | CPPUNIT_TEST( TestTimeDST ); | |
223 | CPPUNIT_TEST( TestTimeFormat ); | |
2747a51b | 224 | CPPUNIT_TEST( TestTimeParse ); |
1bf29a7a | 225 | CPPUNIT_TEST( TestTimeSpanFormat ); |
ccd6aacd | 226 | CPPUNIT_TEST( TestTimeTicks ); |
8605eb1a VZ |
227 | CPPUNIT_TEST( TestParceRFC822 ); |
228 | CPPUNIT_TEST( TestDateParse ); | |
f3f2e255 | 229 | CPPUNIT_TEST( TestDateParseISO ); |
804eeca5 | 230 | CPPUNIT_TEST( TestDateTimeParse ); |
ccd6aacd | 231 | CPPUNIT_TEST( TestTimeArithmetics ); |
a480d0ab | 232 | CPPUNIT_TEST( TestDSTBug ); |
fb96cf85 | 233 | CPPUNIT_TEST( TestDateOnly ); |
ccd6aacd VZ |
234 | CPPUNIT_TEST_SUITE_END(); |
235 | ||
236 | void TestLeapYears(); | |
237 | void TestTimeSet(); | |
238 | void TestTimeJDN(); | |
239 | void TestTimeWNumber(); | |
240 | void TestTimeWDays(); | |
241 | void TestTimeDST(); | |
242 | void TestTimeFormat(); | |
2747a51b | 243 | void TestTimeParse(); |
1bf29a7a | 244 | void TestTimeSpanFormat(); |
ccd6aacd | 245 | void TestTimeTicks(); |
8605eb1a VZ |
246 | void TestParceRFC822(); |
247 | void TestDateParse(); | |
f3f2e255 | 248 | void TestDateParseISO(); |
804eeca5 | 249 | void TestDateTimeParse(); |
ccd6aacd | 250 | void TestTimeArithmetics(); |
a480d0ab | 251 | void TestDSTBug(); |
fb96cf85 | 252 | void TestDateOnly(); |
ccd6aacd VZ |
253 | |
254 | DECLARE_NO_COPY_CLASS(DateTimeTestCase) | |
255 | }; | |
256 | ||
257 | // register in the unnamed registry so that these tests are run by default | |
258 | CPPUNIT_TEST_SUITE_REGISTRATION( DateTimeTestCase ); | |
259 | ||
e3778b4d | 260 | // also include in its own registry so that these tests can be run alone |
ccd6aacd VZ |
261 | CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( DateTimeTestCase, "DateTimeTestCase" ); |
262 | ||
263 | // ============================================================================ | |
264 | // implementation | |
265 | // ============================================================================ | |
266 | ||
267 | // test leap years detection | |
268 | void DateTimeTestCase::TestLeapYears() | |
269 | { | |
270 | static const struct LeapYearTestData | |
271 | { | |
272 | int year; | |
273 | bool isLeap; | |
274 | } years[] = | |
275 | { | |
276 | { 1900, false }, | |
277 | { 1990, false }, | |
278 | { 1976, true }, | |
279 | { 2000, true }, | |
280 | { 2030, false }, | |
281 | { 1984, true }, | |
282 | { 2100, false }, | |
283 | { 2400, true }, | |
284 | }; | |
285 | ||
286 | for ( size_t n = 0; n < WXSIZEOF(years); n++ ) | |
287 | { | |
288 | const LeapYearTestData& y = years[n]; | |
289 | ||
15cb637c | 290 | CPPUNIT_ASSERT_EQUAL( y.isLeap, wxDateTime::IsLeapYear(y.year) ); |
ccd6aacd VZ |
291 | } |
292 | } | |
293 | ||
294 | // test constructing wxDateTime objects | |
295 | void DateTimeTestCase::TestTimeSet() | |
296 | { | |
297 | for ( size_t n = 0; n < WXSIZEOF(testDates); n++ ) | |
298 | { | |
299 | const Date& d1 = testDates[n]; | |
300 | wxDateTime dt = d1.DT(); | |
301 | ||
302 | Date d2; | |
303 | d2.Init(dt.GetTm()); | |
304 | ||
305 | wxString s1 = d1.Format(), | |
306 | s2 = d2.Format(); | |
307 | ||
15cb637c | 308 | CPPUNIT_ASSERT_EQUAL( s1, s2 ); |
ccd6aacd VZ |
309 | } |
310 | } | |
311 | ||
312 | // test conversions to JDN &c | |
313 | void DateTimeTestCase::TestTimeJDN() | |
314 | { | |
315 | for ( size_t n = 0; n < WXSIZEOF(testDates); n++ ) | |
316 | { | |
317 | const Date& d = testDates[n]; | |
318 | wxDateTime dt(d.day, d.month, d.year, d.hour, d.min, d.sec); | |
d26adb9d VZ |
319 | |
320 | // JDNs must be computed for UTC times | |
321 | double jdn = dt.FromUTC().GetJulianDayNumber(); | |
ccd6aacd | 322 | |
93a800a9 | 323 | CPPUNIT_ASSERT_EQUAL( d.jdn, jdn ); |
e3559425 VZ |
324 | |
325 | dt.Set(jdn); | |
93a800a9 | 326 | CPPUNIT_ASSERT_EQUAL( jdn, dt.GetJulianDayNumber() ); |
ccd6aacd VZ |
327 | } |
328 | } | |
329 | ||
330 | // test week days computation | |
331 | void DateTimeTestCase::TestTimeWDays() | |
332 | { | |
333 | // test GetWeekDay() | |
334 | size_t n; | |
335 | for ( n = 0; n < WXSIZEOF(testDates); n++ ) | |
336 | { | |
337 | const Date& d = testDates[n]; | |
338 | wxDateTime dt(d.day, d.month, d.year, d.hour, d.min, d.sec); | |
339 | ||
340 | wxDateTime::WeekDay wday = dt.GetWeekDay(); | |
15cb637c | 341 | CPPUNIT_ASSERT_EQUAL( d.wday, wday ); |
ccd6aacd VZ |
342 | } |
343 | ||
344 | // test SetToWeekDay() | |
345 | struct WeekDateTestData | |
346 | { | |
347 | Date date; // the real date (precomputed) | |
348 | int nWeek; // its week index in the month | |
349 | wxDateTime::WeekDay wday; // the weekday | |
350 | wxDateTime::Month month; // the month | |
351 | int year; // and the year | |
352 | ||
353 | wxString Format() const | |
354 | { | |
355 | wxString s, which; | |
356 | switch ( nWeek < -1 ? -nWeek : nWeek ) | |
357 | { | |
9a83f860 VZ |
358 | case 1: which = wxT("first"); break; |
359 | case 2: which = wxT("second"); break; | |
360 | case 3: which = wxT("third"); break; | |
361 | case 4: which = wxT("fourth"); break; | |
362 | case 5: which = wxT("fifth"); break; | |
ccd6aacd | 363 | |
9a83f860 | 364 | case -1: which = wxT("last"); break; |
ccd6aacd VZ |
365 | } |
366 | ||
367 | if ( nWeek < -1 ) | |
368 | { | |
9a83f860 | 369 | which += wxT(" from end"); |
ccd6aacd VZ |
370 | } |
371 | ||
9a83f860 | 372 | s.Printf(wxT("The %s %s of %s in %d"), |
ccd6aacd VZ |
373 | which.c_str(), |
374 | wxDateTime::GetWeekDayName(wday).c_str(), | |
375 | wxDateTime::GetMonthName(month).c_str(), | |
376 | year); | |
377 | ||
378 | return s; | |
379 | } | |
380 | }; | |
381 | ||
382 | // the array data was generated by the following python program | |
383 | /* | |
384 | from DateTime import * | |
385 | from whrandom import * | |
386 | from string import * | |
387 | ||
388 | monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ] | |
389 | wdayNames = [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ] | |
390 | ||
391 | week = DateTimeDelta(7) | |
392 | ||
393 | for n in range(20): | |
394 | year = randint(1900, 2100) | |
395 | month = randint(1, 12) | |
396 | day = randint(1, 28) | |
397 | dt = DateTime(year, month, day) | |
398 | wday = dt.day_of_week | |
399 | ||
400 | countFromEnd = choice([-1, 1]) | |
401 | weekNum = 0; | |
402 | ||
403 | while dt.month is month: | |
404 | dt = dt - countFromEnd * week | |
405 | weekNum = weekNum + countFromEnd | |
406 | ||
407 | data = { 'day': rjust(`day`, 2), 'month': monthNames[month - 1], 'year': year, 'weekNum': rjust(`weekNum`, 2), 'wday': wdayNames[wday] } | |
408 | ||
409 | print "{ { %(day)s, wxDateTime::%(month)s, %(year)d }, %(weekNum)d, "\ | |
410 | "wxDateTime::%(wday)s, wxDateTime::%(month)s, %(year)d }," % data | |
411 | */ | |
412 | ||
413 | static const WeekDateTestData weekDatesTestData[] = | |
414 | { | |
a669640b VZ |
415 | { { 20, wxDateTime::Mar, 2045, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 3, wxDateTime::Mon, wxDateTime::Mar, 2045 }, |
416 | { { 5, wxDateTime::Jun, 1985, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, -4, wxDateTime::Wed, wxDateTime::Jun, 1985 }, | |
417 | { { 12, wxDateTime::Nov, 1961, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, -3, wxDateTime::Sun, wxDateTime::Nov, 1961 }, | |
418 | { { 27, wxDateTime::Feb, 2093, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, -1, wxDateTime::Fri, wxDateTime::Feb, 2093 }, | |
419 | { { 4, wxDateTime::Jul, 2070, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, -4, wxDateTime::Fri, wxDateTime::Jul, 2070 }, | |
420 | { { 2, wxDateTime::Apr, 1906, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, -5, wxDateTime::Mon, wxDateTime::Apr, 1906 }, | |
421 | { { 19, wxDateTime::Jul, 2023, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, -2, wxDateTime::Wed, wxDateTime::Jul, 2023 }, | |
422 | { { 5, wxDateTime::May, 1958, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, -4, wxDateTime::Mon, wxDateTime::May, 1958 }, | |
423 | { { 11, wxDateTime::Aug, 1900, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 2, wxDateTime::Sat, wxDateTime::Aug, 1900 }, | |
424 | { { 14, wxDateTime::Feb, 1945, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 2, wxDateTime::Wed, wxDateTime::Feb, 1945 }, | |
425 | { { 25, wxDateTime::Jul, 1967, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, -1, wxDateTime::Tue, wxDateTime::Jul, 1967 }, | |
426 | { { 9, wxDateTime::May, 1916, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, -4, wxDateTime::Tue, wxDateTime::May, 1916 }, | |
427 | { { 20, wxDateTime::Jun, 1927, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 3, wxDateTime::Mon, wxDateTime::Jun, 1927 }, | |
428 | { { 2, wxDateTime::Aug, 2000, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 1, wxDateTime::Wed, wxDateTime::Aug, 2000 }, | |
429 | { { 20, wxDateTime::Apr, 2044, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 3, wxDateTime::Wed, wxDateTime::Apr, 2044 }, | |
430 | { { 20, wxDateTime::Feb, 1932, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, -2, wxDateTime::Sat, wxDateTime::Feb, 1932 }, | |
431 | { { 25, wxDateTime::Jul, 2069, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 4, wxDateTime::Thu, wxDateTime::Jul, 2069 }, | |
432 | { { 3, wxDateTime::Apr, 1925, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 1, wxDateTime::Fri, wxDateTime::Apr, 1925 }, | |
433 | { { 21, wxDateTime::Mar, 2093, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 3, wxDateTime::Sat, wxDateTime::Mar, 2093 }, | |
434 | { { 3, wxDateTime::Dec, 2074, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, -5, wxDateTime::Mon, wxDateTime::Dec, 2074 } | |
ccd6aacd VZ |
435 | }; |
436 | ||
ccd6aacd VZ |
437 | wxDateTime dt; |
438 | for ( n = 0; n < WXSIZEOF(weekDatesTestData); n++ ) | |
439 | { | |
440 | const WeekDateTestData& wd = weekDatesTestData[n]; | |
441 | ||
442 | dt.SetToWeekDay(wd.wday, wd.nWeek, wd.month, wd.year); | |
443 | ||
444 | const Date& d = wd.date; | |
445 | CPPUNIT_ASSERT( d.SameDay(dt.GetTm()) ); | |
446 | } | |
447 | } | |
448 | ||
449 | // test the computation of (ISO) week numbers | |
450 | void DateTimeTestCase::TestTimeWNumber() | |
451 | { | |
452 | struct WeekNumberTestData | |
453 | { | |
454 | Date date; // the date | |
455 | wxDateTime::wxDateTime_t week; // the week number in the year | |
456 | wxDateTime::wxDateTime_t wmon; // the week number in the month | |
457 | wxDateTime::wxDateTime_t wmon2; // same but week starts with Sun | |
458 | wxDateTime::wxDateTime_t dnum; // day number in the year | |
459 | }; | |
460 | ||
461 | // data generated with the following python script: | |
462 | /* | |
463 | from DateTime import * | |
464 | from whrandom import * | |
465 | from string import * | |
466 | ||
467 | monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ] | |
468 | wdayNames = [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ] | |
469 | ||
470 | def GetMonthWeek(dt): | |
471 | weekNumMonth = dt.iso_week[1] - DateTime(dt.year, dt.month, 1).iso_week[1] + 1 | |
472 | if weekNumMonth < 0: | |
473 | weekNumMonth = weekNumMonth + 53 | |
474 | return weekNumMonth | |
475 | ||
476 | def GetLastSundayBefore(dt): | |
477 | if dt.iso_week[2] == 7: | |
478 | return dt | |
479 | else: | |
480 | return dt - DateTimeDelta(dt.iso_week[2]) | |
481 | ||
482 | for n in range(20): | |
483 | year = randint(1900, 2100) | |
484 | month = randint(1, 12) | |
485 | day = randint(1, 28) | |
486 | dt = DateTime(year, month, day) | |
487 | dayNum = dt.day_of_year | |
488 | weekNum = dt.iso_week[1] | |
489 | weekNumMonth = GetMonthWeek(dt) | |
490 | ||
491 | weekNumMonth2 = 0 | |
492 | dtSunday = GetLastSundayBefore(dt) | |
493 | ||
494 | while dtSunday >= GetLastSundayBefore(DateTime(dt.year, dt.month, 1)): | |
495 | weekNumMonth2 = weekNumMonth2 + 1 | |
496 | dtSunday = dtSunday - DateTimeDelta(7) | |
497 | ||
498 | data = { 'day': rjust(`day`, 2), \ | |
499 | 'month': monthNames[month - 1], \ | |
500 | 'year': year, \ | |
501 | 'weekNum': rjust(`weekNum`, 2), \ | |
502 | 'weekNumMonth': weekNumMonth, \ | |
503 | 'weekNumMonth2': weekNumMonth2, \ | |
504 | 'dayNum': rjust(`dayNum`, 3) } | |
505 | ||
506 | print " { { %(day)s, "\ | |
507 | "wxDateTime::%(month)s, "\ | |
508 | "%(year)d }, "\ | |
509 | "%(weekNum)s, "\ | |
510 | "%(weekNumMonth)s, "\ | |
511 | "%(weekNumMonth2)s, "\ | |
512 | "%(dayNum)s }," % data | |
513 | ||
514 | */ | |
515 | static const WeekNumberTestData weekNumberTestDates[] = | |
516 | { | |
a669640b VZ |
517 | { { 27, wxDateTime::Dec, 1966, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 52, 5, 5, 361 }, |
518 | { { 22, wxDateTime::Jul, 1926, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 29, 4, 4, 203 }, | |
519 | { { 22, wxDateTime::Oct, 2076, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 43, 4, 4, 296 }, | |
520 | { { 1, wxDateTime::Jul, 1967, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 26, 1, 1, 182 }, | |
521 | { { 8, wxDateTime::Nov, 2004, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 46, 2, 2, 313 }, | |
522 | { { 21, wxDateTime::Mar, 1920, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 12, 3, 4, 81 }, | |
523 | { { 7, wxDateTime::Jan, 1965, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 1, 2, 2, 7 }, | |
524 | { { 19, wxDateTime::Oct, 1999, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 42, 4, 4, 292 }, | |
525 | { { 13, wxDateTime::Aug, 1955, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 32, 2, 2, 225 }, | |
526 | { { 18, wxDateTime::Jul, 2087, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 29, 3, 3, 199 }, | |
527 | { { 2, wxDateTime::Sep, 2028, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 35, 1, 1, 246 }, | |
528 | { { 28, wxDateTime::Jul, 1945, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 30, 5, 4, 209 }, | |
529 | { { 15, wxDateTime::Jun, 1901, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 24, 3, 3, 166 }, | |
530 | { { 10, wxDateTime::Oct, 1939, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 41, 3, 2, 283 }, | |
531 | { { 3, wxDateTime::Dec, 1965, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 48, 1, 1, 337 }, | |
532 | { { 23, wxDateTime::Feb, 1940, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 8, 4, 4, 54 }, | |
533 | { { 2, wxDateTime::Jan, 1987, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 1, 1, 1, 2 }, | |
534 | { { 11, wxDateTime::Aug, 2079, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 32, 2, 2, 223 }, | |
535 | { { 2, wxDateTime::Feb, 2063, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 5, 1, 1, 33 }, | |
536 | { { 16, wxDateTime::Oct, 1942, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 42, 3, 3, 289 }, | |
537 | { { 30, wxDateTime::Dec, 2003, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 1, 5, 5, 364 }, | |
538 | { { 2, wxDateTime::Jan, 2004, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 1, 1, 1, 2 }, | |
404013f8 VZ |
539 | { { 5, wxDateTime::Jan, 2010, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 1, 2, 2, 5 }, |
540 | { { 3, wxDateTime::Jan, 2011, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 1, 2, 2, 3 }, | |
12ce0a74 VZ |
541 | { { 31, wxDateTime::Dec, 2009, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 53, 5, 5, 365 }, |
542 | { { 31, wxDateTime::Dec, 2012, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 1, 6, 6, 366 }, | |
543 | { { 29, wxDateTime::Dec, 2013, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 52, 5, 5, 363 }, | |
544 | { { 30, wxDateTime::Dec, 2013, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 1, 6, 5, 364 }, | |
545 | { { 31, wxDateTime::Dec, 2013, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, 1, 6, 5, 365 }, | |
ccd6aacd VZ |
546 | }; |
547 | ||
548 | for ( size_t n = 0; n < WXSIZEOF(weekNumberTestDates); n++ ) | |
549 | { | |
550 | const WeekNumberTestData& wn = weekNumberTestDates[n]; | |
551 | const Date& d = wn.date; | |
552 | ||
553 | wxDateTime dt = d.DT(); | |
554 | ||
555 | wxDateTime::wxDateTime_t | |
556 | week = dt.GetWeekOfYear(wxDateTime::Monday_First), | |
557 | wmon = dt.GetWeekOfMonth(wxDateTime::Monday_First), | |
558 | wmon2 = dt.GetWeekOfMonth(wxDateTime::Sunday_First), | |
559 | dnum = dt.GetDayOfYear(); | |
560 | ||
404013f8 VZ |
561 | WX_ASSERT_EQUAL_MESSAGE( ("day of year for %s", d.Format()), |
562 | wn.dnum, dnum ); | |
563 | WX_ASSERT_EQUAL_MESSAGE( ("week of month (Monday) for %s", d.Format()), | |
564 | wn.wmon, wmon ); | |
565 | WX_ASSERT_EQUAL_MESSAGE( ("week of month (Sunday) for %s", d.Format()), | |
566 | wn.wmon2, wmon2 ); | |
567 | WX_ASSERT_EQUAL_MESSAGE( ("week of year for %s", d.Format()), | |
568 | wn.week, week ); | |
ccd6aacd | 569 | |
4c27e2fa VZ |
570 | int year = d.year; |
571 | if ( week == 1 && d.month != wxDateTime::Jan ) | |
572 | { | |
573 | // this means we're in the first week of the next year | |
574 | year++; | |
575 | } | |
576 | ||
577 | wxDateTime | |
578 | dt2 = wxDateTime::SetToWeekOfYear(year, week, dt.GetWeekDay()); | |
15cb637c | 579 | CPPUNIT_ASSERT_EQUAL( dt, dt2 ); |
ccd6aacd VZ |
580 | } |
581 | } | |
582 | ||
583 | // test DST applicability | |
584 | void DateTimeTestCase::TestTimeDST() | |
585 | { | |
586 | // taken from http://www.energy.ca.gov/daylightsaving.html | |
6b522db5 | 587 | static const Date datesDST[2][2009 - 1990 + 1] = |
ccd6aacd VZ |
588 | { |
589 | { | |
a669640b VZ |
590 | { 1, wxDateTime::Apr, 1990, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, |
591 | { 7, wxDateTime::Apr, 1991, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
592 | { 5, wxDateTime::Apr, 1992, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
593 | { 4, wxDateTime::Apr, 1993, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
594 | { 3, wxDateTime::Apr, 1994, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
595 | { 2, wxDateTime::Apr, 1995, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
596 | { 7, wxDateTime::Apr, 1996, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
597 | { 6, wxDateTime::Apr, 1997, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
598 | { 5, wxDateTime::Apr, 1998, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
599 | { 4, wxDateTime::Apr, 1999, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
600 | { 2, wxDateTime::Apr, 2000, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
601 | { 1, wxDateTime::Apr, 2001, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
602 | { 7, wxDateTime::Apr, 2002, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
603 | { 6, wxDateTime::Apr, 2003, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
604 | { 4, wxDateTime::Apr, 2004, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
6b522db5 VZ |
605 | { 3, wxDateTime::Apr, 2005, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, |
606 | { 2, wxDateTime::Apr, 2006, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
607 | {11, wxDateTime::Mar, 2007, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
608 | { 9, wxDateTime::Mar, 2008, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
609 | { 8, wxDateTime::Mar, 2009, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
ccd6aacd VZ |
610 | }, |
611 | { | |
a669640b VZ |
612 | { 28, wxDateTime::Oct, 1990, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, |
613 | { 27, wxDateTime::Oct, 1991, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
614 | { 25, wxDateTime::Oct, 1992, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
615 | { 31, wxDateTime::Oct, 1993, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
616 | { 30, wxDateTime::Oct, 1994, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
617 | { 29, wxDateTime::Oct, 1995, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
618 | { 27, wxDateTime::Oct, 1996, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
619 | { 26, wxDateTime::Oct, 1997, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
620 | { 25, wxDateTime::Oct, 1998, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
621 | { 31, wxDateTime::Oct, 1999, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
622 | { 29, wxDateTime::Oct, 2000, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
623 | { 28, wxDateTime::Oct, 2001, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
624 | { 27, wxDateTime::Oct, 2002, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
625 | { 26, wxDateTime::Oct, 2003, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
626 | { 31, wxDateTime::Oct, 2004, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
6b522db5 VZ |
627 | { 30, wxDateTime::Oct, 2005, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, |
628 | { 29, wxDateTime::Oct, 2006, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
629 | { 4, wxDateTime::Nov, 2007, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
630 | { 2, wxDateTime::Nov, 2008, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
631 | { 1, wxDateTime::Nov, 2009, 0, 0, 0, 0.0, wxDateTime::Inv_WeekDay, 0 }, | |
632 | ||
ccd6aacd VZ |
633 | } |
634 | }; | |
635 | ||
6b522db5 | 636 | for ( size_t n = 0; n < WXSIZEOF(datesDST[0]); n++ ) |
ccd6aacd | 637 | { |
6b522db5 | 638 | const int year = 1990 + n; |
ccd6aacd VZ |
639 | wxDateTime dtBegin = wxDateTime::GetBeginDST(year, wxDateTime::USA), |
640 | dtEnd = wxDateTime::GetEndDST(year, wxDateTime::USA); | |
641 | ||
ccd6aacd VZ |
642 | const Date& dBegin = datesDST[0][n]; |
643 | const Date& dEnd = datesDST[1][n]; | |
644 | ||
6b522db5 VZ |
645 | CPPUNIT_ASSERT_EQUAL( dBegin.DT().FormatDate(), dtBegin.FormatDate() ); |
646 | CPPUNIT_ASSERT_EQUAL( dEnd.DT().FormatDate(), dtEnd.FormatDate() ); | |
ccd6aacd VZ |
647 | } |
648 | } | |
649 | ||
650 | // test wxDateTime -> text conversion | |
651 | void DateTimeTestCase::TestTimeFormat() | |
652 | { | |
653 | // some information may be lost during conversion, so store what kind | |
654 | // of info should we recover after a round trip | |
655 | enum CompareKind | |
656 | { | |
657 | CompareNone, // don't try comparing | |
658 | CompareBoth, // dates and times should be identical | |
9807f995 | 659 | CompareYear, // don't compare centuries (fails for 2 digit years) |
ccd6aacd VZ |
660 | CompareDate, // dates only |
661 | CompareTime // time only | |
662 | }; | |
663 | ||
664 | static const struct | |
665 | { | |
666 | CompareKind compareKind; | |
71ebd60b | 667 | const char *format; |
ccd6aacd VZ |
668 | } formatTestFormats[] = |
669 | { | |
71ebd60b VZ |
670 | { CompareYear, "---> %c" }, // %c could use 2 digit years |
671 | { CompareDate, "Date is %A, %d of %B, in year %Y" }, | |
672 | { CompareYear, "Date is %x, time is %X" }, // %x could use 2 digits | |
673 | { CompareTime, "Time is %H:%M:%S or %I:%M:%S %p" }, | |
674 | { CompareNone, "The day of year: %j, the week of year: %W" }, | |
675 | { CompareDate, "ISO date without separators: %Y%m%d" }, | |
444bc2b2 VZ |
676 | { CompareBoth, "RFC 2822 string: %Y-%m-%d %H:%M:%S.%l %z" }, |
677 | ||
678 | }; | |
679 | ||
680 | const long timeZonesOffsets[] = | |
681 | { | |
682 | wxDateTime::TimeZone(wxDateTime::Local).GetOffset(), | |
683 | ||
684 | // Fictitious TimeZone offsets to ensure time zone formating and | |
685 | // interpretation works | |
686 | -(3600 + 2*60), | |
687 | 3*3600 + 30*60 | |
ccd6aacd VZ |
688 | }; |
689 | ||
690 | static const Date formatTestDates[] = | |
691 | { | |
9807f995 VZ |
692 | { 29, wxDateTime::May, 1976, 18, 30, 00, 0.0, wxDateTime::Inv_WeekDay }, |
693 | { 31, wxDateTime::Dec, 1999, 23, 30, 00, 0.0, wxDateTime::Inv_WeekDay }, | |
694 | { 6, wxDateTime::Feb, 1937, 23, 30, 00, 0.0, wxDateTime::Inv_WeekDay }, | |
695 | { 6, wxDateTime::Feb, 1856, 23, 30, 00, 0.0, wxDateTime::Inv_WeekDay }, | |
696 | { 6, wxDateTime::Feb, 1857, 23, 30, 00, 0.0, wxDateTime::Inv_WeekDay }, | |
697 | { 29, wxDateTime::May, 2076, 18, 30, 00, 0.0, wxDateTime::Inv_WeekDay }, | |
89a7e1ff VZ |
698 | |
699 | // FIXME: the test with 02:15:25 time doesn't pass because of DST | |
700 | // computation problems, we get back 03:15:25 | |
701 | { 29, wxDateTime::Feb, 2400, 04, 15, 25, 0.0, wxDateTime::Inv_WeekDay }, | |
ccd6aacd | 702 | #if 0 |
42b62acf | 703 | // Need to add support for BCE dates. |
9807f995 | 704 | { 01, wxDateTime::Jan, -52, 03, 16, 47, 0.0, wxDateTime::Inv_WeekDay }, |
ccd6aacd VZ |
705 | #endif |
706 | }; | |
707 | ||
444bc2b2 | 708 | for ( unsigned idxtz = 0; idxtz < WXSIZEOF(timeZonesOffsets); ++idxtz ) |
ccd6aacd | 709 | { |
444bc2b2 VZ |
710 | wxDateTime::TimeZone tz(timeZonesOffsets[idxtz]); |
711 | const bool isLocalTz = tz.GetOffset() == -wxGetTimeZone(); | |
a6121fc4 | 712 | |
444bc2b2 VZ |
713 | for ( size_t d = 0; d < WXSIZEOF(formatTestDates); d++ ) |
714 | { | |
715 | wxDateTime dt = formatTestDates[d].DT(); | |
716 | for ( unsigned n = 0; n < WXSIZEOF(formatTestFormats); n++ ) | |
717 | { | |
718 | const char *fmt = formatTestFormats[n].format; | |
719 | ||
720 | // skip the check with %p for those locales which have empty AM/PM strings: | |
721 | // for those locales it's impossible to pass the test with %p... | |
722 | wxString am, pm; | |
723 | wxDateTime::GetAmPmStrings(&am, &pm); | |
724 | if (am.empty() && pm.empty() && wxStrstr(fmt, "%p") != NULL) | |
725 | continue; | |
726 | ||
727 | // what can we recover? | |
728 | CompareKind kind = formatTestFormats[n].compareKind; | |
729 | ||
730 | // When using a different time zone we must perform a time zone | |
731 | // conversion below which doesn't always work correctly, check | |
732 | // for the cases when it doesn't. | |
733 | if ( !isLocalTz ) | |
734 | { | |
735 | // DST computation doesn't work correctly for dates above | |
736 | // 2038 currently on the systems with 32 bit time_t. | |
737 | if ( dt.GetYear() >= 2038 ) | |
738 | continue; | |
739 | ||
740 | // We can't compare just dates nor just times when doing TZ | |
741 | // conversion as both are affected by the DST: for the | |
742 | // dates, the DST can switch midnight to 23:00 of the | |
743 | // previous day while for the times DST can be different | |
744 | // for the original date and today. | |
745 | if ( kind == CompareDate || kind == CompareTime ) | |
746 | continue; | |
747 | } | |
1bf29a7a | 748 | |
444bc2b2 VZ |
749 | // do convert date to string |
750 | wxString s = dt.Format(fmt, tz); | |
ccd6aacd | 751 | |
444bc2b2 VZ |
752 | // convert back |
753 | wxDateTime dt2; | |
754 | const char *result = dt2.ParseFormat(s, fmt); | |
755 | if ( !result ) | |
ccd6aacd | 756 | { |
444bc2b2 VZ |
757 | // conversion failed - should it have? |
758 | WX_ASSERT_MESSAGE( | |
759 | ("Test #%u failed: failed to parse \"%s\"", n, s), | |
760 | kind == CompareNone | |
761 | ); | |
762 | } | |
763 | else // conversion succeeded | |
764 | { | |
765 | // currently ParseFormat() doesn't support "%Z" and so is | |
766 | // incapable of parsing time zone part used at the end of date | |
767 | // representations in many (but not "C") locales, compensate | |
768 | // for it ourselves by simply consuming and ignoring it | |
769 | while ( *result && (*result >= 'A' && *result <= 'Z') ) | |
770 | result++; | |
771 | ||
772 | WX_ASSERT_MESSAGE( | |
773 | ("Test #%u failed: \"%s\" was left unparsed in \"%s\"", | |
774 | n, result, s), | |
775 | !*result | |
776 | ); | |
777 | ||
778 | // Without "%z" we can't recover the time zone used in the | |
779 | // call to Format() so we need to call MakeFromTimezone() | |
780 | // explicitly. | |
781 | if ( !strstr(fmt, "%z") && !isLocalTz ) | |
782 | dt2.MakeFromTimezone(tz); | |
783 | ||
784 | switch ( kind ) | |
785 | { | |
786 | case CompareYear: | |
787 | if ( dt2.GetCentury() != dt.GetCentury() ) | |
788 | { | |
789 | CPPUNIT_ASSERT_EQUAL(dt.GetYear() % 100, | |
790 | dt2.GetYear() % 100); | |
791 | ||
792 | dt2.SetYear(dt.GetYear()); | |
793 | } | |
794 | // fall through and compare everything | |
795 | ||
796 | case CompareBoth: | |
797 | CPPUNIT_ASSERT_EQUAL( dt, dt2 ); | |
798 | break; | |
799 | ||
800 | case CompareDate: | |
801 | CPPUNIT_ASSERT( dt.IsSameDate(dt2) ); | |
802 | break; | |
803 | ||
804 | case CompareTime: | |
805 | CPPUNIT_ASSERT( dt.IsSameTime(dt2) ); | |
806 | break; | |
807 | ||
808 | case CompareNone: | |
809 | wxFAIL_MSG( wxT("unexpected") ); | |
810 | break; | |
811 | } | |
ccd6aacd VZ |
812 | } |
813 | } | |
814 | } | |
815 | } | |
425eee41 | 816 | |
b5f85206 VZ |
817 | wxDateTime dt; |
818 | ||
89a7e1ff VZ |
819 | #if 0 |
820 | // special case which was known to fail | |
821 | CPPUNIT_ASSERT( dt.ParseFormat("02/06/1856", "%x") ); | |
822 | CPPUNIT_ASSERT_EQUAL( 1856, dt.GetYear() ); | |
823 | #endif | |
824 | ||
52256b21 VZ |
825 | // also test %l separately |
826 | CPPUNIT_ASSERT( dt.ParseFormat("12:23:45.678", "%H:%M:%S.%l") ); | |
827 | CPPUNIT_ASSERT_EQUAL( 678, dt.GetMillisecond() ); | |
828 | ||
829 | // test special case of %l matching 0 milliseconds | |
830 | CPPUNIT_ASSERT( dt.ParseFormat("12:23:45.000", "%H:%M:%S.%l") ); | |
831 | CPPUNIT_ASSERT_EQUAL( 0, dt.GetMillisecond() ); | |
832 | ||
b5f85206 VZ |
833 | // test partially specified dates too |
834 | wxDateTime dtDef(26, wxDateTime::Sep, 2008); | |
835 | CPPUNIT_ASSERT( dt.ParseFormat("17", "%d") ); | |
836 | CPPUNIT_ASSERT_EQUAL( 17, dt.GetDay() ); | |
837 | ||
649148f9 VZ |
838 | // test some degenerate cases |
839 | CPPUNIT_ASSERT( !dt.ParseFormat("", "%z") ); | |
1f29ecb3 | 840 | CPPUNIT_ASSERT( !dt.ParseFormat("", "%%") ); |
649148f9 | 841 | |
425eee41 VZ |
842 | // test compilation of some calls which should compile (and not result in |
843 | // ambiguity because of char*<->wxCStrData<->wxString conversions) | |
425eee41 VZ |
844 | wxString s("foo"); |
845 | CPPUNIT_ASSERT( !dt.ParseFormat("foo") ); | |
846 | CPPUNIT_ASSERT( !dt.ParseFormat(wxT("foo")) ); | |
847 | CPPUNIT_ASSERT( !dt.ParseFormat(s) ); | |
d44dc1be | 848 | dt.ParseFormat(s.c_str()); // Simply test compilation of this one. |
425eee41 VZ |
849 | |
850 | CPPUNIT_ASSERT( !dt.ParseFormat("foo", "%c") ); | |
851 | CPPUNIT_ASSERT( !dt.ParseFormat(wxT("foo"), "%c") ); | |
852 | CPPUNIT_ASSERT( !dt.ParseFormat(s, "%c") ); | |
d44dc1be | 853 | dt.ParseFormat(s.c_str(), "%c"); |
425eee41 VZ |
854 | |
855 | CPPUNIT_ASSERT( !dt.ParseFormat("foo", wxT("%c")) ); | |
856 | CPPUNIT_ASSERT( !dt.ParseFormat(wxT("foo"), wxT("%c")) ); | |
857 | CPPUNIT_ASSERT( !dt.ParseFormat(s, "%c") ); | |
d44dc1be | 858 | dt.ParseFormat(s.c_str(), wxT("%c")); |
425eee41 VZ |
859 | |
860 | wxString spec("%c"); | |
861 | CPPUNIT_ASSERT( !dt.ParseFormat("foo", spec) ); | |
862 | CPPUNIT_ASSERT( !dt.ParseFormat(wxT("foo"), spec) ); | |
863 | CPPUNIT_ASSERT( !dt.ParseFormat(s, spec) ); | |
d44dc1be | 864 | dt.ParseFormat(s.c_str(), spec); |
ccd6aacd VZ |
865 | } |
866 | ||
2747a51b VZ |
867 | // Test parsing time in free format. |
868 | void DateTimeTestCase::TestTimeParse() | |
869 | { | |
870 | wxDateTime dt; | |
871 | ||
872 | // Parsing standard formats should work. | |
873 | CPPUNIT_ASSERT( dt.ParseTime("12:34:56") ); | |
874 | CPPUNIT_ASSERT_EQUAL( "12:34:56", dt.FormatISOTime() ); | |
875 | ||
876 | // Parsing just hours should work too. | |
877 | dt.ResetTime(); | |
878 | CPPUNIT_ASSERT( dt.ParseTime("17") ); | |
879 | CPPUNIT_ASSERT_EQUAL( "17:00:00", dt.FormatISOTime() ); | |
880 | ||
881 | // Parsing gibberish shouldn't work. | |
882 | CPPUNIT_ASSERT( !dt.ParseTime("bloordyblop") ); | |
883 | } | |
884 | ||
1bf29a7a VZ |
885 | void DateTimeTestCase::TestTimeSpanFormat() |
886 | { | |
887 | static const struct TimeSpanFormatTestData | |
888 | { | |
889 | long h, min, sec, msec; | |
71ebd60b VZ |
890 | const char *fmt; |
891 | const char *result; | |
1bf29a7a VZ |
892 | } testSpans[] = |
893 | { | |
71ebd60b VZ |
894 | { 12, 34, 56, 789, "%H:%M:%S.%l", "12:34:56.789" }, |
895 | { 1, 2, 3, 0, "%H:%M:%S", "01:02:03" }, | |
896 | { 1, 2, 3, 0, "%S", "3723" }, | |
897 | { -1, -2, -3, 0, "%S", "-3723" }, | |
898 | { -1, -2, -3, 0, "%H:%M:%S", "-01:02:03" }, | |
899 | { 26, 0, 0, 0, "%H", "26" }, | |
900 | { 26, 0, 0, 0, "%D, %H", "1, 02" }, | |
901 | { -26, 0, 0, 0, "%H", "-26" }, | |
902 | { -26, 0, 0, 0, "%D, %H", "-1, 02" }, | |
903 | { 219, 0, 0, 0, "%H", "219" }, | |
904 | { 219, 0, 0, 0, "%D, %H", "9, 03" }, | |
905 | { 219, 0, 0, 0, "%E, %D, %H", "1, 2, 03" }, | |
c9e46dea VZ |
906 | { 0, -1, 0, 0, "%H:%M:%S", "-00:01:00" }, |
907 | { 0, 0, -1, 0, "%H:%M:%S", "-00:00:01" }, | |
1bf29a7a VZ |
908 | }; |
909 | ||
910 | for ( size_t n = 0; n < WXSIZEOF(testSpans); n++ ) | |
911 | { | |
912 | const TimeSpanFormatTestData& td = testSpans[n]; | |
913 | wxTimeSpan ts(td.h, td.min, td.sec, td.msec); | |
c9e46dea | 914 | CPPUNIT_ASSERT_EQUAL( td.result, ts.Format(td.fmt) ); |
1bf29a7a VZ |
915 | } |
916 | } | |
917 | ||
ccd6aacd VZ |
918 | void DateTimeTestCase::TestTimeTicks() |
919 | { | |
a669640b VZ |
920 | static const wxDateTime::TimeZone TZ_LOCAL(wxDateTime::Local); |
921 | static const wxDateTime::TimeZone TZ_TEST(wxDateTime::NZST); | |
c4e25288 | 922 | |
a669640b VZ |
923 | // this offset is needed to make the test work in any time zone when we |
924 | // only have expected test results in UTC in testDates | |
925 | static const long tzOffset = TZ_LOCAL.GetOffset() - TZ_TEST.GetOffset(); | |
c4e25288 | 926 | |
ccd6aacd VZ |
927 | for ( size_t n = 0; n < WXSIZEOF(testDates); n++ ) |
928 | { | |
929 | const Date& d = testDates[n]; | |
a669640b | 930 | if ( d.gmticks == -1 ) |
ccd6aacd VZ |
931 | continue; |
932 | ||
a669640b | 933 | wxDateTime dt = d.DT().MakeTimezone(TZ_TEST, true /* no DST */); |
c4e25288 | 934 | |
a669640b VZ |
935 | // GetValue() returns internal UTC-based representation, we need to |
936 | // convert it to local TZ before comparing | |
ece97e28 | 937 | time_t ticks = (dt.GetValue() / 1000).ToLong() + TZ_LOCAL.GetOffset(); |
a669640b VZ |
938 | if ( dt.IsDST() ) |
939 | ticks += 3600; | |
1de532f5 | 940 | CPPUNIT_ASSERT_EQUAL( d.gmticks, ticks + tzOffset ); |
ccd6aacd | 941 | |
c4e25288 | 942 | dt = d.DT().FromTimezone(wxDateTime::UTC); |
ccd6aacd | 943 | ticks = (dt.GetValue() / 1000).ToLong(); |
1de532f5 | 944 | CPPUNIT_ASSERT_EQUAL( d.gmticks, ticks ); |
ccd6aacd VZ |
945 | } |
946 | } | |
947 | ||
8605eb1a VZ |
948 | // test parsing dates in RFC822 format |
949 | void DateTimeTestCase::TestParceRFC822() | |
ccd6aacd VZ |
950 | { |
951 | static const struct ParseTestData | |
952 | { | |
71ebd60b | 953 | const char *rfc822; |
d26adb9d | 954 | Date date; // NB: this should be in UTC |
ccd6aacd VZ |
955 | bool good; |
956 | } parseTestDates[] = | |
957 | { | |
d26adb9d | 958 | { |
71ebd60b | 959 | "Sat, 18 Dec 1999 00:46:40 +0100", |
1cf57808 | 960 | { 17, wxDateTime::Dec, 1999, 23, 46, 40 }, |
d26adb9d VZ |
961 | true |
962 | }, | |
963 | { | |
71ebd60b | 964 | "Wed, 1 Dec 1999 05:17:20 +0300", |
1cf57808 | 965 | { 1, wxDateTime::Dec, 1999, 2, 17, 20 }, |
d26adb9d VZ |
966 | true |
967 | }, | |
968 | { | |
71ebd60b | 969 | "Sun, 28 Aug 2005 03:31:30 +0200", |
cf9f6737 | 970 | { 28, wxDateTime::Aug, 2005, 1, 31, 30 }, |
1cf57808 VZ |
971 | true |
972 | }, | |
973 | ||
974 | { | |
71ebd60b | 975 | "Sat, 18 Dec 1999 10:48:30 -0500", |
cf9f6737 | 976 | { 18, wxDateTime::Dec, 1999, 15, 48, 30 }, |
d26adb9d VZ |
977 | true |
978 | }, | |
cf9f6737 VZ |
979 | |
980 | // seconds are optional according to the RFC | |
981 | { | |
982 | "Sun, 01 Jun 2008 16:30 +0200", | |
983 | { 1, wxDateTime::Jun, 2008, 14, 30, 00 }, | |
984 | true | |
985 | }, | |
986 | ||
987 | // try some bogus ones too | |
988 | { | |
989 | "Sun, 01 Jun 2008 16:30: +0200", | |
990 | { 0 }, | |
991 | false | |
992 | }, | |
ccd6aacd VZ |
993 | }; |
994 | ||
b7c746d0 | 995 | for ( unsigned n = 0; n < WXSIZEOF(parseTestDates); n++ ) |
ccd6aacd | 996 | { |
71ebd60b | 997 | const char * const datestr = parseTestDates[n].rfc822; |
b7c746d0 | 998 | |
ccd6aacd | 999 | wxDateTime dt; |
b7c746d0 | 1000 | if ( dt.ParseRfc822Date(datestr) ) |
ccd6aacd | 1001 | { |
b7c746d0 VZ |
1002 | WX_ASSERT_MESSAGE( |
1003 | ("Erroneously parsed \"%s\"", datestr), | |
1004 | parseTestDates[n].good | |
1005 | ); | |
ccd6aacd | 1006 | |
d26adb9d | 1007 | wxDateTime dtReal = parseTestDates[n].date.DT().FromUTC(); |
8605eb1a VZ |
1008 | CPPUNIT_ASSERT_EQUAL( dtReal, dt ); |
1009 | } | |
1010 | else // failed to parse | |
1011 | { | |
b7c746d0 VZ |
1012 | WX_ASSERT_MESSAGE( |
1013 | ("Failed to parse \"%s\"", datestr), | |
1014 | !parseTestDates[n].good | |
1015 | ); | |
8605eb1a VZ |
1016 | } |
1017 | } | |
1018 | } | |
1019 | ||
1020 | // test parsing dates in free format | |
1021 | void DateTimeTestCase::TestDateParse() | |
1022 | { | |
1023 | static const struct ParseTestData | |
1024 | { | |
71ebd60b | 1025 | const char *str; |
8605eb1a VZ |
1026 | Date date; // NB: this should be in UTC |
1027 | bool good; | |
1028 | } parseTestDates[] = | |
1029 | { | |
71ebd60b VZ |
1030 | { "21 Mar 2006", { 21, wxDateTime::Mar, 2006 }, true }, |
1031 | { "29 Feb 1976", { 29, wxDateTime::Feb, 1976 }, true }, | |
1032 | { "Feb 29 1976", { 29, wxDateTime::Feb, 1976 }, true }, | |
1033 | { "31/03/06", { 31, wxDateTime::Mar, 6 }, true }, | |
1034 | { "31/03/2006", { 31, wxDateTime::Mar, 2006 }, true }, | |
8605eb1a VZ |
1035 | |
1036 | // some invalid ones too | |
71ebd60b VZ |
1037 | { "29 Feb 2006" }, |
1038 | { "31/04/06" }, | |
1039 | { "bloordyblop" }, | |
e4f54cce | 1040 | { "2 . . " }, |
8605eb1a VZ |
1041 | }; |
1042 | ||
1043 | // special cases | |
1044 | wxDateTime dt; | |
9a83f860 | 1045 | CPPUNIT_ASSERT( dt.ParseDate(wxT("today")) ); |
8605eb1a VZ |
1046 | CPPUNIT_ASSERT_EQUAL( wxDateTime::Today(), dt ); |
1047 | ||
1048 | for ( size_t n = 0; n < WXSIZEOF(parseTestDates); n++ ) | |
1049 | { | |
66f22f4a | 1050 | const wxString datestr = TranslateDate(parseTestDates[n].str); |
3aa3163f VZ |
1051 | |
1052 | const char * const end = dt.ParseDate(datestr); | |
1053 | if ( end && !*end ) | |
8605eb1a | 1054 | { |
3aa3163f VZ |
1055 | WX_ASSERT_MESSAGE( |
1056 | ("Erroneously parsed \"%s\"", datestr), | |
1057 | parseTestDates[n].good | |
1058 | ); | |
8605eb1a | 1059 | |
804eeca5 VZ |
1060 | CPPUNIT_ASSERT_EQUAL( parseTestDates[n].date.DT(), dt ); |
1061 | } | |
1062 | else // failed to parse | |
1063 | { | |
3aa3163f VZ |
1064 | WX_ASSERT_MESSAGE( |
1065 | ("Failed to parse \"%s\"", datestr), | |
1066 | !parseTestDates[n].good | |
1067 | ); | |
804eeca5 VZ |
1068 | } |
1069 | } | |
f17ac574 VZ |
1070 | |
1071 | // Check that incomplete parse works correctly. | |
1072 | const char* p = dt.ParseFormat("2012-03-23 12:34:56", "%Y-%m-%d"); | |
1073 | CPPUNIT_ASSERT_EQUAL( " 12:34:56", wxString(p) ); | |
804eeca5 VZ |
1074 | } |
1075 | ||
f3f2e255 VZ |
1076 | void DateTimeTestCase::TestDateParseISO() |
1077 | { | |
1078 | static const struct | |
1079 | { | |
1080 | const char *str; | |
1081 | Date date; // NB: this should be in UTC | |
1082 | bool good; | |
1083 | } parseTestDates[] = | |
1084 | { | |
1085 | { "2006-03-21", { 21, wxDateTime::Mar, 2006 }, true }, | |
1086 | { "1976-02-29", { 29, wxDateTime::Feb, 1976 }, true }, | |
1087 | { "0006-03-31", { 31, wxDateTime::Mar, 6 }, true }, | |
1088 | ||
1089 | // some invalid ones too | |
1090 | { "2006:03:31" }, | |
1091 | { "31/04/06" }, | |
1092 | { "bloordyblop" }, | |
1093 | { "" }, | |
1094 | }; | |
1095 | ||
1096 | static const struct | |
1097 | { | |
1098 | const char *str; | |
1099 | wxDateTime::wxDateTime_t hour, min, sec; | |
1100 | bool good; | |
1101 | } parseTestTimes[] = | |
1102 | { | |
1103 | { "13:42:17", 13, 42, 17, true }, | |
1104 | { "02:17:01", 2, 17, 1, true }, | |
1105 | ||
1106 | // some invalid ones too | |
1107 | { "66:03:31" }, | |
1108 | { "31/04/06" }, | |
1109 | { "bloordyblop" }, | |
1110 | { "" }, | |
1111 | }; | |
1112 | ||
1113 | for ( size_t n = 0; n < WXSIZEOF(parseTestDates); n++ ) | |
1114 | { | |
1115 | wxDateTime dt; | |
1116 | if ( dt.ParseISODate(parseTestDates[n].str) ) | |
1117 | { | |
1118 | CPPUNIT_ASSERT( parseTestDates[n].good ); | |
1119 | ||
1120 | CPPUNIT_ASSERT_EQUAL( parseTestDates[n].date.DT(), dt ); | |
1121 | ||
1122 | for ( size_t m = 0; m < WXSIZEOF(parseTestTimes); m++ ) | |
1123 | { | |
1124 | wxString dtCombined; | |
1125 | dtCombined << parseTestDates[n].str | |
1126 | << 'T' | |
1127 | << parseTestTimes[m].str; | |
1128 | ||
1129 | if ( dt.ParseISOCombined(dtCombined) ) | |
1130 | { | |
1131 | CPPUNIT_ASSERT( parseTestTimes[m].good ); | |
1132 | ||
1133 | CPPUNIT_ASSERT_EQUAL( parseTestTimes[m].hour, dt.GetHour()) ; | |
1134 | CPPUNIT_ASSERT_EQUAL( parseTestTimes[m].min, dt.GetMinute()) ; | |
1135 | CPPUNIT_ASSERT_EQUAL( parseTestTimes[m].sec, dt.GetSecond()) ; | |
1136 | } | |
1137 | else // failed to parse combined date/time | |
1138 | { | |
1139 | CPPUNIT_ASSERT( !parseTestTimes[m].good ); | |
1140 | } | |
1141 | } | |
1142 | } | |
1143 | else // failed to parse | |
1144 | { | |
1145 | CPPUNIT_ASSERT( !parseTestDates[n].good ); | |
1146 | } | |
1147 | } | |
1148 | } | |
1149 | ||
804eeca5 VZ |
1150 | void DateTimeTestCase::TestDateTimeParse() |
1151 | { | |
1152 | static const struct ParseTestData | |
1153 | { | |
71ebd60b | 1154 | const char *str; |
804eeca5 VZ |
1155 | Date date; // NB: this should be in UTC |
1156 | bool good; | |
1157 | } parseTestDates[] = | |
1158 | { | |
8b7d411f VZ |
1159 | { |
1160 | "Thu 22 Nov 2007 07:40:00 PM", | |
595c23b3 | 1161 | { 22, wxDateTime::Nov, 2007, 19, 40, 0 }, |
8b7d411f VZ |
1162 | true |
1163 | }, | |
1164 | ||
1165 | { | |
1166 | "2010-01-04 14:30", | |
595c23b3 | 1167 | { 4, wxDateTime::Jan, 2010, 14, 30, 0 }, |
8b7d411f VZ |
1168 | true |
1169 | }, | |
1170 | ||
1171 | { | |
1172 | "bloordyblop", | |
595c23b3 | 1173 | { 1, wxDateTime::Jan, 9999, 0, 0, 0}, |
8b7d411f VZ |
1174 | false |
1175 | }, | |
444bc2b2 VZ |
1176 | |
1177 | { | |
1178 | "2012-01-01 10:12:05 +0100", | |
1179 | { 1, wxDateTime::Jan, 2012, 10, 12, 5, -1 }, | |
1180 | false // ParseDateTime does know yet +0100 | |
1181 | }, | |
804eeca5 VZ |
1182 | }; |
1183 | ||
66f22f4a VZ |
1184 | // the test strings here use "PM" which is not available in all locales so |
1185 | // we need to use "C" locale for them | |
34d4d286 VZ |
1186 | CLocaleSetter cloc; |
1187 | ||
804eeca5 VZ |
1188 | wxDateTime dt; |
1189 | for ( size_t n = 0; n < WXSIZEOF(parseTestDates); n++ ) | |
1190 | { | |
66f22f4a | 1191 | const wxString datestr = TranslateDate(parseTestDates[n].str); |
3aa3163f | 1192 | |
66f22f4a VZ |
1193 | const char * const end = dt.ParseDateTime(datestr); |
1194 | if ( end && !*end ) | |
804eeca5 | 1195 | { |
3aa3163f VZ |
1196 | WX_ASSERT_MESSAGE( |
1197 | ("Erroneously parsed \"%s\"", datestr), | |
1198 | parseTestDates[n].good | |
1199 | ); | |
804eeca5 | 1200 | |
8605eb1a | 1201 | CPPUNIT_ASSERT_EQUAL( parseTestDates[n].date.DT(), dt ); |
ccd6aacd VZ |
1202 | } |
1203 | else // failed to parse | |
1204 | { | |
3aa3163f VZ |
1205 | WX_ASSERT_MESSAGE( |
1206 | ("Failed to parse \"%s\"", datestr), | |
1207 | !parseTestDates[n].good | |
1208 | ); | |
1209 | ||
ccd6aacd VZ |
1210 | CPPUNIT_ASSERT( !parseTestDates[n].good ); |
1211 | } | |
1212 | } | |
1213 | } | |
1214 | ||
1215 | void DateTimeTestCase::TestTimeArithmetics() | |
1216 | { | |
1217 | static const wxDateSpan testArithmData[] = | |
1218 | { | |
1219 | wxDateSpan::Day(), | |
1220 | wxDateSpan::Week(), | |
1221 | wxDateSpan::Month(), | |
1222 | wxDateSpan::Year(), | |
1223 | }; | |
1224 | ||
1225 | // the test will *not* work with arbitrary date! | |
1226 | wxDateTime dt(2, wxDateTime::Dec, 1999), | |
1227 | dt1, | |
1228 | dt2; | |
1229 | ||
1230 | for ( size_t n = 0; n < WXSIZEOF(testArithmData); n++ ) | |
1231 | { | |
1232 | const wxDateSpan& span = testArithmData[n]; | |
1233 | dt1 = dt + span; | |
1234 | dt2 = dt - span; | |
1235 | ||
15cb637c VZ |
1236 | CPPUNIT_ASSERT_EQUAL( dt, dt1 - span ); |
1237 | CPPUNIT_ASSERT_EQUAL( dt, dt2 + span ); | |
1238 | CPPUNIT_ASSERT_EQUAL( dt1, dt2 + 2*span ); | |
77dd7daa | 1239 | CPPUNIT_ASSERT_EQUAL( span, dt1.DiffAsDateSpan(dt) ); |
ccd6aacd | 1240 | } |
f4370376 VZ |
1241 | |
1242 | // More date span arithmetics tests | |
1243 | wxDateTime dtd1(5, wxDateTime::Jun, 1998); | |
1244 | wxDateTime dtd2(6, wxDateTime::Aug, 1999); | |
1245 | ||
1246 | // All parts in dtd2 is after dtd1 | |
1247 | CPPUNIT_ASSERT_EQUAL( wxDateSpan(1, 2, 0, 1), dtd2.DiffAsDateSpan(dtd1) ); | |
1248 | ||
1249 | // Year and month after, day earlier, so no full month | |
1250 | // Jul has 31 days, so it's 31 - 5 + 4 = 30, or 4w 2d | |
1251 | dtd2.Set(4, wxDateTime::Aug, 1999); | |
1252 | CPPUNIT_ASSERT_EQUAL( wxDateSpan(1, 1, 4, 2), dtd2.DiffAsDateSpan(dtd1) ); | |
1253 | ||
1254 | // Year and day after, month earlier, so no full year, but same day diff as | |
1255 | // first example | |
1256 | dtd2.Set(6, wxDateTime::May, 1999); | |
1257 | CPPUNIT_ASSERT_EQUAL( wxDateSpan(0, 11, 0, 1), dtd2.DiffAsDateSpan(dtd1) ); | |
1258 | ||
1259 | // Year after, month and day earlier, so no full month and no full year | |
1260 | // April has 30 days, so it's 30 - 5 + 4 = 29, or 4w 1d | |
1261 | dtd2.Set(4, wxDateTime::May, 1999); | |
1262 | CPPUNIT_ASSERT_EQUAL( wxDateSpan(0, 10, 4, 1), dtd2.DiffAsDateSpan(dtd1) ); | |
1263 | ||
1264 | // And a reverse. Now we should use days in Jun (again 30 => 4w 1d) | |
1265 | CPPUNIT_ASSERT_EQUAL( wxDateSpan(0, -10, -4, -1), dtd1.DiffAsDateSpan(dtd2) ); | |
ccd6aacd VZ |
1266 | } |
1267 | ||
a480d0ab VZ |
1268 | void DateTimeTestCase::TestDSTBug() |
1269 | { | |
1270 | ///////////////////////// | |
1271 | // Test GetEndDST() | |
c6a95dd6 | 1272 | wxDateTime dt = wxDateTime::GetEndDST(2004, wxDateTime::France); |
a480d0ab VZ |
1273 | CPPUNIT_ASSERT_EQUAL(31, (int)dt.GetDay()); |
1274 | CPPUNIT_ASSERT_EQUAL(wxDateTime::Oct, dt.GetMonth()); | |
1275 | CPPUNIT_ASSERT_EQUAL(2004, (int)dt.GetYear()); | |
770882a6 | 1276 | CPPUNIT_ASSERT_EQUAL(1, (int)dt.GetHour()); |
a480d0ab VZ |
1277 | CPPUNIT_ASSERT_EQUAL(0, (int)dt.GetMinute()); |
1278 | CPPUNIT_ASSERT_EQUAL(0, (int)dt.GetSecond()); | |
1279 | CPPUNIT_ASSERT_EQUAL(0, (int)dt.GetMillisecond()); | |
1280 | ||
1281 | ///////////////////////// | |
1282 | // Test ResetTime() | |
1283 | dt.SetHour(5); | |
1284 | CPPUNIT_ASSERT_EQUAL(5, (int)dt.GetHour()); | |
1285 | dt.ResetTime(); | |
1286 | CPPUNIT_ASSERT_EQUAL(31, (int)dt.GetDay()); | |
1287 | CPPUNIT_ASSERT_EQUAL(wxDateTime::Oct, dt.GetMonth()); | |
1288 | CPPUNIT_ASSERT_EQUAL(2004, (int)dt.GetYear()); | |
1289 | CPPUNIT_ASSERT_EQUAL(0, (int)dt.GetHour()); | |
1290 | CPPUNIT_ASSERT_EQUAL(0, (int)dt.GetMinute()); | |
1291 | CPPUNIT_ASSERT_EQUAL(0, (int)dt.GetSecond()); | |
1292 | CPPUNIT_ASSERT_EQUAL(0, (int)dt.GetMillisecond()); | |
1293 | ||
fcae7135 VZ |
1294 | dt.Set(1, 0, 0, 0); |
1295 | CPPUNIT_ASSERT_EQUAL(1, (int)dt.GetHour()); | |
1296 | ||
a480d0ab VZ |
1297 | ///////////////////////// |
1298 | // Test Today() | |
1299 | #ifdef CHANGE_SYSTEM_DATE | |
1300 | { | |
1301 | DateChanger change(2004, 10, 31, 5, 0, 0); | |
1302 | dt = wxDateTime::Today(); | |
1303 | } | |
1304 | ||
1305 | CPPUNIT_ASSERT_EQUAL(31, (int)dt.GetDay()); | |
1306 | CPPUNIT_ASSERT_EQUAL(wxDateTime::Oct, dt.GetMonth()); | |
1307 | CPPUNIT_ASSERT_EQUAL(2004, (int)dt.GetYear()); | |
1308 | CPPUNIT_ASSERT_EQUAL(0, (int)dt.GetHour()); | |
1309 | CPPUNIT_ASSERT_EQUAL(0, (int)dt.GetMinute()); | |
1310 | CPPUNIT_ASSERT_EQUAL(0, (int)dt.GetSecond()); | |
1311 | CPPUNIT_ASSERT_EQUAL(0, (int)dt.GetMillisecond()); | |
1312 | ||
1313 | ///////////////////////// | |
1314 | // Test Set(hour, minute, second, milli) | |
1315 | wxDateTime dt2; | |
1316 | { | |
1317 | DateChanger change(2004, 10, 31, 5, 0, 0); | |
1318 | dt.Set(1, 30, 0, 0); | |
1319 | dt2.Set(5, 30, 0, 0); | |
1320 | } | |
1321 | ||
1322 | CPPUNIT_ASSERT_EQUAL(31, (int)dt.GetDay()); | |
1323 | CPPUNIT_ASSERT_EQUAL(wxDateTime::Oct, dt.GetMonth()); | |
1324 | CPPUNIT_ASSERT_EQUAL(2004, (int)dt.GetYear()); | |
1325 | CPPUNIT_ASSERT_EQUAL(1, (int)dt.GetHour()); | |
1326 | CPPUNIT_ASSERT_EQUAL(30, (int)dt.GetMinute()); | |
1327 | CPPUNIT_ASSERT_EQUAL(0, (int)dt.GetSecond()); | |
1328 | CPPUNIT_ASSERT_EQUAL(0, (int)dt.GetMillisecond()); | |
1329 | ||
1330 | CPPUNIT_ASSERT_EQUAL(31, (int)dt2.GetDay()); | |
1331 | CPPUNIT_ASSERT_EQUAL(wxDateTime::Oct, dt2.GetMonth()); | |
1332 | CPPUNIT_ASSERT_EQUAL(2004, (int)dt2.GetYear()); | |
1333 | CPPUNIT_ASSERT_EQUAL(5, (int)dt2.GetHour()); | |
1334 | CPPUNIT_ASSERT_EQUAL(30, (int)dt2.GetMinute()); | |
1335 | CPPUNIT_ASSERT_EQUAL(0, (int)dt2.GetSecond()); | |
1336 | CPPUNIT_ASSERT_EQUAL(0, (int)dt2.GetMillisecond()); | |
1337 | #endif // CHANGE_SYSTEM_DATE | |
17d698cc VZ |
1338 | |
1339 | // Verify that setting the date to the beginning of the DST period moves it | |
1340 | // forward (as this date on its own would be invalid). The problem here is | |
1341 | // that our GetBeginDST() is far from being trustworthy, so just try a | |
1342 | // couple of dates for the common time zones and check that all of them are | |
1343 | // either unchanged or moved forward. | |
1344 | wxDateTime dtDST(10, wxDateTime::Mar, 2013, 2, 0, 0); | |
1345 | if ( dtDST.GetHour() != 2 ) | |
1346 | CPPUNIT_ASSERT_EQUAL( 3, dtDST.GetHour() ); | |
1347 | ||
1348 | dtDST = wxDateTime(31, wxDateTime::Mar, 2013, 2, 0, 0); | |
1349 | if ( dtDST.GetHour() != 2 ) | |
1350 | CPPUNIT_ASSERT_EQUAL( 3, dtDST.GetHour() ); | |
a480d0ab VZ |
1351 | } |
1352 | ||
fb96cf85 VZ |
1353 | void DateTimeTestCase::TestDateOnly() |
1354 | { | |
1355 | wxDateTime dt(19, wxDateTime::Jan, 2007, 15, 01, 00); | |
1356 | ||
1357 | static const wxDateTime::wxDateTime_t DATE_ZERO = 0; | |
1358 | CPPUNIT_ASSERT_EQUAL( DATE_ZERO, dt.GetDateOnly().GetHour() ); | |
1359 | CPPUNIT_ASSERT_EQUAL( DATE_ZERO, dt.GetDateOnly().GetMinute() ); | |
1360 | CPPUNIT_ASSERT_EQUAL( DATE_ZERO, dt.GetDateOnly().GetSecond() ); | |
1361 | CPPUNIT_ASSERT_EQUAL( DATE_ZERO, dt.GetDateOnly().GetMillisecond() ); | |
1362 | ||
1363 | dt.ResetTime(); | |
1364 | CPPUNIT_ASSERT_EQUAL( wxDateTime(19, wxDateTime::Jan, 2007), dt ); | |
1365 | ||
1366 | CPPUNIT_ASSERT_EQUAL( wxDateTime::Today(), wxDateTime::Now().GetDateOnly() ); | |
1367 | } | |
1368 | ||
34af0de4 | 1369 | #endif // wxUSE_DATETIME |