/*! @param t UTC time to calculate offset to local time * This adjustment depends on the following observations about the * workings of the DST boundary offset. Since UTC time labels are * monotonically increasing we can determine if a given local time * is in DST or not and therefore adjust the offset appropriately. * * The logic is as follows. Starting with UTC time use the offset to * create a label for an non-dst adjusted local time. Then call * dst_rules::local_is_dst with the non adjust local time. The * results of this function will either unabiguously decide that * the initial local time is in dst or return an illegal or * ambiguous result. An illegal result only occurs at the end * of dst (where labels are skipped) and indicates that dst has * ended. An ambiguous result means that we need to recheck by * making a dst adjustment and then rechecking. If the dst offset * is added to the utc time and the recheck proves non-ambiguous * then we are past the boundary. If it is still ambiguous then * we are ahead of the boundary and dst is still in effect. * * TODO -- check if all dst offsets are positive. If not then * the algorithm needs to check for this and reverse the * illegal/ambiguous logic. */ static time_duration_type utc_to_local_offset(const time_type& t) { //get initial local time guess by applying utc offset time_type initial = t + utc_to_local_base_offset(); time_is_dst_result dst_flag = dst_rules::local_is_dst(initial.date(), initial.time_of_day()); switch(dst_flag) { case is_in_dst: return utc_to_local_base_offset() + dst_offset(); case is_not_in_dst: return utc_to_local_base_offset(); case invalid_time_label:return utc_to_local_base_offset() + dst_offset(); case ambiguous: { time_type retry = initial + dst_offset(); dst_flag = dst_rules::local_is_dst(retry.date(), retry.time_of_day()); //if still ambibuous then the utc time still translates to a dst time if (dst_flag == ambiguous) { return utc_to_local_base_offset() + dst_offset(); } // we are past the dst boundary else { return utc_to_local_base_offset(); } } }//case //TODO better excpetion type throw std::out_of_range("Unreachable case"); }
//! Returns a POSIX time_zone string for this object virtual string_type to_posix_string() const { // std offset dst [offset],start[/time],end[/time] - w/o spaces stringstream_type ss; ss.fill('0'); boost::shared_ptr<dst_calc_rule> no_rules; // std ss << std_zone_abbrev(); // offset if(base_utc_offset().is_negative()) { // inverting the sign guarantees we get two digits ss << '-' << std::setw(2) << base_utc_offset().invert_sign().hours(); } else { ss << '+' << std::setw(2) << base_utc_offset().hours(); } if(base_utc_offset().minutes() != 0 || base_utc_offset().seconds() != 0) { ss << ':' << std::setw(2) << base_utc_offset().minutes(); if(base_utc_offset().seconds() != 0) { ss << ':' << std::setw(2) << base_utc_offset().seconds(); } } if(dst_calc_rules_ != no_rules) { // dst ss << dst_zone_abbrev(); // dst offset if(dst_offset().is_negative()) { // inverting the sign guarantees we get two digits ss << '-' << std::setw(2) << dst_offset().invert_sign().hours(); } else { ss << '+' << std::setw(2) << dst_offset().hours(); } if(dst_offset().minutes() != 0 || dst_offset().seconds() != 0) { ss << ':' << std::setw(2) << dst_offset().minutes(); if(dst_offset().seconds() != 0) { ss << ':' << std::setw(2) << dst_offset().seconds(); } } // start/time ss << ',' << date_time::convert_string_type<char, char_type>(dst_calc_rules_->start_rule_as_string()) << '/' << std::setw(2) << dst_offsets_.dst_start_offset_.hours() << ':' << std::setw(2) << dst_offsets_.dst_start_offset_.minutes(); if(dst_offsets_.dst_start_offset_.seconds() != 0) { ss << ':' << std::setw(2) << dst_offsets_.dst_start_offset_.seconds(); } // end/time ss << ',' << date_time::convert_string_type<char, char_type>(dst_calc_rules_->end_rule_as_string()) << '/' << std::setw(2) << dst_offsets_.dst_end_offset_.hours() << ':' << std::setw(2) << dst_offsets_.dst_end_offset_.minutes(); if(dst_offsets_.dst_end_offset_.seconds() != 0) { ss << ':' << std::setw(2) << dst_offsets_.dst_end_offset_.seconds(); } } return ss.str(); }
//! Presumes local time time_duration_type utc_offset(bool is_dst) { if (is_dst) { return utc_offset_ + dst_offset(); } else { return utc_offset_; } }
//! Get the offset to UTC given a local time static time_duration_type local_to_utc_offset(const time_type& t, date_time::dst_flags dst=date_time::calculate) { switch (dst) { case is_dst: return local_to_utc_base_offset() - dst_offset(); case not_dst: return local_to_utc_base_offset(); case calculate: time_is_dst_result res = dst_rules::local_is_dst(t.date(), t.time_of_day()); switch(res) { case is_in_dst: return local_to_utc_base_offset() - dst_offset(); case is_not_in_dst: return local_to_utc_base_offset(); case ambiguous: return local_to_utc_base_offset(); case invalid_time_label: throw std::out_of_range("Time label invalid"); } } throw std::out_of_range("Time label invalid"); }