123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- #ifndef DATE_TIME_DST_RULES_HPP__
- #define DATE_TIME_DST_RULES_HPP__
- /* Copyright (c) 2002,2003, 2007 CrystalClear Software, Inc.
- * Use, modification and distribution is subject to the
- * Boost Software License, Version 1.0. (See accompanying
- * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
- * Author: Jeff Garland, Bart Garst
- * $Date$
- */
- /*! @file dst_rules.hpp
- Contains template class to provide static dst rule calculations
- */
- #include "boost/date_time/date_generators.hpp"
- #include "boost/date_time/period.hpp"
- #include "boost/date_time/date_defs.hpp"
- #include <stdexcept>
- namespace boost {
- namespace date_time {
- enum time_is_dst_result {is_not_in_dst, is_in_dst,
- ambiguous, invalid_time_label};
- //! Dynamic class used to caluclate dst transition information
- template<class date_type_,
- class time_duration_type_>
- class dst_calculator
- {
- public:
- typedef time_duration_type_ time_duration_type;
- typedef date_type_ date_type;
- //! Check the local time offset when on dst start day
- /*! On this dst transition, the time label between
- * the transition boundary and the boudary + the offset
- * are invalid times. If before the boundary then still
- * not in dst.
- *@param time_of_day Time offset in the day for the local time
- *@param dst_start_offset_minutes Local day offset for start of dst
- *@param dst_length_minutes Number of minutes to adjust clock forward
- *@retval status of time label w.r.t. dst
- */
- static time_is_dst_result
- process_local_dst_start_day(const time_duration_type& time_of_day,
- unsigned int dst_start_offset_minutes,
- long dst_length_minutes)
- {
- //std::cout << "here" << std::endl;
- if (time_of_day < time_duration_type(0,dst_start_offset_minutes,0)) {
- return is_not_in_dst;
- }
- long offset = dst_start_offset_minutes + dst_length_minutes;
- if (time_of_day >= time_duration_type(0,offset,0)) {
- return is_in_dst;
- }
- return invalid_time_label;
- }
- //! Check the local time offset when on the last day of dst
- /*! This is the calculation for the DST end day. On that day times
- * prior to the conversion time - dst_length (1 am in US) are still
- * in dst. Times between the above and the switch time are
- * ambiguous. Times after the start_offset are not in dst.
- *@param time_of_day Time offset in the day for the local time
- *@param dst_end_offset_minutes Local time of day for end of dst
- *@retval status of time label w.r.t. dst
- */
- static time_is_dst_result
- process_local_dst_end_day(const time_duration_type& time_of_day,
- unsigned int dst_end_offset_minutes,
- long dst_length_minutes)
- {
- //in US this will be 60 so offset in day is 1,0,0
- int offset = dst_end_offset_minutes-dst_length_minutes;
- if (time_of_day < time_duration_type(0,offset,0)) {
- return is_in_dst;
- }
- if (time_of_day >= time_duration_type(0,dst_end_offset_minutes,0)) {
- return is_not_in_dst;
- }
- return ambiguous;
- }
- //! Calculates if the given local time is dst or not
- /*! Determines if the time is really in DST or not. Also checks for
- * invalid and ambiguous.
- * @param current_day The day to check for dst
- * @param time_of_day Time offset within the day to check
- * @param dst_start_day Starting day of dst for the given locality
- * @param dst_start_offset Time offset within day for dst boundary
- * @param dst_end_day Ending day of dst for the given locality
- * @param dst_end_offset Time offset within day given in dst for dst boundary
- * @param dst_length_minutes length of dst adjusment
- * @retval The time is either ambiguous, invalid, in dst, or not in dst
- */
- static time_is_dst_result
- local_is_dst(const date_type& current_day,
- const time_duration_type& time_of_day,
- const date_type& dst_start_day,
- const time_duration_type& dst_start_offset,
- const date_type& dst_end_day,
- const time_duration_type& dst_end_offset,
- const time_duration_type& dst_length)
- {
- unsigned int start_minutes = static_cast<unsigned>(
- dst_start_offset.hours() * 60 + dst_start_offset.minutes());
- unsigned int end_minutes = static_cast<unsigned>(
- dst_end_offset.hours() * 60 + dst_end_offset.minutes());
- long length_minutes = static_cast<long>(
- dst_length.hours() * 60 + dst_length.minutes());
- return local_is_dst(current_day, time_of_day,
- dst_start_day, start_minutes,
- dst_end_day, end_minutes,
- length_minutes);
- }
- //! Calculates if the given local time is dst or not
- /*! Determines if the time is really in DST or not. Also checks for
- * invalid and ambiguous.
- * @param current_day The day to check for dst
- * @param time_of_day Time offset within the day to check
- * @param dst_start_day Starting day of dst for the given locality
- * @param dst_start_offset_minutes Offset within day for dst
- * boundary (eg 120 for US which is 02:00:00)
- * @param dst_end_day Ending day of dst for the given locality
- * @param dst_end_offset_minutes Offset within day given in dst for dst
- * boundary (eg 120 for US which is 02:00:00)
- * @param dst_length_minutes Length of dst adjusment (eg: 60 for US)
- * @retval The time is either ambiguous, invalid, in dst, or not in dst
- */
- static time_is_dst_result
- local_is_dst(const date_type& current_day,
- const time_duration_type& time_of_day,
- const date_type& dst_start_day,
- unsigned int dst_start_offset_minutes,
- const date_type& dst_end_day,
- unsigned int dst_end_offset_minutes,
- long dst_length_minutes)
- {
- //in northern hemisphere dst is in the middle of the year
- if (dst_start_day < dst_end_day) {
- if ((current_day > dst_start_day) && (current_day < dst_end_day)) {
- return is_in_dst;
- }
- if ((current_day < dst_start_day) || (current_day > dst_end_day)) {
- return is_not_in_dst;
- }
- }
- else {//southern hemisphere dst is at begining /end of year
- if ((current_day < dst_start_day) && (current_day > dst_end_day)) {
- return is_not_in_dst;
- }
- if ((current_day > dst_start_day) || (current_day < dst_end_day)) {
- return is_in_dst;
- }
- }
- if (current_day == dst_start_day) {
- return process_local_dst_start_day(time_of_day,
- dst_start_offset_minutes,
- dst_length_minutes);
- }
- if (current_day == dst_end_day) {
- return process_local_dst_end_day(time_of_day,
- dst_end_offset_minutes,
- dst_length_minutes);
- }
- //you should never reach this statement
- return invalid_time_label;
- }
- };
- //! Compile-time configurable daylight savings time calculation engine
- /* This template provides the ability to configure a daylight savings
- * calculation at compile time covering all the cases. Unfortunately
- * because of the number of dimensions related to daylight savings
- * calculation the number of parameters is high. In addition, the
- * start and end transition rules are complex types that specify
- * an algorithm for calculation of the starting day and ending
- * day of daylight savings time including the month and day
- * specifications (eg: last sunday in October).
- *
- * @param date_type A type that represents dates, typically gregorian::date
- * @param time_duration_type Used for the offset in the day calculations
- * @param dst_traits A set of traits that define the rules of dst
- * calculation. The dst_trait must include the following:
- * start_rule_functor - Rule to calculate the starting date of a
- * dst transition (eg: last_kday_of_month).
- * start_day - static function that returns month of dst start for
- * start_rule_functor
- * start_month -static function that returns day or day of week for
- * dst start of dst
- * end_rule_functor - Rule to calculate the end of dst day.
- * end_day - static fucntion that returns end day for end_rule_functor
- * end_month - static function that returns end month for end_rule_functor
- * dst_start_offset_minutes - number of minutes from start of day to transition to dst -- 120 (or 2:00 am) is typical for the U.S. and E.U.
- * dst_start_offset_minutes - number of minutes from start of day to transition off of dst -- 180 (or 3:00 am) is typical for E.U.
- * dst_length_minutes - number of minutes that dst shifts clock
- */
- template<class date_type,
- class time_duration_type,
- class dst_traits>
- class dst_calc_engine
- {
- public:
- typedef typename date_type::year_type year_type;
- typedef typename date_type::calendar_type calendar_type;
- typedef dst_calculator<date_type, time_duration_type> dstcalc;
- //! Calculates if the given local time is dst or not
- /*! Determines if the time is really in DST or not. Also checks for
- * invalid and ambiguous.
- * @retval The time is either ambiguous, invalid, in dst, or not in dst
- */
- static time_is_dst_result local_is_dst(const date_type& d,
- const time_duration_type& td)
- {
- year_type y = d.year();
- date_type dst_start = local_dst_start_day(y);
- date_type dst_end = local_dst_end_day(y);
- return dstcalc::local_is_dst(d,td,
- dst_start,
- dst_traits::dst_start_offset_minutes(),
- dst_end,
- dst_traits::dst_end_offset_minutes(),
- dst_traits::dst_shift_length_minutes());
- }
- static bool is_dst_boundary_day(date_type d)
- {
- year_type y = d.year();
- return ((d == local_dst_start_day(y)) ||
- (d == local_dst_end_day(y)));
- }
- //! The time of day for the dst transition (eg: typically 01:00:00 or 02:00:00)
- static time_duration_type dst_offset()
- {
- return time_duration_type(0,dst_traits::dst_shift_length_minutes(),0);
- }
- static date_type local_dst_start_day(year_type year)
- {
- return dst_traits::local_dst_start_day(year);
- }
- static date_type local_dst_end_day(year_type year)
- {
- return dst_traits::local_dst_end_day(year);
- }
- };
- //! Depricated: Class to calculate dst boundaries for US time zones
- /* Use dst_calc_engine instead.
- * In 2007 US/Canada DST rules changed
- * (http://en.wikipedia.org/wiki/Energy_Policy_Act_of_2005#Change_to_daylight_saving_time).
- */
- template<class date_type_,
- class time_duration_type_,
- unsigned int dst_start_offset_minutes=120, //from start of day
- short dst_length_minutes=60> //1 hour == 60 min in US
- class us_dst_rules
- {
- public:
- typedef time_duration_type_ time_duration_type;
- typedef date_type_ date_type;
- typedef typename date_type::year_type year_type;
- typedef typename date_type::calendar_type calendar_type;
- typedef date_time::last_kday_of_month<date_type> lkday;
- typedef date_time::first_kday_of_month<date_type> fkday;
- typedef date_time::nth_kday_of_month<date_type> nkday;
- typedef dst_calculator<date_type, time_duration_type> dstcalc;
- //! Calculates if the given local time is dst or not
- /*! Determines if the time is really in DST or not. Also checks for
- * invalid and ambiguous.
- * @retval The time is either ambiguous, invalid, in dst, or not in dst
- */
- static time_is_dst_result local_is_dst(const date_type& d,
- const time_duration_type& td)
- {
- year_type y = d.year();
- date_type dst_start = local_dst_start_day(y);
- date_type dst_end = local_dst_end_day(y);
- return dstcalc::local_is_dst(d,td,
- dst_start,dst_start_offset_minutes,
- dst_end, dst_start_offset_minutes,
- dst_length_minutes);
- }
- static bool is_dst_boundary_day(date_type d)
- {
- year_type y = d.year();
- return ((d == local_dst_start_day(y)) ||
- (d == local_dst_end_day(y)));
- }
- static date_type local_dst_start_day(year_type year)
- {
- if (year >= year_type(2007)) {
- //second sunday in march
- nkday ssim(nkday::second, Sunday, date_time::Mar);
- return ssim.get_date(year);
- } else {
- //first sunday in april
- fkday fsia(Sunday, date_time::Apr);
- return fsia.get_date(year);
- }
- }
- static date_type local_dst_end_day(year_type year)
- {
- if (year >= year_type(2007)) {
- //first sunday in november
- fkday fsin(Sunday, date_time::Nov);
- return fsin.get_date(year);
- } else {
- //last sunday in october
- lkday lsio(Sunday, date_time::Oct);
- return lsio.get_date(year);
- }
- }
- static time_duration_type dst_offset()
- {
- return time_duration_type(0,dst_length_minutes,0);
- }
- private:
- };
- //! Used for local time adjustments in places that don't use dst
- template<class date_type_, class time_duration_type_>
- class null_dst_rules
- {
- public:
- typedef time_duration_type_ time_duration_type;
- typedef date_type_ date_type;
- //! Calculates if the given local time is dst or not
- /*! @retval Always is_not_in_dst since this is for zones without dst
- */
- static time_is_dst_result local_is_dst(const date_type&,
- const time_duration_type&)
- {
- return is_not_in_dst;
- }
- //! Calculates if the given utc time is in dst
- static time_is_dst_result utc_is_dst(const date_type&,
- const time_duration_type&)
- {
- return is_not_in_dst;
- }
- static bool is_dst_boundary_day(date_type /*d*/)
- {
- return false;
- }
- static time_duration_type dst_offset()
- {
- return time_duration_type(0,0,0);
- }
- };
- } } //namespace date_time
- #endif
|