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 s("20050229"); // no Feb-29 in 2005
86       date d(not_a_date_time);
87       try {
88         d = date_from_iso_string(s);
89         check("Expected exception not thrown: from ISO string (bad_day_of_month)", false);
90         std::cout << date_from_iso_string(s) << std::endl;
91       }
92       catch(bad_day_of_month& e) {
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       s = "2005022"; // missing a digit
100       try {
101         d = date_from_iso_string(s);
102         check("Expected exception not thrown: from ISO string (missing digit)", false);
103         std::cout << date_from_iso_string(s) << 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       s = "20050228"; // now it's correct
113       d = date_from_iso_string(s);
114       check("from ISO string", date(2005,Feb,28) == d);
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   }
349   catch(std::exception& e) {
350     check(std::string("empty string parse (exception expected): ") + e.what(),  true);
351   }
352 
353 
354 //Calendar Week + Day Number
355 // CCYYWwwDThhmmss
356 // 1986W105T
357 // week == 10 day=5
358 // see page 5
359 
360 
361 //Duration rep
362 //CCYYMMDDThhmmss/PnYnMnDTnHnMnS
363 
364   return printTestStats();
365 
366 }
367 
368