| 1 | #ifndef DATE_TIME_DATE_GENERATORS_HPP__ | 
|---|
| 2 | #define DATE_TIME_DATE_GENERATORS_HPP__ | 
|---|
| 3 |  | 
|---|
| 4 | /* Copyright (c) 2002,2003,2005 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: 2005/04/17 21:48:19 $ | 
|---|
| 10 |  */ | 
|---|
| 11 |  | 
|---|
| 12 | /*! @file date_generators.hpp | 
|---|
| 13 |   Definition and implementation of date algorithm templates | 
|---|
| 14 | */ | 
|---|
| 15 | #include <stdexcept> | 
|---|
| 16 | #include <sstream> | 
|---|
| 17 | #include "boost/date_time/date.hpp" | 
|---|
| 18 | #include "boost/date_time/compiler_config.hpp" | 
|---|
| 19 |  | 
|---|
| 20 | namespace boost { | 
|---|
| 21 | namespace date_time { | 
|---|
| 22 |  | 
|---|
| 23 |   //! Base class for all generators that take a year and produce a date. | 
|---|
| 24 |   /*! This class is a base class for polymorphic function objects that take | 
|---|
| 25 |     a year and produce a concrete date. | 
|---|
| 26 |     @param date_type The type representing a date.  This type must | 
|---|
| 27 |     export a calender_type which defines a year_type. | 
|---|
| 28 |   */ | 
|---|
| 29 |   template<class date_type> | 
|---|
| 30 |   class year_based_generator | 
|---|
| 31 |   { | 
|---|
| 32 |   public: | 
|---|
| 33 |     typedef typename date_type::calendar_type calendar_type; | 
|---|
| 34 |     typedef typename calendar_type::year_type        year_type; | 
|---|
| 35 |     year_based_generator() {}; | 
|---|
| 36 |     virtual ~year_based_generator() {}; | 
|---|
| 37 |     virtual date_type get_date(year_type y) const = 0; | 
|---|
| 38 |     //! Returns a string for use in a POSIX time_zone string | 
|---|
| 39 |     virtual std::string to_string() const =0; | 
|---|
| 40 |   }; | 
|---|
| 41 |    | 
|---|
| 42 |   //! Generates a date by applying the year to the given month and day. | 
|---|
| 43 |   /*! | 
|---|
| 44 |     Example usage:  | 
|---|
| 45 |     @code | 
|---|
| 46 |     partial_date pd(1, Jan); | 
|---|
| 47 |     partial_date pd2(70); | 
|---|
| 48 |     date d = pd.get_date(2002); //2002-Jan-01 | 
|---|
| 49 |     date d2 = pd2.get_date(2002); //2002-Mar-10 | 
|---|
| 50 |     @endcode | 
|---|
| 51 |     \ingroup date_alg | 
|---|
| 52 |   */ | 
|---|
| 53 |   template<class date_type> | 
|---|
| 54 |  class partial_date : public year_based_generator<date_type> | 
|---|
| 55 |  { | 
|---|
| 56 |  public: | 
|---|
| 57 |    typedef typename date_type::calendar_type calendar_type; | 
|---|
| 58 |    typedef typename calendar_type::day_type         day_type; | 
|---|
| 59 |    typedef typename calendar_type::month_type       month_type; | 
|---|
| 60 |    typedef typename calendar_type::year_type        year_type; | 
|---|
| 61 |    typedef typename date_type::duration_type        duration_type; | 
|---|
| 62 |    typedef typename duration_type::duration_rep     duration_rep; | 
|---|
| 63 |    partial_date(day_type d, month_type m) : | 
|---|
| 64 |      day_(d), | 
|---|
| 65 |      month_(m) | 
|---|
| 66 |    {} | 
|---|
| 67 |    //! Partial date created from number of days into year. Range 1-366 | 
|---|
| 68 |    /*! Allowable values range from 1 to 366. 1=Jan1, 366=Dec31. If argument | 
|---|
| 69 |     * exceeds range, partial_date will be created with closest in-range value. | 
|---|
| 70 |     * 60 will always be Feb29, if get_date() is called with a non-leap year | 
|---|
| 71 |     * an exception will be thrown */ | 
|---|
| 72 |    partial_date(duration_rep days) : | 
|---|
| 73 |      day_(1), // default values | 
|---|
| 74 |      month_(1) | 
|---|
| 75 |    { | 
|---|
| 76 |      date_type d1(2000,1,1); | 
|---|
| 77 |      if(days > 1) { | 
|---|
| 78 |        if(days > 366) // prevents wrapping | 
|---|
| 79 |        { | 
|---|
| 80 |          days = 366; | 
|---|
| 81 |        } | 
|---|
| 82 |        days = days - 1; | 
|---|
| 83 |        duration_type dd(days); | 
|---|
| 84 |        d1 = d1 + dd; | 
|---|
| 85 |      } | 
|---|
| 86 |      day_ = d1.day(); | 
|---|
| 87 |      month_ = d1.month(); | 
|---|
| 88 |    } | 
|---|
| 89 |    //! Return a concrete date when provided with a year specific year. | 
|---|
| 90 |    /*! Will throw an 'invalid_argument' exception if a partial_date object, | 
|---|
| 91 |     * instantiated with Feb-29, has get_date called with a non-leap year. | 
|---|
| 92 |     * Example: | 
|---|
| 93 |     * @code | 
|---|
| 94 |     * partial_date pd(29, Feb); | 
|---|
| 95 |     * pd.get_date(2003); // throws invalid_argument exception | 
|---|
| 96 |     * pg.get_date(2000); // returns 2000-2-29 | 
|---|
| 97 |     * @endcode | 
|---|
| 98 |          */ | 
|---|
| 99 |    date_type get_date(year_type y) const | 
|---|
| 100 |    { | 
|---|
| 101 |      if((day_ == 29) && (month_ == 2) && !(calendar_type::is_leap_year(y))) { | 
|---|
| 102 |        std::stringstream ss(""); | 
|---|
| 103 |        ss << "No Feb 29th in given year of " << y << "."; | 
|---|
| 104 |        throw std::invalid_argument(ss.str()); | 
|---|
| 105 |        //return date_type(1,1,1); // should never reach | 
|---|
| 106 |      } else { | 
|---|
| 107 |        return date_type(y, month_, day_); | 
|---|
| 108 |      } | 
|---|
| 109 |    } | 
|---|
| 110 |    date_type operator()(year_type y) const | 
|---|
| 111 |    { | 
|---|
| 112 |      return get_date(y); | 
|---|
| 113 |      //return date_type(y, month_, day_); | 
|---|
| 114 |    } | 
|---|
| 115 |    bool operator==(const partial_date& rhs) const | 
|---|
| 116 |    { | 
|---|
| 117 |      return (month_ == rhs.month_) && (day_ == rhs.day_); | 
|---|
| 118 |    } | 
|---|
| 119 |    bool operator<(const partial_date& rhs) const | 
|---|
| 120 |    { | 
|---|
| 121 |      if (month_ < rhs.month_) return true; | 
|---|
| 122 |      if (month_ > rhs.month_) return false; | 
|---|
| 123 |      //months are equal | 
|---|
| 124 |      return (day_ < rhs.day_); | 
|---|
| 125 |    } | 
|---|
| 126 |     | 
|---|
| 127 |    // added for streaming purposes | 
|---|
| 128 |    month_type month() const  | 
|---|
| 129 |    { | 
|---|
| 130 |      return month_; | 
|---|
| 131 |    } | 
|---|
| 132 |    day_type day() const | 
|---|
| 133 |    { | 
|---|
| 134 |      return day_; | 
|---|
| 135 |    } | 
|---|
| 136 |  | 
|---|
| 137 |    //! Returns string suitable for use in POSIX time zone string | 
|---|
| 138 |    /*! Returns string formatted with up to 3 digits:  | 
|---|
| 139 |     * Jan-01 == "0"  | 
|---|
| 140 |     * Feb-29 == "58" | 
|---|
| 141 |     * Dec-31 == "365" */ | 
|---|
| 142 |    virtual std::string to_string() const | 
|---|
| 143 |    { | 
|---|
| 144 |      std::stringstream ss; | 
|---|
| 145 |      date_type d(2004, month_, day_); | 
|---|
| 146 |      unsigned short c = d.day_of_year();      | 
|---|
| 147 |      c--; // numbered 0-365 while day_of_year is 1 based... | 
|---|
| 148 |      ss << c; | 
|---|
| 149 |      return ss.str(); | 
|---|
| 150 |    } | 
|---|
| 151 |  private: | 
|---|
| 152 |    day_type day_; | 
|---|
| 153 |    month_type month_; | 
|---|
| 154 |  }; | 
|---|
| 155 |  | 
|---|
| 156 |  | 
|---|
| 157 |   //! Useful generator functor for finding holidays | 
|---|
| 158 |   /*! Based on the idea in Cal. Calc. for finding holidays that are | 
|---|
| 159 |    *  the 'first Monday of September'. When instantiated with | 
|---|
| 160 |    *  'fifth' kday of month, the result will be the last kday of month | 
|---|
| 161 |    *  which can be the fourth or fifth depending on the structure of  | 
|---|
| 162 |    *  the month. | 
|---|
| 163 |    * | 
|---|
| 164 |    *  The algorithm here basically guesses for the first | 
|---|
| 165 |    *  day of the month.  Then finds the first day of the correct | 
|---|
| 166 |    *  type.  That is, if the first of the month is a Tuesday | 
|---|
| 167 |    *  and it needs Wenesday then we simply increment by a day | 
|---|
| 168 |    *  and then we can add the length of a week until we get | 
|---|
| 169 |    *  to the 'nth kday'.  There are probably more efficient  | 
|---|
| 170 |    *  algorithms based on using a mod 7, but this one works  | 
|---|
| 171 |    *  reasonably well for basic applications. | 
|---|
| 172 |    *  \ingroup date_alg | 
|---|
| 173 |    */ | 
|---|
| 174 |   template<class date_type> | 
|---|
| 175 |   class nth_kday_of_month : public year_based_generator<date_type> | 
|---|
| 176 |   { | 
|---|
| 177 |   public: | 
|---|
| 178 |     typedef typename date_type::calendar_type calendar_type; | 
|---|
| 179 |     typedef typename calendar_type::day_of_week_type  day_of_week_type; | 
|---|
| 180 |     typedef typename calendar_type::month_type        month_type; | 
|---|
| 181 |     typedef typename calendar_type::year_type         year_type; | 
|---|
| 182 |     typedef typename date_type::duration_type        duration_type; | 
|---|
| 183 |     enum week_num {first=1, second, third, fourth, fifth}; | 
|---|
| 184 |     nth_kday_of_month(week_num week_no, | 
|---|
| 185 |                       day_of_week_type dow, | 
|---|
| 186 |                       month_type m) : | 
|---|
| 187 |       month_(m), | 
|---|
| 188 |       wn_(week_no), | 
|---|
| 189 |       dow_(dow) | 
|---|
| 190 |     {} | 
|---|
| 191 |     //! Return a concrete date when provided with a year specific year. | 
|---|
| 192 |     date_type get_date(year_type y) const | 
|---|
| 193 |     { | 
|---|
| 194 |       date_type d(y, month_, 1); //first day of month | 
|---|
| 195 |       duration_type one_day(1); | 
|---|
| 196 |       duration_type one_week(7); | 
|---|
| 197 |       while (dow_ != d.day_of_week()) { | 
|---|
| 198 |         d = d + one_day; | 
|---|
| 199 |       } | 
|---|
| 200 |       int week = 1; | 
|---|
| 201 |       while (week < wn_) { | 
|---|
| 202 |         d = d + one_week; | 
|---|
| 203 |         week++; | 
|---|
| 204 |       } | 
|---|
| 205 |       // remove wrapping to next month behavior | 
|---|
| 206 |       if(d.month() != month_) { | 
|---|
| 207 |         d = d - one_week; | 
|---|
| 208 |       } | 
|---|
| 209 |       return d; | 
|---|
| 210 |     } | 
|---|
| 211 |     // added for streaming | 
|---|
| 212 |     month_type month() const | 
|---|
| 213 |     { | 
|---|
| 214 |       return month_; | 
|---|
| 215 |     } | 
|---|
| 216 |     week_num nth_week() const | 
|---|
| 217 |     { | 
|---|
| 218 |       return wn_; | 
|---|
| 219 |     } | 
|---|
| 220 |     day_of_week_type day_of_week() const | 
|---|
| 221 |     { | 
|---|
| 222 |       return dow_; | 
|---|
| 223 |     } | 
|---|
| 224 |     const char* nth_week_as_str() const | 
|---|
| 225 |     { | 
|---|
| 226 |       return nth_as_str(wn_); | 
|---|
| 227 |     } | 
|---|
| 228 |     //! Returns string suitable for use in POSIX time zone string | 
|---|
| 229 |     /*! Returns a string formatted as "M4.3.0" ==> 3rd Sunday in April. */ | 
|---|
| 230 |     virtual std::string to_string() const | 
|---|
| 231 |     { | 
|---|
| 232 |      std::stringstream ss; | 
|---|
| 233 |      ss << 'M'  | 
|---|
| 234 |        << static_cast<int>(month_) << '.' | 
|---|
| 235 |        << static_cast<int>(wn_) << '.' | 
|---|
| 236 |        << static_cast<int>(dow_); | 
|---|
| 237 |      return ss.str(); | 
|---|
| 238 |     } | 
|---|
| 239 |   private: | 
|---|
| 240 |     month_type month_; | 
|---|
| 241 |     week_num wn_; | 
|---|
| 242 |     day_of_week_type dow_; | 
|---|
| 243 |   }; | 
|---|
| 244 |    | 
|---|
| 245 |   //! Returns nth arg as string. 1 -> "first", 2 -> "second", max is 5. | 
|---|
| 246 |   BOOST_DATE_TIME_DECL const char* nth_as_str(int n); | 
|---|
| 247 |  | 
|---|
| 248 |   //! Useful generator functor for finding holidays and daylight savings | 
|---|
| 249 |   /*! Similar to nth_kday_of_month, but requires less paramters | 
|---|
| 250 |    *  \ingroup date_alg | 
|---|
| 251 |    */ | 
|---|
| 252 |   template<class date_type> | 
|---|
| 253 |   class first_kday_of_month : public year_based_generator<date_type> | 
|---|
| 254 |   { | 
|---|
| 255 |   public: | 
|---|
| 256 |     typedef typename date_type::calendar_type calendar_type; | 
|---|
| 257 |     typedef typename calendar_type::day_of_week_type  day_of_week_type; | 
|---|
| 258 |     typedef typename calendar_type::month_type        month_type; | 
|---|
| 259 |     typedef typename calendar_type::year_type         year_type; | 
|---|
| 260 |     typedef typename date_type::duration_type        duration_type; | 
|---|
| 261 |     //!Specify the first 'Sunday' in 'April' spec | 
|---|
| 262 |     /*!@param dow The day of week, eg: Sunday, Monday, etc | 
|---|
| 263 |      * @param m The month of the year, eg: Jan, Feb, Mar, etc | 
|---|
| 264 |      */ | 
|---|
| 265 |     first_kday_of_month(day_of_week_type dow, month_type m) : | 
|---|
| 266 |       month_(m), | 
|---|
| 267 |       dow_(dow) | 
|---|
| 268 |     {} | 
|---|
| 269 |     //! Return a concrete date when provided with a year specific year. | 
|---|
| 270 |     date_type get_date(year_type year) const | 
|---|
| 271 |     { | 
|---|
| 272 |       date_type d(year, month_,1); | 
|---|
| 273 |       duration_type one_day(1); | 
|---|
| 274 |       while (dow_ != d.day_of_week()) { | 
|---|
| 275 |         d = d + one_day; | 
|---|
| 276 |       } | 
|---|
| 277 |       return d; | 
|---|
| 278 |         } | 
|---|
| 279 |     // added for streaming | 
|---|
| 280 |     month_type month() const | 
|---|
| 281 |     { | 
|---|
| 282 |       return month_; | 
|---|
| 283 |     } | 
|---|
| 284 |     day_of_week_type day_of_week() const | 
|---|
| 285 |     { | 
|---|
| 286 |       return dow_; | 
|---|
| 287 |     } | 
|---|
| 288 |     //! Returns string suitable for use in POSIX time zone string | 
|---|
| 289 |     /*! Returns a string formatted as "M4.1.0" ==> 1st Sunday in April. */ | 
|---|
| 290 |     virtual std::string to_string() const | 
|---|
| 291 |     { | 
|---|
| 292 |      std::stringstream ss; | 
|---|
| 293 |      ss << 'M'  | 
|---|
| 294 |        << static_cast<int>(month_) << '.' | 
|---|
| 295 |        << 1 << '.' | 
|---|
| 296 |        << static_cast<int>(dow_); | 
|---|
| 297 |      return ss.str(); | 
|---|
| 298 |     } | 
|---|
| 299 |   private: | 
|---|
| 300 |     month_type month_; | 
|---|
| 301 |     day_of_week_type dow_; | 
|---|
| 302 |   }; | 
|---|
| 303 |    | 
|---|
| 304 |    | 
|---|
| 305 |    | 
|---|
| 306 |   //! Calculate something like Last Sunday of January | 
|---|
| 307 |   /*! Useful generator functor for finding holidays and daylight savings | 
|---|
| 308 |    *  Get the last day of the month and then calculate the difference | 
|---|
| 309 |    *  to the last previous day. | 
|---|
| 310 |    *  @param date_type A date class that exports day_of_week, month_type, etc. | 
|---|
| 311 |    *  \ingroup date_alg | 
|---|
| 312 |    */ | 
|---|
| 313 |   template<class date_type> | 
|---|
| 314 |   class last_kday_of_month : public year_based_generator<date_type> | 
|---|
| 315 |   { | 
|---|
| 316 |   public: | 
|---|
| 317 |     typedef typename date_type::calendar_type calendar_type; | 
|---|
| 318 |     typedef typename calendar_type::day_of_week_type  day_of_week_type; | 
|---|
| 319 |     typedef typename calendar_type::month_type        month_type; | 
|---|
| 320 |     typedef typename calendar_type::year_type         year_type; | 
|---|
| 321 |     typedef typename date_type::duration_type        duration_type; | 
|---|
| 322 |     //!Specify the date spec like last 'Sunday' in 'April' spec | 
|---|
| 323 |     /*!@param dow The day of week, eg: Sunday, Monday, etc | 
|---|
| 324 |      * @param m The month of the year, eg: Jan, Feb, Mar, etc | 
|---|
| 325 |      */ | 
|---|
| 326 |     last_kday_of_month(day_of_week_type dow, month_type m) : | 
|---|
| 327 |       month_(m), | 
|---|
| 328 |       dow_(dow) | 
|---|
| 329 |     {} | 
|---|
| 330 |     //! Return a concrete date when provided with a year specific year. | 
|---|
| 331 |     date_type get_date(year_type year) const | 
|---|
| 332 |     { | 
|---|
| 333 |       date_type d(year, month_, calendar_type::end_of_month_day(year,month_)); | 
|---|
| 334 |       duration_type one_day(1); | 
|---|
| 335 |       while (dow_ != d.day_of_week()) { | 
|---|
| 336 |         d = d - one_day; | 
|---|
| 337 |       } | 
|---|
| 338 |       return d; | 
|---|
| 339 |     } | 
|---|
| 340 |     // added for streaming | 
|---|
| 341 |     month_type month() const | 
|---|
| 342 |     { | 
|---|
| 343 |       return month_; | 
|---|
| 344 |     } | 
|---|
| 345 |     day_of_week_type day_of_week() const | 
|---|
| 346 |     { | 
|---|
| 347 |       return dow_; | 
|---|
| 348 |     } | 
|---|
| 349 |     //! Returns string suitable for use in POSIX time zone string | 
|---|
| 350 |     /*! Returns a string formatted as "M4.5.0" ==> last Sunday in April. */ | 
|---|
| 351 |     virtual std::string to_string() const | 
|---|
| 352 |     { | 
|---|
| 353 |       std::stringstream ss; | 
|---|
| 354 |       ss << 'M'  | 
|---|
| 355 |          << static_cast<int>(month_) << '.' | 
|---|
| 356 |          << 5 << '.' | 
|---|
| 357 |          << static_cast<int>(dow_); | 
|---|
| 358 |       return ss.str(); | 
|---|
| 359 |     } | 
|---|
| 360 |   private: | 
|---|
| 361 |     month_type month_; | 
|---|
| 362 |     day_of_week_type dow_; | 
|---|
| 363 |    }; | 
|---|
| 364 |    | 
|---|
| 365 |    | 
|---|
| 366 |   //! Calculate something like "First Sunday after Jan 1,2002 | 
|---|
| 367 |   /*! Date generator that takes a date and finds kday after | 
|---|
| 368 |    *@code | 
|---|
| 369 |      typedef boost::date_time::first_kday_after<date> firstkdayafter; | 
|---|
| 370 |      firstkdayafter fkaf(Monday); | 
|---|
| 371 |      fkaf.get_date(date(2002,Feb,1)); | 
|---|
| 372 |    @endcode | 
|---|
| 373 |    *  \ingroup date_alg | 
|---|
| 374 |    */ | 
|---|
| 375 |   template<class date_type> | 
|---|
| 376 |   class first_kday_after | 
|---|
| 377 |   { | 
|---|
| 378 |   public: | 
|---|
| 379 |     typedef typename date_type::calendar_type calendar_type; | 
|---|
| 380 |     typedef typename calendar_type::day_of_week_type day_of_week_type; | 
|---|
| 381 |     typedef typename date_type::duration_type        duration_type; | 
|---|
| 382 |     first_kday_after(day_of_week_type dow) : | 
|---|
| 383 |       dow_(dow) | 
|---|
| 384 |     {} | 
|---|
| 385 |     //! Return next kday given. | 
|---|
| 386 |     date_type get_date(date_type start_day) const | 
|---|
| 387 |     { | 
|---|
| 388 |       duration_type one_day(1); | 
|---|
| 389 |       date_type d = start_day + one_day; | 
|---|
| 390 |       while (dow_ != d.day_of_week()) { | 
|---|
| 391 |         d = d + one_day; | 
|---|
| 392 |       } | 
|---|
| 393 |       return d; | 
|---|
| 394 |     } | 
|---|
| 395 |     // added for streaming | 
|---|
| 396 |     day_of_week_type day_of_week() const | 
|---|
| 397 |     { | 
|---|
| 398 |       return dow_; | 
|---|
| 399 |     } | 
|---|
| 400 |   private: | 
|---|
| 401 |     day_of_week_type dow_; | 
|---|
| 402 |   }; | 
|---|
| 403 |    | 
|---|
| 404 |   //! Calculate something like "First Sunday before Jan 1,2002 | 
|---|
| 405 |   /*! Date generator that takes a date and finds kday after | 
|---|
| 406 |    *@code | 
|---|
| 407 |      typedef boost::date_time::first_kday_before<date> firstkdaybefore; | 
|---|
| 408 |      firstkdaybefore fkbf(Monday); | 
|---|
| 409 |      fkbf.get_date(date(2002,Feb,1)); | 
|---|
| 410 |    @endcode | 
|---|
| 411 |    *  \ingroup date_alg | 
|---|
| 412 |    */ | 
|---|
| 413 |   template<class date_type> | 
|---|
| 414 |   class first_kday_before | 
|---|
| 415 |   { | 
|---|
| 416 |   public: | 
|---|
| 417 |     typedef typename date_type::calendar_type calendar_type; | 
|---|
| 418 |     typedef typename calendar_type::day_of_week_type day_of_week_type; | 
|---|
| 419 |     typedef typename date_type::duration_type        duration_type; | 
|---|
| 420 |     first_kday_before(day_of_week_type dow) : | 
|---|
| 421 |       dow_(dow) | 
|---|
| 422 |     {} | 
|---|
| 423 |     //! Return next kday given. | 
|---|
| 424 |     date_type get_date(date_type start_day) const | 
|---|
| 425 |     { | 
|---|
| 426 |       duration_type one_day(1); | 
|---|
| 427 |       date_type d = start_day - one_day; | 
|---|
| 428 |       while (dow_ != d.day_of_week()) { | 
|---|
| 429 |         d = d - one_day; | 
|---|
| 430 |       } | 
|---|
| 431 |       return d; | 
|---|
| 432 |     } | 
|---|
| 433 |     // added for streaming | 
|---|
| 434 |     day_of_week_type day_of_week() const | 
|---|
| 435 |     { | 
|---|
| 436 |       return dow_; | 
|---|
| 437 |     } | 
|---|
| 438 |   private: | 
|---|
| 439 |     day_of_week_type dow_; | 
|---|
| 440 |   }; | 
|---|
| 441 |    | 
|---|
| 442 |   //! Calculates the number of days until the next weekday | 
|---|
| 443 |   /*! Calculates the number of days until the next weekday. | 
|---|
| 444 |    * If the date given falls on a Sunday and the given weekday  | 
|---|
| 445 |    * is Tuesday the result will be 2 days */ | 
|---|
| 446 |   template<typename date_type, class weekday_type> | 
|---|
| 447 |   inline | 
|---|
| 448 |   typename date_type::duration_type days_until_weekday(const date_type& d, const weekday_type& wd) | 
|---|
| 449 |   { | 
|---|
| 450 |     typedef typename date_type::duration_type duration_type; | 
|---|
| 451 |     duration_type wks(0); | 
|---|
| 452 |     duration_type dd(wd.as_number() - d.day_of_week().as_number()); | 
|---|
| 453 |     if(dd.is_negative()){ | 
|---|
| 454 |       wks = duration_type(7); | 
|---|
| 455 |     } | 
|---|
| 456 |     return dd + wks; | 
|---|
| 457 |   } | 
|---|
| 458 |  | 
|---|
| 459 |   //! Calculates the number of days since the previous weekday | 
|---|
| 460 |   /*! Calculates the number of days since the previous weekday | 
|---|
| 461 |    * If the date given falls on a Sunday and the given weekday  | 
|---|
| 462 |    * is Tuesday the result will be 5 days. The answer will be a positive  | 
|---|
| 463 |    * number because Tuesday is 5 days before Sunday, not -5 days before. */ | 
|---|
| 464 |   template<typename date_type, class weekday_type> | 
|---|
| 465 |   inline | 
|---|
| 466 |   typename date_type::duration_type days_before_weekday(const date_type& d, const weekday_type& wd) | 
|---|
| 467 |   { | 
|---|
| 468 |     typedef typename date_type::duration_type duration_type; | 
|---|
| 469 |     duration_type wks(0); | 
|---|
| 470 |     duration_type dd(wd.as_number() - d.day_of_week().as_number()); | 
|---|
| 471 |     if(dd.days() > 0){ | 
|---|
| 472 |       wks = duration_type(7); | 
|---|
| 473 |     } | 
|---|
| 474 |     // we want a number of days, not an offset. The value returned must | 
|---|
| 475 |     // be zero or larger. | 
|---|
| 476 |     return (-dd + wks); | 
|---|
| 477 |   } | 
|---|
| 478 |  | 
|---|
| 479 |   //! Generates a date object representing the date of the following weekday from the given date | 
|---|
| 480 |   /*! Generates a date object representing the date of the following  | 
|---|
| 481 |    * weekday from the given date. If the date given is 2004-May-9  | 
|---|
| 482 |    * (a Sunday) and the given weekday is Tuesday then the resulting date  | 
|---|
| 483 |    * will be 2004-May-11. */ | 
|---|
| 484 |   template<class date_type, class weekday_type> | 
|---|
| 485 |   inline | 
|---|
| 486 |   date_type next_weekday(const date_type& d, const weekday_type& wd) | 
|---|
| 487 |   { | 
|---|
| 488 |     return d + days_until_weekday(d, wd); | 
|---|
| 489 |   } | 
|---|
| 490 |  | 
|---|
| 491 |   //! Generates a date object representing the date of the previous weekday from the given date | 
|---|
| 492 |   /*! Generates a date object representing the date of the previous  | 
|---|
| 493 |    * weekday from the given date. If the date given is 2004-May-9  | 
|---|
| 494 |    * (a Sunday) and the given weekday is Tuesday then the resulting date  | 
|---|
| 495 |    * will be 2004-May-4. */ | 
|---|
| 496 |   template<class date_type, class weekday_type> | 
|---|
| 497 |   inline | 
|---|
| 498 |   date_type previous_weekday(const date_type& d, const weekday_type& wd) | 
|---|
| 499 |   { | 
|---|
| 500 |     return d - days_before_weekday(d, wd); | 
|---|
| 501 |   } | 
|---|
| 502 |  | 
|---|
| 503 | } } //namespace date_time | 
|---|
| 504 |  | 
|---|
| 505 |  | 
|---|
| 506 |  | 
|---|
| 507 |  | 
|---|
| 508 | #endif | 
|---|
| 509 |  | 
|---|