1 2 #ifndef _DATE_TIME_FACET__HPP__ 3 #define _DATE_TIME_FACET__HPP__ 4 5 /* Copyright (c) 2004-2005 CrystalClear Software, Inc. 6 * Use, modification and distribution is subject to the 7 * Boost Software License, Version 1.0. (See accompanying 8 * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) 9 * Author: Martin Andrian, Jeff Garland, Bart Garst 10 * $Date$ 11 */ 12 13 #include <cctype> 14 #include <exception> 15 #include <iomanip> 16 #include <iterator> // i/ostreambuf_iterator 17 #include <locale> 18 #include <limits> 19 #include <sstream> 20 #include <string> 21 #include <boost/assert.hpp> 22 #include <boost/lexical_cast.hpp> 23 #include <boost/throw_exception.hpp> 24 #include <boost/range/as_literal.hpp> 25 #include <boost/algorithm/string/erase.hpp> 26 #include <boost/algorithm/string/replace.hpp> 27 #include <boost/date_time/compiler_config.hpp> 28 #include <boost/date_time/date_facet.hpp> 29 #include <boost/date_time/string_convert.hpp> 30 #include <boost/date_time/special_defs.hpp> 31 #include <boost/date_time/time_resolution_traits.hpp> // absolute_value 32 33 namespace boost { 34 namespace date_time { 35 36 template <class CharT> 37 struct time_formats { 38 public: 39 typedef CharT char_type; 40 static const char_type fractional_seconds_format[3]; // f 41 static const char_type fractional_seconds_or_none_format[3]; // F 42 static const char_type seconds_with_fractional_seconds_format[3]; // s 43 static const char_type seconds_format[3]; // S 44 static const char_type hours_format[3]; // H 45 static const char_type unrestricted_hours_format[3]; // O 46 static const char_type full_24_hour_time_format[3]; // T 47 static const char_type full_24_hour_time_expanded_format[9]; // HH:MM:SS 48 static const char_type short_24_hour_time_format[3]; // R 49 static const char_type short_24_hour_time_expanded_format[6]; // HH:MM 50 static const char_type standard_format[9]; // x X 51 static const char_type zone_abbrev_format[3]; // z 52 static const char_type zone_name_format[3]; // Z 53 static const char_type zone_iso_format[3]; // q 54 static const char_type zone_iso_extended_format[3]; // Q 55 static const char_type posix_zone_string_format[4]; // ZP 56 static const char_type duration_sign_negative_only[3]; // - 57 static const char_type duration_sign_always[3]; // + 58 static const char_type duration_seperator[2]; 59 static const char_type negative_sign[2]; //- 60 static const char_type positive_sign[2]; //+ 61 static const char_type iso_time_format_specifier[18]; 62 static const char_type iso_time_format_extended_specifier[22]; 63 //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz] 64 static const char_type default_time_format[23]; 65 // default_time_input_format uses a posix_time_zone_string instead of a time zone abbrev 66 static const char_type default_time_input_format[24]; 67 //default time_duration format is HH:MM:SS[.fff...] 68 static const char_type default_time_duration_format[11]; 69 }; 70 71 template <class CharT> 72 const typename time_formats<CharT>::char_type 73 time_formats<CharT>::fractional_seconds_format[3] = {'%','f'}; 74 75 template <class CharT> 76 const typename time_formats<CharT>::char_type 77 time_formats<CharT>::fractional_seconds_or_none_format[3] = {'%','F'}; 78 79 template <class CharT> 80 const typename time_formats<CharT>::char_type 81 time_formats<CharT>::seconds_with_fractional_seconds_format[3] = {'%','s'}; 82 83 template <class CharT> 84 const typename time_formats<CharT>::char_type 85 time_formats<CharT>::seconds_format[3] = {'%','S'}; 86 87 template <class CharT> 88 const typename time_formats<CharT>::char_type 89 time_formats<CharT>::hours_format[3] = {'%','H'}; 90 91 template <class CharT> 92 const typename time_formats<CharT>::char_type 93 time_formats<CharT>::unrestricted_hours_format[3] = {'%','O'}; 94 95 template <class CharT> 96 const typename time_formats<CharT>::char_type 97 time_formats<CharT>::full_24_hour_time_format[3] = {'%','T'}; 98 99 template <class CharT> 100 const typename time_formats<CharT>::char_type 101 time_formats<CharT>::full_24_hour_time_expanded_format[9] = 102 {'%','H',':','%','M',':','%','S'}; 103 104 template <class CharT> 105 const typename time_formats<CharT>::char_type 106 time_formats<CharT>::short_24_hour_time_format[3] = {'%','R'}; 107 108 template <class CharT> 109 const typename time_formats<CharT>::char_type 110 time_formats<CharT>::short_24_hour_time_expanded_format[6] = 111 {'%','H',':','%','M'}; 112 113 template <class CharT> 114 const typename time_formats<CharT>::char_type 115 //time_formats<CharT>::standard_format[5] = {'%','c',' ','%','z'}; 116 time_formats<CharT>::standard_format[9] = {'%','x',' ','%','X',' ','%','z'}; 117 118 template <class CharT> 119 const typename time_formats<CharT>::char_type 120 time_formats<CharT>::zone_abbrev_format[3] = {'%','z'}; 121 122 template <class CharT> 123 const typename time_formats<CharT>::char_type 124 time_formats<CharT>::zone_name_format[3] = {'%','Z'}; 125 126 template <class CharT> 127 const typename time_formats<CharT>::char_type 128 time_formats<CharT>::zone_iso_format[3] = {'%','q'}; 129 130 template <class CharT> 131 const typename time_formats<CharT>::char_type 132 time_formats<CharT>::zone_iso_extended_format[3] ={'%','Q'}; 133 134 template <class CharT> 135 const typename time_formats<CharT>::char_type 136 time_formats<CharT>::posix_zone_string_format[4] ={'%','Z','P'}; 137 138 template <class CharT> 139 const typename time_formats<CharT>::char_type 140 time_formats<CharT>::duration_seperator[2] = {':'}; 141 142 template <class CharT> 143 const typename time_formats<CharT>::char_type 144 time_formats<CharT>::negative_sign[2] = {'-'}; 145 146 template <class CharT> 147 const typename time_formats<CharT>::char_type 148 time_formats<CharT>::positive_sign[2] = {'+'}; 149 150 template <class CharT> 151 const typename time_formats<CharT>::char_type 152 time_formats<CharT>::duration_sign_negative_only[3] ={'%','-'}; 153 154 template <class CharT> 155 const typename time_formats<CharT>::char_type 156 time_formats<CharT>::duration_sign_always[3] ={'%','+'}; 157 158 template <class CharT> 159 const typename time_formats<CharT>::char_type 160 time_formats<CharT>::iso_time_format_specifier[18] = 161 {'%', 'Y', '%', 'm', '%', 'd', 'T', 162 '%', 'H', '%', 'M', '%', 'S', '%', 'F', '%','q' }; 163 164 template <class CharT> 165 const typename time_formats<CharT>::char_type 166 time_formats<CharT>::iso_time_format_extended_specifier[22] = 167 {'%', 'Y', '-', '%', 'm', '-', '%', 'd', ' ', 168 '%', 'H', ':', '%', 'M', ':', '%', 'S', '%', 'F','%','Q'}; 169 170 template <class CharT> 171 const typename time_formats<CharT>::char_type 172 time_formats<CharT>::default_time_format[23] = 173 {'%','Y','-','%','b','-','%','d',' ', 174 '%','H',':','%','M',':','%','S','%','F',' ','%','z'}; 175 176 template <class CharT> 177 const typename time_formats<CharT>::char_type 178 time_formats<CharT>::default_time_input_format[24] = 179 {'%','Y','-','%','b','-','%','d',' ', 180 '%','H',':','%','M',':','%','S','%','F',' ','%','Z','P'}; 181 182 template <class CharT> 183 const typename time_formats<CharT>::char_type 184 time_formats<CharT>::default_time_duration_format[11] = 185 {'%','O',':','%','M',':','%','S','%','F'}; 186 187 188 189 /*! Facet used for format-based output of time types 190 * This class provides for the use of format strings to output times. In addition 191 * to the flags for formatting date elements, the following are the allowed format flags: 192 * - %x %X => default format - enables addition of more flags to default (ie. "%x %X %z") 193 * - %f => fractional seconds ".123456" 194 * - %F => fractional seconds or none: like frac sec but empty if frac sec == 0 195 * - %s => seconds w/ fractional sec "02.123" (this is the same as "%S%f) 196 * - %S => seconds "02" 197 * - %z => abbreviated time zone "EDT" 198 * - %Z => full time zone name "Eastern Daylight Time" 199 */ 200 template <class time_type, 201 class CharT, 202 class OutItrT = std::ostreambuf_iterator<CharT, std::char_traits<CharT> > > 203 class BOOST_SYMBOL_VISIBLE time_facet : 204 public boost::date_time::date_facet<typename time_type::date_type , CharT, OutItrT> { 205 typedef time_formats< CharT > formats_type; 206 public: 207 typedef typename time_type::date_type date_type; 208 typedef typename time_type::time_duration_type time_duration_type; 209 typedef boost::date_time::period<time_type,time_duration_type> period_type; 210 typedef boost::date_time::date_facet<typename time_type::date_type, CharT, OutItrT> base_type; 211 typedef typename base_type::string_type string_type; 212 typedef typename base_type::char_type char_type; 213 typedef typename base_type::period_formatter_type period_formatter_type; 214 typedef typename base_type::special_values_formatter_type special_values_formatter_type; 215 typedef typename base_type::date_gen_formatter_type date_gen_formatter_type; 216 static const char_type* fractional_seconds_format; // %f 217 static const char_type* fractional_seconds_or_none_format; // %F 218 static const char_type* seconds_with_fractional_seconds_format; // %s 219 static const char_type* seconds_format; // %S 220 static const char_type* hours_format; // %H 221 static const char_type* unrestricted_hours_format; // %O 222 static const char_type* standard_format; // %x X 223 static const char_type* zone_abbrev_format; // %z 224 static const char_type* zone_name_format; // %Z 225 static const char_type* zone_iso_format; // %q 226 static const char_type* zone_iso_extended_format; // %Q 227 static const char_type* posix_zone_string_format; // %ZP 228 static const char_type* duration_seperator; 229 static const char_type* duration_sign_always; // %+ 230 static const char_type* duration_sign_negative_only; // %- 231 static const char_type* negative_sign; //- 232 static const char_type* positive_sign; //+ 233 static const char_type* iso_time_format_specifier; 234 static const char_type* iso_time_format_extended_specifier; 235 236 //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz] 237 static const char_type* default_time_format; 238 //default time_duration format is HH:MM:SS[.fff...] 239 static const char_type* default_time_duration_format; 240 static std::locale::id id; 241 242 #if defined (__SUNPRO_CC) && defined (_RWSTD_VER) __get_id(void) const243 std::locale::id& __get_id (void) const { return id; } 244 #endif 245 246 //! sets default formats for ptime, local_date_time, and time_duration time_facet(::size_t ref_arg=0)247 explicit time_facet(::size_t ref_arg = 0) 248 : base_type(default_time_format, period_formatter_type(), special_values_formatter_type(), date_gen_formatter_type(), ref_arg), 249 m_time_duration_format(string_type(duration_sign_negative_only) + default_time_duration_format) 250 {} 251 252 //! Construct the facet with an explicitly specified format time_facet(const char_type * format_arg,period_formatter_type period_formatter_arg=period_formatter_type (),const special_values_formatter_type & special_value_formatter=special_values_formatter_type (),date_gen_formatter_type dg_formatter=date_gen_formatter_type (),::size_t ref_arg=0)253 explicit time_facet(const char_type* format_arg, 254 period_formatter_type period_formatter_arg = period_formatter_type(), 255 const special_values_formatter_type& special_value_formatter = special_values_formatter_type(), 256 date_gen_formatter_type dg_formatter = date_gen_formatter_type(), 257 ::size_t ref_arg = 0) 258 : base_type(format_arg, 259 period_formatter_arg, 260 special_value_formatter, 261 dg_formatter, 262 ref_arg), 263 m_time_duration_format(string_type(duration_sign_negative_only) + default_time_duration_format) 264 {} 265 266 //! Changes format for time_duration time_duration_format(const char_type * const format)267 void time_duration_format(const char_type* const format) 268 { 269 m_time_duration_format = format; 270 } 271 set_iso_format()272 void set_iso_format() BOOST_OVERRIDE 273 { 274 this->m_format = iso_time_format_specifier; 275 } set_iso_extended_format()276 void set_iso_extended_format() BOOST_OVERRIDE 277 { 278 this->m_format = iso_time_format_extended_specifier; 279 } 280 put(OutItrT next_arg,std::ios_base & ios_arg,char_type fill_arg,const time_type & time_arg) const281 OutItrT put(OutItrT next_arg, 282 std::ios_base& ios_arg, 283 char_type fill_arg, 284 const time_type& time_arg) const 285 { 286 if (time_arg.is_special()) { 287 return this->do_put_special(next_arg, ios_arg, fill_arg, 288 time_arg.date().as_special()); 289 } 290 string_type local_format(this->m_format); 291 292 // %T and %R have to be replaced here since they are not standard 293 boost::algorithm::replace_all(local_format, 294 boost::as_literal(formats_type::full_24_hour_time_format), 295 boost::as_literal(formats_type::full_24_hour_time_expanded_format)); 296 boost::algorithm::replace_all(local_format, 297 boost::as_literal(formats_type::short_24_hour_time_format), 298 boost::as_literal(formats_type::short_24_hour_time_expanded_format)); 299 300 string_type frac_str; 301 if (local_format.find(seconds_with_fractional_seconds_format) != string_type::npos) { 302 // replace %s with %S.nnn 303 frac_str = 304 fractional_seconds_as_string(time_arg.time_of_day(), false); 305 char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point(); 306 307 string_type replace_string(seconds_format); 308 replace_string += sep; 309 replace_string += frac_str; 310 boost::algorithm::replace_all(local_format, 311 seconds_with_fractional_seconds_format, 312 replace_string); 313 } 314 /* NOTE: replacing posix_zone_string_format must be done BEFORE 315 * zone_name_format: "%ZP" & "%Z", if Z is checked first it will 316 * incorrectly replace a zone_name where a posix_string should go */ 317 if (local_format.find(posix_zone_string_format) != string_type::npos) { 318 if(time_arg.zone_abbrev().empty()) { 319 // if zone_abbrev() returns an empty string, we want to 320 // erase posix_zone_string_format from format 321 boost::algorithm::erase_all(local_format, posix_zone_string_format); 322 } 323 else{ 324 boost::algorithm::replace_all(local_format, 325 posix_zone_string_format, 326 time_arg.zone_as_posix_string()); 327 } 328 } 329 if (local_format.find(zone_name_format) != string_type::npos) { 330 if(time_arg.zone_name().empty()) { 331 /* TODO: this'll probably create problems if a user places 332 * the zone_*_format flag in the format with a ptime. This 333 * code removes the flag from the default formats */ 334 335 // if zone_name() returns an empty string, we want to 336 // erase zone_name_format & one preceeding space 337 std::basic_ostringstream<char_type> ss; 338 ss << ' ' << zone_name_format; 339 boost::algorithm::erase_all(local_format, ss.str()); 340 } 341 else{ 342 boost::algorithm::replace_all(local_format, 343 zone_name_format, 344 time_arg.zone_name()); 345 } 346 } 347 if (local_format.find(zone_abbrev_format) != string_type::npos) { 348 if(time_arg.zone_abbrev(false).empty()) { 349 /* TODO: this'll probably create problems if a user places 350 * the zone_*_format flag in the format with a ptime. This 351 * code removes the flag from the default formats */ 352 353 // if zone_abbrev() returns an empty string, we want to 354 // erase zone_abbrev_format & one preceeding space 355 std::basic_ostringstream<char_type> ss; 356 ss << ' ' << zone_abbrev_format; 357 boost::algorithm::erase_all(local_format, ss.str()); 358 } 359 else{ 360 boost::algorithm::replace_all(local_format, 361 zone_abbrev_format, 362 time_arg.zone_abbrev(false)); 363 } 364 } 365 if (local_format.find(zone_iso_extended_format) != string_type::npos) { 366 if(time_arg.zone_name(true).empty()) { 367 /* TODO: this'll probably create problems if a user places 368 * the zone_*_format flag in the format with a ptime. This 369 * code removes the flag from the default formats */ 370 371 // if zone_name() returns an empty string, we want to 372 // erase zone_iso_extended_format from format 373 boost::algorithm::erase_all(local_format, zone_iso_extended_format); 374 } 375 else{ 376 boost::algorithm::replace_all(local_format, 377 zone_iso_extended_format, 378 time_arg.zone_name(true)); 379 } 380 } 381 382 if (local_format.find(zone_iso_format) != string_type::npos) { 383 if(time_arg.zone_abbrev(true).empty()) { 384 /* TODO: this'll probably create problems if a user places 385 * the zone_*_format flag in the format with a ptime. This 386 * code removes the flag from the default formats */ 387 388 // if zone_abbrev() returns an empty string, we want to 389 // erase zone_iso_format from format 390 boost::algorithm::erase_all(local_format, zone_iso_format); 391 } 392 else{ 393 boost::algorithm::replace_all(local_format, 394 zone_iso_format, 395 time_arg.zone_abbrev(true)); 396 } 397 } 398 if (local_format.find(fractional_seconds_format) != string_type::npos) { 399 // replace %f with nnnnnnn 400 if (frac_str.empty()) { 401 frac_str = fractional_seconds_as_string(time_arg.time_of_day(), false); 402 } 403 boost::algorithm::replace_all(local_format, 404 fractional_seconds_format, 405 frac_str); 406 } 407 408 if (local_format.find(fractional_seconds_or_none_format) != string_type::npos) { 409 // replace %F with nnnnnnn or nothing if fs == 0 410 frac_str = 411 fractional_seconds_as_string(time_arg.time_of_day(), true); 412 if (!frac_str.empty()) { 413 char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point(); 414 string_type replace_string; 415 replace_string += sep; 416 replace_string += frac_str; 417 boost::algorithm::replace_all(local_format, 418 fractional_seconds_or_none_format, 419 replace_string); 420 } 421 else { 422 boost::algorithm::erase_all(local_format, 423 fractional_seconds_or_none_format); 424 } 425 } 426 427 return this->do_put_tm(next_arg, ios_arg, fill_arg, 428 to_tm(time_arg), local_format); 429 } 430 431 //! put function for time_duration put(OutItrT next_arg,std::ios_base & ios_arg,char_type fill_arg,const time_duration_type & time_dur_arg) const432 OutItrT put(OutItrT next_arg, 433 std::ios_base& ios_arg, 434 char_type fill_arg, 435 const time_duration_type& time_dur_arg) const 436 { 437 if (time_dur_arg.is_special()) { 438 return this->do_put_special(next_arg, ios_arg, fill_arg, 439 time_dur_arg.get_rep().as_special()); 440 } 441 442 string_type format(m_time_duration_format); 443 if (time_dur_arg.is_negative()) { 444 // replace %- with minus sign. Should we use the numpunct facet? 445 boost::algorithm::replace_all(format, 446 duration_sign_negative_only, 447 negative_sign); 448 // remove all the %+ in the string with '-' 449 boost::algorithm::replace_all(format, 450 duration_sign_always, 451 negative_sign); 452 } 453 else { //duration is positive 454 // remove all the %- combos from the string 455 boost::algorithm::erase_all(format, duration_sign_negative_only); 456 // remove all the %+ in the string with '+' 457 boost::algorithm::replace_all(format, 458 duration_sign_always, 459 positive_sign); 460 } 461 462 // %T and %R have to be replaced here since they are not standard 463 boost::algorithm::replace_all(format, 464 boost::as_literal(formats_type::full_24_hour_time_format), 465 boost::as_literal(formats_type::full_24_hour_time_expanded_format)); 466 boost::algorithm::replace_all(format, 467 boost::as_literal(formats_type::short_24_hour_time_format), 468 boost::as_literal(formats_type::short_24_hour_time_expanded_format)); 469 470 /* 471 * It is possible for a time duration to span more then 24 hours. 472 * Standard time_put::put is obliged to behave the same as strftime 473 * (See ISO 14882-2003 22.2.5.3.1 par. 1) and strftime's behavior is 474 * unspecified for the case when tm_hour field is outside 0-23 range 475 * (See ISO 9899-1999 7.23.3.5 par. 3). So we must output %H and %O 476 * here ourself. 477 */ 478 string_type hours_str; 479 if (format.find(unrestricted_hours_format) != string_type::npos) { 480 hours_str = hours_as_string(time_dur_arg); 481 boost::algorithm::replace_all(format, unrestricted_hours_format, hours_str); 482 } 483 // We still have to process restricted hours format specifier. In order to 484 // support parseability of durations in ISO format (%H%M%S), we'll have to 485 // restrict the stringified hours length to 2 characters. 486 if (format.find(hours_format) != string_type::npos) { 487 if (hours_str.empty()) 488 hours_str = hours_as_string(time_dur_arg); 489 BOOST_ASSERT(hours_str.length() <= 2); 490 boost::algorithm::replace_all(format, hours_format, hours_str); 491 } 492 493 string_type frac_str; 494 if (format.find(seconds_with_fractional_seconds_format) != string_type::npos) { 495 // replace %s with %S.nnn 496 frac_str = 497 fractional_seconds_as_string(time_dur_arg, false); 498 char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point(); 499 500 string_type replace_string(seconds_format); 501 replace_string += sep; 502 replace_string += frac_str; 503 boost::algorithm::replace_all(format, 504 seconds_with_fractional_seconds_format, 505 replace_string); 506 } 507 if (format.find(fractional_seconds_format) != string_type::npos) { 508 // replace %f with nnnnnnn 509 if (!frac_str.size()) { 510 frac_str = fractional_seconds_as_string(time_dur_arg, false); 511 } 512 boost::algorithm::replace_all(format, 513 fractional_seconds_format, 514 frac_str); 515 } 516 517 if (format.find(fractional_seconds_or_none_format) != string_type::npos) { 518 // replace %F with nnnnnnn or nothing if fs == 0 519 frac_str = 520 fractional_seconds_as_string(time_dur_arg, true); 521 if (frac_str.size()) { 522 char_type sep = std::use_facet<std::numpunct<char_type> >(ios_arg.getloc()).decimal_point(); 523 string_type replace_string; 524 replace_string += sep; 525 replace_string += frac_str; 526 boost::algorithm::replace_all(format, 527 fractional_seconds_or_none_format, 528 replace_string); 529 } 530 else { 531 boost::algorithm::erase_all(format, 532 fractional_seconds_or_none_format); 533 } 534 } 535 536 return this->do_put_tm(next_arg, ios_arg, fill_arg, 537 to_tm(time_dur_arg), format); 538 } 539 put(OutItrT next,std::ios_base & ios_arg,char_type fill,const period_type & p) const540 OutItrT put(OutItrT next, std::ios_base& ios_arg, 541 char_type fill, const period_type& p) const 542 { 543 return this->m_period_formatter.put_period(next, ios_arg, fill,p,*this); 544 } 545 546 547 protected: 548 549 static 550 string_type fractional_seconds_as_string(const time_duration_type & time_arg,bool null_when_zero)551 fractional_seconds_as_string(const time_duration_type& time_arg, 552 bool null_when_zero) 553 { 554 typename time_duration_type::fractional_seconds_type frac_sec = 555 time_arg.fractional_seconds(); 556 557 if (null_when_zero && (frac_sec == 0)) { 558 return string_type(); 559 } 560 561 //make sure there is no sign 562 return integral_as_string( 563 date_time::absolute_value(frac_sec), 564 time_duration_type::num_fractional_digits()); 565 } 566 567 static 568 string_type hours_as_string(const time_duration_type & time_arg,int width=2)569 hours_as_string(const time_duration_type& time_arg, int width = 2) 570 { 571 return integral_as_string(date_time::absolute_value(time_arg.hours()), width); 572 } 573 574 template< typename IntT > 575 static 576 string_type integral_as_string(IntT val,int width=2)577 integral_as_string(IntT val, int width = 2) 578 { 579 std::basic_ostringstream<char_type> ss; 580 ss.imbue(std::locale::classic()); // don't want any formatting 581 ss << std::setw(width) 582 << std::setfill(static_cast<char_type>('0')); 583 #if (defined(BOOST_MSVC) && (_MSC_VER < 1300)) 584 // JDG [7/6/02 VC++ compatibility] 585 char_type buff[34]; 586 ss << _i64toa(static_cast<boost::int64_t>(val), buff, 10); 587 #else 588 ss << val; 589 #endif 590 return ss.str(); 591 } 592 593 private: 594 string_type m_time_duration_format; 595 596 }; 597 598 template <class time_type, class CharT, class OutItrT> 599 std::locale::id time_facet<time_type, CharT, OutItrT>::id; 600 601 template <class time_type, class CharT, class OutItrT> 602 const typename time_facet<time_type, CharT, OutItrT>::char_type* 603 time_facet<time_type, CharT, OutItrT>::fractional_seconds_format = time_formats<CharT>::fractional_seconds_format; 604 605 template <class time_type, class CharT, class OutItrT> 606 const typename time_facet<time_type, CharT, OutItrT>::char_type* 607 time_facet<time_type, CharT, OutItrT>::fractional_seconds_or_none_format = time_formats<CharT>::fractional_seconds_or_none_format; 608 609 template <class time_type, class CharT, class OutItrT> 610 const typename time_facet<time_type, CharT, OutItrT>::char_type* 611 time_facet<time_type, CharT, OutItrT>::seconds_with_fractional_seconds_format = 612 time_formats<CharT>::seconds_with_fractional_seconds_format; 613 614 615 template <class time_type, class CharT, class OutItrT> 616 const typename time_facet<time_type, CharT, OutItrT>::char_type* 617 time_facet<time_type, CharT, OutItrT>::zone_name_format = time_formats<CharT>::zone_name_format; 618 619 template <class time_type, class CharT, class OutItrT> 620 const typename time_facet<time_type, CharT, OutItrT>::char_type* 621 time_facet<time_type, CharT, OutItrT>::zone_abbrev_format = time_formats<CharT>::zone_abbrev_format; 622 623 template <class time_type, class CharT, class OutItrT> 624 const typename time_facet<time_type, CharT, OutItrT>::char_type* 625 time_facet<time_type, CharT, OutItrT>::zone_iso_extended_format =time_formats<CharT>::zone_iso_extended_format; 626 627 template <class time_type, class CharT, class OutItrT> 628 const typename time_facet<time_type, CharT, OutItrT>::char_type* 629 time_facet<time_type, CharT, OutItrT>::posix_zone_string_format =time_formats<CharT>::posix_zone_string_format; 630 631 template <class time_type, class CharT, class OutItrT> 632 const typename time_facet<time_type, CharT, OutItrT>::char_type* 633 time_facet<time_type, CharT, OutItrT>::zone_iso_format = time_formats<CharT>::zone_iso_format; 634 635 template <class time_type, class CharT, class OutItrT> 636 const typename time_facet<time_type, CharT, OutItrT>::char_type* 637 time_facet<time_type, CharT, OutItrT>::seconds_format = time_formats<CharT>::seconds_format; 638 639 template <class time_type, class CharT, class OutItrT> 640 const typename time_facet<time_type, CharT, OutItrT>::char_type* 641 time_facet<time_type, CharT, OutItrT>::hours_format = time_formats<CharT>::hours_format; 642 643 template <class time_type, class CharT, class OutItrT> 644 const typename time_facet<time_type, CharT, OutItrT>::char_type* 645 time_facet<time_type, CharT, OutItrT>::unrestricted_hours_format = time_formats<CharT>::unrestricted_hours_format; 646 647 template <class time_type, class CharT, class OutItrT> 648 const typename time_facet<time_type, CharT, OutItrT>::char_type* 649 time_facet<time_type, CharT, OutItrT>::standard_format = time_formats<CharT>::standard_format; 650 651 template <class time_type, class CharT, class OutItrT> 652 const typename time_facet<time_type, CharT, OutItrT>::char_type* 653 time_facet<time_type, CharT, OutItrT>::duration_seperator = time_formats<CharT>::duration_seperator; 654 655 template <class time_type, class CharT, class OutItrT> 656 const typename time_facet<time_type, CharT, OutItrT>::char_type* 657 time_facet<time_type, CharT, OutItrT>::negative_sign = time_formats<CharT>::negative_sign; 658 659 template <class time_type, class CharT, class OutItrT> 660 const typename time_facet<time_type, CharT, OutItrT>::char_type* 661 time_facet<time_type, CharT, OutItrT>::positive_sign = time_formats<CharT>::positive_sign; 662 663 template <class time_type, class CharT, class OutItrT> 664 const typename time_facet<time_type, CharT, OutItrT>::char_type* 665 time_facet<time_type, CharT, OutItrT>::duration_sign_negative_only = time_formats<CharT>::duration_sign_negative_only; 666 667 template <class time_type, class CharT, class OutItrT> 668 const typename time_facet<time_type, CharT, OutItrT>::char_type* 669 time_facet<time_type, CharT, OutItrT>::duration_sign_always = time_formats<CharT>::duration_sign_always; 670 671 template <class time_type, class CharT, class OutItrT> 672 const typename time_facet<time_type,CharT, OutItrT>::char_type* 673 time_facet<time_type,CharT, OutItrT>::iso_time_format_specifier = time_formats<CharT>::iso_time_format_specifier; 674 675 template <class time_type, class CharT, class OutItrT> 676 const typename time_facet<time_type, CharT, OutItrT>::char_type* 677 time_facet<time_type, CharT, OutItrT>::iso_time_format_extended_specifier = time_formats<CharT>::iso_time_format_extended_specifier; 678 679 template <class time_type, class CharT, class OutItrT> 680 const typename time_facet<time_type, CharT, OutItrT>::char_type* 681 time_facet<time_type, CharT, OutItrT>::default_time_format = 682 time_formats<CharT>::default_time_format; 683 684 template <class time_type, class CharT, class OutItrT> 685 const typename time_facet<time_type, CharT, OutItrT>::char_type* 686 time_facet<time_type, CharT, OutItrT>::default_time_duration_format = 687 time_formats<CharT>::default_time_duration_format; 688 689 690 //! Facet for format-based input. 691 /*! 692 */ 693 template <class time_type, 694 class CharT, 695 class InItrT = std::istreambuf_iterator<CharT, std::char_traits<CharT> > > 696 class BOOST_SYMBOL_VISIBLE time_input_facet : 697 public boost::date_time::date_input_facet<typename time_type::date_type , CharT, InItrT> { 698 public: 699 typedef typename time_type::date_type date_type; 700 typedef typename time_type::time_duration_type time_duration_type; 701 typedef typename time_duration_type::fractional_seconds_type fracional_seconds_type; 702 typedef boost::date_time::period<time_type,time_duration_type> period_type; 703 typedef boost::date_time::date_input_facet<typename time_type::date_type, CharT, InItrT> base_type; 704 typedef typename base_type::duration_type date_duration_type; 705 typedef typename base_type::year_type year_type; 706 typedef typename base_type::month_type month_type; 707 typedef typename base_type::day_type day_type; 708 typedef typename base_type::string_type string_type; 709 typedef typename string_type::const_iterator const_itr; 710 typedef typename base_type::char_type char_type; 711 typedef typename base_type::format_date_parser_type format_date_parser_type; 712 typedef typename base_type::period_parser_type period_parser_type; 713 typedef typename base_type::special_values_parser_type special_values_parser_type; 714 typedef typename base_type::date_gen_parser_type date_gen_parser_type; 715 typedef typename base_type::special_values_parser_type::match_results match_results; 716 717 static const char_type* fractional_seconds_format; // f 718 static const char_type* fractional_seconds_or_none_format; // F 719 static const char_type* seconds_with_fractional_seconds_format; // s 720 static const char_type* seconds_format; // S 721 static const char_type* standard_format; // x X 722 static const char_type* zone_abbrev_format; // z 723 static const char_type* zone_name_format; // Z 724 static const char_type* zone_iso_format; // q 725 static const char_type* zone_iso_extended_format; // Q 726 static const char_type* duration_seperator; 727 static const char_type* iso_time_format_specifier; 728 static const char_type* iso_time_format_extended_specifier; 729 static const char_type* default_time_input_format; 730 static const char_type* default_time_duration_format; 731 static std::locale::id id; 732 733 //! Constructor that takes a format string for a ptime time_input_facet(const string_type & format,::size_t ref_arg=0)734 explicit time_input_facet(const string_type& format, ::size_t ref_arg = 0) 735 : base_type(format, ref_arg), 736 m_time_duration_format(default_time_duration_format) 737 { } 738 time_input_facet(const string_type & format,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_arg=0)739 explicit time_input_facet(const string_type& format, 740 const format_date_parser_type& date_parser, 741 const special_values_parser_type& sv_parser, 742 const period_parser_type& per_parser, 743 const date_gen_parser_type& date_gen_parser, 744 ::size_t ref_arg = 0) 745 : base_type(format, 746 date_parser, 747 sv_parser, 748 per_parser, 749 date_gen_parser, 750 ref_arg), 751 m_time_duration_format(default_time_duration_format) 752 {} 753 754 //! sets default formats for ptime, local_date_time, and time_duration time_input_facet(::size_t ref_arg=0)755 explicit time_input_facet(::size_t ref_arg = 0) 756 : base_type(default_time_input_format, ref_arg), 757 m_time_duration_format(default_time_duration_format) 758 { } 759 760 //! Set the format for time_duration time_duration_format(const char_type * const format)761 void time_duration_format(const char_type* const format) { 762 m_time_duration_format = format; 763 } set_iso_format()764 virtual void set_iso_format() 765 { 766 this->m_format = iso_time_format_specifier; 767 } set_iso_extended_format()768 virtual void set_iso_extended_format() 769 { 770 this->m_format = iso_time_format_extended_specifier; 771 } 772 get(InItrT & sitr,InItrT & stream_end,std::ios_base & ios_arg,period_type & p) const773 InItrT get(InItrT& sitr, 774 InItrT& stream_end, 775 std::ios_base& ios_arg, 776 period_type& p) const 777 { 778 p = this->m_period_parser.get_period(sitr, 779 stream_end, 780 ios_arg, 781 p, 782 time_duration_type::unit(), 783 *this); 784 return sitr; 785 } 786 787 //default ptime format is YYYY-Mon-DD HH:MM:SS[.fff...][ zzz] 788 //default time_duration format is %H:%M:%S%F HH:MM:SS[.fff...] 789 get(InItrT & sitr,InItrT & stream_end,std::ios_base & ios_arg,time_duration_type & td) const790 InItrT get(InItrT& sitr, 791 InItrT& stream_end, 792 std::ios_base& ios_arg, 793 time_duration_type& td) const 794 { 795 // skip leading whitespace 796 while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; } 797 798 bool use_current_char = false; 799 800 // num_get will consume the +/-, we may need a copy if special_value 801 char_type c = '\0'; 802 if((sitr != stream_end) && (*sitr == '-' || *sitr == '+')) { 803 c = *sitr; 804 } 805 806 typedef typename time_duration_type::hour_type hour_type; 807 typedef typename time_duration_type::min_type min_type; 808 typedef typename time_duration_type::sec_type sec_type; 809 810 hour_type hour = 0; 811 min_type min = 0; 812 sec_type sec = 0; 813 typename time_duration_type::fractional_seconds_type frac(0); 814 815 typedef std::num_get<CharT, InItrT> num_get; 816 if(!std::has_facet<num_get>(ios_arg.getloc())) { 817 num_get* ng = new num_get(); 818 std::locale loc = std::locale(ios_arg.getloc(), ng); 819 ios_arg.imbue(loc); 820 } 821 822 const_itr itr(m_time_duration_format.begin()); 823 while (itr != m_time_duration_format.end() && (sitr != stream_end)) { 824 if (*itr == '%') { 825 if (++itr == m_time_duration_format.end()) break; 826 if (*itr != '%') { 827 switch(*itr) { 828 case 'O': 829 { 830 // A period may span more than 24 hours. In that case the format 831 // string should be composed with the unrestricted hours specifier. 832 hour = var_string_to_int<hour_type, CharT>(sitr, stream_end, 833 std::numeric_limits<hour_type>::digits10 + 1); 834 if(hour == -1){ 835 return check_special_value(sitr, stream_end, td, c); 836 } 837 break; 838 } 839 case 'H': 840 { 841 match_results mr; 842 hour = fixed_string_to_int<hour_type, CharT>(sitr, stream_end, mr, 2); 843 if(hour == -1){ 844 return check_special_value(sitr, stream_end, td, c); 845 } 846 break; 847 } 848 case 'M': 849 { 850 match_results mr; 851 min = fixed_string_to_int<min_type, CharT>(sitr, stream_end, mr, 2); 852 if(min == -1){ 853 return check_special_value(sitr, stream_end, td, c); 854 } 855 break; 856 } 857 case 's': 858 case 'S': 859 { 860 match_results mr; 861 sec = fixed_string_to_int<sec_type, CharT>(sitr, stream_end, mr, 2); 862 if(sec == -1){ 863 return check_special_value(sitr, stream_end, td, c); 864 } 865 if (*itr == 'S') 866 break; 867 // %s is the same as %S%f so we drop through into %f 868 } 869 /* Falls through. */ 870 case 'f': 871 { 872 // check for decimal, check special_values if missing 873 if(*sitr == '.') { 874 ++sitr; 875 parse_frac_type(sitr, stream_end, frac); 876 // sitr will point to next expected char after this parsing 877 // is complete so no need to advance it 878 use_current_char = true; 879 } 880 else { 881 return check_special_value(sitr, stream_end, td, c); 882 } 883 break; 884 } 885 case 'F': 886 { 887 // check for decimal, skip if missing 888 if(*sitr == '.') { 889 ++sitr; 890 parse_frac_type(sitr, stream_end, frac); 891 // sitr will point to next expected char after this parsing 892 // is complete so no need to advance it 893 use_current_char = true; 894 } 895 else { 896 // nothing was parsed so we don't want to advance sitr 897 use_current_char = true; 898 } 899 break; 900 } 901 default: 902 {} // ignore what we don't understand? 903 }// switch 904 } 905 else { // itr == '%', second consecutive 906 ++sitr; 907 } 908 909 ++itr; //advance past format specifier 910 } 911 else { //skip past chars in format and in buffer 912 ++itr; 913 // set use_current_char when sitr is already 914 // pointing at the next character to process 915 if (use_current_char) { 916 use_current_char = false; 917 } 918 else { 919 ++sitr; 920 } 921 } 922 } 923 924 td = time_duration_type(hour, min, sec, frac); 925 return sitr; 926 } 927 928 929 //! Parses a time object from the input stream get(InItrT & sitr,InItrT & stream_end,std::ios_base & ios_arg,time_type & t) const930 InItrT get(InItrT& sitr, 931 InItrT& stream_end, 932 std::ios_base& ios_arg, 933 time_type& t) const 934 { 935 string_type tz_str; 936 return get(sitr, stream_end, ios_arg, t, tz_str, false); 937 } 938 //! Expects a time_zone in the input stream get_local_time(InItrT & sitr,InItrT & stream_end,std::ios_base & ios_arg,time_type & t,string_type & tz_str) const939 InItrT get_local_time(InItrT& sitr, 940 InItrT& stream_end, 941 std::ios_base& ios_arg, 942 time_type& t, 943 string_type& tz_str) const 944 { 945 return get(sitr, stream_end, ios_arg, t, tz_str, true); 946 } 947 948 protected: 949 get(InItrT & sitr,InItrT & stream_end,std::ios_base & ios_arg,time_type & t,string_type & tz_str,bool time_is_local) const950 InItrT get(InItrT& sitr, 951 InItrT& stream_end, 952 std::ios_base& ios_arg, 953 time_type& t, 954 string_type& tz_str, 955 bool time_is_local) const 956 { 957 // skip leading whitespace 958 while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; } 959 960 bool use_current_char = false; 961 bool use_current_format_char = false; // used with two character flags 962 963 // num_get will consume the +/-, we may need a copy if special_value 964 char_type c = '\0'; 965 if((sitr != stream_end) && (*sitr == '-' || *sitr == '+')) { 966 c = *sitr; 967 } 968 969 typedef typename time_duration_type::hour_type hour_type; 970 typedef typename time_duration_type::min_type min_type; 971 typedef typename time_duration_type::sec_type sec_type; 972 973 // time elements 974 hour_type hour = 0; 975 min_type min = 0; 976 sec_type sec = 0; 977 typename time_duration_type::fractional_seconds_type frac(0); 978 // date elements 979 short day_of_year(0); 980 /* Initialized the following to their minimum values. These intermediate 981 * objects are used so we get specific exceptions when part of the input 982 * is unparsable. 983 * Ex: "205-Jan-15" will throw a bad_year, "2005-Jsn-15"- bad_month, etc.*/ 984 year_type t_year(1400); 985 month_type t_month(1); 986 day_type t_day(1); 987 988 typedef std::num_get<CharT, InItrT> num_get; 989 if(!std::has_facet<num_get>(ios_arg.getloc())) { 990 num_get* ng = new num_get(); 991 std::locale loc = std::locale(ios_arg.getloc(), ng); 992 ios_arg.imbue(loc); 993 } 994 995 const_itr itr(this->m_format.begin()); 996 while (itr != this->m_format.end() && (sitr != stream_end)) { 997 if (*itr == '%') { 998 if (++itr == this->m_format.end()) break; 999 if (*itr != '%') { 1000 // the cases are grouped by date & time flags - not alphabetical order 1001 switch(*itr) { 1002 // date flags 1003 case 'Y': 1004 case 'y': 1005 { 1006 char_type cs[3] = { '%', *itr }; 1007 string_type s(cs); 1008 match_results mr; 1009 try { 1010 t_year = this->m_parser.parse_year(sitr, stream_end, s, mr); 1011 } 1012 catch(std::out_of_range&) { // base class for bad_year exception 1013 if(this->m_sv_parser.match(sitr, stream_end, mr)) { 1014 t = time_type(static_cast<special_values>(mr.current_match)); 1015 return sitr; 1016 } 1017 else { 1018 throw; // rethrow bad_year 1019 } 1020 } 1021 break; 1022 } 1023 case 'B': 1024 case 'b': 1025 case 'm': 1026 { 1027 char_type cs[3] = { '%', *itr }; 1028 string_type s(cs); 1029 match_results mr; 1030 try { 1031 t_month = this->m_parser.parse_month(sitr, stream_end, s, mr); 1032 } 1033 catch(std::out_of_range&) { // base class for bad_month exception 1034 if(this->m_sv_parser.match(sitr, stream_end, mr)) { 1035 t = time_type(static_cast<special_values>(mr.current_match)); 1036 return sitr; 1037 } 1038 else { 1039 throw; // rethrow bad_month 1040 } 1041 } 1042 // did m_parser already advance sitr to next char? 1043 if(mr.has_remaining()) { 1044 use_current_char = true; 1045 } 1046 break; 1047 } 1048 case 'a': 1049 case 'A': 1050 case 'w': 1051 { 1052 // weekday is not used in construction but we need to get it out of the stream 1053 char_type cs[3] = { '%', *itr }; 1054 string_type s(cs); 1055 match_results mr; 1056 typename date_type::day_of_week_type wd(0); 1057 try { 1058 wd = this->m_parser.parse_weekday(sitr, stream_end, s, mr); 1059 } 1060 catch(std::out_of_range&) { // base class for bad_weekday exception 1061 if(this->m_sv_parser.match(sitr, stream_end, mr)) { 1062 t = time_type(static_cast<special_values>(mr.current_match)); 1063 return sitr; 1064 } 1065 else { 1066 throw; // rethrow bad_weekday 1067 } 1068 } 1069 // did m_parser already advance sitr to next char? 1070 if(mr.has_remaining()) { 1071 use_current_char = true; 1072 } 1073 break; 1074 } 1075 case 'j': 1076 { 1077 // code that gets julian day (from format_date_parser) 1078 match_results mr; 1079 day_of_year = fixed_string_to_int<unsigned short, CharT>(sitr, stream_end, mr, 3); 1080 if(day_of_year == -1) { 1081 if(this->m_sv_parser.match(sitr, stream_end, mr)) { 1082 t = time_type(static_cast<special_values>(mr.current_match)); 1083 return sitr; 1084 } 1085 } 1086 // these next two lines are so we get an exception with bad input 1087 typedef typename time_type::date_type::day_of_year_type day_of_year_type; 1088 day_of_year_type t_day_of_year(day_of_year); 1089 break; 1090 } 1091 case 'd': 1092 case 'e': 1093 { 1094 try { 1095 t_day = (*itr == 'd') ? 1096 this->m_parser.parse_day_of_month(sitr, stream_end) : 1097 this->m_parser.parse_var_day_of_month(sitr, stream_end); 1098 } 1099 catch(std::out_of_range&) { // base class for exception bad_day_of_month 1100 match_results mr; 1101 if(this->m_sv_parser.match(sitr, stream_end, mr)) { 1102 t = time_type(static_cast<special_values>(mr.current_match)); 1103 return sitr; 1104 } 1105 else { 1106 throw; // rethrow bad_day_of_month 1107 } 1108 } 1109 break; 1110 } 1111 // time flags 1112 case 'H': 1113 { 1114 match_results mr; 1115 hour = fixed_string_to_int<hour_type, CharT>(sitr, stream_end, mr, 2); 1116 if(hour == -1){ 1117 return check_special_value(sitr, stream_end, t, c); 1118 } 1119 break; 1120 } 1121 case 'M': 1122 { 1123 match_results mr; 1124 min = fixed_string_to_int<min_type, CharT>(sitr, stream_end, mr, 2); 1125 if(min == -1){ 1126 return check_special_value(sitr, stream_end, t, c); 1127 } 1128 break; 1129 } 1130 case 's': 1131 case 'S': 1132 { 1133 match_results mr; 1134 sec = fixed_string_to_int<sec_type, CharT>(sitr, stream_end, mr, 2); 1135 if(sec == -1){ 1136 return check_special_value(sitr, stream_end, t, c); 1137 } 1138 if (*itr == 'S' || sitr == stream_end) 1139 break; 1140 // %s is the same as %S%f so we drop through into %f if we are 1141 // not at the end of the stream 1142 } 1143 /* Falls through. */ 1144 case 'f': 1145 { 1146 // check for decimal, check SV if missing 1147 if(*sitr == '.') { 1148 ++sitr; 1149 parse_frac_type(sitr, stream_end, frac); 1150 // sitr will point to next expected char after this parsing 1151 // is complete so no need to advance it 1152 use_current_char = true; 1153 } 1154 else { 1155 return check_special_value(sitr, stream_end, t, c); 1156 } 1157 break; 1158 } 1159 case 'F': 1160 { 1161 // check for decimal, skip if missing 1162 if(*sitr == '.') { 1163 ++sitr; 1164 parse_frac_type(sitr, stream_end, frac); 1165 // sitr will point to next expected char after this parsing 1166 // is complete so no need to advance it 1167 use_current_char = true; 1168 } 1169 else { 1170 // nothing was parsed so we don't want to advance sitr 1171 use_current_char = true; 1172 } 1173 break; 1174 } 1175 // time_zone flags 1176 //case 'q': 1177 //case 'Q': 1178 //case 'z': 1179 case 'Z': 1180 { 1181 if(time_is_local) { // skip if 't' is a ptime 1182 ++itr; 1183 if(*itr == 'P') { 1184 // skip leading whitespace 1185 while((sitr != stream_end) && std::isspace(*sitr)) { ++sitr; } 1186 // parse zone 1187 while((sitr != stream_end) && (!std::isspace(*sitr))) { 1188 tz_str += *sitr; 1189 ++sitr; 1190 } 1191 } 1192 else { 1193 use_current_format_char = true; 1194 } 1195 1196 } 1197 else { 1198 // nothing was parsed so we don't want to advance sitr 1199 use_current_char = true; 1200 } 1201 1202 break; 1203 } 1204 default: 1205 {} // ignore what we don't understand? 1206 }// switch 1207 } 1208 else { // itr == '%', second consecutive 1209 ++sitr; 1210 } 1211 1212 if(use_current_format_char) { 1213 use_current_format_char = false; 1214 } 1215 else { 1216 ++itr; //advance past format specifier 1217 } 1218 1219 } 1220 else { //skip past chars in format and in buffer 1221 ++itr; 1222 // set use_current_char when sitr is already 1223 // pointing at the next character to process 1224 if (use_current_char) { 1225 use_current_char = false; 1226 } 1227 else { 1228 ++sitr; 1229 } 1230 } 1231 } 1232 1233 date_type d(not_a_date_time); 1234 if (day_of_year > 0) { 1235 d = date_type(static_cast<unsigned short>(t_year),1,1) + date_duration_type(day_of_year-1); 1236 } 1237 else { 1238 d = date_type(t_year, t_month, t_day); 1239 } 1240 1241 time_duration_type td(hour, min, sec, frac); 1242 t = time_type(d, td); 1243 return sitr; 1244 } 1245 1246 //! Helper function to check for special_value 1247 /*! First character may have been consumed during original parse 1248 * attempt. Parameter 'c' should be a copy of that character. 1249 * Throws ios_base::failure if parse fails. */ 1250 template<class temporal_type> 1251 inline check_special_value(InItrT & sitr,InItrT & stream_end,temporal_type & tt,char_type c='\\0') const1252 InItrT check_special_value(InItrT& sitr,InItrT& stream_end, temporal_type& tt, char_type c='\0') const 1253 { 1254 match_results mr; 1255 if((c == '-' || c == '+') && (*sitr != c)) { // was the first character consumed? 1256 mr.cache += c; 1257 } 1258 (void)this->m_sv_parser.match(sitr, stream_end, mr); 1259 if(mr.current_match == match_results::PARSE_ERROR) { 1260 std::string tmp = convert_string_type<char_type, char>(mr.cache); 1261 boost::throw_exception(std::ios_base::failure("Parse failed. No match found for '" + tmp + "'")); 1262 BOOST_DATE_TIME_UNREACHABLE_EXPRESSION(return sitr); // should never reach 1263 } 1264 tt = temporal_type(static_cast<special_values>(mr.current_match)); 1265 return sitr; 1266 } 1267 1268 //! Helper function for parsing a fractional second type from the stream parse_frac_type(InItrT & sitr,InItrT & stream_end,fracional_seconds_type & frac) const1269 void parse_frac_type(InItrT& sitr, 1270 InItrT& stream_end, 1271 fracional_seconds_type& frac) const 1272 { 1273 string_type cache; 1274 while((sitr != stream_end) && std::isdigit(*sitr)) { 1275 cache += *sitr; 1276 ++sitr; 1277 } 1278 if(cache.size() > 0) { 1279 unsigned short precision = time_duration_type::num_fractional_digits(); 1280 // input may be only the first few decimal places 1281 if(cache.size() < precision) { 1282 frac = lexical_cast<fracional_seconds_type>(cache); 1283 frac = decimal_adjust(frac, static_cast<unsigned short>(precision - cache.size())); 1284 } 1285 else { 1286 // if input has too many decimal places, drop excess digits 1287 frac = lexical_cast<fracional_seconds_type>(cache.substr(0, precision)); 1288 } 1289 } 1290 } 1291 1292 private: 1293 string_type m_time_duration_format; 1294 1295 //! Helper function to adjust trailing zeros when parsing fractional digits 1296 template<class int_type> 1297 inline decimal_adjust(int_type val,const unsigned short places) const1298 int_type decimal_adjust(int_type val, const unsigned short places) const 1299 { 1300 unsigned long factor = 1; 1301 for(int i = 0; i < places; ++i){ 1302 factor *= 10; // shift decimal to the right 1303 } 1304 return val * factor; 1305 } 1306 1307 }; 1308 1309 template <class time_type, class CharT, class InItrT> 1310 std::locale::id time_input_facet<time_type, CharT, InItrT>::id; 1311 1312 template <class time_type, class CharT, class InItrT> 1313 const typename time_input_facet<time_type, CharT, InItrT>::char_type* 1314 time_input_facet<time_type, CharT, InItrT>::fractional_seconds_format = time_formats<CharT>::fractional_seconds_format; 1315 1316 template <class time_type, class CharT, class InItrT> 1317 const typename time_input_facet<time_type, CharT, InItrT>::char_type* 1318 time_input_facet<time_type, CharT, InItrT>::fractional_seconds_or_none_format = time_formats<CharT>::fractional_seconds_or_none_format; 1319 1320 template <class time_type, class CharT, class InItrT> 1321 const typename time_input_facet<time_type, CharT, InItrT>::char_type* 1322 time_input_facet<time_type, CharT, InItrT>::seconds_with_fractional_seconds_format = time_formats<CharT>::seconds_with_fractional_seconds_format; 1323 1324 template <class time_type, class CharT, class InItrT> 1325 const typename time_input_facet<time_type, CharT, InItrT>::char_type* 1326 time_input_facet<time_type, CharT, InItrT>::seconds_format = time_formats<CharT>::seconds_format; 1327 1328 template <class time_type, class CharT, class InItrT> 1329 const typename time_input_facet<time_type, CharT, InItrT>::char_type* 1330 time_input_facet<time_type, CharT, InItrT>::standard_format = time_formats<CharT>::standard_format; 1331 1332 template <class time_type, class CharT, class InItrT> 1333 const typename time_input_facet<time_type, CharT, InItrT>::char_type* 1334 time_input_facet<time_type, CharT, InItrT>::zone_abbrev_format = time_formats<CharT>::zone_abbrev_format; 1335 1336 template <class time_type, class CharT, class InItrT> 1337 const typename time_input_facet<time_type, CharT, InItrT>::char_type* 1338 time_input_facet<time_type, CharT, InItrT>::zone_name_format = time_formats<CharT>::zone_name_format; 1339 1340 template <class time_type, class CharT, class InItrT> 1341 const typename time_input_facet<time_type, CharT, InItrT>::char_type* 1342 time_input_facet<time_type, CharT, InItrT>::zone_iso_format = time_formats<CharT>::zone_iso_format; 1343 1344 template <class time_type, class CharT, class InItrT> 1345 const typename time_input_facet<time_type, CharT, InItrT>::char_type* 1346 time_input_facet<time_type, CharT, InItrT>::zone_iso_extended_format = time_formats<CharT>::zone_iso_extended_format; 1347 1348 template <class time_type, class CharT, class InItrT> 1349 const typename time_input_facet<time_type, CharT, InItrT>::char_type* 1350 time_input_facet<time_type, CharT, InItrT>::duration_seperator = time_formats<CharT>::duration_seperator; 1351 1352 template <class time_type, class CharT, class InItrT> 1353 const typename time_input_facet<time_type, CharT, InItrT>::char_type* 1354 time_input_facet<time_type, CharT, InItrT>::iso_time_format_specifier = time_formats<CharT>::iso_time_format_specifier; 1355 1356 template <class time_type, class CharT, class InItrT> 1357 const typename time_input_facet<time_type, CharT, InItrT>::char_type* 1358 time_input_facet<time_type, CharT, InItrT>::iso_time_format_extended_specifier = time_formats<CharT>::iso_time_format_extended_specifier; 1359 1360 template <class time_type, class CharT, class InItrT> 1361 const typename time_input_facet<time_type, CharT, InItrT>::char_type* 1362 time_input_facet<time_type, CharT, InItrT>::default_time_input_format = time_formats<CharT>::default_time_input_format; 1363 1364 template <class time_type, class CharT, class InItrT> 1365 const typename time_input_facet<time_type, CharT, InItrT>::char_type* 1366 time_input_facet<time_type, CharT, InItrT>::default_time_duration_format = time_formats<CharT>::default_time_duration_format; 1367 1368 } } // namespaces 1369 1370 #endif 1371