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