testtime_input_facet.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /* Copyright (c) 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. * $Date$
  7. */
  8. #include "boost/date_time/gregorian/gregorian.hpp"
  9. #include "boost/date_time/posix_time/posix_time.hpp"
  10. #include "../testfrmwk.hpp"
  11. #include <iostream>
  12. #include <sstream>
  13. #include <string>
  14. #include <vector>
  15. // for tests that are expected to fail and throw exceptions
  16. template<class temporal_type, class exception_type>
  17. bool failure_test(temporal_type component,
  18. const std::string& input,
  19. exception_type const& /*except*/,
  20. boost::posix_time::time_input_facet* facet)
  21. {
  22. using namespace boost::posix_time;
  23. bool result = false;
  24. std::istringstream iss(input);
  25. iss.exceptions(std::ios_base::failbit); // turn on exceptions
  26. iss.imbue(std::locale(std::locale::classic(), facet));
  27. try {
  28. iss >> component;
  29. }
  30. catch(exception_type& e) {
  31. std::cout << "Expected exception caught: \""
  32. << e.what() << "\"" << std::endl;
  33. result = iss.fail(); // failbit must be set to pass test
  34. }
  35. catch(...) {
  36. result = false;
  37. }
  38. return result;
  39. }
  40. // for tests that are expected to fail quietly
  41. template<class temporal_type>
  42. bool failure_test(temporal_type& component,
  43. const std::string& input,
  44. boost::posix_time::time_input_facet* facet)
  45. {
  46. using namespace boost::posix_time;
  47. std::istringstream iss(input);
  48. /* leave exceptions turned off
  49. * iss.exceptions(std::ios_base::failbit); */
  50. iss.imbue(std::locale(std::locale::classic(), facet));
  51. try {
  52. iss >> component;
  53. }
  54. catch(...) {
  55. std::cout << "Caught unexpected exception" << std::endl;
  56. return false;
  57. }
  58. return iss.fail(); // failbit must be set to pass test
  59. }
  60. using namespace boost::gregorian;
  61. using namespace boost::posix_time;
  62. void
  63. do_all_tests()
  64. {
  65. #if defined(USE_DATE_TIME_PRE_1_33_FACET_IO) // skip this file
  66. check("No tests run for this compiler. Incompatible IO", true);
  67. #else
  68. // set up initial objects
  69. time_duration td = hours(0);
  70. ptime pt(not_a_date_time);
  71. time_period tp(pt, td);
  72. // exceptions for failure_tests
  73. std::ios_base::failure e_failure("default");
  74. /* test ptime, time_duration, time_period.
  75. * test all formats.
  76. * test for bad input.
  77. * test special values.
  78. * do not test custom names (done in gregorian).
  79. *
  80. * format flags to test H,M,S,s,F,f,j
  81. */
  82. // default format tests: time_duration, ptime
  83. std::istringstream iss("09:59:01.321987654321 2005-Jan-15 10:15:03.123456789123");
  84. iss >> td;
  85. iss >> pt;
  86. #if defined(BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG)
  87. check_equal("Default format time_duration", td, time_duration(9,59,1,321987654));
  88. check_equal("Default format ptime", pt, ptime(date(2005,01,15),time_duration(10,15,3,123456789)));
  89. #else
  90. check_equal("Default format time_duration", td, time_duration(9,59,1,321987));
  91. check_equal("Default format ptime", pt, ptime(date(2005,01,15),time_duration(10,15,3,123456)));
  92. #endif
  93. // test all flags that appear in time_input_facet
  94. iss.str("12:34:56 2005-Jan-15 12:34:56");
  95. iss >> td;
  96. iss >> pt;
  97. check_equal("Default format time_duration no frac_sec", td, time_duration(12,34,56));
  98. // the following test insures %F parsing stops at the appropriate point
  99. check_equal("Default format ptime", pt, ptime(date(2005,01,15),time_duration(12,34,56)));
  100. iss.str("14:13:12 extra stuff"); // using default %H:%M:%S%F format
  101. iss >> td;
  102. check_equal("Default frac_sec format time_duration", td, time_duration(14,13,12));
  103. time_input_facet* facet = new time_input_facet();
  104. std::locale loc(std::locale::classic(), facet);
  105. facet->time_duration_format("%H:%M:%S""%f");
  106. iss.imbue(loc);
  107. iss.str("14:13:12.0 extra stuff");
  108. iss >> td;
  109. check_equal("Required-frac_sec format time_duration", td, time_duration(14,13,12));
  110. iss.str("12");
  111. facet->time_duration_format("%H");
  112. iss >> td;
  113. check_equal("Hours format", td, hours(12));
  114. iss.str("05");
  115. facet->time_duration_format("%M");
  116. iss >> td;
  117. check_equal("Minutes format", td, minutes(5));
  118. iss.str("45");
  119. facet->time_duration_format("%S");
  120. iss >> td;
  121. check_equal("Seconds w/o frac_sec format", td, seconds(45));
  122. iss.str("10.01");
  123. facet->time_duration_format("%s");
  124. iss >> td;
  125. #if defined(BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG)
  126. check_equal("Seconds w/ frac_sec format", td, time_duration(0,0,10,10000000));
  127. #else
  128. check_equal("Seconds w/ frac_sec format", td, time_duration(0,0,10,10000));
  129. #endif
  130. iss.str("2005-105T23:59");
  131. facet->format("%Y-%jT%H:%M"); // extended ordinal format
  132. iss >> pt;
  133. check_equal("Extended Ordinal format", pt, ptime(date(2005,4,15),time_duration(23,59,0)));
  134. /* this is not implemented yet. The flags: %I & %p are not parsed
  135. iss.str("2005-Jun-14 03:15:00 PM");
  136. facet->format("%Y-%b-%d %I:%M:%S %p");
  137. iss >> pt;
  138. check_equal("12 hour time format (AM/PM)", pt, ptime(date(2005,6,14),time_duration(15,15,0)));
  139. */
  140. iss.str("2005-Jun-14 15:15:00 %d");
  141. facet->format("%Y-%b-%d %H:%M:%S %%d");
  142. iss >> pt;
  143. check_equal("Literal '%' in format", pt, ptime(date(2005,6,14),time_duration(15,15,0)));
  144. iss.str("15:15:00 %d");
  145. facet->time_duration_format("%H:%M:%S %%d");
  146. iss >> td;
  147. check_equal("Literal '%' in time_duration format", td, time_duration(15,15,0));
  148. iss.str("2005-Jun-14 15:15:00 %14");
  149. facet->format("%Y-%b-%d %H:%M:%S %%%d"); // %% => % & %d => day_of_month
  150. iss >> pt;
  151. check_equal("Multiple literal '%'s in format", pt, ptime(date(2005,6,14),time_duration(15,15,0)));
  152. iss.str("15:15:00 %15");
  153. facet->time_duration_format("%H:%M:%S %%%M");
  154. iss >> td;
  155. check_equal("Multiple literal '%'s in time_duration format", td, time_duration(15,15,0));
  156. { /****** iso format tests (and custom 'scrunched-together formats) ******/
  157. time_input_facet *facet2 = new time_input_facet();
  158. facet2->set_iso_format();
  159. facet2->time_duration_format("%H""%M""%S""%F"); // iso format
  160. std::stringstream ss;
  161. ss.imbue(std::locale(std::locale::classic(), facet2));
  162. ptime pt2(not_a_date_time);
  163. time_duration tdx(not_a_date_time);
  164. date dx(2002,Oct,17);
  165. #if defined(BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG)
  166. time_duration td2(23,12,17,123450000);
  167. #else
  168. time_duration td2(23,12,17,123450);
  169. #endif
  170. ptime result(dx, td2);
  171. ss.str("20021017T231217.12345");
  172. ss >> pt2;
  173. check_equal("iso_format ptime", pt2, result);
  174. ss.str("");
  175. facet2->set_iso_extended_format();
  176. ss.str("2002-10-17 23:12:17.12345");
  177. ss >> pt2;
  178. check_equal("iso_extended_format ptime", pt2, result);
  179. ss.str("");
  180. ss.str("231217.12345");
  181. ss >> tdx;
  182. check_equal("iso_format time_duration", tdx, td2);
  183. ss.str("");
  184. ss.str("-infinity");
  185. ss >> tdx;
  186. check_equal("iso_format time_duration (special_value)",
  187. tdx, time_duration(neg_infin));
  188. ss.str("");
  189. // the above tests prove correct parsing of time values in these formats.
  190. // these tests show they also handle special_values & exceptions properly
  191. time_duration nadt(not_a_date_time);
  192. ss.exceptions(std::ios_base::failbit); // we need exceptions turned on here
  193. int count = 0;
  194. try {
  195. facet2->time_duration_format("%H""%M""%S""%F");
  196. ss.str("not-a-date-time");
  197. ++count;
  198. ss >> tdx;
  199. check_equal("special value w/ hours flag", tdx, nadt);
  200. ss.str("");
  201. facet2->time_duration_format("%M""%S""%F");
  202. ss.str("not-a-date-time");
  203. ++count;
  204. ss >> tdx;
  205. check_equal("special value w/ minutes flag", tdx, nadt);
  206. ss.str("");
  207. facet2->time_duration_format("%S""%F");
  208. ss.str("not-a-date-time");
  209. ++count;
  210. ss >> tdx;
  211. check_equal("special value w/ seconds flag", tdx, nadt);
  212. ss.str("");
  213. facet2->time_duration_format("%s");
  214. ss.str("not-a-date-time");
  215. ++count;
  216. ss >> tdx;
  217. check_equal("special value w/ sec w/frac_sec (always) flag", tdx, nadt);
  218. ss.str("");
  219. facet2->time_duration_format("%f");
  220. ss.str("not-a-date-time");
  221. ++count;
  222. ss >> tdx;
  223. check_equal("special value w/ frac_sec (always) flag", tdx, nadt);
  224. ss.str("");
  225. }
  226. catch(...) {
  227. // any exception is a failure
  228. std::stringstream msg;
  229. msg << "special_values with scrunched formats failed at test" << count;
  230. check(msg.str(), false);
  231. }
  232. // exception tests
  233. std::ios_base::failure exc("failure");
  234. check("failure test w/ hours flag",
  235. failure_test(td, "bad_input", exc, new time_input_facet("%H""%M""%S""%F")));
  236. check("silent failure test w/ hours flag",
  237. failure_test(td, "bad_input", new time_input_facet("%H""%M""%S""%F")));
  238. check("failure test w/ minute flag",
  239. failure_test(td, "bad_input", exc, new time_input_facet("%M""%S""%F")));
  240. check("silent failure test w/ minute flag",
  241. failure_test(td, "bad_input", new time_input_facet("%M""%S""%F")));
  242. check("failure test w/ second flag",
  243. failure_test(td, "bad_input", exc, new time_input_facet("%S""%F")));
  244. check("silent failure test w/ second flag",
  245. failure_test(td, "bad_input", new time_input_facet("%S""%F")));
  246. check("failure test w/ sec w/frac (always) flag",
  247. failure_test(td, "bad_input", exc, new time_input_facet("%s")));
  248. check("silent failure test w/ sec w/frac (always) flag",
  249. failure_test(td, "bad_input", new time_input_facet("%s")));
  250. check("failure test w/ frac_sec flag",
  251. failure_test(td, "bad_input", exc, new time_input_facet("%f")));
  252. check("silent failure test w/ frac_sec flag",
  253. failure_test(td, "bad_input", new time_input_facet("%f")));
  254. }
  255. // special_values tests. prove the individual flags catch special_values
  256. // NOTE: these flags all by themselves will not parse a complete ptime,
  257. // these are *specific* special_values tests
  258. iss.str("+infinity -infinity");
  259. facet->format("%H");
  260. facet->time_duration_format("%H");
  261. iss >> pt;
  262. iss >> td;
  263. check_equal("Special value: ptime %H flag", pt, ptime(pos_infin));
  264. check_equal("Special value: time_duration %H flag", td, time_duration(neg_infin));
  265. iss.str("not-a-date-time +infinity");
  266. facet->format("%M");
  267. facet->time_duration_format("%M");
  268. iss >> pt;
  269. iss >> td;
  270. check_equal("Special value: ptime %M flag", pt, ptime(not_a_date_time));
  271. check_equal("Special value: time_duration %M flag", td, time_duration(pos_infin));
  272. iss.str("-infinity not-a-date-time ");
  273. facet->format("%S");
  274. facet->time_duration_format("%S");
  275. iss >> pt;
  276. iss >> td;
  277. check_equal("Special value: ptime %S flag", pt, ptime(neg_infin));
  278. check_equal("Special value: time_duration %S flag", td, time_duration(not_a_date_time));
  279. iss.str("+infinity -infinity");
  280. facet->format("%s");
  281. facet->time_duration_format("%s");
  282. iss >> pt;
  283. iss >> td;
  284. check_equal("Special value: ptime %s flag", pt, ptime(pos_infin));
  285. check_equal("Special value: time_duration %s flag", td, time_duration(neg_infin));
  286. iss.str("not-a-date-time +infinity");
  287. facet->format("%j");
  288. facet->time_duration_format("%f");
  289. iss >> pt;
  290. iss >> td;
  291. check_equal("Special value: ptime %j flag", pt, ptime(not_a_date_time));
  292. check_equal("Special value: time_duration %f flag", td, time_duration(pos_infin));
  293. // time_period tests - the time_period_parser is thoroughly tested in gregorian tests
  294. // default period format is closed range so last ptime is included in peiod
  295. iss.str("[2005-Jan-01 00:00:00/2005-Dec-31 23:59:59]");
  296. facet->format(time_input_facet::default_time_input_format); // reset format
  297. iss >> tp;
  298. check("Time period, default formats",
  299. (tp.begin() == ptime(date(2005,1,1),hours(0))) &&
  300. (tp.last() == ptime(date(2005,12,31),time_duration(23,59,59))) &&
  301. (tp.end() == ptime(date(2005,12,31),time_duration(23,59,59,1))) );
  302. {
  303. std::stringstream ss;
  304. ptime ptx(not_a_date_time);
  305. ptime pt2 = second_clock::local_time();
  306. ptime pt3(neg_infin);
  307. ptime pt4(pos_infin);
  308. time_period tpx(pt2, ptx); // ptime/nadt
  309. time_period tp2(ptx, ptx); // nadt/nadt
  310. time_period tp3(pt3, pt4);
  311. ss << tpx;
  312. ss >> tp2;
  313. check_equal("Special values period (reversibility test)", tpx, tp2);
  314. ss.str("[-infinity/+infinity]");
  315. ss >> tp2;
  316. check_equal("Special values period (infinities)", tp3, tp2);
  317. }
  318. // Failure tests
  319. // faliure tests for date elements tested in gregorian tests
  320. time_input_facet* facet2 = new time_input_facet();
  321. facet2->time_duration_format("%H:%M:%S""%f");
  322. check("Failure test: Missing frac_sec with %f flag (w/exceptions)",
  323. failure_test(td, "14:13:12 extra stuff", e_failure, facet2));
  324. time_input_facet* facet3 = new time_input_facet();
  325. facet3->time_duration_format("%H:%M:%S""%f");
  326. check("Failure test: Missing frac_sec with %f flag (no exceptions)",
  327. failure_test(td, "14:13:12 extra stuff", facet3));
  328. // Reversable format tests
  329. time_duration td_io(10,11,12,1234567);
  330. ptime pt_io(date(2004,03,15), td_io);
  331. time_facet* otp_facet = new time_facet();
  332. time_input_facet* inp_facet = new time_input_facet();
  333. std::stringstream ss;
  334. std::locale loc2(std::locale::classic(), otp_facet);
  335. ss.imbue(std::locale(loc2, inp_facet)); // imbue locale containing both facets
  336. ss.str("");
  337. ss << pt_io; // stream out pt_io
  338. ss >> pt;
  339. check_equal("Stream out one ptime then into another: default format", pt_io, pt);
  340. ss.str("");
  341. ss << td_io; // stream out td_io
  342. ss >> td;
  343. check_equal("Stream out one time_duration then into another: default format", td_io, td);
  344. td_io = time_duration(1,29,59); // no frac_sec, default format has %F
  345. pt_io = ptime(date(2004,2,29), td_io); // leap year
  346. ss.str("");
  347. ss << pt_io; // stream out pt_io
  348. ss >> pt;
  349. check_equal("Stream out one ptime then into another: default format", pt_io, pt);
  350. ss.str("");
  351. ss << td_io; // stream out td_io
  352. ss >> td;
  353. check_equal("Stream out one time_duration then into another: default format", td_io, td);
  354. td_io = time_duration(13,05,0); // no seconds as the next formats won't use them
  355. pt_io = ptime(date(2004,2,29), td_io); // leap year
  356. otp_facet->format("%Y-%jT%H:%M"); // extended ordinal
  357. inp_facet->format("%Y-%jT%H:%M");
  358. ss.str("");
  359. ss << pt_io; // stream out pt_io
  360. ss >> pt;
  361. check_equal("Stream out one ptime then into another: extended ordinal format", pt_io, pt);
  362. otp_facet->format("Time: %H:%M, Date: %B %d, %Y"); // custom format with extra words
  363. inp_facet->format("Time: %H:%M, Date: %B %d, %Y");
  364. ss.str("");
  365. ss << pt_io; // stream out pt_io
  366. ss >> pt;
  367. check_equal("Stream out one ptime then into another: custom format (" + ss.str() + ")", pt_io, pt);
  368. {
  369. // fully parameterized constructor - compile only test, all other features tested in gregorian
  370. boost::date_time::format_date_parser<date, char> fdp("%Y-%b-%d", std::locale::classic());
  371. special_values_parser svp; // default constructor
  372. period_parser pp; // default constructor
  373. boost::date_time::date_generator_parser<date, char> dgp; // default constructor
  374. time_input_facet tif("%Y-%m-%d %H:%M:%s", fdp, svp, pp, dgp);
  375. }
  376. // trac 13194 (https://svn.boost.org/trac10/ticket/13194)
  377. {
  378. const std::string value = "December 07:27:10.435945 5 2017";
  379. boost::posix_time::time_input_facet* facet4 = new boost::posix_time::time_input_facet("%B %H:%M:%s %e %Y");
  380. boost::posix_time::ptime ptx;
  381. check("trac 13194 %e on \"5\" failbit set", !failure_test(ptx, value, facet4)); // proves failbit was not set
  382. check_equal("trac 13194 %e on \" 5\" valid value", "2017-12-05T07:27:10.435945000", to_iso_extended_string(ptx));
  383. }
  384. // trac 12910
  385. {
  386. const std::string value = "263-08:09:10";
  387. boost::posix_time::time_input_facet* facet = new boost::posix_time::time_input_facet("%j-%H:%M:%S");
  388. boost::posix_time::ptime pt;
  389. check("trac 12910 %j without %Y no failbit", !failure_test(pt, value, facet)); // proves failbit was not set
  390. check_equal("trac 12910 %j without %Y value", "1400-09-20T08:09:10", to_iso_extended_string(pt));
  391. }
  392. #endif // USE_DATE_TIME_PRE_1_33_FACET_IO
  393. }
  394. int main(){
  395. try { //wrap all the tests -- we don't expect an exception
  396. do_all_tests();
  397. }
  398. catch(std::exception& e) {
  399. std::string failure("std::exception caught: ");
  400. failure += e.what();
  401. check(failure, false);
  402. }
  403. catch(...) {
  404. check("Unknown exception caught -- failing", false);
  405. }
  406. return printTestStats();
  407. }