time_facet.hpp 58 KB

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