| 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: 2007/06/01 16:12:07 $ | 
|---|
| 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 | //! Returns nth arg as string. 1 -> "first", 2 -> "second", max is 5. | 
|---|
| 157 | BOOST_DATE_TIME_DECL const char* nth_as_str(int n); | 
|---|
| 158 |  | 
|---|
| 159 | //! Useful generator functor for finding holidays | 
|---|
| 160 | /*! Based on the idea in Cal. Calc. for finding holidays that are | 
|---|
| 161 | *  the 'first Monday of September'. When instantiated with | 
|---|
| 162 | *  'fifth' kday of month, the result will be the last kday of month | 
|---|
| 163 | *  which can be the fourth or fifth depending on the structure of | 
|---|
| 164 | *  the month. | 
|---|
| 165 | * | 
|---|
| 166 | *  The algorithm here basically guesses for the first | 
|---|
| 167 | *  day of the month.  Then finds the first day of the correct | 
|---|
| 168 | *  type.  That is, if the first of the month is a Tuesday | 
|---|
| 169 | *  and it needs Wenesday then we simply increment by a day | 
|---|
| 170 | *  and then we can add the length of a week until we get | 
|---|
| 171 | *  to the 'nth kday'.  There are probably more efficient | 
|---|
| 172 | *  algorithms based on using a mod 7, but this one works | 
|---|
| 173 | *  reasonably well for basic applications. | 
|---|
| 174 | *  \ingroup date_alg | 
|---|
| 175 | */ | 
|---|
| 176 | template<class date_type> | 
|---|
| 177 | class nth_kday_of_month : public year_based_generator<date_type> | 
|---|
| 178 | { | 
|---|
| 179 | public: | 
|---|
| 180 | typedef typename date_type::calendar_type calendar_type; | 
|---|
| 181 | typedef typename calendar_type::day_of_week_type  day_of_week_type; | 
|---|
| 182 | typedef typename calendar_type::month_type        month_type; | 
|---|
| 183 | typedef typename calendar_type::year_type         year_type; | 
|---|
| 184 | typedef typename date_type::duration_type        duration_type; | 
|---|
| 185 | enum week_num {first=1, second, third, fourth, fifth}; | 
|---|
| 186 | nth_kday_of_month(week_num week_no, | 
|---|
| 187 | day_of_week_type dow, | 
|---|
| 188 | month_type m) : | 
|---|
| 189 | month_(m), | 
|---|
| 190 | wn_(week_no), | 
|---|
| 191 | dow_(dow) | 
|---|
| 192 | {} | 
|---|
| 193 | //! Return a concrete date when provided with a year specific year. | 
|---|
| 194 | date_type get_date(year_type y) const | 
|---|
| 195 | { | 
|---|
| 196 | date_type d(y, month_, 1); //first day of month | 
|---|
| 197 | duration_type one_day(1); | 
|---|
| 198 | duration_type one_week(7); | 
|---|
| 199 | while (dow_ != d.day_of_week()) { | 
|---|
| 200 | d = d + one_day; | 
|---|
| 201 | } | 
|---|
| 202 | int week = 1; | 
|---|
| 203 | while (week < wn_) { | 
|---|
| 204 | d = d + one_week; | 
|---|
| 205 | week++; | 
|---|
| 206 | } | 
|---|
| 207 | // remove wrapping to next month behavior | 
|---|
| 208 | if(d.month() != month_) { | 
|---|
| 209 | d = d - one_week; | 
|---|
| 210 | } | 
|---|
| 211 | return d; | 
|---|
| 212 | } | 
|---|
| 213 | // added for streaming | 
|---|
| 214 | month_type month() const | 
|---|
| 215 | { | 
|---|
| 216 | return month_; | 
|---|
| 217 | } | 
|---|
| 218 | week_num nth_week() const | 
|---|
| 219 | { | 
|---|
| 220 | return wn_; | 
|---|
| 221 | } | 
|---|
| 222 | day_of_week_type day_of_week() const | 
|---|
| 223 | { | 
|---|
| 224 | return dow_; | 
|---|
| 225 | } | 
|---|
| 226 | const char* nth_week_as_str() const | 
|---|
| 227 | { | 
|---|
| 228 | return nth_as_str(wn_); | 
|---|
| 229 | } | 
|---|
| 230 | //! Returns string suitable for use in POSIX time zone string | 
|---|
| 231 | /*! Returns a string formatted as "M4.3.0" ==> 3rd Sunday in April. */ | 
|---|
| 232 | virtual std::string to_string() const | 
|---|
| 233 | { | 
|---|
| 234 | std::stringstream ss; | 
|---|
| 235 | ss << 'M' | 
|---|
| 236 | << static_cast<int>(month_) << '.' | 
|---|
| 237 | << static_cast<int>(wn_) << '.' | 
|---|
| 238 | << static_cast<int>(dow_); | 
|---|
| 239 | return ss.str(); | 
|---|
| 240 | } | 
|---|
| 241 | private: | 
|---|
| 242 | month_type month_; | 
|---|
| 243 | week_num wn_; | 
|---|
| 244 | day_of_week_type dow_; | 
|---|
| 245 | }; | 
|---|
| 246 |  | 
|---|
| 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 |  | 
|---|