1 #ifndef _DATE_TIME_ADJUST_FUNCTORS_HPP___
2 #define _DATE_TIME_ADJUST_FUNCTORS_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.txt or http://www.boost.org/LICENSE_1_0.txt)
8  * Author: Jeff Garland, Bart Garst
9  * $Date$
10  */
11 
12 #include "boost/date_time/date.hpp"
13 #include "boost/date_time/wrapping_int.hpp"
14 
15 namespace boost {
16 namespace date_time {
17 
18 
19   //! Functor to iterate a fixed number of days
20   template<class date_type>
21   class day_functor
22   {
23   public:
24     typedef typename date_type::duration_type duration_type;
day_functor(int f)25     day_functor(int f) : f_(f) {}
get_offset(const date_type &) const26     duration_type get_offset(const date_type&) const
27     {
28       return duration_type(f_);
29     }
get_neg_offset(const date_type &) const30     duration_type get_neg_offset(const date_type&) const
31     {
32       return duration_type(-f_);
33     }
34   private:
35     int f_;
36   };
37 
38 
39   //! Provides calculation to find next nth month given a date
40   /*! This adjustment function provides the logic for 'month-based'
41    *  advancement on a ymd based calendar.  The policy it uses
42    *  to handle the non existant end of month days is to back
43    *  up to the last day of the month.  Also, if the starting
44    *  date is the last day of a month, this functor will attempt
45    *  to adjust to the end of the month.
46 
47    */
48   template<class date_type>
49   class month_functor
50   {
51   public:
52     typedef typename date_type::duration_type duration_type;
53     typedef typename date_type::calendar_type cal_type;
54     typedef typename cal_type::ymd_type ymd_type;
55     typedef typename cal_type::day_type day_type;
56 
month_functor(int f)57     month_functor(int f) : f_(f), origDayOfMonth_(0) {}
get_offset(const date_type & d) const58     duration_type get_offset(const date_type& d) const
59     {
60       ymd_type ymd(d.year_month_day());
61       if (origDayOfMonth_ == 0) {
62         origDayOfMonth_ = ymd.day;
63         day_type endOfMonthDay(cal_type::end_of_month_day(ymd.year,ymd.month));
64         if (endOfMonthDay == ymd.day) {
65           origDayOfMonth_ = -1; //force the value to the end of month
66         }
67       }
68       typedef date_time::wrapping_int2<short,1,12> wrap_int2;
69       wrap_int2 wi(ymd.month);
70       //calc the year wrap around, add() returns 0 or 1 if wrapped
71       const typename ymd_type::year_type year(static_cast<typename ymd_type::year_type::value_type>(ymd.year + wi.add(f_)));
72 //       std::cout << "trace wi: " << wi.as_int() << std::endl;
73 //       std::cout << "trace year: " << year << std::endl;
74       //find the last day for the new month
75       day_type resultingEndOfMonthDay(cal_type::end_of_month_day(year, wi.as_int()));
76       //original was the end of month -- force to last day of month
77       if (origDayOfMonth_ == -1) {
78         return date_type(year, wi.as_int(), resultingEndOfMonthDay) - d;
79       }
80       day_type dayOfMonth = origDayOfMonth_;
81       if (dayOfMonth > resultingEndOfMonthDay) {
82         dayOfMonth = resultingEndOfMonthDay;
83       }
84       return date_type(year, wi.as_int(), dayOfMonth) - d;
85     }
86     //! Returns a negative duration_type
get_neg_offset(const date_type & d) const87     duration_type get_neg_offset(const date_type& d) const
88     {
89       ymd_type ymd(d.year_month_day());
90       if (origDayOfMonth_ == 0) {
91         origDayOfMonth_ = ymd.day;
92         day_type endOfMonthDay(cal_type::end_of_month_day(ymd.year,ymd.month));
93         if (endOfMonthDay == ymd.day) {
94           origDayOfMonth_ = -1; //force the value to the end of month
95         }
96       }
97       typedef date_time::wrapping_int2<short,1,12> wrap_int2;
98       wrap_int2 wi(ymd.month);
99       //calc the year wrap around, add() returns 0 or 1 if wrapped
100       const typename ymd_type::year_type year(static_cast<typename ymd_type::year_type::value_type>(ymd.year + wi.subtract(f_)));
101       //find the last day for the new month
102       day_type resultingEndOfMonthDay(cal_type::end_of_month_day(year, wi.as_int()));
103       //original was the end of month -- force to last day of month
104       if (origDayOfMonth_ == -1) {
105         return date_type(year, wi.as_int(), resultingEndOfMonthDay) - d;
106       }
107       day_type dayOfMonth = origDayOfMonth_;
108       if (dayOfMonth > resultingEndOfMonthDay) {
109         dayOfMonth = resultingEndOfMonthDay;
110       }
111       return date_type(year, wi.as_int(), dayOfMonth) - d;
112     }
113   private:
114     int f_;
115     mutable short origDayOfMonth_;
116   };
117 
118 
119   //! Functor to iterate a over weeks
120   template<class date_type>
121   class week_functor
122   {
123   public:
124     typedef typename date_type::duration_type duration_type;
125     typedef typename date_type::calendar_type calendar_type;
week_functor(int f)126     week_functor(int f) : f_(f) {}
get_offset(const date_type &) const127     duration_type get_offset(const date_type&) const
128     {
129       return duration_type(f_*static_cast<int>(calendar_type::days_in_week()));
130     }
get_neg_offset(const date_type &) const131     duration_type get_neg_offset(const date_type&) const
132     {
133       return duration_type(-f_*static_cast<int>(calendar_type::days_in_week()));
134     }
135   private:
136     int f_;
137   };
138 
139   //! Functor to iterate by a year adjusting for leap years
140   template<class date_type>
141   class year_functor
142   {
143   public:
144     //typedef typename date_type::year_type year_type;
145     typedef typename date_type::duration_type duration_type;
year_functor(int f)146     year_functor(int f) : _mf(f * 12) {}
get_offset(const date_type & d) const147     duration_type get_offset(const date_type& d) const
148     {
149       return _mf.get_offset(d);
150     }
get_neg_offset(const date_type & d) const151     duration_type get_neg_offset(const date_type& d) const
152     {
153       return _mf.get_neg_offset(d);
154     }
155   private:
156     month_functor<date_type> _mf;
157   };
158 
159 
160 } }//namespace date_time
161 
162 
163 #endif
164 
165