1 | #ifndef _DATE_TIME_POSIX_TIME_ZONE__ |
---|
2 | #define _DATE_TIME_POSIX_TIME_ZONE__ |
---|
3 | |
---|
4 | /* Copyright (c) 2003-2005 CrystalClear Software, Inc. |
---|
5 | * Subject to the 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: 2010-06-10 13:24:38 -0400 (Thu, 10 Jun 2010) $ |
---|
9 | */ |
---|
10 | |
---|
11 | #include <string> |
---|
12 | #include <sstream> |
---|
13 | #include <stdexcept> |
---|
14 | #include <boost/tokenizer.hpp> |
---|
15 | #include <boost/throw_exception.hpp> |
---|
16 | #include <boost/date_time/gregorian/gregorian.hpp> |
---|
17 | #include <boost/date_time/time_zone_names.hpp> |
---|
18 | #include <boost/date_time/time_zone_base.hpp> |
---|
19 | #include <boost/date_time/local_time/dst_transition_day_rules.hpp> |
---|
20 | #include <boost/date_time/posix_time/posix_time.hpp> |
---|
21 | #include <boost/date_time/string_convert.hpp> |
---|
22 | #include <boost/date_time/time_parsing.hpp> |
---|
23 | |
---|
24 | namespace boost{ |
---|
25 | namespace local_time{ |
---|
26 | |
---|
27 | //! simple exception for UTC and Daylight savings start/end offsets |
---|
28 | struct bad_offset : public std::out_of_range |
---|
29 | { |
---|
30 | bad_offset(std::string const& msg = std::string()) : |
---|
31 | std::out_of_range(std::string("Offset out of range: " + msg)) {} |
---|
32 | }; |
---|
33 | //! simple exception for UTC daylight savings adjustment |
---|
34 | struct bad_adjustment : public std::out_of_range |
---|
35 | { |
---|
36 | bad_adjustment(std::string const& msg = std::string()) : |
---|
37 | std::out_of_range(std::string("Adjustment out of range: " + msg)) {} |
---|
38 | }; |
---|
39 | |
---|
40 | typedef boost::date_time::dst_adjustment_offsets<boost::posix_time::time_duration> dst_adjustment_offsets; |
---|
41 | |
---|
42 | //! A time zone class constructed from a POSIX time zone string |
---|
43 | /*! A POSIX time zone string takes the form of:<br> |
---|
44 | * "std offset dst [offset],start[/time],end[/time]" (w/no spaces) |
---|
45 | * 'std' specifies the abbrev of the time zone.<br> |
---|
46 | * 'offset' is the offset from UTC.<br> |
---|
47 | * 'dst' specifies the abbrev of the time zone during daylight savings time.<br> |
---|
48 | * The second offset is how many hours changed during DST. Default=1<br> |
---|
49 | * 'start' and'end' are the dates when DST goes into (and out of) effect.<br> |
---|
50 | * 'offset' takes the form of: [+|-]hh[:mm[:ss]] {h=0-23, m/s=0-59}<br> |
---|
51 | * 'time' and 'offset' take the same form. Time defaults=02:00:00<br> |
---|
52 | * 'start' and 'end' can be one of three forms:<br> |
---|
53 | * Mm.w.d {month=1-12, week=1-5 (5 is always last), day=0-6}<br> |
---|
54 | * Jn {n=1-365 Feb29 is never counted}<br> |
---|
55 | * n {n=0-365 Feb29 is counted in leap years}<br> |
---|
56 | * Example "PST-5PDT01:00:00,M4.1.0/02:00:00,M10.1.0/02:00:00" |
---|
57 | * <br> |
---|
58 | * Exceptions will be thrown under these conditions:<br> |
---|
59 | * An invalid date spec (see date class)<br> |
---|
60 | * A boost::local_time::bad_offset exception will be thrown for:<br> |
---|
61 | * A DST start or end offset that is negative or more than 24 hours<br> |
---|
62 | * A UTC zone that is greater than +14 or less than -12 hours<br> |
---|
63 | * A boost::local_time::bad_adjustment exception will be thrown for:<br> |
---|
64 | * A DST adjustment that is 24 hours or more (positive or negative)<br> |
---|
65 | * |
---|
66 | * Note that UTC zone offsets can be greater than +12: |
---|
67 | * http://www.worldtimezone.com/utc/utc+1200.html |
---|
68 | */ |
---|
69 | template<class CharT> |
---|
70 | class posix_time_zone_base : public date_time::time_zone_base<posix_time::ptime,CharT> { |
---|
71 | public: |
---|
72 | typedef boost::posix_time::time_duration time_duration_type; |
---|
73 | typedef date_time::time_zone_names_base<CharT> time_zone_names; |
---|
74 | typedef date_time::time_zone_base<posix_time::ptime,CharT> base_type; |
---|
75 | typedef typename base_type::string_type string_type; |
---|
76 | typedef CharT char_type; |
---|
77 | typedef typename base_type::stringstream_type stringstream_type; |
---|
78 | typedef boost::char_separator<char_type, std::char_traits<char_type> > char_separator_type; |
---|
79 | typedef boost::tokenizer<char_separator_type, |
---|
80 | typename string_type::const_iterator, |
---|
81 | string_type> tokenizer_type; |
---|
82 | typedef typename tokenizer_type::iterator tokenizer_iterator_type; |
---|
83 | |
---|
84 | //! Construct from a POSIX time zone string |
---|
85 | posix_time_zone_base(const string_type& s) : |
---|
86 | //zone_names_("std_name","std_abbrev","no-dst","no-dst"), |
---|
87 | zone_names_(), |
---|
88 | has_dst_(false), |
---|
89 | base_utc_offset_(posix_time::hours(0)), |
---|
90 | dst_offsets_(posix_time::hours(0),posix_time::hours(0),posix_time::hours(0)), |
---|
91 | dst_calc_rules_() |
---|
92 | { |
---|
93 | #ifdef __HP_aCC |
---|
94 | // Work around bug in aC++ compiler: see QXCR1000880488 in the |
---|
95 | // HP bug tracking system |
---|
96 | const char_type sep_chars[2] = {',',0}; |
---|
97 | #else |
---|
98 | const char_type sep_chars[2] = {','}; |
---|
99 | #endif |
---|
100 | char_separator_type sep(sep_chars); |
---|
101 | tokenizer_type tokens(s, sep); |
---|
102 | tokenizer_iterator_type it = tokens.begin(), end = tokens.end(); |
---|
103 | if (it == end) |
---|
104 | BOOST_THROW_EXCEPTION(std::invalid_argument("Could not parse time zone name")); |
---|
105 | calc_zone(*it++); |
---|
106 | if(has_dst_) |
---|
107 | { |
---|
108 | if (it == end) |
---|
109 | BOOST_THROW_EXCEPTION(std::invalid_argument("Could not parse DST begin time")); |
---|
110 | string_type dst_begin = *it++; |
---|
111 | |
---|
112 | if (it == end) |
---|
113 | BOOST_THROW_EXCEPTION(std::invalid_argument("Could not parse DST end time")); |
---|
114 | string_type dst_end = *it; |
---|
115 | calc_rules(dst_begin, dst_end); |
---|
116 | } |
---|
117 | } |
---|
118 | virtual ~posix_time_zone_base() {}; |
---|
119 | //!String for the zone when not in daylight savings (eg: EST) |
---|
120 | virtual string_type std_zone_abbrev()const |
---|
121 | { |
---|
122 | return zone_names_.std_zone_abbrev(); |
---|
123 | } |
---|
124 | //!String for the timezone when in daylight savings (eg: EDT) |
---|
125 | /*! For those time zones that have no DST, an empty string is used */ |
---|
126 | virtual string_type dst_zone_abbrev() const |
---|
127 | { |
---|
128 | return zone_names_.dst_zone_abbrev(); |
---|
129 | } |
---|
130 | //!String for the zone when not in daylight savings (eg: Eastern Standard Time) |
---|
131 | /*! The full STD name is not extracted from the posix time zone string. |
---|
132 | * Therefore, the STD abbreviation is used in it's place */ |
---|
133 | virtual string_type std_zone_name()const |
---|
134 | { |
---|
135 | return zone_names_.std_zone_name(); |
---|
136 | } |
---|
137 | //!String for the timezone when in daylight savings (eg: Eastern Daylight Time) |
---|
138 | /*! The full DST name is not extracted from the posix time zone string. |
---|
139 | * Therefore, the STD abbreviation is used in it's place. For time zones |
---|
140 | * that have no DST, an empty string is used */ |
---|
141 | virtual string_type dst_zone_name()const |
---|
142 | { |
---|
143 | return zone_names_.dst_zone_name(); |
---|
144 | } |
---|
145 | //! True if zone uses daylight savings adjustments otherwise false |
---|
146 | virtual bool has_dst()const |
---|
147 | { |
---|
148 | return has_dst_; |
---|
149 | } |
---|
150 | //! Local time that DST starts -- NADT if has_dst is false |
---|
151 | virtual posix_time::ptime dst_local_start_time(gregorian::greg_year y)const |
---|
152 | { |
---|
153 | gregorian::date d(gregorian::not_a_date_time); |
---|
154 | if(has_dst_) |
---|
155 | { |
---|
156 | d = dst_calc_rules_->start_day(y); |
---|
157 | } |
---|
158 | return posix_time::ptime(d, dst_offsets_.dst_start_offset_); |
---|
159 | } |
---|
160 | //! Local time that DST ends -- NADT if has_dst is false |
---|
161 | virtual posix_time::ptime dst_local_end_time(gregorian::greg_year y)const |
---|
162 | { |
---|
163 | gregorian::date d(gregorian::not_a_date_time); |
---|
164 | if(has_dst_) |
---|
165 | { |
---|
166 | d = dst_calc_rules_->end_day(y); |
---|
167 | } |
---|
168 | return posix_time::ptime(d, dst_offsets_.dst_end_offset_); |
---|
169 | } |
---|
170 | //! Base offset from UTC for zone (eg: -07:30:00) |
---|
171 | virtual time_duration_type base_utc_offset()const |
---|
172 | { |
---|
173 | return base_utc_offset_; |
---|
174 | } |
---|
175 | //! Adjustment forward or back made while DST is in effect |
---|
176 | virtual time_duration_type dst_offset()const |
---|
177 | { |
---|
178 | return dst_offsets_.dst_adjust_; |
---|
179 | } |
---|
180 | |
---|
181 | //! Returns a POSIX time_zone string for this object |
---|
182 | virtual string_type to_posix_string() const |
---|
183 | { |
---|
184 | // std offset dst [offset],start[/time],end[/time] - w/o spaces |
---|
185 | stringstream_type ss; |
---|
186 | ss.fill('0'); |
---|
187 | boost::shared_ptr<dst_calc_rule> no_rules; |
---|
188 | // std |
---|
189 | ss << std_zone_abbrev(); |
---|
190 | // offset |
---|
191 | if(base_utc_offset().is_negative()) { |
---|
192 | // inverting the sign guarantees we get two digits |
---|
193 | ss << '-' << std::setw(2) << base_utc_offset().invert_sign().hours(); |
---|
194 | } |
---|
195 | else { |
---|
196 | ss << '+' << std::setw(2) << base_utc_offset().hours(); |
---|
197 | } |
---|
198 | if(base_utc_offset().minutes() != 0 || base_utc_offset().seconds() != 0) { |
---|
199 | ss << ':' << std::setw(2) << base_utc_offset().minutes(); |
---|
200 | if(base_utc_offset().seconds() != 0) { |
---|
201 | ss << ':' << std::setw(2) << base_utc_offset().seconds(); |
---|
202 | } |
---|
203 | } |
---|
204 | if(dst_calc_rules_ != no_rules) { |
---|
205 | // dst |
---|
206 | ss << dst_zone_abbrev(); |
---|
207 | // dst offset |
---|
208 | if(dst_offset().is_negative()) { |
---|
209 | // inverting the sign guarantees we get two digits |
---|
210 | ss << '-' << std::setw(2) << dst_offset().invert_sign().hours(); |
---|
211 | } |
---|
212 | else { |
---|
213 | ss << '+' << std::setw(2) << dst_offset().hours(); |
---|
214 | } |
---|
215 | if(dst_offset().minutes() != 0 || dst_offset().seconds() != 0) { |
---|
216 | ss << ':' << std::setw(2) << dst_offset().minutes(); |
---|
217 | if(dst_offset().seconds() != 0) { |
---|
218 | ss << ':' << std::setw(2) << dst_offset().seconds(); |
---|
219 | } |
---|
220 | } |
---|
221 | // start/time |
---|
222 | ss << ',' << date_time::convert_string_type<char, char_type>(dst_calc_rules_->start_rule_as_string()) << '/' |
---|
223 | << std::setw(2) << dst_offsets_.dst_start_offset_.hours() << ':' |
---|
224 | << std::setw(2) << dst_offsets_.dst_start_offset_.minutes(); |
---|
225 | if(dst_offsets_.dst_start_offset_.seconds() != 0) { |
---|
226 | ss << ':' << std::setw(2) << dst_offsets_.dst_start_offset_.seconds(); |
---|
227 | } |
---|
228 | // end/time |
---|
229 | ss << ',' << date_time::convert_string_type<char, char_type>(dst_calc_rules_->end_rule_as_string()) << '/' |
---|
230 | << std::setw(2) << dst_offsets_.dst_end_offset_.hours() << ':' |
---|
231 | << std::setw(2) << dst_offsets_.dst_end_offset_.minutes(); |
---|
232 | if(dst_offsets_.dst_end_offset_.seconds() != 0) { |
---|
233 | ss << ':' << std::setw(2) << dst_offsets_.dst_end_offset_.seconds(); |
---|
234 | } |
---|
235 | } |
---|
236 | |
---|
237 | return ss.str(); |
---|
238 | } |
---|
239 | private: |
---|
240 | time_zone_names zone_names_; |
---|
241 | bool has_dst_; |
---|
242 | time_duration_type base_utc_offset_; |
---|
243 | dst_adjustment_offsets dst_offsets_; |
---|
244 | boost::shared_ptr<dst_calc_rule> dst_calc_rules_; |
---|
245 | |
---|
246 | /*! Extract time zone abbreviations for STD & DST as well |
---|
247 | * as the offsets for the time shift that occurs and how |
---|
248 | * much of a shift. At this time full time zone names are |
---|
249 | * NOT extracted so the abbreviations are used in their place */ |
---|
250 | void calc_zone(const string_type& obj){ |
---|
251 | const char_type empty_string[2] = {'\0'}; |
---|
252 | stringstream_type ss(empty_string); |
---|
253 | typename string_type::const_pointer sit = obj.c_str(), obj_end = sit + obj.size(); |
---|
254 | string_type l_std_zone_abbrev, l_dst_zone_abbrev; |
---|
255 | |
---|
256 | // get 'std' name/abbrev |
---|
257 | while(std::isalpha(*sit)){ |
---|
258 | ss << *sit++; |
---|
259 | } |
---|
260 | l_std_zone_abbrev = ss.str(); |
---|
261 | ss.str(empty_string); |
---|
262 | |
---|
263 | // get UTC offset |
---|
264 | if(sit != obj_end){ |
---|
265 | // get duration |
---|
266 | while(sit != obj_end && !std::isalpha(*sit)){ |
---|
267 | ss << *sit++; |
---|
268 | } |
---|
269 | base_utc_offset_ = date_time::str_from_delimited_time_duration<time_duration_type,char_type>(ss.str()); |
---|
270 | ss.str(empty_string); |
---|
271 | |
---|
272 | // base offset must be within range of -12 hours to +14 hours |
---|
273 | if(base_utc_offset_ < time_duration_type(-12,0,0) || |
---|
274 | base_utc_offset_ > time_duration_type(14,0,0)) |
---|
275 | { |
---|
276 | boost::throw_exception(bad_offset(posix_time::to_simple_string(base_utc_offset_))); |
---|
277 | } |
---|
278 | } |
---|
279 | |
---|
280 | // get DST data if given |
---|
281 | if(sit != obj_end){ |
---|
282 | has_dst_ = true; |
---|
283 | |
---|
284 | // get 'dst' name/abbrev |
---|
285 | while(sit != obj_end && std::isalpha(*sit)){ |
---|
286 | ss << *sit++; |
---|
287 | } |
---|
288 | l_dst_zone_abbrev = ss.str(); |
---|
289 | ss.str(empty_string); |
---|
290 | |
---|
291 | // get DST offset if given |
---|
292 | if(sit != obj_end){ |
---|
293 | // get duration |
---|
294 | while(sit != obj_end && !std::isalpha(*sit)){ |
---|
295 | ss << *sit++; |
---|
296 | } |
---|
297 | dst_offsets_.dst_adjust_ = date_time::str_from_delimited_time_duration<time_duration_type,char_type>(ss.str()); |
---|
298 | ss.str(empty_string); |
---|
299 | } |
---|
300 | else{ // default DST offset |
---|
301 | dst_offsets_.dst_adjust_ = posix_time::hours(1); |
---|
302 | } |
---|
303 | |
---|
304 | // adjustment must be within +|- 1 day |
---|
305 | if(dst_offsets_.dst_adjust_ <= time_duration_type(-24,0,0) || |
---|
306 | dst_offsets_.dst_adjust_ >= time_duration_type(24,0,0)) |
---|
307 | { |
---|
308 | boost::throw_exception(bad_adjustment(posix_time::to_simple_string(dst_offsets_.dst_adjust_))); |
---|
309 | } |
---|
310 | } |
---|
311 | // full names not extracted so abbrevs used in their place |
---|
312 | zone_names_ = time_zone_names(l_std_zone_abbrev, l_std_zone_abbrev, l_dst_zone_abbrev, l_dst_zone_abbrev); |
---|
313 | } |
---|
314 | |
---|
315 | void calc_rules(const string_type& start, const string_type& end){ |
---|
316 | #ifdef __HP_aCC |
---|
317 | // Work around bug in aC++ compiler: see QXCR1000880488 in the |
---|
318 | // HP bug tracking system |
---|
319 | const char_type sep_chars[2] = {'/',0}; |
---|
320 | #else |
---|
321 | const char_type sep_chars[2] = {'/'}; |
---|
322 | #endif |
---|
323 | char_separator_type sep(sep_chars); |
---|
324 | tokenizer_type st_tok(start, sep); |
---|
325 | tokenizer_type et_tok(end, sep); |
---|
326 | tokenizer_iterator_type sit = st_tok.begin(); |
---|
327 | tokenizer_iterator_type eit = et_tok.begin(); |
---|
328 | |
---|
329 | // generate date spec |
---|
330 | char_type x = string_type(*sit).at(0); |
---|
331 | if(x == 'M'){ |
---|
332 | M_func(*sit, *eit); |
---|
333 | } |
---|
334 | else if(x == 'J'){ |
---|
335 | julian_no_leap(*sit, *eit); |
---|
336 | } |
---|
337 | else{ |
---|
338 | julian_day(*sit, *eit); |
---|
339 | } |
---|
340 | |
---|
341 | ++sit; |
---|
342 | ++eit; |
---|
343 | // generate durations |
---|
344 | // starting offset |
---|
345 | if(sit != st_tok.end()){ |
---|
346 | dst_offsets_.dst_start_offset_ = date_time::str_from_delimited_time_duration<time_duration_type,char_type>(*sit); |
---|
347 | } |
---|
348 | else{ |
---|
349 | // default |
---|
350 | dst_offsets_.dst_start_offset_ = posix_time::hours(2); |
---|
351 | } |
---|
352 | // start/end offsets must fall on given date |
---|
353 | if(dst_offsets_.dst_start_offset_ < time_duration_type(0,0,0) || |
---|
354 | dst_offsets_.dst_start_offset_ >= time_duration_type(24,0,0)) |
---|
355 | { |
---|
356 | boost::throw_exception(bad_offset(posix_time::to_simple_string(dst_offsets_.dst_start_offset_))); |
---|
357 | } |
---|
358 | |
---|
359 | // ending offset |
---|
360 | if(eit != et_tok.end()){ |
---|
361 | dst_offsets_.dst_end_offset_ = date_time::str_from_delimited_time_duration<time_duration_type,char_type>(*eit); |
---|
362 | } |
---|
363 | else{ |
---|
364 | // default |
---|
365 | dst_offsets_.dst_end_offset_ = posix_time::hours(2); |
---|
366 | } |
---|
367 | // start/end offsets must fall on given date |
---|
368 | if(dst_offsets_.dst_end_offset_ < time_duration_type(0,0,0) || |
---|
369 | dst_offsets_.dst_end_offset_ >= time_duration_type(24,0,0)) |
---|
370 | { |
---|
371 | boost::throw_exception(bad_offset(posix_time::to_simple_string(dst_offsets_.dst_end_offset_))); |
---|
372 | } |
---|
373 | } |
---|
374 | |
---|
375 | /* Parses out a start/end date spec from a posix time zone string. |
---|
376 | * Date specs come in three possible formats, this function handles |
---|
377 | * the 'M' spec. Ex "M2.2.4" => 2nd month, 2nd week, 4th day . |
---|
378 | */ |
---|
379 | void M_func(const string_type& s, const string_type& e){ |
---|
380 | typedef gregorian::nth_kday_of_month nkday; |
---|
381 | unsigned short sm=0,sw=0,sd=0,em=0,ew=0,ed=0; // start/end month,week,day |
---|
382 | #ifdef __HP_aCC |
---|
383 | // Work around bug in aC++ compiler: see QXCR1000880488 in the |
---|
384 | // HP bug tracking system |
---|
385 | const char_type sep_chars[3] = {'M','.',0}; |
---|
386 | #else |
---|
387 | const char_type sep_chars[3] = {'M','.'}; |
---|
388 | #endif |
---|
389 | char_separator_type sep(sep_chars); |
---|
390 | tokenizer_type stok(s, sep), etok(e, sep); |
---|
391 | |
---|
392 | tokenizer_iterator_type it = stok.begin(); |
---|
393 | sm = lexical_cast<unsigned short>(*it++); |
---|
394 | sw = lexical_cast<unsigned short>(*it++); |
---|
395 | sd = lexical_cast<unsigned short>(*it); |
---|
396 | |
---|
397 | it = etok.begin(); |
---|
398 | em = lexical_cast<unsigned short>(*it++); |
---|
399 | ew = lexical_cast<unsigned short>(*it++); |
---|
400 | ed = lexical_cast<unsigned short>(*it); |
---|
401 | |
---|
402 | dst_calc_rules_ = shared_ptr<dst_calc_rule>( |
---|
403 | new nth_kday_dst_rule( |
---|
404 | nth_last_dst_rule::start_rule( |
---|
405 | static_cast<nkday::week_num>(sw),sd,sm), |
---|
406 | nth_last_dst_rule::start_rule( |
---|
407 | static_cast<nkday::week_num>(ew),ed,em) |
---|
408 | ) |
---|
409 | ); |
---|
410 | } |
---|
411 | |
---|
412 | //! Julian day. Feb29 is never counted, even in leap years |
---|
413 | // expects range of 1-365 |
---|
414 | void julian_no_leap(const string_type& s, const string_type& e){ |
---|
415 | typedef gregorian::gregorian_calendar calendar; |
---|
416 | const unsigned short year = 2001; // Non-leap year |
---|
417 | unsigned short sm=1; |
---|
418 | int sd=0; |
---|
419 | sd = lexical_cast<int>(s.substr(1)); // skip 'J' |
---|
420 | while(sd >= calendar::end_of_month_day(year,sm)){ |
---|
421 | sd -= calendar::end_of_month_day(year,sm++); |
---|
422 | } |
---|
423 | unsigned short em=1; |
---|
424 | int ed=0; |
---|
425 | ed = lexical_cast<int>(e.substr(1)); // skip 'J' |
---|
426 | while(ed > calendar::end_of_month_day(year,em)){ |
---|
427 | ed -= calendar::end_of_month_day(year,em++); |
---|
428 | } |
---|
429 | |
---|
430 | dst_calc_rules_ = shared_ptr<dst_calc_rule>( |
---|
431 | new partial_date_dst_rule( |
---|
432 | partial_date_dst_rule::start_rule( |
---|
433 | sd, static_cast<date_time::months_of_year>(sm)), |
---|
434 | partial_date_dst_rule::end_rule( |
---|
435 | ed, static_cast<date_time::months_of_year>(em)) |
---|
436 | ) |
---|
437 | ); |
---|
438 | } |
---|
439 | |
---|
440 | //! Julian day. Feb29 is always counted, but exception thrown in non-leap years |
---|
441 | // expects range of 0-365 |
---|
442 | void julian_day(const string_type& s, const string_type& e){ |
---|
443 | int sd=0, ed=0; |
---|
444 | sd = lexical_cast<int>(s); |
---|
445 | ed = lexical_cast<int>(e); |
---|
446 | dst_calc_rules_ = shared_ptr<dst_calc_rule>( |
---|
447 | new partial_date_dst_rule( |
---|
448 | partial_date_dst_rule::start_rule(++sd),// args are 0-365 |
---|
449 | partial_date_dst_rule::end_rule(++ed) // pd expects 1-366 |
---|
450 | ) |
---|
451 | ); |
---|
452 | } |
---|
453 | |
---|
454 | //! helper function used when throwing exceptions |
---|
455 | static std::string td_as_string(const time_duration_type& td) |
---|
456 | { |
---|
457 | std::string s; |
---|
458 | #if defined(USE_DATE_TIME_PRE_1_33_FACET_IO) |
---|
459 | s = posix_time::to_simple_string(td); |
---|
460 | #else |
---|
461 | std::stringstream ss; |
---|
462 | ss << td; |
---|
463 | s = ss.str(); |
---|
464 | #endif |
---|
465 | return s; |
---|
466 | } |
---|
467 | }; |
---|
468 | |
---|
469 | typedef posix_time_zone_base<char> posix_time_zone; |
---|
470 | |
---|
471 | } } // namespace boost::local_time |
---|
472 | |
---|
473 | |
---|
474 | #endif // _DATE_TIME_POSIX_TIME_ZONE__ |
---|