source: NonGTP/Boost/boost/date_time/dst_rules.hpp @ 857

Revision 857, 15.1 KB checked in by igarcia, 18 years ago (diff)
Line 
1#ifndef DATE_TIME_DST_RULES_HPP__
2#define DATE_TIME_DST_RULES_HPP__
3
4/* Copyright (c) 2002,2003 CrystalClear Software, Inc.
5 * Use, modification and distribution is subject to the
6 * Boost Software License, Version 1.0. (See accompanying
7 * file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
8 * Author: Jeff Garland, Bart Garst
9 * $Date: 2004/10/02 18:49:16 $
10 */
11
12/*! @file dst_rules.hpp
13  Contains template class to provide static dst rule calculations
14*/
15
16#include "boost/date_time/date_generators.hpp"
17#include "boost/date_time/period.hpp"
18#include "boost/date_time/date_defs.hpp"
19#include <stdexcept>
20
21namespace boost {
22  namespace date_time {
23
24    enum time_is_dst_result {is_not_in_dst, is_in_dst,
25                             ambiguous, invalid_time_label};
26
27
28    //! Dynamic class used to caluclate dst transition information
29    template<class date_type_,
30             class time_duration_type_>
31    class dst_calculator
32    {
33    public:
34      typedef time_duration_type_ time_duration_type;
35      typedef date_type_ date_type;
36
37      //! Check the local time offset when on dst start day
38      /*! On this dst transition, the time label between
39       *  the transition boundary and the boudary + the offset
40       *  are invalid times.  If before the boundary then still
41       *  not in dst. 
42       *@param time_of_day Time offset in the day for the local time
43       *@param dst_start_offset_minutes Local day offset for start of dst
44       *@param dst_length_minutes Number of minutes to adjust clock forward
45       *@retval status of time label w.r.t. dst
46       */
47      static time_is_dst_result
48      process_local_dst_start_day(const time_duration_type& time_of_day,
49                                  unsigned int dst_start_offset_minutes,
50                                  long dst_length_minutes)
51      {
52        //std::cout << "here" << std::endl;
53        if (time_of_day < time_duration_type(0,dst_start_offset_minutes,0)) {
54          return is_not_in_dst;
55        }
56        long offset = dst_start_offset_minutes + dst_length_minutes;
57        if (time_of_day >= time_duration_type(0,offset,0)) {
58          return is_in_dst;
59        }
60        return invalid_time_label;
61      }
62
63      //! Check the local time offset when on the last day of dst
64      /*! This is the calculation for the DST end day.  On that day times
65       *  prior to the conversion time - dst_length (1 am in US) are still
66       *  in dst.  Times between the above and the switch time are
67       *  ambiguous.  Times after the start_offset are not in dst.
68       *@param time_of_day Time offset in the day for the local time
69       *@param dst_end_offset_minutes Local time of day for end of dst
70       *@retval status of time label w.r.t. dst
71       */
72      static time_is_dst_result
73      process_local_dst_end_day(const time_duration_type& time_of_day,
74                                unsigned int dst_end_offset_minutes,
75                                long dst_length_minutes)
76      {
77        //in US this will be 60 so offset in day is 1,0,0
78        int offset = dst_end_offset_minutes-dst_length_minutes;
79        if (time_of_day < time_duration_type(0,offset,0)) {
80          return is_in_dst;
81        }
82        if (time_of_day >= time_duration_type(0,dst_end_offset_minutes,0)) {
83          return is_not_in_dst;
84        }
85        return ambiguous;
86      }
87
88      //! Calculates if the given local time is dst or not
89      /*! Determines if the time is really in DST or not.  Also checks for
90       *  invalid and ambiguous.
91       *  @param current_day The day to check for dst
92       *  @param time_of_day Time offset within the day to check
93       *  @param dst_start_day  Starting day of dst for the given locality
94       *  @param dst_start_offset Time offset within day for dst boundary
95       *  @param dst_end_day    Ending day of dst for the given locality
96       *  @param dst_end_offset Time offset within day given in dst for dst boundary
97       *  @param dst_length lenght of dst adjusment
98       *  @retval The time is either ambiguous, invalid, in dst, or not in dst
99       */
100      static time_is_dst_result
101      local_is_dst(const date_type& current_day,
102                   const time_duration_type& time_of_day,
103                   const date_type& dst_start_day,
104                   const time_duration_type& dst_start_offset,
105                   const date_type& dst_end_day,
106                   const time_duration_type& dst_end_offset,
107                   const time_duration_type& dst_length_minutes)
108      {
109        unsigned int start_minutes =
110          dst_start_offset.hours() * 60 + dst_start_offset.minutes();
111        unsigned int end_minutes =
112          dst_end_offset.hours() * 60 + dst_end_offset.minutes();
113        long length_minutes = 
114          dst_length_minutes.hours() * 60 + dst_length_minutes.minutes();
115
116        return local_is_dst(current_day, time_of_day,
117                            dst_start_day, start_minutes,
118                            dst_end_day, end_minutes,
119                            length_minutes);
120      }
121
122      //! Calculates if the given local time is dst or not
123      /*! Determines if the time is really in DST or not.  Also checks for
124       *  invalid and ambiguous.
125       *  @param current_day The day to check for dst
126       *  @param time_of_day Time offset within the day to check
127       *  @param dst_start_day  Starting day of dst for the given locality
128       *  @param dst_start_offset_minutes Offset within day for dst
129       *         boundary (eg 120 for US which is 02:00:00)
130       *  @param dst_end_day    Ending day of dst for the given locality
131       *  @param dst_end_offset_minutes Offset within day given in dst for dst
132       *         boundary (eg 120 for US which is 02:00:00)
133       *  @param dst_length_minutes Length of dst adjusment (eg: 60 for US)
134       *  @retval The time is either ambiguous, invalid, in dst, or not in dst
135       */
136      static time_is_dst_result
137      local_is_dst(const date_type& current_day,
138                   const time_duration_type& time_of_day,
139                   const date_type& dst_start_day,
140                   unsigned int dst_start_offset_minutes,
141                   const date_type& dst_end_day,
142                   unsigned int dst_end_offset_minutes,
143                   long dst_length_minutes)
144      {
145        //in northern hemisphere dst is in the middle of the year
146        if (dst_start_day < dst_end_day) {
147          if ((current_day > dst_start_day) && (current_day < dst_end_day)) {
148            return is_in_dst;
149          }
150          if ((current_day < dst_start_day) || (current_day > dst_end_day)) {
151            return is_not_in_dst;
152          }
153        }
154        else {//southern hemisphere dst is at begining /end of year
155          if ((current_day < dst_start_day) && (current_day > dst_end_day)) {
156            return is_not_in_dst;
157          }
158          if ((current_day > dst_start_day) || (current_day < dst_end_day)) {
159            return is_in_dst;
160          }
161        }
162
163        if (current_day == dst_start_day) {
164          return process_local_dst_start_day(time_of_day,
165                                             dst_start_offset_minutes,
166                                             dst_length_minutes);
167        }
168     
169        if (current_day == dst_end_day) {
170          return process_local_dst_end_day(time_of_day,
171                                           dst_end_offset_minutes,
172                                           dst_length_minutes);
173        }
174        //you should never reach this statement
175        return invalid_time_label;
176      }
177
178    };
179
180
181    //! Compile-time configurable daylight savings time calculation engine
182    /* This template provides the ability to configure a daylight savings
183     * calculation at compile time covering all the cases.  Unfortunately
184     * because of the number of dimensions related to daylight savings
185     * calculation the number of parameters is high.  In addition, the
186     * start and end transition rules are complex types that specify
187     * an algorithm for calculation of the starting day and ending
188     * day of daylight savings time including the month and day
189     * specifications (eg: last sunday in October).
190     *
191     * @param date_type A type that represents dates, typically gregorian::date
192     * @param time_duration_type Used for the offset in the day calculations
193     * @param dst_traits A set of traits that define the rules of dst
194     *        calculation.  The dst_trait must include the following:
195     * start_rule_functor - Rule to calculate the starting date of a
196     *                      dst transition (eg: last_kday_of_month).
197     * start_day - static function that returns month of dst start for
198     *             start_rule_functor
199     * start_month -static function that returns day or day of week for
200     *              dst start of dst
201     * end_rule_functor - Rule to calculate the end of dst day.
202     * end_day - static fucntion that returns end day for end_rule_functor
203     * end_month - static function that returns end month for end_rule_functor
204     * 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.
205     * 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.
206     * dst_length_minutes - number of minutes that dst shifts clock
207     */
208    template<class date_type,
209             class time_duration_type,
210             class dst_traits>
211    class dst_calc_engine
212    {
213    public:
214      typedef typename date_type::year_type year_type;
215      typedef typename date_type::calendar_type calendar_type;
216      typedef dst_calculator<date_type, time_duration_type> dstcalc;
217
218      //! Calculates if the given local time is dst or not
219      /*! Determines if the time is really in DST or not.  Also checks for
220       *  invalid and ambiguous.
221       *  @retval The time is either ambiguous, invalid, in dst, or not in dst
222       */
223      static time_is_dst_result local_is_dst(const date_type& d,
224                                             const time_duration_type& td)
225      {
226
227        year_type y = d.year();
228        date_type dst_start = local_dst_start_day(y);
229        date_type dst_end   = local_dst_end_day(y);
230        return dstcalc::local_is_dst(d,td,
231                                     dst_start,
232                                     dst_traits::dst_start_offset_minutes(),
233                                     dst_end,
234                                     dst_traits::dst_end_offset_minutes(),
235                                     dst_traits::dst_shift_length_minutes());
236     
237      }
238
239      static bool is_dst_boundary_day(date_type d)
240      {
241        year_type y = d.year();
242        return ((d == local_dst_start_day(y)) ||
243                (d == local_dst_end_day(y)));
244      }
245
246      //! The time of day for the dst transition (eg: typically 01:00:00 or 02:00:00)
247      static time_duration_type dst_offset()
248      {
249        return time_duration_type(0,dst_traits::dst_shift_length_minutes(),0);
250      }
251
252      static date_type local_dst_start_day(year_type year)
253      {
254        typedef typename dst_traits::start_rule_functor start_rule;
255        start_rule start(dst_traits::start_day(),
256                         dst_traits::start_month());
257        return start.get_date(year);     
258      }
259
260      static date_type local_dst_end_day(year_type year)
261      {
262        typedef typename dst_traits::end_rule_functor end_rule;
263        end_rule end(dst_traits::end_day(),
264                     dst_traits::end_month());
265        return end.get_date(year);     
266      }
267
268
269    };
270
271    //! Depricated: Class to calculate dst boundaries for US time zones
272    /* Use dst_calc_engine instead.
273     */
274    template<class date_type_,
275             class time_duration_type_,
276             unsigned int dst_start_offset_minutes=120, //from start of day
277             short dst_length_minutes=60>  //1 hour == 60 min in US
278    class us_dst_rules
279    {
280    public:
281      typedef time_duration_type_ time_duration_type;
282      typedef date_type_ date_type;
283      typedef typename date_type::year_type year_type;
284      typedef typename date_type::calendar_type calendar_type;
285      typedef date_time::last_kday_of_month<date_type> lkday;
286      typedef date_time::first_kday_of_month<date_type> fkday;
287      typedef dst_calculator<date_type, time_duration_type> dstcalc;
288
289      //! Calculates if the given local time is dst or not
290      /*! Determines if the time is really in DST or not.  Also checks for
291       *  invalid and ambiguous.
292       *  @retval The time is either ambiguous, invalid, in dst, or not in dst
293       */
294      static time_is_dst_result local_is_dst(const date_type& d,
295                                             const time_duration_type& td)
296      {
297
298        year_type y = d.year();
299        date_type dst_start = local_dst_start_day(y);
300        date_type dst_end   = local_dst_end_day(y);
301        return dstcalc::local_is_dst(d,td,
302                                     dst_start,dst_start_offset_minutes,
303                                     dst_end, dst_start_offset_minutes,
304                                     dst_length_minutes);
305     
306      }
307
308
309      static bool is_dst_boundary_day(date_type d)
310      {
311        year_type y = d.year();
312        return ((d == local_dst_start_day(y)) ||
313                (d == local_dst_end_day(y)));
314      }
315
316      static date_type local_dst_start_day(year_type year)
317      {
318        //first sunday in april
319        fkday fsia(Sunday, gregorian::Apr);
320        return fsia.get_date(year);     
321      }
322
323      static date_type local_dst_end_day(year_type year)
324      {
325        //last sunday in october
326        lkday lsio(Sunday, gregorian::Oct);
327        return lsio.get_date(year);
328      }
329
330      static time_duration_type dst_offset()
331      {
332        return time_duration_type(0,dst_length_minutes,0);
333      }
334
335
336    };
337
338    //! Used for local time adjustments in places that don't use dst
339    template<class date_type_, class time_duration_type_>
340    class null_dst_rules
341    {
342    public:
343      typedef time_duration_type_ time_duration_type;
344      typedef date_type_ date_type;
345
346
347      //! Calculates if the given local time is dst or not
348      /*! @retval Always is_not_in_dst since this is for zones without dst
349       */
350      static time_is_dst_result local_is_dst(const date_type&,
351                                             const time_duration_type&)
352      {
353        return is_not_in_dst;
354      }
355   
356      //! Calculates if the given utc time is in dst
357      static time_is_dst_result utc_is_dst(const date_type&,
358                                           const time_duration_type&)
359      {
360        return is_not_in_dst;
361      }
362
363      static bool is_dst_boundary_day(date_type d)
364      {
365        return false;
366      }
367
368      static time_duration_type dst_offset()
369      {
370        return time_duration_type(0,0,0);
371      }
372
373    };
374
375
376  } } //namespace date_time
377
378
379
380#endif
Note: See TracBrowser for help on using the repository browser.