greg_facet.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. #ifndef GREGORIAN_FACET_HPP___
  2. #define GREGORIAN_FACET_HPP___
  3. /* Copyright (c) 2002,2003 CrystalClear Software, Inc.
  4. * Use, modification and distribution is subject to the
  5. * Boost Software License, Version 1.0. (See accompanying
  6. * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
  7. * Author: Jeff Garland, Bart Garst
  8. * $Date$
  9. */
  10. #include <boost/date_time/compiler_config.hpp>
  11. #include <boost/date_time/gregorian/gregorian_types.hpp>
  12. #include <boost/date_time/date_formatting_locales.hpp> // sets BOOST_DATE_TIME_NO_LOCALE
  13. #include <boost/date_time/gregorian/parsers.hpp>
  14. #include <boost/io/ios_state.hpp>
  15. //This file is basically commented out if locales are not supported
  16. #ifndef BOOST_DATE_TIME_NO_LOCALE
  17. #include <string>
  18. #include <memory>
  19. #include <locale>
  20. #include <iostream>
  21. #include <exception>
  22. namespace boost {
  23. namespace gregorian {
  24. //! Configuration of the output facet template
  25. struct BOOST_SYMBOL_VISIBLE greg_facet_config
  26. {
  27. typedef boost::gregorian::greg_month month_type;
  28. typedef boost::date_time::special_values special_value_enum;
  29. typedef boost::gregorian::months_of_year month_enum;
  30. typedef boost::date_time::weekdays weekday_enum;
  31. };
  32. #if defined(USE_DATE_TIME_PRE_1_33_FACET_IO)
  33. //! Create the base facet type for gregorian::date
  34. typedef boost::date_time::date_names_put<greg_facet_config> greg_base_facet;
  35. //! ostream operator for gregorian::date
  36. /*! Uses the date facet to determine various output parameters including:
  37. * - string values for the month (eg: Jan, Feb, Mar) (default: English)
  38. * - string values for special values (eg: not-a-date-time) (default: English)
  39. * - selection of long, short strings, or numerical month representation (default: short string)
  40. * - month day year order (default yyyy-mmm-dd)
  41. */
  42. template <class charT, class traits>
  43. inline
  44. std::basic_ostream<charT, traits>&
  45. operator<<(std::basic_ostream<charT, traits>& os, const date& d)
  46. {
  47. typedef boost::date_time::date_names_put<greg_facet_config, charT> facet_def;
  48. typedef boost::date_time::ostream_date_formatter<date, facet_def, charT> greg_ostream_formatter;
  49. greg_ostream_formatter::date_put(d, os);
  50. return os;
  51. }
  52. //! operator<< for gregorian::greg_month typically streaming: Jan, Feb, Mar...
  53. /*! Uses the date facet to determine output string as well as selection of long or short strings.
  54. * Default if no facet is installed is to output a 2 wide numeric value for the month
  55. * eg: 01 == Jan, 02 == Feb, ... 12 == Dec.
  56. */
  57. template <class charT, class traits>
  58. inline
  59. std::basic_ostream<charT, traits>&
  60. operator<<(std::basic_ostream<charT, traits>& os, const greg_month& m)
  61. {
  62. typedef boost::date_time::date_names_put<greg_facet_config, charT> facet_def;
  63. typedef boost::date_time::ostream_month_formatter<facet_def, charT> greg_month_formatter;
  64. std::locale locale = os.getloc();
  65. if (std::has_facet<facet_def>(locale)) {
  66. const facet_def& f = std::use_facet<facet_def>(locale);
  67. greg_month_formatter::format_month(m, os, f);
  68. }
  69. else { // default to numeric
  70. boost::io::basic_ios_fill_saver<charT> ifs(os);
  71. os << std::setw(2) << std::setfill(os.widen('0')) << m.as_number();
  72. }
  73. return os;
  74. }
  75. //! operator<< for gregorian::greg_weekday typically streaming: Sun, Mon, Tue, ...
  76. /*! Uses the date facet to determine output string as well as selection of long or short string.
  77. * Default if no facet is installed is to output a 3 char english string for the
  78. * day of the week.
  79. */
  80. template <class charT, class traits>
  81. inline
  82. std::basic_ostream<charT, traits>&
  83. operator<<(std::basic_ostream<charT, traits>& os, const greg_weekday& wd)
  84. {
  85. typedef boost::date_time::date_names_put<greg_facet_config, charT> facet_def;
  86. typedef boost::date_time::ostream_weekday_formatter<greg_weekday, facet_def, charT> greg_weekday_formatter;
  87. std::locale locale = os.getloc();
  88. if (std::has_facet<facet_def>(locale)) {
  89. const facet_def& f = std::use_facet<facet_def>(locale);
  90. greg_weekday_formatter::format_weekday(wd, os, f, true);
  91. }
  92. else { //default to short English string eg: Sun, Mon, Tue, Wed...
  93. os << wd.as_short_string();
  94. }
  95. return os;
  96. }
  97. //! operator<< for gregorian::date_period typical output: [2002-Jan-01/2002-Jan-31]
  98. /*! Uses the date facet to determine output string as well as selection of long
  99. * or short string fr dates.
  100. * Default if no facet is installed is to output a 3 char english string for the
  101. * day of the week.
  102. */
  103. template <class charT, class traits>
  104. inline
  105. std::basic_ostream<charT, traits>&
  106. operator<<(std::basic_ostream<charT, traits>& os, const date_period& dp)
  107. {
  108. os << '['; //TODO: facet or manipulator for periods?
  109. os << dp.begin();
  110. os << '/'; //TODO: facet or manipulator for periods?
  111. os << dp.last();
  112. os << ']';
  113. return os;
  114. }
  115. template <class charT, class traits>
  116. inline
  117. std::basic_ostream<charT, traits>&
  118. operator<<(std::basic_ostream<charT, traits>& os, const date_duration& dd)
  119. {
  120. //os << dd.days();
  121. os << dd.get_rep();
  122. return os;
  123. }
  124. //! operator<< for gregorian::partial_date. Output: "Jan 1"
  125. template <class charT, class traits>
  126. inline
  127. std::basic_ostream<charT, traits>&
  128. operator<<(std::basic_ostream<charT, traits>& os, const partial_date& pd)
  129. {
  130. boost::io::basic_ios_fill_saver<charT> ifs(os);
  131. os << std::setw(2) << std::setfill(os.widen('0')) << pd.day() << ' '
  132. << pd.month().as_short_string() ;
  133. return os;
  134. }
  135. //! operator<< for gregorian::nth_kday_of_month. Output: "first Mon of Jun"
  136. template <class charT, class traits>
  137. inline
  138. std::basic_ostream<charT, traits>&
  139. operator<<(std::basic_ostream<charT, traits>& os,
  140. const nth_kday_of_month& nkd)
  141. {
  142. os << nkd.nth_week_as_str() << ' '
  143. << nkd.day_of_week() << " of "
  144. << nkd.month().as_short_string() ;
  145. return os;
  146. }
  147. //! operator<< for gregorian::first_kday_of_month. Output: "first Mon of Jun"
  148. template <class charT, class traits>
  149. inline
  150. std::basic_ostream<charT, traits>&
  151. operator<<(std::basic_ostream<charT, traits>& os,
  152. const first_kday_of_month& fkd)
  153. {
  154. os << "first " << fkd.day_of_week() << " of "
  155. << fkd.month().as_short_string() ;
  156. return os;
  157. }
  158. //! operator<< for gregorian::last_kday_of_month. Output: "last Mon of Jun"
  159. template <class charT, class traits>
  160. inline
  161. std::basic_ostream<charT, traits>&
  162. operator<<(std::basic_ostream<charT, traits>& os,
  163. const last_kday_of_month& lkd)
  164. {
  165. os << "last " << lkd.day_of_week() << " of "
  166. << lkd.month().as_short_string() ;
  167. return os;
  168. }
  169. //! operator<< for gregorian::first_kday_after. Output: "first Mon after"
  170. template <class charT, class traits>
  171. inline
  172. std::basic_ostream<charT, traits>&
  173. operator<<(std::basic_ostream<charT, traits>& os,
  174. const first_kday_after& fka)
  175. {
  176. os << fka.day_of_week() << " after";
  177. return os;
  178. }
  179. //! operator<< for gregorian::first_kday_before. Output: "first Mon before"
  180. template <class charT, class traits>
  181. inline
  182. std::basic_ostream<charT, traits>&
  183. operator<<(std::basic_ostream<charT, traits>& os,
  184. const first_kday_before& fkb)
  185. {
  186. os << fkb.day_of_week() << " before";
  187. return os;
  188. }
  189. #endif // USE_DATE_TIME_PRE_1_33_FACET_IO
  190. /**************** Input Streaming ******************/
  191. #if !defined(BOOST_NO_STD_ITERATOR_TRAITS)
  192. //! operator>> for gregorian::date
  193. template<class charT>
  194. inline
  195. std::basic_istream<charT>& operator>>(std::basic_istream<charT>& is, date& d)
  196. {
  197. std::istream_iterator<std::basic_string<charT>, charT> beg(is), eos;
  198. d = from_stream(beg, eos);
  199. return is;
  200. }
  201. #endif // BOOST_NO_STD_ITERATOR_TRAITS
  202. //! operator>> for gregorian::date_duration
  203. template<class charT>
  204. inline
  205. std::basic_istream<charT>& operator>>(std::basic_istream<charT>& is,
  206. date_duration& dd)
  207. {
  208. long v;
  209. is >> v;
  210. dd = date_duration(v);
  211. return is;
  212. }
  213. //! operator>> for gregorian::date_period
  214. template<class charT>
  215. inline
  216. std::basic_istream<charT>& operator>>(std::basic_istream<charT>& is,
  217. date_period& dp)
  218. {
  219. std::basic_string<charT> s;
  220. is >> s;
  221. dp = date_time::from_simple_string_type<date>(s);
  222. return is;
  223. }
  224. //! generates a locale with the set of gregorian name-strings of type char*
  225. BOOST_DATE_TIME_DECL std::locale generate_locale(std::locale& loc, char type);
  226. //! Returns a pointer to a facet with a default set of names (English)
  227. /* Necessary in the event an exception is thrown from op>> for
  228. * weekday or month. See comments in those functions for more info */
  229. BOOST_DATE_TIME_DECL boost::date_time::all_date_names_put<greg_facet_config, char>* create_facet_def(char type);
  230. #ifndef BOOST_NO_STD_WSTRING
  231. //! generates a locale with the set of gregorian name-strings of type wchar_t*
  232. BOOST_DATE_TIME_DECL std::locale generate_locale(std::locale& loc, wchar_t type);
  233. //! Returns a pointer to a facet with a default set of names (English)
  234. /* Necessary in the event an exception is thrown from op>> for
  235. * weekday or month. See comments in those functions for more info */
  236. BOOST_DATE_TIME_DECL boost::date_time::all_date_names_put<greg_facet_config, wchar_t>* create_facet_def(wchar_t type);
  237. #endif // BOOST_NO_STD_WSTRING
  238. //! operator>> for gregorian::greg_month - throws exception if invalid month given
  239. template<class charT>
  240. inline
  241. std::basic_istream<charT>& operator>>(std::basic_istream<charT>& is,greg_month& m)
  242. {
  243. typedef boost::date_time::all_date_names_put<greg_facet_config, charT> facet_def;
  244. std::basic_string<charT> s;
  245. is >> s;
  246. if(!std::has_facet<facet_def>(is.getloc())) {
  247. std::locale loc = is.getloc();
  248. charT a = '\0';
  249. is.imbue(generate_locale(loc, a));
  250. }
  251. short num = 0;
  252. try{
  253. const facet_def& f = std::use_facet<facet_def>(is.getloc());
  254. num = date_time::find_match(f.get_short_month_names(),
  255. f.get_long_month_names(),
  256. (greg_month::max)(), s); // greg_month spans 1..12, so max returns the array size,
  257. // which is needed by find_match
  258. }
  259. /* bad_cast will be thrown if the desired facet is not accessible
  260. * so we can generate the facet. This has the drawback of using english
  261. * names as a default. */
  262. catch(std::bad_cast&){
  263. charT a = '\0';
  264. #if defined(BOOST_NO_CXX11_SMART_PTR)
  265. std::auto_ptr< const facet_def > f(create_facet_def(a));
  266. #else
  267. std::unique_ptr< const facet_def > f(create_facet_def(a));
  268. #endif
  269. num = date_time::find_match(f->get_short_month_names(),
  270. f->get_long_month_names(),
  271. (greg_month::max)(), s); // greg_month spans 1..12, so max returns the array size,
  272. // which is needed by find_match
  273. }
  274. ++num; // months numbered 1-12
  275. m = greg_month(num);
  276. return is;
  277. }
  278. //! operator>> for gregorian::greg_weekday - throws exception if invalid weekday given
  279. template<class charT>
  280. inline
  281. std::basic_istream<charT>& operator>>(std::basic_istream<charT>& is,greg_weekday& wd)
  282. {
  283. typedef boost::date_time::all_date_names_put<greg_facet_config, charT> facet_def;
  284. std::basic_string<charT> s;
  285. is >> s;
  286. if(!std::has_facet<facet_def>(is.getloc())) {
  287. std::locale loc = is.getloc();
  288. charT a = '\0';
  289. is.imbue(generate_locale(loc, a));
  290. }
  291. short num = 0;
  292. try{
  293. const facet_def& f = std::use_facet<facet_def>(is.getloc());
  294. num = date_time::find_match(f.get_short_weekday_names(),
  295. f.get_long_weekday_names(),
  296. (greg_weekday::max)() + 1, s); // greg_weekday spans 0..6, so increment is needed
  297. // to form the array size which is needed by find_match
  298. }
  299. /* bad_cast will be thrown if the desired facet is not accessible
  300. * so we can generate the facet. This has the drawback of using english
  301. * names as a default. */
  302. catch(std::bad_cast&){
  303. charT a = '\0';
  304. #if defined(BOOST_NO_CXX11_SMART_PTR)
  305. std::auto_ptr< const facet_def > f(create_facet_def(a));
  306. #else
  307. std::unique_ptr< const facet_def > f(create_facet_def(a));
  308. #endif
  309. num = date_time::find_match(f->get_short_weekday_names(),
  310. f->get_long_weekday_names(),
  311. (greg_weekday::max)() + 1, s); // greg_weekday spans 0..6, so increment is needed
  312. // to form the array size which is needed by find_match
  313. }
  314. wd = greg_weekday(num); // weekdays numbered 0-6
  315. return is;
  316. }
  317. } } //namespace gregorian
  318. #endif
  319. #endif