date_time.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. /*
  2. * Copyright Andrey Semashev 2007 - 2015.
  3. * Distributed under the Boost Software License, Version 1.0.
  4. * (See accompanying file LICENSE_1_0.txt or copy at
  5. * http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. /*!
  8. * \file support/date_time.hpp
  9. * \author Andrey Semashev
  10. * \date 07.11.2012
  11. *
  12. * This header enables Boost.DateTime support for Boost.Log.
  13. */
  14. #ifndef BOOST_LOG_SUPPORT_DATE_TIME_HPP_INCLUDED_
  15. #define BOOST_LOG_SUPPORT_DATE_TIME_HPP_INCLUDED_
  16. #include <ctime>
  17. #include <string>
  18. #include <locale>
  19. #include <ostream>
  20. #include <iterator>
  21. #include <boost/cstdint.hpp>
  22. #include <boost/move/core.hpp>
  23. #include <boost/move/utility_core.hpp>
  24. #include <boost/date_time/time.hpp>
  25. #include <boost/date_time/date.hpp>
  26. #include <boost/date_time/gregorian/gregorian_types.hpp>
  27. #include <boost/date_time/local_time/local_time_types.hpp>
  28. #include <boost/date_time/posix_time/posix_time_types.hpp>
  29. #include <boost/log/detail/config.hpp>
  30. #include <boost/log/detail/date_time_format_parser.hpp>
  31. #include <boost/log/detail/light_function.hpp>
  32. #include <boost/log/detail/decomposed_time.hpp>
  33. #include <boost/log/detail/date_time_fmt_gen_traits_fwd.hpp>
  34. #include <boost/log/utility/formatting_ostream.hpp>
  35. #include <boost/log/detail/header.hpp>
  36. #ifdef BOOST_HAS_PRAGMA_ONCE
  37. #pragma once
  38. #endif
  39. namespace boost {
  40. BOOST_LOG_OPEN_NAMESPACE
  41. namespace expressions {
  42. namespace aux {
  43. namespace date_time_support {
  44. template< typename DateT, typename ValueT >
  45. inline void decompose_date(DateT const& d, boost::log::aux::decomposed_time_wrapper< ValueT >& v)
  46. {
  47. typedef typename DateT::ymd_type ymd_type;
  48. ymd_type ymd = d.year_month_day();
  49. v.year = static_cast< uint32_t >(ymd.year);
  50. v.month = static_cast< uint32_t >(ymd.month);
  51. v.day = static_cast< uint32_t >(ymd.day);
  52. }
  53. template< typename TimeDurationT, typename ValueT >
  54. inline void decompose_time_of_day(TimeDurationT const& tod, boost::log::aux::decomposed_time_wrapper< ValueT >& v)
  55. {
  56. v.hours = static_cast< uint32_t >(tod.hours());
  57. v.minutes = static_cast< uint32_t >(tod.minutes());
  58. v.seconds = static_cast< uint32_t >(tod.seconds());
  59. typedef typename TimeDurationT::traits_type traits_type;
  60. enum
  61. {
  62. adjustment_ratio = (traits_type::ticks_per_second > boost::log::aux::decomposed_time::subseconds_per_second ?
  63. traits_type::ticks_per_second / boost::log::aux::decomposed_time::subseconds_per_second :
  64. boost::log::aux::decomposed_time::subseconds_per_second / traits_type::ticks_per_second)
  65. };
  66. uint64_t frac = tod.fractional_seconds();
  67. v.subseconds = static_cast< uint32_t >(traits_type::ticks_per_second > boost::log::aux::decomposed_time::subseconds_per_second ? frac / adjustment_ratio : frac * adjustment_ratio);
  68. }
  69. template< typename TimeDurationT, typename ValueT >
  70. inline void decompose_time_duration(TimeDurationT const& dur, boost::log::aux::decomposed_time_wrapper< ValueT >& v)
  71. {
  72. if (dur.is_negative())
  73. {
  74. v.negative = true;
  75. (decompose_time_of_day)(-dur, v);
  76. }
  77. else
  78. (decompose_time_of_day)(dur, v);
  79. }
  80. template< typename DateDurationT, typename ValueT >
  81. inline void decompose_date_duration(DateDurationT const& dur, boost::log::aux::decomposed_time_wrapper< ValueT >& v)
  82. {
  83. if (dur.is_negative())
  84. {
  85. v.negative = true;
  86. v.day = static_cast< uint32_t >((-dur).days());
  87. }
  88. else
  89. v.day = static_cast< uint32_t >(dur.days());
  90. }
  91. template< typename TimeT, typename ValueT >
  92. inline void decompose_time(TimeT const& t, boost::log::aux::decomposed_time_wrapper< ValueT >& v)
  93. {
  94. (decompose_date)(t.date(), v);
  95. (decompose_time_of_day)(t.time_of_day(), v);
  96. }
  97. } // namespace date_time_support
  98. template< typename TimeT, typename CharT >
  99. struct date_time_formatter_generator_traits_impl
  100. {
  101. //! Character type
  102. typedef CharT char_type;
  103. //! String type
  104. typedef std::basic_string< char_type > string_type;
  105. //! Formatting stream type
  106. typedef basic_formatting_ostream< char_type > stream_type;
  107. //! Value type
  108. typedef TimeT value_type;
  109. //! Formatter function
  110. typedef boost::log::aux::light_function< void (stream_type&, value_type const&) > formatter_function_type;
  111. //! Formatter implementation
  112. class formatter :
  113. public boost::log::aux::date_time_formatter< boost::log::aux::decomposed_time_wrapper< value_type >, char_type >
  114. {
  115. BOOST_COPYABLE_AND_MOVABLE_ALT(formatter)
  116. private:
  117. // Do not change this typedef, copy-pasting the inherited class from above will break compilation with MSVC 2012 because it incorrectly binds value_type.
  118. typedef typename formatter::date_time_formatter_ base_type;
  119. public:
  120. typedef typename base_type::result_type result_type;
  121. // This typedef is needed to work around MSVC 2012 crappy name lookup. Otherwise base_type::value_type is bound instead.
  122. typedef typename date_time_formatter_generator_traits_impl< TimeT, CharT >::value_type value_type;
  123. public:
  124. BOOST_DEFAULTED_FUNCTION(formatter(), {})
  125. formatter(formatter const& that) : base_type(static_cast< base_type const& >(that)) {}
  126. formatter(BOOST_RV_REF(formatter) that) { this->swap(that); }
  127. formatter& operator= (formatter that)
  128. {
  129. this->swap(that);
  130. return *this;
  131. }
  132. result_type operator() (stream_type& strm, value_type const& value) const
  133. {
  134. if (value.is_not_a_date_time())
  135. strm << "not-a-date-time";
  136. else if (value.is_pos_infinity())
  137. strm << "+infinity";
  138. else if (value.is_neg_infinity())
  139. strm << "-infinity";
  140. else
  141. {
  142. boost::log::aux::decomposed_time_wrapper< value_type > val(value);
  143. date_time_support::decompose_time(value, val);
  144. base_type::operator() (strm, val);
  145. }
  146. }
  147. };
  148. //! The function parses format string and constructs formatter function
  149. static formatter_function_type parse(string_type const& format)
  150. {
  151. formatter fmt;
  152. boost::log::aux::decomposed_time_formatter_builder< formatter, char_type > builder(fmt);
  153. boost::log::aux::parse_date_time_format(format, builder);
  154. return formatter_function_type(boost::move(fmt));
  155. }
  156. };
  157. template< typename CharT, typename VoidT >
  158. struct date_time_formatter_generator_traits< posix_time::ptime, CharT, VoidT > :
  159. public date_time_formatter_generator_traits_impl< posix_time::ptime, CharT >
  160. {
  161. };
  162. template< typename TimeT, typename TimeZoneT, typename CharT, typename VoidT >
  163. struct date_time_formatter_generator_traits< local_time::local_date_time_base< TimeT, TimeZoneT >, CharT, VoidT >
  164. {
  165. //! Character type
  166. typedef CharT char_type;
  167. //! String type
  168. typedef std::basic_string< char_type > string_type;
  169. //! Formatting stream type
  170. typedef basic_formatting_ostream< char_type > stream_type;
  171. //! Value type
  172. typedef local_time::local_date_time_base< TimeT, TimeZoneT > value_type;
  173. //! Formatter function
  174. typedef boost::log::aux::light_function< void (stream_type&, value_type const&) > formatter_function_type;
  175. //! Formatter implementation
  176. class formatter :
  177. public boost::log::aux::date_time_formatter< boost::log::aux::decomposed_time_wrapper< value_type >, char_type >
  178. {
  179. BOOST_COPYABLE_AND_MOVABLE_ALT(formatter)
  180. private:
  181. // Do not change this typedef, copy-pasting the inherited class from above will break compilation with MSVC 2012 because it incorrectly binds value_type.
  182. typedef typename formatter::date_time_formatter_ base_type;
  183. public:
  184. typedef typename base_type::result_type result_type;
  185. typedef typename base_type::context context;
  186. // This typedef is needed to work around MSVC 2012 crappy name lookup. Otherwise base_type::value_type is bound instead.
  187. typedef typename date_time_formatter_generator_traits< local_time::local_date_time_base< TimeT, TimeZoneT >, CharT, VoidT >::value_type value_type;
  188. public:
  189. BOOST_DEFAULTED_FUNCTION(formatter(), {})
  190. formatter(formatter const& that) : base_type(static_cast< base_type const& >(that)) {}
  191. formatter(BOOST_RV_REF(formatter) that) { this->swap(that); }
  192. formatter& operator= (formatter that)
  193. {
  194. this->swap(that);
  195. return *this;
  196. }
  197. result_type operator() (stream_type& strm, value_type const& value) const
  198. {
  199. if (value.is_not_a_date_time())
  200. strm << "not-a-date-time";
  201. else if (value.is_pos_infinity())
  202. strm << "+infinity";
  203. else if (value.is_neg_infinity())
  204. strm << "-infinity";
  205. else
  206. {
  207. boost::log::aux::decomposed_time_wrapper< value_type > val(value);
  208. date_time_support::decompose_time(value.local_time(), val);
  209. base_type::operator() (strm, val);
  210. }
  211. }
  212. public:
  213. static void format_iso_time_zone(context& ctx)
  214. {
  215. ctx.strm << ctx.value.m_time.zone_abbrev(true);
  216. ctx.strm.flush();
  217. }
  218. static void format_extended_iso_time_zone(context& ctx)
  219. {
  220. ctx.strm << ctx.value.m_time.zone_name(true);
  221. ctx.strm.flush();
  222. }
  223. };
  224. class formatter_builder :
  225. public boost::log::aux::decomposed_time_formatter_builder< formatter, char_type >
  226. {
  227. private:
  228. typedef boost::log::aux::decomposed_time_formatter_builder< formatter, char_type > base_type;
  229. public:
  230. explicit formatter_builder(formatter& fmt) : base_type(fmt)
  231. {
  232. }
  233. void on_iso_time_zone()
  234. {
  235. this->m_formatter.add_formatter(&formatter::format_iso_time_zone);
  236. }
  237. void on_extended_iso_time_zone()
  238. {
  239. this->m_formatter.add_formatter(&formatter::format_extended_iso_time_zone);
  240. }
  241. };
  242. //! The function parses format string and constructs formatter function
  243. static formatter_function_type parse(string_type const& format)
  244. {
  245. formatter fmt;
  246. formatter_builder builder(fmt);
  247. boost::log::aux::parse_date_time_format(format, builder);
  248. return formatter_function_type(boost::move(fmt));
  249. }
  250. };
  251. template< typename DateT, typename CharT >
  252. struct date_formatter_generator_traits_impl
  253. {
  254. //! Character type
  255. typedef CharT char_type;
  256. //! String type
  257. typedef std::basic_string< char_type > string_type;
  258. //! Formatting stream type
  259. typedef basic_formatting_ostream< char_type > stream_type;
  260. //! Value type
  261. typedef DateT value_type;
  262. //! Formatter function
  263. typedef boost::log::aux::light_function< void (stream_type&, value_type const&) > formatter_function_type;
  264. //! Formatter implementation
  265. class formatter :
  266. public boost::log::aux::date_time_formatter< boost::log::aux::decomposed_time_wrapper< value_type >, char_type >
  267. {
  268. BOOST_COPYABLE_AND_MOVABLE_ALT(formatter)
  269. private:
  270. // Do not change this typedef, copy-pasting the inherited class from above will break compilation with MSVC 2012 because it incorrectly binds value_type.
  271. typedef typename formatter::date_time_formatter_ base_type;
  272. public:
  273. typedef typename base_type::result_type result_type;
  274. // This typedef is needed to work around MSVC 2012 crappy name lookup. Otherwise base_type::value_type is bound instead.
  275. typedef typename date_formatter_generator_traits_impl< DateT, CharT >::value_type value_type;
  276. public:
  277. BOOST_DEFAULTED_FUNCTION(formatter(), {})
  278. formatter(formatter const& that) : base_type(static_cast< base_type const& >(that)) {}
  279. formatter(BOOST_RV_REF(formatter) that) { this->swap(that); }
  280. formatter& operator= (formatter that)
  281. {
  282. this->swap(that);
  283. return *this;
  284. }
  285. result_type operator() (stream_type& strm, value_type const& value) const
  286. {
  287. if (value.is_not_a_date())
  288. strm << "not-a-date-time";
  289. else if (value.is_pos_infinity())
  290. strm << "+infinity";
  291. else if (value.is_neg_infinity())
  292. strm << "-infinity";
  293. else
  294. {
  295. boost::log::aux::decomposed_time_wrapper< value_type > val(value);
  296. date_time_support::decompose_date(value, val);
  297. base_type::operator() (strm, val);
  298. }
  299. }
  300. };
  301. //! The function parses format string and constructs formatter function
  302. static formatter_function_type parse(string_type const& format)
  303. {
  304. formatter fmt;
  305. boost::log::aux::decomposed_time_formatter_builder< formatter, char_type > builder(fmt);
  306. boost::log::aux::parse_date_format(format, builder);
  307. return formatter_function_type(boost::move(fmt));
  308. }
  309. };
  310. template< typename CharT, typename VoidT >
  311. struct date_time_formatter_generator_traits< gregorian::date, CharT, VoidT > :
  312. public date_formatter_generator_traits_impl< gregorian::date, CharT >
  313. {
  314. };
  315. template< typename TimeDurationT, typename CharT >
  316. struct time_duration_formatter_generator_traits_impl
  317. {
  318. //! Character type
  319. typedef CharT char_type;
  320. //! String type
  321. typedef std::basic_string< char_type > string_type;
  322. //! Formatting stream type
  323. typedef basic_formatting_ostream< char_type > stream_type;
  324. //! Value type
  325. typedef TimeDurationT value_type;
  326. //! Formatter function
  327. typedef boost::log::aux::light_function< void (stream_type&, value_type const&) > formatter_function_type;
  328. //! Formatter implementation
  329. class formatter :
  330. public boost::log::aux::date_time_formatter< boost::log::aux::decomposed_time_wrapper< value_type >, char_type >
  331. {
  332. BOOST_COPYABLE_AND_MOVABLE_ALT(formatter)
  333. private:
  334. // Do not change this typedef, copy-pasting the inherited class from above will break compilation with MSVC 2012 because it incorrectly binds value_type.
  335. typedef typename formatter::date_time_formatter_ base_type;
  336. public:
  337. typedef typename base_type::result_type result_type;
  338. // This typedef is needed to work around MSVC 2012 crappy name lookup. Otherwise base_type::value_type is bound instead.
  339. typedef typename time_duration_formatter_generator_traits_impl< TimeDurationT, CharT >::value_type value_type;
  340. public:
  341. BOOST_DEFAULTED_FUNCTION(formatter(), {})
  342. formatter(formatter const& that) : base_type(static_cast< base_type const& >(that)) {}
  343. formatter(BOOST_RV_REF(formatter) that) { this->swap(that); }
  344. formatter& operator= (formatter that)
  345. {
  346. this->swap(that);
  347. return *this;
  348. }
  349. result_type operator() (stream_type& strm, value_type const& value) const
  350. {
  351. if (value.is_not_a_date_time())
  352. strm << "not-a-date-time";
  353. else if (value.is_pos_infinity())
  354. strm << "+infinity";
  355. else if (value.is_neg_infinity())
  356. strm << "-infinity";
  357. else
  358. {
  359. boost::log::aux::decomposed_time_wrapper< value_type > val(value);
  360. date_time_support::decompose_time_duration(value, val);
  361. base_type::operator() (strm, val);
  362. }
  363. }
  364. };
  365. //! The function parses format string and constructs formatter function
  366. static formatter_function_type parse(string_type const& format)
  367. {
  368. formatter fmt;
  369. boost::log::aux::decomposed_time_formatter_builder< formatter, char_type > builder(fmt);
  370. boost::log::aux::parse_time_format(format, builder);
  371. return formatter_function_type(boost::move(fmt));
  372. }
  373. };
  374. template< typename CharT, typename VoidT >
  375. struct date_time_formatter_generator_traits< posix_time::time_duration, CharT, VoidT > :
  376. public time_duration_formatter_generator_traits_impl< posix_time::time_duration, CharT >
  377. {
  378. };
  379. template< typename CharT, typename VoidT >
  380. struct date_time_formatter_generator_traits< posix_time::hours, CharT, VoidT > :
  381. public time_duration_formatter_generator_traits_impl< posix_time::hours, CharT >
  382. {
  383. };
  384. template< typename CharT, typename VoidT >
  385. struct date_time_formatter_generator_traits< posix_time::minutes, CharT, VoidT > :
  386. public time_duration_formatter_generator_traits_impl< posix_time::minutes, CharT >
  387. {
  388. };
  389. template< typename CharT, typename VoidT >
  390. struct date_time_formatter_generator_traits< posix_time::seconds, CharT, VoidT > :
  391. public time_duration_formatter_generator_traits_impl< posix_time::seconds, CharT >
  392. {
  393. };
  394. template< typename BaseDurationT, uint64_t FracOfSecondV, typename CharT, typename VoidT >
  395. struct date_time_formatter_generator_traits< date_time::subsecond_duration< BaseDurationT, FracOfSecondV >, CharT, VoidT > :
  396. public time_duration_formatter_generator_traits_impl< date_time::subsecond_duration< BaseDurationT, FracOfSecondV >, CharT >
  397. {
  398. };
  399. template< typename DateDurationT, typename CharT >
  400. struct date_duration_formatter_generator_traits_impl
  401. {
  402. //! Character type
  403. typedef CharT char_type;
  404. //! String type
  405. typedef std::basic_string< char_type > string_type;
  406. //! Formatting stream type
  407. typedef basic_formatting_ostream< char_type > stream_type;
  408. //! Value type
  409. typedef DateDurationT value_type;
  410. //! Formatter function
  411. typedef boost::log::aux::light_function< void (stream_type&, value_type const&) > formatter_function_type;
  412. //! Formatter implementation
  413. class formatter :
  414. public boost::log::aux::date_time_formatter< boost::log::aux::decomposed_time_wrapper< value_type >, char_type >
  415. {
  416. BOOST_COPYABLE_AND_MOVABLE_ALT(formatter)
  417. private:
  418. // Do not change this typedef, copy-pasting the inherited class from above will break compilation with MSVC 2012 because it incorrectly binds value_type.
  419. typedef typename formatter::date_time_formatter_ base_type;
  420. public:
  421. typedef typename base_type::result_type result_type;
  422. // This typedef is needed to work around MSVC 2012 crappy name lookup. Otherwise base_type::value_type is bound instead.
  423. typedef typename date_duration_formatter_generator_traits_impl< DateDurationT, CharT >::value_type value_type;
  424. public:
  425. BOOST_DEFAULTED_FUNCTION(formatter(), {})
  426. formatter(formatter const& that) : base_type(static_cast< base_type const& >(that)) {}
  427. formatter(BOOST_RV_REF(formatter) that) { this->swap(that); }
  428. formatter& operator= (formatter that)
  429. {
  430. this->swap(that);
  431. return *this;
  432. }
  433. result_type operator() (stream_type& strm, value_type const& value) const
  434. {
  435. if (value.is_not_a_date())
  436. strm << "not-a-date-time";
  437. else if (value.is_pos_infinity())
  438. strm << "+infinity";
  439. else if (value.is_neg_infinity())
  440. strm << "-infinity";
  441. else
  442. {
  443. boost::log::aux::decomposed_time_wrapper< value_type > val(value);
  444. date_time_support::decompose_date_duration(value, val);
  445. base_type::operator() (strm, val);
  446. }
  447. }
  448. };
  449. //! The function parses format string and constructs formatter function
  450. static formatter_function_type parse(string_type const& format)
  451. {
  452. formatter fmt;
  453. boost::log::aux::decomposed_time_formatter_builder< formatter, char_type > builder(fmt);
  454. boost::log::aux::parse_date_format(format, builder);
  455. return formatter_function_type(boost::move(fmt));
  456. }
  457. };
  458. template< typename CharT, typename VoidT >
  459. struct date_time_formatter_generator_traits< gregorian::date_duration, CharT, VoidT > :
  460. public date_formatter_generator_traits_impl< gregorian::date_duration, CharT >
  461. {
  462. };
  463. } // namespace aux
  464. } // namespace expressions
  465. BOOST_LOG_CLOSE_NAMESPACE // namespace log
  466. } // namespace boost
  467. #include <boost/log/detail/footer.hpp>
  468. #endif // BOOST_LOG_SUPPORT_DATE_TIME_HPP_INCLUDED_