1 /* Copyright (c) 2003-2005 CrystalClear Software, Inc.
2 * Subject to the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
4 * Author: Jeff Garland, Bart Garst
5 * $Date$
6 */
7
8
9 #include "boost/date_time/local_time/custom_time_zone.hpp"
10 #include "boost/date_time/posix_time/posix_time.hpp"
11 #include "boost/date_time/local_time/local_time.hpp"
12 // #include "boost/date_time/local_time/posix_time_zone.hpp"
13 #include "../testfrmwk.hpp"
14 //#include "boost/date_time/c_time.hpp"
15 #include <iostream>
16
17 #include <sstream>
18 // function eases testing
tm_out(const tm & ptr)19 std::string tm_out(const tm& ptr){
20 std::stringstream ss;
21
22 ss
23 << ptr.tm_wday << ' ' << ptr.tm_yday << ' '
24 << std::setw(2) << std::setfill('0') << ptr.tm_mon + 1 << '/'
25 << std::setw(2) << std::setfill('0') << ptr.tm_mday << '/'
26 << std::setw(2) << std::setfill('0') << ptr.tm_year + 1900 << ' '
27 << std::setw(2) << std::setfill('0') << ptr.tm_hour << ':'
28 << std::setw(2) << std::setfill('0') << ptr.tm_min << ':'
29 << std::setw(2) << std::setfill('0') << ptr.tm_sec << ' ';
30 if(ptr.tm_isdst >= 0){
31 ss << (ptr.tm_isdst ? "DST" : "STD");
32 }
33 else{
34 ss << "DST/STD unknown";
35 }
36 return ss.str();
37 }
38
39 int
main()40 main()
41 {
42
43 using namespace boost::gregorian;
44 using namespace boost::posix_time;
45 using namespace boost::local_time;
46
47 // since local_date_time inherits it's math operations from time, the
48 // tests here only show that the operations work. The thorough testing
49 // of these operations is done in the posix_time tests
50
51 try {
52 time_zone_ptr az_tz(new posix_time_zone("MST-07"));
53 time_zone_ptr ny_tz(new posix_time_zone("EST-05EDT,M4.1.0,M10.5.0"));
54 // EST & EST for sydney is correct, according to zoneinfo files
55 time_zone_ptr sydney(new posix_time_zone("EST+10EST,M10.5.0,M3.5.0/03:00"));
56 time_zone_ptr null_tz;
57 date d(2003, 12, 20);
58 hours h(12);
59 ptime t(d,h);
60 local_date_time az_time(t, az_tz); // ptime constructor is a UTC time
61
62 check("Zone abbreviation", az_time.zone()->std_zone_abbrev() == std::string("MST"));
63 check("base offset", az_time.zone()->base_utc_offset() == hours(-7));
64 check("zone has dst", az_time.zone()->has_dst() == false);
65 check("is_dst check", az_time.is_dst() == false);
66 check("to_string: " + az_time.to_string(),
67 az_time.to_string() == "2003-Dec-20 05:00:00 MST");
68
69
70
71 std::cout << "\nChecking copy construction" << std::endl;
72 local_date_time az_time2(az_time); //copy constructor
73 // Now test the copy
74 check("is_dst check", az_time2.is_dst() == false);
75 check("to_string: " + az_time2.to_string(),
76 az_time2.to_string() == "2003-Dec-20 05:00:00 MST");
77 check("zone has dst", az_time2.zone()->has_dst() == false);
78 check("base offset", az_time2.zone()->base_utc_offset() == hours(-7));
79
80
81 std::cout << "\nChecking special_value construction" << std::endl;
82 // since local_date_time inherits its special value operatorations
83 // from time, we only need to show here that they work as thorough
84 // testing is done in the posix_time tests
85 ptime svpt(not_a_date_time);
86 local_date_time sv_time(svpt, ny_tz);
87 check("is special_value", sv_time.is_not_a_date_time());
88 check("to_string: " + sv_time.to_string(),
89 sv_time.to_string() == "not-a-date-time");
90 check("is_dst", sv_time.is_dst() == false);
91 local_date_time sv_time2(pos_infin);
92 check("is special_value", sv_time2.is_pos_infinity());
93 check("to_string: " + sv_time2.to_string(),
94 sv_time2.to_string() == "+infinity");
95 check("is_dst", sv_time2.is_dst() == false);
96 sv_time2 += days(12); // add a duration to a special value
97 check("Add a duration to a special value", sv_time2.is_pos_infinity());
98
99 local_date_time sv_time3(max_date_time, ny_tz);
100 #ifdef BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG
101 check("max_date_time to_string: " + sv_time3.to_string(),
102 sv_time3.to_string() == "9999-Dec-31 18:59:59.999999999 EST");
103 #else
104 check("max_date_time to_string: " + sv_time3.to_string(),
105 sv_time3.to_string() == "9999-Dec-31 18:59:59.999999 EST");
106 #endif
107
108 try {
109 local_date_time sv_time4(min_date_time);
110 check("min_date_time to_string: " + sv_time4.to_string(),
111 sv_time4.to_string() == "1400-Jan-01 00:00:00 UTC");
112 }
113 catch (std::exception& e) {
114 check("min_date_time to_string -- exception" , false);
115 std::cout << "Exception is : " << e.what() << std::endl;
116 }
117
118 /** todo -- this will cause an out of range when min_date is adjusted for ny_tz
119 local_date_time sv_time5(min_date_time, ny_tz);
120 std::cout << sv_time5.to_string() << std::endl;
121 **/
122
123 std::cout << "\nChecking calc_options construction" << std::endl;
124 { // invalid NADT
125 date dx(2004, Apr, 4);
126 time_duration td(2,30,0); // invalid local time in ny_tz
127 local_date_time calcop(dx, td, ny_tz, local_date_time::NOT_DATE_TIME_ON_ERROR);
128 check("is NADT", calcop.is_not_a_date_time());
129 }
130 { // invalid exception
131 date dx(2004, Apr, 4);
132 time_duration td(2,30,0); // invalid local time in ny_tz
133 try{
134 local_date_time calcop(dx, td, ny_tz, local_date_time::EXCEPTION_ON_ERROR);
135 check("Did not catch expected exception", false);
136 }catch(time_label_invalid& /*i*/){
137 check("Caught expected exception", true);
138 }catch(...){
139 check("Caught unexpected exception", false);
140 }
141 }
142 { // ambig NADT
143 date dx(2004, Oct, 31);
144 time_duration td(1,30,0); // ambig local time in ny_tz
145 local_date_time calcop(dx, td, ny_tz, local_date_time::NOT_DATE_TIME_ON_ERROR);
146 check("is NADT", calcop.is_not_a_date_time());
147 }
148 { // ambig exception
149 date dx(2004, Oct, 31);
150 time_duration td(1,30,0); // ambig local time in ny_tz
151 try{
152 local_date_time calcop(dx, td, ny_tz, local_date_time::EXCEPTION_ON_ERROR);
153 check("Did not catch expected exception", false);
154 }catch(ambiguous_result& /*a*/){
155 check("Caught expected exception", true);
156 }catch(...){
157 check("Caught unexpected exception", false);
158 }
159 }
160
161
162 //Now construct with a date and time
163 std::cout << "\nChecking construct with date and time_duration" << std::endl;
164 local_date_time az_time3(d, h, az_tz, false);
165 check("Zone abbreviation", az_time3.zone()->std_zone_abbrev() == std::string("MST"));
166 check("base offset", az_time3.zone()->base_utc_offset() == hours(-7));
167 check("base offset", az_time3.zone()->has_dst() == false);
168 check("is_dst check", az_time3.is_dst() == false);
169 check("to_string: " + az_time3.to_string(),
170 az_time3.to_string() == "2003-Dec-20 12:00:00 MST");
171
172 // construct with a null tz
173 //local_date_time null_tz_time(d, h, null_tz, false);
174 local_date_time null_tz_time(d, h, null_tz, true);
175 // TODO: how to handle calls to null_tz_time.zone()->...
176 check("is_dst check", null_tz_time.is_dst() == false);
177 check("to_string: " + null_tz_time.to_string(),
178 null_tz_time.to_string() == "2003-Dec-20 12:00:00 UTC");
179
180 //Now construct with a date and time - invalid parameters
181 try{
182 local_date_time blt(d, h, ny_tz, true);
183 check("Did not catch expected exception (dst_not_valid)", false);
184 }catch(dst_not_valid& e){
185 check(std::string("Caught expected exception (dst_not_valid) ") + e.what(), true);
186 }catch(std::exception& e){
187 check(std::string("Caught unexpected exception ") + e.what(), false);
188 }
189 try{
190 local_date_time blt(date(2004,Apr,4), time_duration(2,30,0), ny_tz, true);
191 check("Did not catch expected exception (Invalid_Time_Label)", false);
192 }catch(time_label_invalid& e){
193 check(std::string("Caught expected exception (Invalid_Time_Label) ") + e.what(), true);
194 }catch(std::exception& e){
195 check(std::string("Caught unexpected exception ") + e.what(), false);
196 }
197
198
199 // thorough is_dst() tests, tests againts null_tz and non dst tz are
200 // done where those local times were tested
201 {
202 date dx(2004,Apr,4);
203 time_duration td(1,15,0); // local
204 local_date_time lt1(dx,td,ny_tz,false);
205 local_date_time lt2(ptime(dx,time_duration(6,15,0)), ny_tz);
206 check("are local_times equal", lt1.utc_time() == lt2.utc_time());
207 check("is_dst - transition in 1", lt1.is_dst() == false);
208 check("is_dst - transition in 2", lt2.is_dst() == false);
209 lt1 += hours(1);
210 lt2 += hours(1);
211 check("is_dst - transition in 1", lt1.is_dst() == true);
212 check("is_dst - transition in 2", lt2.is_dst() == true);
213 }
214 {
215 date dx(2004,Oct,31);
216 time_duration td(1,15,0); // local
217 local_date_time lt1(dx,td,ny_tz,true);
218 /*try{
219 //local_date_time lt1(dx,td,ny_tz,false);
220 local_date_time lt1(dx,td,ny_tz,true);
221 std::cout << "no exception thrown" << std::endl;
222 }catch(time_label_invalid& e){
223 std::cout << "caught: " << e.what() << std::endl;
224 }*/
225 local_date_time lt2(ptime(dx,time_duration(5,15,0)), ny_tz);
226 check("are local_times equal", lt1.utc_time() == lt2.utc_time());
227 check("is_dst - transition out 1", lt1.is_dst() == true);
228 check("is_dst - transition out 2", lt2.is_dst() == true);
229 lt1 += hours(1);
230 lt2 += hours(1);
231 check("is_dst - transition out 1", lt1.is_dst() == false);
232 check("is_dst - transition out 2", lt2.is_dst() == false);
233 }
234 { // southern hemisphere
235 date dx(2004,Oct,31);
236 time_duration td(1,15,0); // local
237 local_date_time lt1(dx,td,sydney,false);
238 check("is_dst - transition in (sydney)", lt1.is_dst() == false);
239 lt1 += hours(1);
240 check("is_dst - transition in (sydney)", lt1.is_dst() == true);
241 }
242 {
243 date dx(2004,Mar,28);
244 time_duration td(2,15,0); // local; sydney has a weird trans time
245 local_date_time lt1(dx,td,sydney,true);
246 check("is_dst - transition out (sydney)", lt1.is_dst() == true);
247 lt1 += hours(1);
248 check("is_dst - transition out (sydney)", lt1.is_dst() == false);
249 }
250
251
252
253 std::cout << "\nTest conversion of time zone from Arizona to New York" << std::endl;
254 local_date_time ny_time = az_time.local_time_in(ny_tz);
255 check("Zone abbreviation", ny_time.zone()->std_zone_abbrev() == std::string("EST"));
256 check("base offset", ny_time.zone()->base_utc_offset() == hours(-5));
257 check("base offset", ny_time.zone()->has_dst() == true);
258 check("to_string: " + ny_time.to_string(),
259 ny_time.to_string() == "2003-Dec-20 07:00:00 EST");
260 ny_time += hours(3);
261 check("to_string after add 3 hours: " + ny_time.to_string(),
262 ny_time.to_string() == "2003-Dec-20 10:00:00 EST");
263 ny_time += days(3);
264 check("to_string after add 3 days: " + ny_time.to_string(),
265 ny_time.to_string() == "2003-Dec-23 10:00:00 EST");
266
267
268 { // test comparisons & math operations
269 date dx(2003, Aug, 28);
270 ptime sv_pt(pos_infin);
271 local_date_time sv_lt(sv_pt, ny_tz);
272 ptime utc_pt(dx, hours(12));
273 // all 4 of the following local times happen at the same instant
274 // so they are all equal
275 local_date_time utc_lt(utc_pt, null_tz); // noon in utc
276 local_date_time az_lt(dx, hours(5), az_tz, false); // 5am local std
277 local_date_time ny_lt(dx, hours(8), ny_tz, true); // 8am local dst
278 local_date_time au_lt(dx, hours(22), sydney, false);// 10pm local std
279
280 check("local_date_time to tm",
281 std::string("4 239 08/28/2003 05:00:00 STD") == tm_out(to_tm(az_lt)));
282 check("local_date_time to tm",
283 std::string("4 239 08/28/2003 08:00:00 DST") == tm_out(to_tm(ny_lt)));
284 check("local_date_time to tm",
285 std::string("4 239 08/28/2003 22:00:00 STD") == tm_out(to_tm(au_lt)));
286
287 try{
288 local_date_time ldt(not_a_date_time);
289 tm ldt_tm = to_tm(ldt);
290 check("Exception not thrown (special_value to_tm)", false);
291 //does nothing useful but stops compiler from complaining about unused ldt_tm
292 std::cout << ldt_tm.tm_sec << std::endl;
293 }catch(std::out_of_range&){
294 check("Caught expected exception (special_value to_tm)", true);
295 }catch(...){
296 check("Caught un-expected exception (special_value to_tm)", false);
297 }
298 // check that all are equal to sv_pt
299 check("local == utc", az_lt == utc_lt);
300 check("local == utc", ny_lt == utc_lt);
301 check("local == utc", au_lt == utc_lt);
302 check("local <= utc", au_lt <= utc_lt);
303 check("local >= utc", au_lt >= utc_lt);
304 check("local == local", az_lt == ny_lt);
305 check("local < local", az_lt < ny_lt+seconds(1));
306 check("local > local", az_lt+seconds(1) > ny_lt);
307 check("local <= local", az_lt <= ny_lt);
308 check("local >= local", az_lt >= ny_lt);
309 check("local != local", az_lt+seconds(1) != ny_lt);
310
311 au_lt += hours(1);
312 check("local != after +=", au_lt != utc_lt);
313 check("local <= after +=", utc_lt <= au_lt);
314 check("local >= after +=", au_lt >= utc_lt);
315 check("local < after +=", utc_lt < au_lt);
316 check("local > after +=", au_lt > utc_lt);
317 au_lt -= hours(1);
318 check("local == utc after -=", au_lt == utc_lt);
319
320 check("local + days",
321 (az_lt + days(2)).to_string() == "2003-Aug-30 05:00:00 MST");
322 check("local - days",
323 (az_lt - days(2)).to_string() == "2003-Aug-26 05:00:00 MST");
324 check("local += days",
325 (az_lt += days(2)).to_string() == "2003-Aug-30 05:00:00 MST");
326 check("local -= days",
327 (az_lt -= days(2)).to_string() == "2003-Aug-28 05:00:00 MST");
328 check("local + time_duration",
329 (az_lt + hours(2)).to_string() == "2003-Aug-28 07:00:00 MST");
330 check("local - time_duration",
331 (az_lt - hours(2)).to_string() == "2003-Aug-28 03:00:00 MST");
332 // special_values is more thoroughly tested in posix_time
333 check("pos_infinity > local", sv_lt > au_lt);
334 local_date_time sv_lt2(sv_lt + days(2));
335 check("pos_infin + duration == pos_infin", sv_lt2 == sv_lt);
336
337 #if defined(BOOST_DATE_TIME_OPTIONAL_GREGORIAN_TYPES)
338 months m(2);
339 years y(2);
340 check("Local + months",
341 (az_lt + m).to_string() == "2003-Oct-28 05:00:00 MST");
342 az_lt += m;
343 check("Local += months",
344 az_lt.to_string() == "2003-Oct-28 05:00:00 MST");
345 check("Local - months",
346 (az_lt - m).to_string() == "2003-Aug-28 05:00:00 MST");
347 az_lt -= m;
348 check("Local -= months",
349 az_lt.to_string() == "2003-Aug-28 05:00:00 MST");
350 check("Local + years",
351 (az_lt + y).to_string() == "2005-Aug-28 05:00:00 MST");
352 az_lt += y;
353 check("Local += years",
354 az_lt.to_string() == "2005-Aug-28 05:00:00 MST");
355 check("Local - years",
356 (az_lt - y).to_string() == "2003-Aug-28 05:00:00 MST");
357 az_lt -= y;
358 check("Local -= years",
359 az_lt.to_string() == "2003-Aug-28 05:00:00 MST");
360
361 #endif // BOOST_DATE_TIME_OPTIONAL_GREGORIAN_TYPES
362 }
363 }
364 catch(std::exception& e) {
365 check(std::string("test failed due to exception: ") + e.what(), false);
366 }
367
368 return printTestStats();
369 }
370
371