1 #ifndef _DATE_TIME_DATE_FACET__HPP___ 2 #define _DATE_TIME_DATE_FACET__HPP___ 3 4 /* Copyright (c) 2004-2005 CrystalClear Software, Inc. 5 * Use, modification and distribution is subject to the 6 * Boost Software License, Version 1.0. (See accompanying 7 * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) 8 * Author: Martin Andrian, Jeff Garland, Bart Garst 9 * $Date$ 10 */ 11 12 #include <iterator> // ostreambuf_iterator 13 #include <locale> 14 #include <string> 15 #include <vector> 16 #include <boost/throw_exception.hpp> 17 #include <boost/algorithm/string/replace.hpp> 18 #include <boost/date_time/compiler_config.hpp> 19 #include <boost/date_time/period.hpp> 20 #include <boost/date_time/special_defs.hpp> 21 #include <boost/date_time/special_values_formatter.hpp> 22 #include <boost/date_time/period_formatter.hpp> 23 #include <boost/date_time/period_parser.hpp> 24 #include <boost/date_time/date_generator_formatter.hpp> 25 #include <boost/date_time/date_generator_parser.hpp> 26 #include <boost/date_time/format_date_parser.hpp> 27 28 namespace boost { namespace date_time { 29 30 31 /*! Class that provides format based I/O facet for date types. 32 * 33 * This class allows the formatting of dates by using format string. 34 * Format strings are: 35 * 36 * - %A => long_weekday_format - Full name Ex: Tuesday 37 * - %a => short_weekday_format - Three letter abbreviation Ex: Tue 38 * - %B => long_month_format - Full name Ex: October 39 * - %b => short_month_format - Three letter abbreviation Ex: Oct 40 * - %x => standard_format_specifier - defined by the locale 41 * - %Y-%b-%d => default_date_format - YYYY-Mon-dd 42 * 43 * Default month format == %b 44 * Default weekday format == %a 45 */ 46 template <class date_type, 47 class CharT, 48 class OutItrT = std::ostreambuf_iterator<CharT, std::char_traits<CharT> > > 49 class BOOST_SYMBOL_VISIBLE date_facet : public std::locale::facet { 50 public: 51 typedef typename date_type::duration_type duration_type; 52 // greg_weekday is gregorian_calendar::day_of_week_type 53 typedef typename date_type::day_of_week_type day_of_week_type; 54 typedef typename date_type::day_type day_type; 55 typedef typename date_type::month_type month_type; 56 typedef boost::date_time::period<date_type,duration_type> period_type; 57 typedef std::basic_string<CharT> string_type; 58 typedef CharT char_type; 59 typedef boost::date_time::period_formatter<CharT> period_formatter_type; 60 typedef boost::date_time::special_values_formatter<CharT> special_values_formatter_type; 61 typedef std::vector<std::basic_string<CharT> > input_collection_type; 62 // used for the output of the date_generators 63 typedef date_generator_formatter<date_type, CharT> date_gen_formatter_type; 64 typedef partial_date<date_type> partial_date_type; 65 typedef nth_kday_of_month<date_type> nth_kday_type; 66 typedef first_kday_of_month<date_type> first_kday_type; 67 typedef last_kday_of_month<date_type> last_kday_type; 68 typedef first_kday_after<date_type> kday_after_type; 69 typedef first_kday_before<date_type> kday_before_type; 70 static const char_type long_weekday_format[3]; 71 static const char_type short_weekday_format[3]; 72 static const char_type long_month_format[3]; 73 static const char_type short_month_format[3]; 74 static const char_type default_period_separator[4]; 75 static const char_type standard_format_specifier[3]; 76 static const char_type iso_format_specifier[7]; 77 static const char_type iso_format_extended_specifier[9]; 78 static const char_type default_date_format[9]; // YYYY-Mon-DD 79 static std::locale::id id; 80 81 #if defined (__SUNPRO_CC) && defined (_RWSTD_VER) __get_id(void) const82 std::locale::id& __get_id (void) const { return id; } 83 #endif 84 date_facet(::size_t a_ref=0)85 explicit date_facet(::size_t a_ref = 0) 86 : std::locale::facet(a_ref), 87 //m_format(standard_format_specifier) 88 m_format(default_date_format), 89 m_month_format(short_month_format), 90 m_weekday_format(short_weekday_format) 91 {} 92 date_facet(const char_type * format_str,const input_collection_type & short_names,::size_t ref_count=0)93 explicit date_facet(const char_type* format_str, 94 const input_collection_type& short_names, 95 ::size_t ref_count = 0) 96 : std::locale::facet(ref_count), 97 m_format(format_str), 98 m_month_format(short_month_format), 99 m_weekday_format(short_weekday_format), 100 m_month_short_names(short_names) 101 {} 102 103 date_facet(const char_type * format_str,period_formatter_type per_formatter=period_formatter_type (),special_values_formatter_type sv_formatter=special_values_formatter_type (),date_gen_formatter_type dg_formatter=date_gen_formatter_type (),::size_t ref_count=0)104 explicit date_facet(const char_type* format_str, 105 period_formatter_type per_formatter = period_formatter_type(), 106 special_values_formatter_type sv_formatter = special_values_formatter_type(), 107 date_gen_formatter_type dg_formatter = date_gen_formatter_type(), 108 ::size_t ref_count = 0) 109 : std::locale::facet(ref_count), 110 m_format(format_str), 111 m_month_format(short_month_format), 112 m_weekday_format(short_weekday_format), 113 m_period_formatter(per_formatter), 114 m_date_gen_formatter(dg_formatter), 115 m_special_values_formatter(sv_formatter) 116 {} format(const char_type * const format_str)117 void format(const char_type* const format_str) { 118 m_format = format_str; 119 } set_iso_format()120 virtual void set_iso_format() 121 { 122 m_format = iso_format_specifier; 123 } set_iso_extended_format()124 virtual void set_iso_extended_format() 125 { 126 m_format = iso_format_extended_specifier; 127 } month_format(const char_type * const format_str)128 void month_format(const char_type* const format_str) { 129 m_month_format = format_str; 130 } weekday_format(const char_type * const format_str)131 void weekday_format(const char_type* const format_str) { 132 m_weekday_format = format_str; 133 } 134 period_formatter(period_formatter_type per_formatter)135 void period_formatter(period_formatter_type per_formatter) { 136 m_period_formatter= per_formatter; 137 } special_values_formatter(const special_values_formatter_type & svf)138 void special_values_formatter(const special_values_formatter_type& svf) 139 { 140 m_special_values_formatter = svf; 141 } short_weekday_names(const input_collection_type & short_names)142 void short_weekday_names(const input_collection_type& short_names) 143 { 144 m_weekday_short_names = short_names; 145 } long_weekday_names(const input_collection_type & long_names)146 void long_weekday_names(const input_collection_type& long_names) 147 { 148 m_weekday_long_names = long_names; 149 } 150 short_month_names(const input_collection_type & short_names)151 void short_month_names(const input_collection_type& short_names) 152 { 153 m_month_short_names = short_names; 154 } 155 long_month_names(const input_collection_type & long_names)156 void long_month_names(const input_collection_type& long_names) 157 { 158 m_month_long_names = long_names; 159 } 160 date_gen_phrase_strings(const input_collection_type & new_strings,typename date_gen_formatter_type::phrase_elements beg_pos=date_gen_formatter_type::first)161 void date_gen_phrase_strings(const input_collection_type& new_strings, 162 typename date_gen_formatter_type::phrase_elements beg_pos=date_gen_formatter_type::first) 163 { 164 m_date_gen_formatter.elements(new_strings, beg_pos); 165 } 166 put(OutItrT next,std::ios_base & a_ios,char_type fill_char,const date_type & d) const167 OutItrT put(OutItrT next, 168 std::ios_base& a_ios, 169 char_type fill_char, 170 const date_type& d) const 171 { 172 if (d.is_special()) { 173 return do_put_special(next, a_ios, fill_char, d.as_special()); 174 } 175 //The following line of code required the date to support a to_tm function 176 return do_put_tm(next, a_ios, fill_char, to_tm(d), m_format); 177 } 178 put(OutItrT next,std::ios_base & a_ios,char_type fill_char,const duration_type & dd) const179 OutItrT put(OutItrT next, 180 std::ios_base& a_ios, 181 char_type fill_char, 182 const duration_type& dd) const 183 { 184 if (dd.is_special()) { 185 return do_put_special(next, a_ios, fill_char, dd.get_rep().as_special()); 186 } 187 188 typedef std::num_put<CharT, OutItrT> num_put; 189 if (std::has_facet<num_put>(a_ios.getloc())) { 190 return std::use_facet<num_put>(a_ios.getloc()).put(next, a_ios, fill_char, dd.get_rep().as_number()); 191 } 192 else { 193 num_put* f = new num_put(); 194 std::locale l = std::locale(a_ios.getloc(), f); 195 a_ios.imbue(l); 196 return f->put(next, a_ios, fill_char, dd.get_rep().as_number()); 197 } 198 199 } 200 201 put(OutItrT next,std::ios_base & a_ios,char_type fill_char,const month_type & m) const202 OutItrT put(OutItrT next, 203 std::ios_base& a_ios, 204 char_type fill_char, 205 const month_type& m) const 206 { 207 //if (d.is_special()) { 208 // return do_put_special(next, a_ios, fill_char, d.as_special()); 209 //} 210 //The following line of code required the date to support a to_tm function 211 std::tm dtm; 212 std::memset(&dtm, 0, sizeof(dtm)); 213 dtm.tm_mon = m - 1; 214 return do_put_tm(next, a_ios, fill_char, dtm, m_month_format); 215 } 216 217 //! puts the day of month put(OutItrT next,std::ios_base & a_ios,char_type fill_char,const day_type & day) const218 OutItrT put(OutItrT next, 219 std::ios_base& a_ios, 220 char_type fill_char, 221 const day_type& day) const 222 { 223 std::tm dtm; 224 std::memset(&dtm, 0, sizeof(dtm)); 225 dtm.tm_mday = day.as_number(); 226 char_type tmp[3] = {'%','d'}; 227 string_type temp_format(tmp); 228 return do_put_tm(next, a_ios, fill_char, dtm, temp_format); 229 } 230 put(OutItrT next,std::ios_base & a_ios,char_type fill_char,const day_of_week_type & dow) const231 OutItrT put(OutItrT next, 232 std::ios_base& a_ios, 233 char_type fill_char, 234 const day_of_week_type& dow) const 235 { 236 //if (d.is_special()) { 237 // return do_put_special(next, a_ios, fill_char, d.as_special()); 238 //} 239 //The following line of code required the date to support a to_tm function 240 std::tm dtm; 241 std::memset(&dtm, 0, sizeof(dtm)); 242 dtm.tm_wday = dow; 243 return do_put_tm(next, a_ios, fill_char, dtm, m_weekday_format); 244 } 245 246 put(OutItrT next,std::ios_base & a_ios,char_type fill_char,const period_type & p) const247 OutItrT put(OutItrT next, 248 std::ios_base& a_ios, 249 char_type fill_char, 250 const period_type& p) const 251 { 252 return m_period_formatter.put_period(next, a_ios, fill_char, p, *this); 253 } 254 put(OutItrT next,std::ios_base & a_ios,char_type fill_char,const partial_date_type & pd) const255 OutItrT put(OutItrT next, 256 std::ios_base& a_ios, 257 char_type fill_char, 258 const partial_date_type& pd) const 259 { 260 return m_date_gen_formatter.put_partial_date(next, a_ios, fill_char, pd, *this); 261 } 262 put(OutItrT next,std::ios_base & a_ios,char_type fill_char,const nth_kday_type & nkd) const263 OutItrT put(OutItrT next, 264 std::ios_base& a_ios, 265 char_type fill_char, 266 const nth_kday_type& nkd) const 267 { 268 return m_date_gen_formatter.put_nth_kday(next, a_ios, fill_char, nkd, *this); 269 } 270 put(OutItrT next,std::ios_base & a_ios,char_type fill_char,const first_kday_type & fkd) const271 OutItrT put(OutItrT next, 272 std::ios_base& a_ios, 273 char_type fill_char, 274 const first_kday_type& fkd) const 275 { 276 return m_date_gen_formatter.put_first_kday(next, a_ios, fill_char, fkd, *this); 277 } 278 put(OutItrT next,std::ios_base & a_ios,char_type fill_char,const last_kday_type & lkd) const279 OutItrT put(OutItrT next, 280 std::ios_base& a_ios, 281 char_type fill_char, 282 const last_kday_type& lkd) const 283 { 284 return m_date_gen_formatter.put_last_kday(next, a_ios, fill_char, lkd, *this); 285 } 286 put(OutItrT next,std::ios_base & a_ios,char_type fill_char,const kday_before_type & fkb) const287 OutItrT put(OutItrT next, 288 std::ios_base& a_ios, 289 char_type fill_char, 290 const kday_before_type& fkb) const 291 { 292 return m_date_gen_formatter.put_kday_before(next, a_ios, fill_char, fkb, *this); 293 } 294 put(OutItrT next,std::ios_base & a_ios,char_type fill_char,const kday_after_type & fka) const295 OutItrT put(OutItrT next, 296 std::ios_base& a_ios, 297 char_type fill_char, 298 const kday_after_type& fka) const 299 { 300 return m_date_gen_formatter.put_kday_after(next, a_ios, fill_char, fka, *this); 301 } 302 303 protected: do_put_special(OutItrT next,std::ios_base &,char_type,const boost::date_time::special_values sv) const304 virtual OutItrT do_put_special(OutItrT next, 305 std::ios_base& /*a_ios*/, 306 char_type /*fill_char*/, 307 const boost::date_time::special_values sv) const 308 { 309 m_special_values_formatter.put_special(next, sv); 310 return next; 311 } do_put_tm(OutItrT next,std::ios_base & a_ios,char_type fill_char,const tm & tm_value,string_type a_format) const312 virtual OutItrT do_put_tm(OutItrT next, 313 std::ios_base& a_ios, 314 char_type fill_char, 315 const tm& tm_value, 316 string_type a_format) const 317 { 318 // update format string with custom names 319 if (!m_weekday_long_names.empty()) { 320 boost::algorithm::replace_all(a_format, 321 long_weekday_format, 322 m_weekday_long_names[tm_value.tm_wday]); 323 } 324 if (!m_weekday_short_names.empty()) { 325 boost::algorithm::replace_all(a_format, 326 short_weekday_format, 327 m_weekday_short_names[tm_value.tm_wday]); 328 329 } 330 if (!m_month_long_names.empty()) { 331 boost::algorithm::replace_all(a_format, 332 long_month_format, 333 m_month_long_names[tm_value.tm_mon]); 334 } 335 if (!m_month_short_names.empty()) { 336 boost::algorithm::replace_all(a_format, 337 short_month_format, 338 m_month_short_names[tm_value.tm_mon]); 339 } 340 // use time_put facet to create final string 341 const char_type* p_format = a_format.c_str(); 342 return std::use_facet<std::time_put<CharT> >(a_ios.getloc()).put(next, a_ios, 343 fill_char, 344 &tm_value, 345 p_format, 346 p_format + a_format.size()); 347 } 348 protected: 349 string_type m_format; 350 string_type m_month_format; 351 string_type m_weekday_format; 352 period_formatter_type m_period_formatter; 353 date_gen_formatter_type m_date_gen_formatter; 354 special_values_formatter_type m_special_values_formatter; 355 input_collection_type m_month_short_names; 356 input_collection_type m_month_long_names; 357 input_collection_type m_weekday_short_names; 358 input_collection_type m_weekday_long_names; 359 private: 360 }; 361 362 template <class date_type, class CharT, class OutItrT> 363 std::locale::id date_facet<date_type, CharT, OutItrT>::id; 364 365 template <class date_type, class CharT, class OutItrT> 366 const typename date_facet<date_type, CharT, OutItrT>::char_type 367 date_facet<date_type, CharT, OutItrT>::long_weekday_format[3] = {'%','A'}; 368 369 template <class date_type, class CharT, class OutItrT> 370 const typename date_facet<date_type, CharT, OutItrT>::char_type 371 date_facet<date_type, CharT, OutItrT>::short_weekday_format[3] = {'%','a'}; 372 373 template <class date_type, class CharT, class OutItrT> 374 const typename date_facet<date_type, CharT, OutItrT>::char_type 375 date_facet<date_type, CharT, OutItrT>::long_month_format[3] = {'%','B'}; 376 377 template <class date_type, class CharT, class OutItrT> 378 const typename date_facet<date_type, CharT, OutItrT>::char_type 379 date_facet<date_type, CharT, OutItrT>::short_month_format[3] = {'%','b'}; 380 381 template <class date_type, class CharT, class OutItrT> 382 const typename date_facet<date_type, CharT, OutItrT>::char_type 383 date_facet<date_type, CharT, OutItrT>::default_period_separator[4] = { ' ', '/', ' '}; 384 385 template <class date_type, class CharT, class OutItrT> 386 const typename date_facet<date_type, CharT, OutItrT>::char_type 387 date_facet<date_type, CharT, OutItrT>::standard_format_specifier[3] = 388 {'%', 'x' }; 389 390 template <class date_type, class CharT, class OutItrT> 391 const typename date_facet<date_type, CharT, OutItrT>::char_type 392 date_facet<date_type, CharT, OutItrT>::iso_format_specifier[7] = 393 {'%', 'Y', '%', 'm', '%', 'd' }; 394 395 template <class date_type, class CharT, class OutItrT> 396 const typename date_facet<date_type, CharT, OutItrT>::char_type 397 date_facet<date_type, CharT, OutItrT>::iso_format_extended_specifier[9] = 398 {'%', 'Y', '-', '%', 'm', '-', '%', 'd' }; 399 400 template <class date_type, class CharT, class OutItrT> 401 const typename date_facet<date_type, CharT, OutItrT>::char_type 402 date_facet<date_type, CharT, OutItrT>::default_date_format[9] = 403 {'%','Y','-','%','b','-','%','d'}; 404 405 406 407 //! Input facet 408 template <class date_type, 409 class CharT, 410 class InItrT = std::istreambuf_iterator<CharT, std::char_traits<CharT> > > 411 class BOOST_SYMBOL_VISIBLE date_input_facet : public std::locale::facet { 412 public: 413 typedef typename date_type::duration_type duration_type; 414 // greg_weekday is gregorian_calendar::day_of_week_type 415 typedef typename date_type::day_of_week_type day_of_week_type; 416 typedef typename date_type::day_type day_type; 417 typedef typename date_type::month_type month_type; 418 typedef typename date_type::year_type year_type; 419 typedef boost::date_time::period<date_type,duration_type> period_type; 420 typedef std::basic_string<CharT> string_type; 421 typedef CharT char_type; 422 typedef boost::date_time::period_parser<date_type, CharT> period_parser_type; 423 typedef boost::date_time::special_values_parser<date_type,CharT> special_values_parser_type; 424 typedef std::vector<std::basic_string<CharT> > input_collection_type; 425 typedef format_date_parser<date_type, CharT> format_date_parser_type; 426 // date_generators stuff goes here 427 typedef date_generator_parser<date_type, CharT> date_gen_parser_type; 428 typedef partial_date<date_type> partial_date_type; 429 typedef nth_kday_of_month<date_type> nth_kday_type; 430 typedef first_kday_of_month<date_type> first_kday_type; 431 typedef last_kday_of_month<date_type> last_kday_type; 432 typedef first_kday_after<date_type> kday_after_type; 433 typedef first_kday_before<date_type> kday_before_type; 434 435 static const char_type long_weekday_format[3]; 436 static const char_type short_weekday_format[3]; 437 static const char_type long_month_format[3]; 438 static const char_type short_month_format[3]; 439 static const char_type four_digit_year_format[3]; 440 static const char_type two_digit_year_format[3]; 441 static const char_type default_period_separator[4]; 442 static const char_type standard_format_specifier[3]; 443 static const char_type iso_format_specifier[7]; 444 static const char_type iso_format_extended_specifier[9]; 445 static const char_type default_date_format[9]; // YYYY-Mon-DD 446 static std::locale::id id; 447 date_input_facet(::size_t a_ref=0)448 explicit date_input_facet(::size_t a_ref = 0) 449 : std::locale::facet(a_ref), 450 m_format(default_date_format), 451 m_month_format(short_month_format), 452 m_weekday_format(short_weekday_format), 453 m_year_format(four_digit_year_format), 454 m_parser(m_format, std::locale::classic()) 455 // default period_parser & special_values_parser used 456 {} 457 date_input_facet(const string_type & format_str,::size_t a_ref=0)458 explicit date_input_facet(const string_type& format_str, 459 ::size_t a_ref = 0) 460 : std::locale::facet(a_ref), 461 m_format(format_str), 462 m_month_format(short_month_format), 463 m_weekday_format(short_weekday_format), 464 m_year_format(four_digit_year_format), 465 m_parser(m_format, std::locale::classic()) 466 // default period_parser & special_values_parser used 467 {} 468 date_input_facet(const string_type & format_str,const format_date_parser_type & date_parser,const special_values_parser_type & sv_parser,const period_parser_type & per_parser,const date_gen_parser_type & date_gen_parser,::size_t ref_count=0)469 explicit date_input_facet(const string_type& format_str, 470 const format_date_parser_type& date_parser, 471 const special_values_parser_type& sv_parser, 472 const period_parser_type& per_parser, 473 const date_gen_parser_type& date_gen_parser, 474 ::size_t ref_count = 0) 475 : std::locale::facet(ref_count), 476 m_format(format_str), 477 m_month_format(short_month_format), 478 m_weekday_format(short_weekday_format), 479 m_year_format(four_digit_year_format), 480 m_parser(date_parser), 481 m_date_gen_parser(date_gen_parser), 482 m_period_parser(per_parser), 483 m_sv_parser(sv_parser) 484 {} 485 486 format(const char_type * const format_str)487 void format(const char_type* const format_str) { 488 m_format = format_str; 489 } set_iso_format()490 virtual void set_iso_format() 491 { 492 m_format = iso_format_specifier; 493 } set_iso_extended_format()494 virtual void set_iso_extended_format() 495 { 496 m_format = iso_format_extended_specifier; 497 } month_format(const char_type * const format_str)498 void month_format(const char_type* const format_str) { 499 m_month_format = format_str; 500 } weekday_format(const char_type * const format_str)501 void weekday_format(const char_type* const format_str) { 502 m_weekday_format = format_str; 503 } year_format(const char_type * const format_str)504 void year_format(const char_type* const format_str) { 505 m_year_format = format_str; 506 } 507 period_parser(period_parser_type per_parser)508 void period_parser(period_parser_type per_parser) { 509 m_period_parser = per_parser; 510 } short_weekday_names(const input_collection_type & weekday_names)511 void short_weekday_names(const input_collection_type& weekday_names) 512 { 513 m_parser.short_weekday_names(weekday_names); 514 } long_weekday_names(const input_collection_type & weekday_names)515 void long_weekday_names(const input_collection_type& weekday_names) 516 { 517 m_parser.long_weekday_names(weekday_names); 518 } 519 short_month_names(const input_collection_type & month_names)520 void short_month_names(const input_collection_type& month_names) 521 { 522 m_parser.short_month_names(month_names); 523 } 524 long_month_names(const input_collection_type & month_names)525 void long_month_names(const input_collection_type& month_names) 526 { 527 m_parser.long_month_names(month_names); 528 } 529 date_gen_element_strings(const input_collection_type & col)530 void date_gen_element_strings(const input_collection_type& col) 531 { 532 m_date_gen_parser.element_strings(col); 533 } date_gen_element_strings(const string_type & first,const string_type & second,const string_type & third,const string_type & fourth,const string_type & fifth,const string_type & last,const string_type & before,const string_type & after,const string_type & of)534 void date_gen_element_strings(const string_type& first, 535 const string_type& second, 536 const string_type& third, 537 const string_type& fourth, 538 const string_type& fifth, 539 const string_type& last, 540 const string_type& before, 541 const string_type& after, 542 const string_type& of) 543 544 { 545 m_date_gen_parser.element_strings(first,second,third,fourth,fifth,last,before,after,of); 546 } 547 special_values_parser(special_values_parser_type sv_parser)548 void special_values_parser(special_values_parser_type sv_parser) 549 { 550 m_sv_parser = sv_parser; 551 } 552 get(InItrT & from,InItrT & to,std::ios_base &,date_type & d) const553 InItrT get(InItrT& from, 554 InItrT& to, 555 std::ios_base& /*a_ios*/, 556 date_type& d) const 557 { 558 d = m_parser.parse_date(from, to, m_format, m_sv_parser); 559 return from; 560 } get(InItrT & from,InItrT & to,std::ios_base &,month_type & m) const561 InItrT get(InItrT& from, 562 InItrT& to, 563 std::ios_base& /*a_ios*/, 564 month_type& m) const 565 { 566 m = m_parser.parse_month(from, to, m_month_format); 567 return from; 568 } get(InItrT & from,InItrT & to,std::ios_base &,day_of_week_type & wd) const569 InItrT get(InItrT& from, 570 InItrT& to, 571 std::ios_base& /*a_ios*/, 572 day_of_week_type& wd) const 573 { 574 wd = m_parser.parse_weekday(from, to, m_weekday_format); 575 return from; 576 } 577 //! Expects 1 or 2 digit day range: 1-31 get(InItrT & from,InItrT & to,std::ios_base &,day_type & d) const578 InItrT get(InItrT& from, 579 InItrT& to, 580 std::ios_base& /*a_ios*/, 581 day_type& d) const 582 { 583 d = m_parser.parse_var_day_of_month(from, to); 584 return from; 585 } get(InItrT & from,InItrT & to,std::ios_base &,year_type & y) const586 InItrT get(InItrT& from, 587 InItrT& to, 588 std::ios_base& /*a_ios*/, 589 year_type& y) const 590 { 591 y = m_parser.parse_year(from, to, m_year_format); 592 return from; 593 } get(InItrT & from,InItrT & to,std::ios_base & a_ios,duration_type & dd) const594 InItrT get(InItrT& from, 595 InItrT& to, 596 std::ios_base& a_ios, 597 duration_type& dd) const 598 { 599 // skip leading whitespace 600 while(std::isspace(*from) && from != to) { ++from; } 601 602 /* num_get.get() will always consume the first character if it 603 * is a sign indicator (+/-). Special value strings may begin 604 * with one of these signs so we'll need a copy of it 605 * in case num_get.get() fails. */ 606 char_type c = '\0'; 607 // TODO Are these characters somewhere in the locale? 608 if(*from == '-' || *from == '+') { 609 c = *from; 610 } 611 typedef std::num_get<CharT, InItrT> num_get; 612 typename duration_type::duration_rep_type val = 0; 613 std::ios_base::iostate err = std::ios_base::goodbit; 614 615 if (std::has_facet<num_get>(a_ios.getloc())) { 616 from = std::use_facet<num_get>(a_ios.getloc()).get(from, to, a_ios, err, val); 617 } 618 else { 619 num_get* ng = new num_get(); 620 std::locale l = std::locale(a_ios.getloc(), ng); 621 a_ios.imbue(l); 622 from = ng->get(from, to, a_ios, err, val); 623 } 624 if(err & std::ios_base::failbit){ 625 typedef typename special_values_parser_type::match_results match_results; 626 match_results mr; 627 if(c == '-' || c == '+') { // was the first character consumed? 628 mr.cache += c; 629 } 630 m_sv_parser.match(from, to, mr); 631 if(mr.current_match == match_results::PARSE_ERROR) { 632 boost::throw_exception(std::ios_base::failure("Parse failed. No match found for '" + mr.cache + "'")); 633 BOOST_DATE_TIME_UNREACHABLE_EXPRESSION(return from); // should never reach 634 } 635 dd = duration_type(static_cast<special_values>(mr.current_match)); 636 } 637 else { 638 dd = duration_type(val); 639 } 640 return from; 641 } get(InItrT & from,InItrT & to,std::ios_base & a_ios,period_type & p) const642 InItrT get(InItrT& from, 643 InItrT& to, 644 std::ios_base& a_ios, 645 period_type& p) const 646 { 647 p = m_period_parser.get_period(from, to, a_ios, p, duration_type::unit(), *this); 648 return from; 649 } get(InItrT & from,InItrT & to,std::ios_base & a_ios,nth_kday_type & nkd) const650 InItrT get(InItrT& from, 651 InItrT& to, 652 std::ios_base& a_ios, 653 nth_kday_type& nkd) const 654 { 655 nkd = m_date_gen_parser.get_nth_kday_type(from, to, a_ios, *this); 656 return from; 657 } get(InItrT & from,InItrT & to,std::ios_base & a_ios,partial_date_type & pd) const658 InItrT get(InItrT& from, 659 InItrT& to, 660 std::ios_base& a_ios, 661 partial_date_type& pd) const 662 { 663 664 pd = m_date_gen_parser.get_partial_date_type(from, to, a_ios, *this); 665 return from; 666 } get(InItrT & from,InItrT & to,std::ios_base & a_ios,first_kday_type & fkd) const667 InItrT get(InItrT& from, 668 InItrT& to, 669 std::ios_base& a_ios, 670 first_kday_type& fkd) const 671 { 672 fkd = m_date_gen_parser.get_first_kday_type(from, to, a_ios, *this); 673 return from; 674 } get(InItrT & from,InItrT & to,std::ios_base & a_ios,last_kday_type & lkd) const675 InItrT get(InItrT& from, 676 InItrT& to, 677 std::ios_base& a_ios, 678 last_kday_type& lkd) const 679 { 680 lkd = m_date_gen_parser.get_last_kday_type(from, to, a_ios, *this); 681 return from; 682 } get(InItrT & from,InItrT & to,std::ios_base & a_ios,kday_before_type & fkb) const683 InItrT get(InItrT& from, 684 InItrT& to, 685 std::ios_base& a_ios, 686 kday_before_type& fkb) const 687 { 688 fkb = m_date_gen_parser.get_kday_before_type(from, to, a_ios, *this); 689 return from; 690 } get(InItrT & from,InItrT & to,std::ios_base & a_ios,kday_after_type & fka) const691 InItrT get(InItrT& from, 692 InItrT& to, 693 std::ios_base& a_ios, 694 kday_after_type& fka) const 695 { 696 fka = m_date_gen_parser.get_kday_after_type(from, to, a_ios, *this); 697 return from; 698 } 699 700 protected: 701 string_type m_format; 702 string_type m_month_format; 703 string_type m_weekday_format; 704 string_type m_year_format; 705 format_date_parser_type m_parser; 706 date_gen_parser_type m_date_gen_parser; 707 period_parser_type m_period_parser; 708 special_values_parser_type m_sv_parser; 709 private: 710 }; 711 712 713 template <class date_type, class CharT, class OutItrT> 714 std::locale::id date_input_facet<date_type, CharT, OutItrT>::id; 715 716 template <class date_type, class CharT, class OutItrT> 717 const typename date_input_facet<date_type, CharT, OutItrT>::char_type 718 date_input_facet<date_type, CharT, OutItrT>::long_weekday_format[3] = {'%','A'}; 719 720 template <class date_type, class CharT, class OutItrT> 721 const typename date_input_facet<date_type, CharT, OutItrT>::char_type 722 date_input_facet<date_type, CharT, OutItrT>::short_weekday_format[3] = {'%','a'}; 723 724 template <class date_type, class CharT, class OutItrT> 725 const typename date_input_facet<date_type, CharT, OutItrT>::char_type 726 date_input_facet<date_type, CharT, OutItrT>::long_month_format[3] = {'%','B'}; 727 728 template <class date_type, class CharT, class OutItrT> 729 const typename date_input_facet<date_type, CharT, OutItrT>::char_type 730 date_input_facet<date_type, CharT, OutItrT>::short_month_format[3] = {'%','b'}; 731 732 template <class date_type, class CharT, class OutItrT> 733 const typename date_input_facet<date_type, CharT, OutItrT>::char_type 734 date_input_facet<date_type, CharT, OutItrT>::four_digit_year_format[3] = {'%','Y'}; 735 736 template <class date_type, class CharT, class OutItrT> 737 const typename date_input_facet<date_type, CharT, OutItrT>::char_type 738 date_input_facet<date_type, CharT, OutItrT>::two_digit_year_format[3] = {'%','y'}; 739 740 template <class date_type, class CharT, class OutItrT> 741 const typename date_input_facet<date_type, CharT, OutItrT>::char_type 742 date_input_facet<date_type, CharT, OutItrT>::default_period_separator[4] = { ' ', '/', ' '}; 743 744 template <class date_type, class CharT, class OutItrT> 745 const typename date_input_facet<date_type, CharT, OutItrT>::char_type 746 date_input_facet<date_type, CharT, OutItrT>::standard_format_specifier[3] = 747 {'%', 'x' }; 748 749 template <class date_type, class CharT, class OutItrT> 750 const typename date_input_facet<date_type, CharT, OutItrT>::char_type 751 date_input_facet<date_type, CharT, OutItrT>::iso_format_specifier[7] = 752 {'%', 'Y', '%', 'm', '%', 'd' }; 753 754 template <class date_type, class CharT, class OutItrT> 755 const typename date_input_facet<date_type, CharT, OutItrT>::char_type 756 date_input_facet<date_type, CharT, OutItrT>::iso_format_extended_specifier[9] = 757 {'%', 'Y', '-', '%', 'm', '-', '%', 'd' }; 758 759 template <class date_type, class CharT, class OutItrT> 760 const typename date_input_facet<date_type, CharT, OutItrT>::char_type 761 date_input_facet<date_type, CharT, OutItrT>::default_date_format[9] = 762 {'%','Y','-','%','b','-','%','d'}; 763 764 } } // namespaces 765 766 #endif 767