File indexing completed on 2025-01-18 09:30:36
0001 #ifndef _DATE_TIME_POSIX_TIME_ZONE__
0002 #define _DATE_TIME_POSIX_TIME_ZONE__
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <string>
0012 #include <sstream>
0013 #include <stdexcept>
0014 #include <boost/tokenizer.hpp>
0015 #include <boost/throw_exception.hpp>
0016 #include <boost/date_time/compiler_config.hpp>
0017 #include <boost/date_time/gregorian/gregorian.hpp>
0018 #include <boost/date_time/time_zone_names.hpp>
0019 #include <boost/date_time/time_zone_base.hpp>
0020 #include <boost/date_time/local_time/dst_transition_day_rules.hpp>
0021 #include <boost/date_time/posix_time/posix_time.hpp>
0022 #include <boost/date_time/string_convert.hpp>
0023 #include <boost/date_time/time_parsing.hpp>
0024
0025 namespace boost{
0026 namespace local_time{
0027
0028
0029 struct BOOST_SYMBOL_VISIBLE bad_offset : public std::out_of_range
0030 {
0031 bad_offset(std::string const& msg = std::string()) :
0032 std::out_of_range(std::string("Offset out of range: " + msg)) {}
0033 };
0034
0035 struct BOOST_SYMBOL_VISIBLE bad_adjustment : public std::out_of_range
0036 {
0037 bad_adjustment(std::string const& msg = std::string()) :
0038 std::out_of_range(std::string("Adjustment out of range: " + msg)) {}
0039 };
0040
0041 typedef boost::date_time::dst_adjustment_offsets<boost::posix_time::time_duration> dst_adjustment_offsets;
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070 template<class CharT>
0071 class BOOST_SYMBOL_VISIBLE posix_time_zone_base : public date_time::time_zone_base<posix_time::ptime,CharT> {
0072 public:
0073 typedef boost::posix_time::time_duration time_duration_type;
0074 typedef date_time::time_zone_names_base<CharT> time_zone_names;
0075 typedef date_time::time_zone_base<posix_time::ptime,CharT> base_type;
0076 typedef typename base_type::string_type string_type;
0077 typedef CharT char_type;
0078 typedef typename base_type::stringstream_type stringstream_type;
0079 typedef boost::char_separator<char_type, std::char_traits<char_type> > char_separator_type;
0080 typedef boost::tokenizer<char_separator_type,
0081 typename string_type::const_iterator,
0082 string_type> tokenizer_type;
0083 typedef typename tokenizer_type::iterator tokenizer_iterator_type;
0084
0085
0086 posix_time_zone_base(const string_type& s) :
0087
0088 zone_names_(),
0089 has_dst_(false),
0090 base_utc_offset_(posix_time::hours(0)),
0091 dst_offsets_(posix_time::hours(0),posix_time::hours(0),posix_time::hours(0)),
0092 dst_calc_rules_()
0093 {
0094 #ifdef __HP_aCC
0095
0096
0097 const char_type sep_chars[2] = {',',0};
0098 #else
0099 const char_type sep_chars[2] = {','};
0100 #endif
0101 char_separator_type sep(sep_chars);
0102 tokenizer_type tokens(s, sep);
0103 tokenizer_iterator_type it = tokens.begin(), end = tokens.end();
0104 if (it == end)
0105 BOOST_THROW_EXCEPTION(std::invalid_argument("Could not parse time zone name"));
0106 calc_zone(*it++);
0107 if(has_dst_)
0108 {
0109 if (it == end)
0110 BOOST_THROW_EXCEPTION(std::invalid_argument("Could not parse DST begin time"));
0111 string_type dst_begin = *it++;
0112
0113 if (it == end)
0114 BOOST_THROW_EXCEPTION(std::invalid_argument("Could not parse DST end time"));
0115 string_type dst_end = *it;
0116 calc_rules(dst_begin, dst_end);
0117 }
0118 }
0119 virtual ~posix_time_zone_base() {}
0120
0121 virtual string_type std_zone_abbrev()const
0122 {
0123 return zone_names_.std_zone_abbrev();
0124 }
0125
0126
0127 virtual string_type dst_zone_abbrev() const
0128 {
0129 return zone_names_.dst_zone_abbrev();
0130 }
0131
0132
0133
0134 virtual string_type std_zone_name()const
0135 {
0136 return zone_names_.std_zone_name();
0137 }
0138
0139
0140
0141
0142 virtual string_type dst_zone_name()const
0143 {
0144 return zone_names_.dst_zone_name();
0145 }
0146
0147 virtual bool has_dst()const
0148 {
0149 return has_dst_;
0150 }
0151
0152 virtual posix_time::ptime dst_local_start_time(gregorian::greg_year y)const
0153 {
0154 gregorian::date d(gregorian::not_a_date_time);
0155 if(has_dst_)
0156 {
0157 d = dst_calc_rules_->start_day(y);
0158 }
0159 return posix_time::ptime(d, dst_offsets_.dst_start_offset_);
0160 }
0161
0162 virtual posix_time::ptime dst_local_end_time(gregorian::greg_year y)const
0163 {
0164 gregorian::date d(gregorian::not_a_date_time);
0165 if(has_dst_)
0166 {
0167 d = dst_calc_rules_->end_day(y);
0168 }
0169 return posix_time::ptime(d, dst_offsets_.dst_end_offset_);
0170 }
0171
0172 virtual time_duration_type base_utc_offset()const
0173 {
0174 return base_utc_offset_;
0175 }
0176
0177 virtual time_duration_type dst_offset()const
0178 {
0179 return dst_offsets_.dst_adjust_;
0180 }
0181
0182
0183 virtual string_type to_posix_string() const
0184 {
0185
0186 stringstream_type ss;
0187 ss.fill('0');
0188 boost::shared_ptr<dst_calc_rule> no_rules;
0189
0190 ss << std_zone_abbrev();
0191
0192 if(base_utc_offset().is_negative()) {
0193
0194 ss << '-' << std::setw(2) << base_utc_offset().invert_sign().hours();
0195 }
0196 else {
0197 ss << '+' << std::setw(2) << base_utc_offset().hours();
0198 }
0199 if(base_utc_offset().minutes() != 0 || base_utc_offset().seconds() != 0) {
0200 ss << ':' << std::setw(2) << base_utc_offset().minutes();
0201 if(base_utc_offset().seconds() != 0) {
0202 ss << ':' << std::setw(2) << base_utc_offset().seconds();
0203 }
0204 }
0205 if(dst_calc_rules_ != no_rules) {
0206
0207 ss << dst_zone_abbrev();
0208
0209 if(dst_offset().is_negative()) {
0210
0211 ss << '-' << std::setw(2) << dst_offset().invert_sign().hours();
0212 }
0213 else {
0214 ss << '+' << std::setw(2) << dst_offset().hours();
0215 }
0216 if(dst_offset().minutes() != 0 || dst_offset().seconds() != 0) {
0217 ss << ':' << std::setw(2) << dst_offset().minutes();
0218 if(dst_offset().seconds() != 0) {
0219 ss << ':' << std::setw(2) << dst_offset().seconds();
0220 }
0221 }
0222
0223 ss << ',' << date_time::convert_string_type<char, char_type>(dst_calc_rules_->start_rule_as_string()) << '/'
0224 << std::setw(2) << dst_offsets_.dst_start_offset_.hours() << ':'
0225 << std::setw(2) << dst_offsets_.dst_start_offset_.minutes();
0226 if(dst_offsets_.dst_start_offset_.seconds() != 0) {
0227 ss << ':' << std::setw(2) << dst_offsets_.dst_start_offset_.seconds();
0228 }
0229
0230 ss << ',' << date_time::convert_string_type<char, char_type>(dst_calc_rules_->end_rule_as_string()) << '/'
0231 << std::setw(2) << dst_offsets_.dst_end_offset_.hours() << ':'
0232 << std::setw(2) << dst_offsets_.dst_end_offset_.minutes();
0233 if(dst_offsets_.dst_end_offset_.seconds() != 0) {
0234 ss << ':' << std::setw(2) << dst_offsets_.dst_end_offset_.seconds();
0235 }
0236 }
0237
0238 return ss.str();
0239 }
0240 private:
0241 time_zone_names zone_names_;
0242 bool has_dst_;
0243 time_duration_type base_utc_offset_;
0244 dst_adjustment_offsets dst_offsets_;
0245 boost::shared_ptr<dst_calc_rule> dst_calc_rules_;
0246
0247
0248
0249
0250
0251 void calc_zone(const string_type& obj){
0252 const char_type empty_string[2] = {'\0'};
0253 stringstream_type ss(empty_string);
0254 typename string_type::const_pointer sit = obj.c_str(), obj_end = sit + obj.size();
0255 string_type l_std_zone_abbrev, l_dst_zone_abbrev;
0256
0257
0258 while(std::isalpha(*sit)){
0259 ss << *sit++;
0260 }
0261 l_std_zone_abbrev = ss.str();
0262 ss.str(empty_string);
0263
0264
0265 if(sit != obj_end){
0266
0267 while(sit != obj_end && !std::isalpha(*sit)){
0268 ss << *sit++;
0269 }
0270 base_utc_offset_ = date_time::str_from_delimited_time_duration<time_duration_type,char_type>(ss.str());
0271 ss.str(empty_string);
0272
0273
0274 if(base_utc_offset_ < time_duration_type(-12,0,0) ||
0275 base_utc_offset_ > time_duration_type(14,0,0))
0276 {
0277 boost::throw_exception(bad_offset(posix_time::to_simple_string(base_utc_offset_)));
0278 }
0279 }
0280
0281
0282 if(sit != obj_end){
0283 has_dst_ = true;
0284
0285
0286 while(sit != obj_end && std::isalpha(*sit)){
0287 ss << *sit++;
0288 }
0289 l_dst_zone_abbrev = ss.str();
0290 ss.str(empty_string);
0291
0292
0293 if(sit != obj_end){
0294
0295 while(sit != obj_end && !std::isalpha(*sit)){
0296 ss << *sit++;
0297 }
0298 dst_offsets_.dst_adjust_ = date_time::str_from_delimited_time_duration<time_duration_type,char_type>(ss.str());
0299 ss.str(empty_string);
0300 }
0301 else{
0302 dst_offsets_.dst_adjust_ = posix_time::hours(1);
0303 }
0304
0305
0306 if(dst_offsets_.dst_adjust_ <= time_duration_type(-24,0,0) ||
0307 dst_offsets_.dst_adjust_ >= time_duration_type(24,0,0))
0308 {
0309 boost::throw_exception(bad_adjustment(posix_time::to_simple_string(dst_offsets_.dst_adjust_)));
0310 }
0311 }
0312
0313 zone_names_ = time_zone_names(l_std_zone_abbrev, l_std_zone_abbrev, l_dst_zone_abbrev, l_dst_zone_abbrev);
0314 }
0315
0316 void calc_rules(const string_type& start, const string_type& end){
0317 #ifdef __HP_aCC
0318
0319
0320 const char_type sep_chars[2] = {'/',0};
0321 #else
0322 const char_type sep_chars[2] = {'/'};
0323 #endif
0324 char_separator_type sep(sep_chars);
0325 tokenizer_type st_tok(start, sep);
0326 tokenizer_type et_tok(end, sep);
0327 tokenizer_iterator_type sit = st_tok.begin();
0328 tokenizer_iterator_type eit = et_tok.begin();
0329
0330
0331 char_type x = string_type(*sit).at(0);
0332 if(x == 'M'){
0333 M_func(*sit, *eit);
0334 }
0335 else if(x == 'J'){
0336 julian_no_leap(*sit, *eit);
0337 }
0338 else{
0339 julian_day(*sit, *eit);
0340 }
0341
0342 ++sit;
0343 ++eit;
0344
0345
0346 if(sit != st_tok.end()){
0347 dst_offsets_.dst_start_offset_ = date_time::str_from_delimited_time_duration<time_duration_type,char_type>(*sit);
0348 }
0349 else{
0350
0351 dst_offsets_.dst_start_offset_ = posix_time::hours(2);
0352 }
0353
0354 if(dst_offsets_.dst_start_offset_ < time_duration_type(0,0,0) ||
0355 dst_offsets_.dst_start_offset_ >= time_duration_type(24,0,0))
0356 {
0357 boost::throw_exception(bad_offset(posix_time::to_simple_string(dst_offsets_.dst_start_offset_)));
0358 }
0359
0360
0361 if(eit != et_tok.end()){
0362 dst_offsets_.dst_end_offset_ = date_time::str_from_delimited_time_duration<time_duration_type,char_type>(*eit);
0363 }
0364 else{
0365
0366 dst_offsets_.dst_end_offset_ = posix_time::hours(2);
0367 }
0368
0369 if(dst_offsets_.dst_end_offset_ < time_duration_type(0,0,0) ||
0370 dst_offsets_.dst_end_offset_ >= time_duration_type(24,0,0))
0371 {
0372 boost::throw_exception(bad_offset(posix_time::to_simple_string(dst_offsets_.dst_end_offset_)));
0373 }
0374 }
0375
0376
0377
0378
0379
0380 void M_func(const string_type& s, const string_type& e){
0381 typedef gregorian::nth_kday_of_month nkday;
0382 unsigned short sm=0,sw=0,sd=0,em=0,ew=0,ed=0;
0383 #ifdef __HP_aCC
0384
0385
0386 const char_type sep_chars[3] = {'M','.',0};
0387 #else
0388 const char_type sep_chars[3] = {'M','.'};
0389 #endif
0390 char_separator_type sep(sep_chars);
0391 tokenizer_type stok(s, sep), etok(e, sep);
0392
0393 tokenizer_iterator_type it = stok.begin();
0394 sm = lexical_cast<unsigned short>(*it++);
0395 sw = lexical_cast<unsigned short>(*it++);
0396 sd = lexical_cast<unsigned short>(*it);
0397
0398 it = etok.begin();
0399 em = lexical_cast<unsigned short>(*it++);
0400 ew = lexical_cast<unsigned short>(*it++);
0401 ed = lexical_cast<unsigned short>(*it);
0402
0403 dst_calc_rules_ = shared_ptr<dst_calc_rule>(
0404 new nth_kday_dst_rule(
0405 nth_last_dst_rule::start_rule(
0406 static_cast<nkday::week_num>(sw),sd,sm),
0407 nth_last_dst_rule::start_rule(
0408 static_cast<nkday::week_num>(ew),ed,em)
0409 )
0410 );
0411 }
0412
0413
0414
0415 void julian_no_leap(const string_type& s, const string_type& e){
0416 typedef gregorian::gregorian_calendar calendar;
0417 const unsigned short year = 2001;
0418 unsigned short sm=1;
0419 int sd=0;
0420 sd = lexical_cast<int>(s.substr(1));
0421 while(sd >= calendar::end_of_month_day(year,sm)){
0422 sd -= calendar::end_of_month_day(year,sm++);
0423 }
0424 unsigned short em=1;
0425 int ed=0;
0426 ed = lexical_cast<int>(e.substr(1));
0427 while(ed > calendar::end_of_month_day(year,em)){
0428 ed -= calendar::end_of_month_day(year,em++);
0429 }
0430
0431 dst_calc_rules_ = shared_ptr<dst_calc_rule>(
0432 new partial_date_dst_rule(
0433 partial_date_dst_rule::start_rule(
0434 static_cast<unsigned short>(sd), static_cast<date_time::months_of_year>(sm)),
0435 partial_date_dst_rule::end_rule(
0436 static_cast<unsigned short>(ed), static_cast<date_time::months_of_year>(em))
0437 )
0438 );
0439 }
0440
0441
0442
0443 void julian_day(const string_type& s, const string_type& e){
0444 int sd=0, ed=0;
0445 sd = lexical_cast<int>(s);
0446 ed = lexical_cast<int>(e);
0447 dst_calc_rules_ = shared_ptr<dst_calc_rule>(
0448 new partial_date_dst_rule(
0449 partial_date_dst_rule::start_rule(++sd),
0450 partial_date_dst_rule::end_rule(++ed)
0451 )
0452 );
0453 }
0454
0455
0456 static std::string td_as_string(const time_duration_type& td)
0457 {
0458 std::string s;
0459 #if defined(USE_DATE_TIME_PRE_1_33_FACET_IO)
0460 s = posix_time::to_simple_string(td);
0461 #else
0462 std::stringstream ss;
0463 ss << td;
0464 s = ss.str();
0465 #endif
0466 return s;
0467 }
0468 };
0469
0470 typedef posix_time_zone_base<char> posix_time_zone;
0471
0472 } }
0473
0474
0475 #endif