time_serialize.hpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. #ifndef POSIX_TIME_SERIALIZE_HPP___
  2. #define POSIX_TIME_SERIALIZE_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: Jeff Garland, Bart Garst
  8. * $Date$
  9. */
  10. #include "boost/date_time/posix_time/posix_time.hpp"
  11. #include "boost/date_time/gregorian/greg_serialize.hpp"
  12. #include "boost/core/nvp.hpp"
  13. #include "boost/numeric/conversion/cast.hpp"
  14. #include "boost/type_traits/integral_constant.hpp"
  15. // Define versions for serialization compatibility
  16. // alows the unit tests to make an older version to check compatibility
  17. #ifndef BOOST_DATE_TIME_POSIX_TIME_DURATION_VERSION
  18. #define BOOST_DATE_TIME_POSIX_TIME_DURATION_VERSION 1
  19. #endif
  20. namespace boost {
  21. namespace serialization {
  22. template<typename T>
  23. struct version;
  24. template<>
  25. struct version<boost::posix_time::time_duration>
  26. : integral_constant<int, BOOST_DATE_TIME_POSIX_TIME_DURATION_VERSION>
  27. {
  28. };
  29. // A macro to split serialize functions into save & load functions.
  30. // It is here to avoid dependency on Boost.Serialization just for the
  31. // BOOST_SERIALIZATION_SPLIT_FREE macro
  32. #define BOOST_DATE_TIME_SPLIT_FREE(T) \
  33. template<class Archive> \
  34. inline void serialize(Archive & ar, \
  35. T & t, \
  36. const unsigned int file_version) \
  37. { \
  38. split_free(ar, t, file_version); \
  39. }
  40. BOOST_DATE_TIME_SPLIT_FREE(boost::posix_time::ptime)
  41. BOOST_DATE_TIME_SPLIT_FREE(boost::posix_time::time_duration)
  42. BOOST_DATE_TIME_SPLIT_FREE(boost::posix_time::time_period)
  43. #undef BOOST_DATE_TIME_SPLIT_FREE
  44. /*** time_duration ***/
  45. //! Function to save posix_time::time_duration objects using serialization lib
  46. /*! time_duration objects are broken down into 4 parts for serialization:
  47. * types are hour_type, min_type, sec_type, and fractional_seconds_type
  48. * as defined in the time_duration class
  49. */
  50. template<class TimeResTraitsSize, class Archive>
  51. void save_td(Archive& ar, const posix_time::time_duration& td)
  52. {
  53. TimeResTraitsSize h = boost::numeric_cast<TimeResTraitsSize>(td.hours());
  54. TimeResTraitsSize m = boost::numeric_cast<TimeResTraitsSize>(td.minutes());
  55. TimeResTraitsSize s = boost::numeric_cast<TimeResTraitsSize>(td.seconds());
  56. posix_time::time_duration::fractional_seconds_type fs = td.fractional_seconds();
  57. ar & make_nvp("time_duration_hours", h);
  58. ar & make_nvp("time_duration_minutes", m);
  59. ar & make_nvp("time_duration_seconds", s);
  60. ar & make_nvp("time_duration_fractional_seconds", fs);
  61. }
  62. template<class Archive>
  63. void save(Archive & ar,
  64. const posix_time::time_duration& td,
  65. unsigned int version)
  66. {
  67. // serialize a bool so we know how to read this back in later
  68. bool is_special = td.is_special();
  69. ar & make_nvp("is_special", is_special);
  70. if(is_special) {
  71. std::string s = to_simple_string(td);
  72. ar & make_nvp("sv_time_duration", s);
  73. }
  74. else {
  75. // Write support for earlier versions allows for upgrade compatibility testing
  76. // See load comments for version information
  77. if (version == 0) {
  78. save_td<int32_t>(ar, td);
  79. } else {
  80. save_td<int64_t>(ar, td);
  81. }
  82. }
  83. }
  84. //! Function to load posix_time::time_duration objects using serialization lib
  85. /*! time_duration objects are broken down into 4 parts for serialization:
  86. * types are hour_type, min_type, sec_type, and fractional_seconds_type
  87. * as defined in the time_duration class
  88. */
  89. template<class TimeResTraitsSize, class Archive>
  90. void load_td(Archive& ar, posix_time::time_duration& td)
  91. {
  92. TimeResTraitsSize h(0);
  93. TimeResTraitsSize m(0);
  94. TimeResTraitsSize s(0);
  95. posix_time::time_duration::fractional_seconds_type fs(0);
  96. ar & make_nvp("time_duration_hours", h);
  97. ar & make_nvp("time_duration_minutes", m);
  98. ar & make_nvp("time_duration_seconds", s);
  99. ar & make_nvp("time_duration_fractional_seconds", fs);
  100. td = posix_time::time_duration(h, m, s, fs);
  101. }
  102. template<class Archive>
  103. void load(Archive & ar,
  104. posix_time::time_duration & td,
  105. unsigned int version)
  106. {
  107. bool is_special = false;
  108. ar & make_nvp("is_special", is_special);
  109. if(is_special) {
  110. std::string s;
  111. ar & make_nvp("sv_time_duration", s);
  112. posix_time::special_values sv = gregorian::special_value_from_string(s);
  113. td = posix_time::time_duration(sv);
  114. }
  115. else {
  116. // Version "0" (Boost 1.65.1 or earlier, which used int32_t for day/hour/minute/second and
  117. // therefore suffered from the year 2038 issue.)
  118. // Version "0.5" (Boost 1.66.0 changed to std::time_t but did not increase the version;
  119. // it was missed in the original change, all code reviews, and there were no
  120. // static assertions to protect the code; further std::time_t can be 32-bit
  121. // or 64-bit so it reduced portability. This makes 1.66.0 hard to handle...)
  122. // Version "1" (Boost 1.67.0 or later uses int64_t and is properly versioned)
  123. // If the size of any of these items changes, a new version is needed.
  124. BOOST_STATIC_ASSERT(sizeof(posix_time::time_duration::hour_type) == sizeof(boost::int64_t));
  125. BOOST_STATIC_ASSERT(sizeof(posix_time::time_duration::min_type) == sizeof(boost::int64_t));
  126. BOOST_STATIC_ASSERT(sizeof(posix_time::time_duration::sec_type) == sizeof(boost::int64_t));
  127. BOOST_STATIC_ASSERT(sizeof(posix_time::time_duration::fractional_seconds_type) == sizeof(boost::int64_t));
  128. if (version == 0) {
  129. load_td<int32_t>(ar, td);
  130. } else {
  131. load_td<int64_t>(ar, td);
  132. }
  133. }
  134. }
  135. // no load_construct_data function provided as time_duration provides a
  136. // default constructor
  137. /*** ptime ***/
  138. //! Function to save posix_time::ptime objects using serialization lib
  139. /*! ptime objects are broken down into 2 parts for serialization:
  140. * a date object and a time_duration onject
  141. */
  142. template<class Archive>
  143. void save(Archive & ar,
  144. const posix_time::ptime& pt,
  145. unsigned int /*version*/)
  146. {
  147. // from_iso_string does not include fractional seconds
  148. // therefore date and time_duration are used
  149. posix_time::ptime::date_type d = pt.date();
  150. ar & make_nvp("ptime_date", d);
  151. if(!pt.is_special()) {
  152. posix_time::ptime::time_duration_type td = pt.time_of_day();
  153. ar & make_nvp("ptime_time_duration", td);
  154. }
  155. }
  156. //! Function to load posix_time::ptime objects using serialization lib
  157. /*! ptime objects are broken down into 2 parts for serialization:
  158. * a date object and a time_duration onject
  159. */
  160. template<class Archive>
  161. void load(Archive & ar,
  162. posix_time::ptime & pt,
  163. unsigned int /*version*/)
  164. {
  165. // from_iso_string does not include fractional seconds
  166. // therefore date and time_duration are used
  167. posix_time::ptime::date_type d(posix_time::not_a_date_time);
  168. posix_time::ptime::time_duration_type td;
  169. ar & make_nvp("ptime_date", d);
  170. if(!d.is_special()) {
  171. ar & make_nvp("ptime_time_duration", td);
  172. pt = boost::posix_time::ptime(d,td);
  173. }
  174. else {
  175. pt = boost::posix_time::ptime(d.as_special());
  176. }
  177. }
  178. //!override needed b/c no default constructor
  179. template<class Archive>
  180. inline void load_construct_data(Archive & /*ar*/,
  181. posix_time::ptime* pt,
  182. const unsigned int /*file_version*/)
  183. {
  184. // retrieve data from archive required to construct new
  185. // invoke inplace constructor to initialize instance of date
  186. new(pt) boost::posix_time::ptime(boost::posix_time::not_a_date_time);
  187. }
  188. /*** time_period ***/
  189. //! Function to save posix_time::time_period objects using serialization lib
  190. /*! time_period objects are broken down into 2 parts for serialization:
  191. * a begining ptime object and an ending ptime object
  192. */
  193. template<class Archive>
  194. void save(Archive & ar,
  195. const posix_time::time_period& tp,
  196. unsigned int /*version*/)
  197. {
  198. posix_time::ptime beg(tp.begin().date(), tp.begin().time_of_day());
  199. posix_time::ptime end(tp.end().date(), tp.end().time_of_day());
  200. ar & make_nvp("time_period_begin", beg);
  201. ar & make_nvp("time_period_end", end);
  202. }
  203. //! Function to load posix_time::time_period objects using serialization lib
  204. /*! time_period objects are broken down into 2 parts for serialization:
  205. * a begining ptime object and an ending ptime object
  206. */
  207. template<class Archive>
  208. void load(Archive & ar,
  209. boost::posix_time::time_period & tp,
  210. unsigned int /*version*/)
  211. {
  212. posix_time::time_duration td(1,0,0);
  213. gregorian::date d(gregorian::not_a_date_time);
  214. posix_time::ptime beg(d,td);
  215. posix_time::ptime end(d,td);
  216. ar & make_nvp("time_period_begin", beg);
  217. ar & make_nvp("time_period_end", end);
  218. tp = boost::posix_time::time_period(beg, end);
  219. }
  220. //!override needed b/c no default constructor
  221. template<class Archive>
  222. inline void load_construct_data(Archive & /*ar*/,
  223. boost::posix_time::time_period* tp,
  224. const unsigned int /*file_version*/)
  225. {
  226. posix_time::time_duration td(1,0,0);
  227. gregorian::date d(gregorian::not_a_date_time);
  228. posix_time::ptime beg(d,td);
  229. posix_time::ptime end(d,td);
  230. new(tp) boost::posix_time::time_period(beg,end);
  231. }
  232. } // namespace serialization
  233. } // namespace boost
  234. #endif