1 /* Copyright (c) 2002,2003,2005 CrystalClear Software, Inc.
2 * Use, modification and distribution is subject to the
3 * Boost Software License, Version 1.0. (See accompanying
4 * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
5 * Author: Jeff Garland, Bart Garst
6 */
7
8 #include "boost/date_time/gregorian/gregorian.hpp"
9 #include "../testfrmwk.hpp"
10 #include "boost/lexical_cast.hpp"
11 #include <iostream>
12 #include <string>
13
14 // missing or misspelled parts of date string tests
15 // 'output_str' will be overwritten with what() from caught exception
failure_tests(std::string date_spec,std::string & output_str)16 bool failure_tests(std::string date_spec,
17 std::string& output_str)
18 {
19 using namespace boost::gregorian;
20 bool result = false;
21 date d(not_a_date_time);
22 try {
23 d = from_simple_string(date_spec);
24 }
25 catch(bad_year& by){ // ex: "205-Jan-15"
26 result = true;
27 output_str = by.what();
28 }
29 catch(bad_month& bm){ // ex: "2005-Jsn-15"
30 result = true;
31 output_str = bm.what();
32 }
33 catch(bad_day_of_month& bd){ // ex: "2005-Jan-51"
34 result = true;
35 output_str = bd.what();
36 }
37 catch(...){
38 // test failed - unexpected exception, leave result set to false
39 }
40 return result;
41 }
42
43 int
main()44 main()
45 {
46
47
48 // Examples from 8601
49 // Full date
50 // Extended CCYY-MM-DD
51 std::string s("2001-10-5");
52
53 //This one aborts gcc2.95.3 on mandrake 8.1 linux with
54 //bad lexical cast?
55 try {
56 boost::gregorian::date d(boost::gregorian::from_string(s));
57 check("check year", d.year() == 2001);
58 check("check month", d.month() == 10);
59 check("check day", d.day() == 5);
60 }
61 catch(std::exception& e) {
62 check("parse 2001-10-5", false);
63 std::cout << "Fail: " << e.what() << std::endl;
64 }
65
66 {
67 using namespace boost::gregorian;
68 // date objects from strings & strings to date objects
69 date d(2000, 2, 29);
70 date d2 = from_string("2000-2-29");
71 check("2000-2-29", d2 == d);
72 date d3 = from_string("2000-FEB-29");
73 check("2000-FEB-29 (uppercase)", d3 == d);
74 date d4 = from_string("2000-february-29");
75 check("2000-february-29 (lowercase)", d4 == d);
76 date d5 = from_string(to_simple_string(d));
77 check("date to string to date", d5 == d);
78 date d6 = from_string(to_iso_extended_string(d));
79 check("date to string to date", d6 == d);
80 date d7 = from_us_string("Feb-29-2000");
81 check("date from month-day-year string", d7 == d);
82 date d8 = from_uk_string("29-Feb-2000");
83 check("date from day-month-year string", d8 == d);
84 {
85 std::string sn("20050229"); // no Feb-29 in 2005
86 date dn(not_a_date_time);
87 try {
88 dn = date_from_iso_string(sn);
89 check("Expected exception not thrown: from ISO string (bad_day_of_month)", false);
90 std::cout << date_from_iso_string(sn) << std::endl;
91 }
92 catch(bad_day_of_month&) {
93 check("Caught expected exception: bad_day_of_month ", true);
94 }
95 catch(...) {
96 check("Caught unexpected exception", false);
97 }
98 /* not currently passing due to a bug in boost::offset_separator (reported 2005-Aug-02)
99 sn = "2005022"; // missing a digit
100 try {
101 d = date_from_iso_string(sn);
102 check("Expected exception not thrown: from ISO string (missing digit)", false);
103 std::cout << date_from_iso_string(sn) << std::endl;
104 }
105 catch(bad_day_of_month& e) {
106 check("Caught expected exception: bad_day_of_month ", true);
107 }
108 catch(...) {
109 check("Caught unexpected exception", false);
110 }
111 */
112 sn = "20050228"; // now it's correct
113 dn = date_from_iso_string(sn);
114 check("from ISO string", date(2005,Feb,28) == dn);
115 }
116
117 date d9 = from_us_string(__DATE__);
118 std::cout << "Today's date: " << to_simple_string(d9) << std::endl;
119 date d10 = from_us_string("Feb 29, 2000");
120 std::cout << "With comma: " << to_simple_string(d10) << std::endl;
121 check("american date with comma: Feb 29, 2000 ", d10 == d);
122
123 date d11 = from_us_string("feb 29 2000");
124 check("american date with comma: feb 29 2000 ", d11 == d);
125
126 // test for missing or misspelled date spec components
127 std::string output_str("unexpected exception caught");
128 check("Year misspelled/out of range: " + output_str,
129 failure_tests("205-Jan-15", output_str));
130 output_str = "unexpected exception caught";
131 check("Month misspelled: " + output_str,
132 failure_tests("2005-Jsn-15", output_str));
133 output_str = "unexpected exception caught";
134 check("Day out of range: " + output_str,
135 failure_tests("2005-Jan-55", output_str));
136 output_str = "unexpected exception caught";
137 check("Missing month and day: " + output_str,
138 failure_tests("2005", output_str));
139 output_str = "unexpected exception caught";
140 check("Missing day: " + output_str,
141 failure_tests("2005-Jan", output_str));
142
143
144 #if defined(BOOST_DATE_TIME_NO_LOCALE) || defined(BOOST_NO_STD_ITERATOR_TRAITS) || !defined(USE_DATE_TIME_PRE_1_33_FACET_IO)
145
146 //TODO -- all these PRE_1_33 exclusions need to be removed. In the meantime, don't make
147 //this stuff fail.
148 #if defined(USE_DATE_TIME_PRE_1_33_FACET_IO)
149 check("input streaming for date not available", false); // force a failure
150 #endif
151 #else
152 {
153 std::stringstream ss("2000-2-29");
154 ss >> d2;
155 check("2000-2-29 stream-in", d2 == d);
156 }
157 {
158 std::stringstream ss("2000-FEB-29");
159 ss >> d2;
160 //std::cout << d2 << std::endl;
161 check("2000-FEB-29 stream-in (uppercase)", d2 == d);
162 }
163 {
164 std::stringstream ss("2000-february-29");
165 ss >> d2;
166 check("2000-february-29 stream-in (lowercase)", d2 == d);
167 }
168 // the removed (3) tests require a stream manipulator for date_order
169 // and date_separator (not yet implemented)
170 /*{
171 std::stringstream ss("Feb-29-2000");
172 ss >> d2;
173 check("date from month-day-year string stream-in", d2 == d);
174 }
175 {
176 std::stringstream ss("29-Feb-2000");
177 ss >> d2;
178 check("date from day-month-year string stream-in", d2 == d);
179 }
180 {
181 std::stringstream ss("Feb 29, 2000");
182 ss >> d2;
183 check("american date with comma: Feb 29, 2000 stream-in", d2 == d);
184 }*/
185 #endif //BOOST_DATE_TIME_NO_LOCALE
186
187
188
189 // check proper range
190 d = date(2001, 1, 1);
191 d2 = from_string("2001-Jan-1");
192 d3 = from_string("2001-January-1");
193 check("January", d == d2);
194 check("January", d == d3);
195 d = date(2001, 12, 1);
196 d2 = from_string("2001-Dec-1");
197 d3 = from_string("2001-December-1");
198 check("December", d == d2);
199 check("December", d == d3);
200 #if defined(BOOST_NO_STD_ITERATOR_TRAITS)
201 check("date from stream not available: no std iterator traits", false);
202 #else
203 // from stream
204 d = date(2000, 10, 31);
205 std::stringstream ss("");
206 ss << "2000-Oct-31 is Halloween 2k!";
207 std::istream_iterator<std::string> iter(ss), eos;
208 check("from stream - stringstream", d == from_stream(iter, eos));
209 #if !(defined(BOOST_NO_STD_WSTRING))
210 #if !(defined(BOOST_DATE_TIME_NO_WISTREAM_ITERATOR))
211 std::wstringstream ws;
212 ws << "2000-Oct-31 is Halloween 2k!";
213 std::istream_iterator<std::wstring, wchar_t> witer(ws), weos;
214 check("from stream - wstringstream", d == from_stream(witer, weos));
215 #endif // NO_WSTREAM_ITERATOR
216 #endif // BOOST_NO_WSTRING
217 char d2_string[] = {"2000-10-31 is Halloween 2k!"};
218 char* end = d2_string + sizeof(d2_string) - 1;
219 check("from stream - char[]", d == from_stream(d2_string, end));
220
221 std::string s1_string("2000-Oct-31 is Halloween 2k!");
222 std::string::iterator s1_start = s1_string.begin();
223 std::string::iterator s1_end = s1_string.end();
224 check("from stream - string", d == from_stream(s1_start, s1_end));
225 #ifndef BOOST_NO_STD_WSTRING
226 std::wstring w1_string(boost::lexical_cast<std::wstring>("2000-Oct-31 is Halloween 2k!"));
227 std::wstring::iterator w1_start = w1_string.begin();
228 std::wstring::iterator w1_end = w1_string.end();
229 check("from stream - wstring", d == from_stream(w1_start, w1_end));
230 #endif // BOOST_NO_STD_WSTRING
231 #endif // BOOST_NO_STD_ITERATOR_TRAITS
232 /* date objects from strings & strings to date objects
233 * with misspelled months */
234 try {
235 date bd = from_string("2002-Jull-4");
236 std::cout << "Shouldn't be reached." <<
237 boost::gregorian::to_simple_string(bd) << std::endl;
238 }
239 catch(boost::gregorian::bad_month&){
240 check("bad spelling 'Jull'", true);
241 }
242 catch(std::exception& e){
243 check("bad spelling", false);
244 std::cout << "Fail: " << e.what() << std::endl;
245 }
246 }
247
248
249 try {
250 std::string s2("2001-12-41"); //oops should be 31
251 boost::gregorian::date bad_day(boost::gregorian::from_string(s2)); //won't construct
252 check("check bad day", false);
253 //The line below won't execute, but make the compiler think
254 //we are using bad day....
255 std::cout << "Oh oh, this shouldn't be reached: "
256 << boost::gregorian::to_iso_string(bad_day) << std::endl;
257
258 }
259 catch(boost::gregorian::bad_day_of_month&) { //expected
260 check("check bad day", true);
261 }
262 catch(std::exception& e) {
263 //oops wrong exception
264 check("check bad day", false);
265 std::cout << "Fail: " << e.what() << std::endl;
266 }
267
268 try {
269 std::string s2("2001-02-29"); //oops should be 28
270 boost::gregorian::date bad_day(boost::gregorian::from_string(s2)); //won't construct
271 check("check bad leap year", false);
272 //The line below won't execute, but make the compiler think
273 //we are using bad day....
274 std::cout << "Oh oh, this shouldn't be reached: "
275 << boost::gregorian::to_iso_string(bad_day) << std::endl;
276
277 }
278 catch(boost::gregorian::bad_day_of_month&) { //expected
279 check("check bad leap year", true);
280 }
281 catch(std::exception& e) {
282 //oops wrong exception
283 check("check bad leap year", false);
284 std::cout << "Fail: " << e.what() << std::endl;
285 }
286
287 try {
288 std::string s2("2001-14-1"); //oops should be <= 12
289 boost::gregorian::date bad_month(boost::date_time::parse_date<boost::gregorian::date>(s2));
290 check("check bad month", false); //fail the test
291 //The line below won't execute, but make the compiler think
292 //we are using bad day....
293 std::cout << "Oh oh, this shouldn't be reached: "
294 << boost::gregorian::to_iso_string(bad_month) << std::endl;
295
296 }
297 catch(boost::gregorian::bad_month&) { //expected
298 check("check bad month", true);
299 }
300 catch(std::exception& e) {
301 //oops wrong exception
302 check("check bad month", false);
303 std::cout << "Fail: " << e.what() << std::endl;
304 }
305
306 //This one aborts gcc2.95.3 on mandrake 8.1 linux with
307 //bad lexical cast?
308 try {
309 //Example of ISO Standard -- CCYYMMDD
310 using namespace boost::gregorian;
311 std::string ud("20011009"); //2001-Oct-09
312 date d1(boost::gregorian::from_undelimited_string(ud));
313 // std::cout << to_string(d1) << std::endl;
314 check("undelimited date string", d1 == date(2001,Oct,9));
315
316
317 std::string ad("2001/10/09");
318 date d2(boost::date_time::parse_date<date>(ad));
319 check("check american date", d2 == date(2001,Oct,9));
320 }
321 catch(std::exception& e) {
322 check("more parsing", false);
323 std::cout << "Fail: " << e.what() << std::endl;
324 }
325
326 using namespace boost::gregorian;
327 std::string s2("2003-07-28");
328 date d2(from_string(s2));
329 check("check date", d2.month() == 7 &&
330 d2.year() == 2003 &&
331 d2.day() == 28);
332 // std::string s1("2001-Oct-5");
333 // gregorian::date d1(parse_date<gregorian::date>(s1));
334 // check("check month", d1.month() == 10);
335
336
337 //Check that the from_string and to_string can be reversed
338 date d10(2003, 10, 19);
339 std::string d10s = to_simple_string(d10);
340 date d11 = from_simple_string(d10s);
341 check("to from string inversion", d10 == d11);
342
343 try {
344 using namespace boost::gregorian;
345 std::string ud(""); //empty string error sf bug# 1155556
346 date d1(from_simple_string(ud));
347 check("empty string", false); //should never reach this piont
348 (void)d1;
349 }
350 catch(std::exception& e) {
351 check(std::string("empty string parse (exception expected): ") + e.what(), true);
352 }
353
354
355 //Calendar Week + Day Number
356 // CCYYWwwDThhmmss
357 // 1986W105T
358 // week == 10 day=5
359 // see page 5
360
361
362 //Duration rep
363 //CCYYMMDDThhmmss/PnYnMnDTnHnMnS
364
365 return printTestStats();
366
367 }
368
369