File indexing completed on 2025-01-18 09:30:35
0001 #ifndef LOCAL_TIME_LOCAL_DATE_TIME_HPP__
0002 #define LOCAL_TIME_LOCAL_DATE_TIME_HPP__
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <string>
0012 #include <iomanip>
0013 #include <sstream>
0014 #include <stdexcept>
0015 #include <boost/shared_ptr.hpp>
0016 #include <boost/throw_exception.hpp>
0017 #include <boost/date_time/time.hpp>
0018 #include <boost/date_time/posix_time/posix_time.hpp> //todo remove?
0019 #include <boost/date_time/compiler_config.hpp>
0020 #include <boost/date_time/dst_rules.hpp>
0021 #include <boost/date_time/time_zone_base.hpp>
0022 #include <boost/date_time/special_defs.hpp>
0023 #include <boost/date_time/time_resolution_traits.hpp> // absolute_value
0024
0025 namespace boost {
0026 namespace local_time {
0027
0028
0029 struct BOOST_SYMBOL_VISIBLE ambiguous_result : public std::logic_error
0030 {
0031 ambiguous_result (std::string const& msg = std::string()) :
0032 std::logic_error(std::string("Daylight Savings Results are ambiguous: " + msg)) {}
0033 };
0034
0035 struct BOOST_SYMBOL_VISIBLE time_label_invalid : public std::logic_error
0036 {
0037 time_label_invalid (std::string const& msg = std::string()) :
0038 std::logic_error(std::string("Time label given is invalid: " + msg)) {}
0039 };
0040 struct BOOST_SYMBOL_VISIBLE dst_not_valid: public std::logic_error
0041 {
0042 dst_not_valid(std::string const& msg = std::string()) :
0043 std::logic_error(std::string("is_dst flag does not match resulting dst for time label given: " + msg)) {}
0044 };
0045
0046
0047
0048 using date_time::time_is_dst_result;
0049 using date_time::is_in_dst;
0050 using date_time::is_not_in_dst;
0051 using date_time::ambiguous;
0052 using date_time::invalid_time_label;
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063 template<class utc_time_=posix_time::ptime,
0064 class tz_type=date_time::time_zone_base<utc_time_,char> >
0065 class BOOST_SYMBOL_VISIBLE local_date_time_base : public date_time::base_time<utc_time_,
0066 boost::posix_time::posix_time_system> {
0067 public:
0068 typedef utc_time_ utc_time_type;
0069 typedef typename utc_time_type::time_duration_type time_duration_type;
0070 typedef typename utc_time_type::date_type date_type;
0071 typedef typename date_type::duration_type date_duration_type;
0072 typedef typename utc_time_type::time_system_type time_system_type;
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 local_date_time_base(utc_time_type t,
0083 boost::shared_ptr<tz_type> tz) :
0084 date_time::base_time<utc_time_type, time_system_type>(t),
0085 zone_(tz)
0086 {
0087
0088 }
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101 local_date_time_base(date_type d,
0102 time_duration_type td,
0103 boost::shared_ptr<tz_type> tz,
0104 bool dst_flag) :
0105 date_time::base_time<utc_time_type,time_system_type>(construction_adjustment(utc_time_type(d, td), tz, dst_flag)),
0106 zone_(tz)
0107 {
0108 if(tz != boost::shared_ptr<tz_type>() && tz->has_dst()){
0109
0110
0111 time_is_dst_result result = check_dst(d, td, tz);
0112 bool in_dst = (result == is_in_dst);
0113
0114
0115 if(result == invalid_time_label){
0116
0117 std::ostringstream ss;
0118 ss << "time given: " << d << ' ' << td;
0119 boost::throw_exception(time_label_invalid(ss.str()));
0120 }
0121 else if(result != ambiguous && in_dst != dst_flag){
0122
0123
0124 std::ostringstream ss;
0125 ss.setf(std::ios_base::boolalpha);
0126 ss << "flag given: dst=" << dst_flag << ", dst calculated: dst=" << in_dst;
0127 boost::throw_exception(dst_not_valid(ss.str()));
0128 }
0129
0130
0131 }
0132 }
0133
0134
0135 enum DST_CALC_OPTIONS { EXCEPTION_ON_ERROR, NOT_DATE_TIME_ON_ERROR };
0136
0137
0138
0139
0140
0141
0142 local_date_time_base(date_type d,
0143 time_duration_type td,
0144 boost::shared_ptr<tz_type> tz,
0145 DST_CALC_OPTIONS calc_option) :
0146
0147 date_time::base_time<utc_time_type,time_system_type>(utc_time_type(d,td)),
0148 zone_(tz)
0149 {
0150 time_is_dst_result result = check_dst(d, td, tz);
0151 if(result == ambiguous) {
0152 if(calc_option == EXCEPTION_ON_ERROR){
0153 std::ostringstream ss;
0154 ss << "time given: " << d << ' ' << td;
0155 boost::throw_exception(ambiguous_result(ss.str()));
0156 }
0157 else{
0158 this->time_ = posix_time::posix_time_system::get_time_rep(date_type(date_time::not_a_date_time), time_duration_type(date_time::not_a_date_time));
0159 }
0160 }
0161 else if(result == invalid_time_label){
0162 if(calc_option == EXCEPTION_ON_ERROR){
0163 std::ostringstream ss;
0164 ss << "time given: " << d << ' ' << td;
0165 boost::throw_exception(time_label_invalid(ss.str()));
0166 }
0167 else{
0168 this->time_ = posix_time::posix_time_system::get_time_rep(date_type(date_time::not_a_date_time), time_duration_type(date_time::not_a_date_time));
0169 }
0170 }
0171 else if(result == is_in_dst){
0172 utc_time_type t =
0173 construction_adjustment(utc_time_type(d, td), tz, true);
0174 this->time_ = posix_time::posix_time_system::get_time_rep(t.date(),
0175 t.time_of_day());
0176 }
0177 else{
0178 utc_time_type t =
0179 construction_adjustment(utc_time_type(d, td), tz, false);
0180 this->time_ = posix_time::posix_time_system::get_time_rep(t.date(),
0181 t.time_of_day());
0182 }
0183 }
0184
0185
0186
0187
0188
0189
0190
0191 static time_is_dst_result check_dst(date_type d,
0192 time_duration_type td,
0193 boost::shared_ptr<tz_type> tz)
0194 {
0195 if(tz != boost::shared_ptr<tz_type>() && tz->has_dst()) {
0196 typedef typename date_time::dst_calculator<date_type, time_duration_type> dst_calculator;
0197 return dst_calculator::local_is_dst(
0198 d, td,
0199 tz->dst_local_start_time(d.year()).date(),
0200 tz->dst_local_start_time(d.year()).time_of_day(),
0201 tz->dst_local_end_time(d.year()).date(),
0202 tz->dst_local_end_time(d.year()).time_of_day(),
0203 tz->dst_offset()
0204 );
0205 }
0206 else{
0207 return is_not_in_dst;
0208 }
0209 }
0210
0211
0212 ~local_date_time_base() {}
0213
0214
0215 local_date_time_base(const local_date_time_base& rhs) :
0216 date_time::base_time<utc_time_type, time_system_type>(rhs),
0217 zone_(rhs.zone_)
0218 {}
0219
0220
0221 explicit local_date_time_base(const boost::date_time::special_values sv,
0222 boost::shared_ptr<tz_type> tz = boost::shared_ptr<tz_type>()) :
0223 date_time::base_time<utc_time_type, time_system_type>(utc_time_type(sv)),
0224 zone_(tz)
0225 {}
0226
0227
0228 boost::shared_ptr<tz_type> zone() const
0229 {
0230 return zone_;
0231 }
0232
0233 bool is_dst() const
0234 {
0235 if(zone_ != boost::shared_ptr<tz_type>() && zone_->has_dst() && !this->is_special()) {
0236
0237 utc_time_type lt(this->time_);
0238 lt += zone_->base_utc_offset();
0239
0240
0241
0242 switch(check_dst(lt.date(), lt.time_of_day(), zone_)){
0243 case is_not_in_dst:
0244 return false;
0245 case is_in_dst:
0246 return true;
0247 case ambiguous:
0248 if(lt + zone_->dst_offset() < zone_->dst_local_end_time(lt.date().year())) {
0249 return true;
0250 }
0251 break;
0252 case invalid_time_label:
0253 if(lt >= zone_->dst_local_start_time(lt.date().year())) {
0254 return true;
0255 }
0256 break;
0257 }
0258 }
0259 return false;
0260 }
0261
0262 utc_time_type utc_time() const
0263 {
0264 return utc_time_type(this->time_);
0265 }
0266
0267 utc_time_type local_time() const
0268 {
0269 if(zone_ != boost::shared_ptr<tz_type>()){
0270 utc_time_type lt = this->utc_time() + zone_->base_utc_offset();
0271 if (is_dst()) {
0272 lt += zone_->dst_offset();
0273 }
0274 return lt;
0275 }
0276 return utc_time_type(this->time_);
0277 }
0278
0279
0280
0281
0282 std::string to_string() const
0283 {
0284
0285 std::ostringstream ss;
0286 if(this->is_special()){
0287 ss << utc_time();
0288 return ss.str();
0289 }
0290 if(zone_ == boost::shared_ptr<tz_type>()) {
0291 ss << utc_time() << " UTC";
0292 return ss.str();
0293 }
0294 bool is_dst_ = is_dst();
0295 utc_time_type lt = this->utc_time() + zone_->base_utc_offset();
0296 if (is_dst_) {
0297 lt += zone_->dst_offset();
0298 }
0299 ss << local_time() << " ";
0300 if (is_dst()) {
0301 ss << zone_->dst_zone_abbrev();
0302 }
0303 else {
0304 ss << zone_->std_zone_abbrev();
0305 }
0306 return ss.str();
0307 }
0308
0309
0310 local_date_time_base local_time_in(boost::shared_ptr<tz_type> new_tz,
0311 time_duration_type td=time_duration_type(0,0,0)) const
0312 {
0313 return local_date_time_base(utc_time_type(this->time_) + td, new_tz);
0314 }
0315
0316
0317
0318
0319
0320 std::string zone_name(bool as_offset=false) const
0321 {
0322 if(zone_ == boost::shared_ptr<tz_type>()) {
0323 if(as_offset) {
0324 return std::string("Z");
0325 }
0326 else {
0327 return std::string("Coordinated Universal Time");
0328 }
0329 }
0330 if (is_dst()) {
0331 if(as_offset) {
0332 time_duration_type td = zone_->base_utc_offset();
0333 td += zone_->dst_offset();
0334 return zone_as_offset(td, ":");
0335 }
0336 else {
0337 return zone_->dst_zone_name();
0338 }
0339 }
0340 else {
0341 if(as_offset) {
0342 time_duration_type td = zone_->base_utc_offset();
0343 return zone_as_offset(td, ":");
0344 }
0345 else {
0346 return zone_->std_zone_name();
0347 }
0348 }
0349 }
0350
0351
0352
0353
0354 std::string zone_abbrev(bool as_offset=false) const
0355 {
0356 if(zone_ == boost::shared_ptr<tz_type>()) {
0357 if(as_offset) {
0358 return std::string("Z");
0359 }
0360 else {
0361 return std::string("UTC");
0362 }
0363 }
0364 if (is_dst()) {
0365 if(as_offset) {
0366 time_duration_type td = zone_->base_utc_offset();
0367 td += zone_->dst_offset();
0368 return zone_as_offset(td, "");
0369 }
0370 else {
0371 return zone_->dst_zone_abbrev();
0372 }
0373 }
0374 else {
0375 if(as_offset) {
0376 time_duration_type td = zone_->base_utc_offset();
0377 return zone_as_offset(td, "");
0378 }
0379 else {
0380 return zone_->std_zone_abbrev();
0381 }
0382 }
0383 }
0384
0385
0386 std::string zone_as_posix_string() const
0387 {
0388 if(zone_ == shared_ptr<tz_type>()) {
0389 return std::string("UTC+00");
0390 }
0391 return zone_->to_posix_string();
0392 }
0393
0394
0395
0396
0397
0398
0399
0400
0401 bool operator==(const local_date_time_base& rhs) const
0402 {
0403 return time_system_type::is_equal(this->time_, rhs.time_);
0404 }
0405
0406 bool operator!=(const local_date_time_base& rhs) const
0407 {
0408 return !(*this == rhs);
0409 }
0410
0411 bool operator<(const local_date_time_base& rhs) const
0412 {
0413 return time_system_type::is_less(this->time_, rhs.time_);
0414 }
0415
0416 bool operator<=(const local_date_time_base& rhs) const
0417 {
0418 return (*this < rhs || *this == rhs);
0419 }
0420
0421 bool operator>(const local_date_time_base& rhs) const
0422 {
0423 return !(*this <= rhs);
0424 }
0425
0426 bool operator>=(const local_date_time_base& rhs) const
0427 {
0428 return (*this > rhs || *this == rhs);
0429 }
0430
0431
0432 local_date_time_base operator+(const date_duration_type& dd) const
0433 {
0434 return local_date_time_base(time_system_type::add_days(this->time_,dd), zone_);
0435 }
0436
0437 local_date_time_base operator+=(const date_duration_type& dd)
0438 {
0439 this->time_ = time_system_type::add_days(this->time_,dd);
0440 return *this;
0441 }
0442
0443 local_date_time_base operator-(const date_duration_type& dd) const
0444 {
0445 return local_date_time_base(time_system_type::subtract_days(this->time_,dd), zone_);
0446 }
0447
0448 local_date_time_base operator-=(const date_duration_type& dd)
0449 {
0450 this->time_ = time_system_type::subtract_days(this->time_,dd);
0451 return *this;
0452 }
0453
0454 local_date_time_base operator+(const time_duration_type& td) const
0455 {
0456 return local_date_time_base(time_system_type::add_time_duration(this->time_,td), zone_);
0457 }
0458
0459 local_date_time_base operator+=(const time_duration_type& td)
0460 {
0461 this->time_ = time_system_type::add_time_duration(this->time_,td);
0462 return *this;
0463 }
0464
0465 local_date_time_base operator-(const time_duration_type& td) const
0466 {
0467 return local_date_time_base(time_system_type::subtract_time_duration(this->time_,td), zone_);
0468 }
0469
0470 local_date_time_base operator-=(const time_duration_type& td)
0471 {
0472 this->time_ = time_system_type::subtract_time_duration(this->time_,td);
0473 return *this;
0474 }
0475
0476 time_duration_type operator-(const local_date_time_base& rhs) const
0477 {
0478 return utc_time_type(this->time_) - utc_time_type(rhs.time_);
0479 }
0480 private:
0481 boost::shared_ptr<tz_type> zone_;
0482
0483
0484
0485
0486 utc_time_type construction_adjustment(utc_time_type t,
0487 boost::shared_ptr<tz_type> z,
0488 bool dst_flag)
0489 {
0490 if(z != boost::shared_ptr<tz_type>()) {
0491 if(dst_flag && z->has_dst()) {
0492 t -= z->dst_offset();
0493 }
0494 t -= z->base_utc_offset();
0495 }
0496 return t;
0497 }
0498
0499
0500
0501 std::string zone_as_offset(const time_duration_type& td,
0502 const std::string& separator) const
0503 {
0504 std::ostringstream ss;
0505 if(td.is_negative()) {
0506
0507
0508
0509 ss << "-";
0510 }
0511 else {
0512 ss << "+";
0513 }
0514 ss << std::setw(2) << std::setfill('0')
0515 << date_time::absolute_value(td.hours())
0516 << separator
0517 << std::setw(2) << std::setfill('0')
0518 << date_time::absolute_value(td.minutes());
0519 return ss.str();
0520 }
0521 };
0522
0523
0524 typedef local_date_time_base<> local_date_time;
0525
0526 } }
0527
0528
0529 #endif