source: XIOS/dev/dev_olga/src/extern/boost/include/boost/date_time/date_generators.hpp @ 1022

Last change on this file since 1022 was 1022, checked in by mhnguyen, 7 years ago
File size: 15.9 KB
Line 
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.txt or http://www.boost.org/LICENSE_1_0.txt)
8 * Author: Jeff Garland, Bart Garst
9 * $Date: 2008-11-12 14:37:53 -0500 (Wed, 12 Nov 2008) $
10 */
11
12/*! @file date_generators.hpp
13  Definition and implementation of date algorithm templates
14*/
15
16#include <stdexcept>
17#include <sstream>
18#include <boost/throw_exception.hpp>
19#include <boost/date_time/date.hpp>
20#include <boost/date_time/compiler_config.hpp>
21
22namespace boost {
23namespace date_time {
24
25  //! Base class for all generators that take a year and produce a date.
26  /*! This class is a base class for polymorphic function objects that take
27    a year and produce a concrete date.
28    @param date_type The type representing a date.  This type must
29    export a calender_type which defines a year_type.
30  */
31  template<class date_type>
32  class year_based_generator
33  {
34  public:
35    typedef typename date_type::calendar_type calendar_type;
36    typedef typename calendar_type::year_type        year_type;
37    year_based_generator() {};
38    virtual ~year_based_generator() {};
39    virtual date_type get_date(year_type y) const = 0;
40    //! Returns a string for use in a POSIX time_zone string
41    virtual std::string to_string() const =0;
42  };
43 
44  //! Generates a date by applying the year to the given month and day.
45  /*!
46    Example usage:
47    @code
48    partial_date pd(1, Jan);
49    partial_date pd2(70);
50    date d = pd.get_date(2002); //2002-Jan-01
51    date d2 = pd2.get_date(2002); //2002-Mar-10
52    @endcode
53    \ingroup date_alg
54  */
55  template<class date_type>
56 class partial_date : public year_based_generator<date_type>
57 {
58 public:
59   typedef typename date_type::calendar_type calendar_type;
60   typedef typename calendar_type::day_type         day_type;
61   typedef typename calendar_type::month_type       month_type;
62   typedef typename calendar_type::year_type        year_type;
63   typedef typename date_type::duration_type        duration_type;
64   typedef typename duration_type::duration_rep     duration_rep;
65   partial_date(day_type d, month_type m) :
66     day_(d),
67     month_(m)
68   {}
69   //! Partial date created from number of days into year. Range 1-366
70   /*! Allowable values range from 1 to 366. 1=Jan1, 366=Dec31. If argument
71    * exceeds range, partial_date will be created with closest in-range value.
72    * 60 will always be Feb29, if get_date() is called with a non-leap year
73    * an exception will be thrown */
74   partial_date(duration_rep days) :
75     day_(1), // default values
76     month_(1)
77   {
78     date_type d1(2000,1,1);
79     if(days > 1) {
80       if(days > 366) // prevents wrapping
81       {
82         days = 366;
83       }
84       days = days - 1;
85       duration_type dd(days);
86       d1 = d1 + dd;
87     }
88     day_ = d1.day();
89     month_ = d1.month();
90   }
91   //! Return a concrete date when provided with a year specific year.
92   /*! Will throw an 'invalid_argument' exception if a partial_date object,
93    * instantiated with Feb-29, has get_date called with a non-leap year.
94    * Example:
95    * @code
96    * partial_date pd(29, Feb);
97    * pd.get_date(2003); // throws invalid_argument exception
98    * pg.get_date(2000); // returns 2000-2-29
99    * @endcode
100         */
101   date_type get_date(year_type y) const
102   {
103     if((day_ == 29) && (month_ == 2) && !(calendar_type::is_leap_year(y))) {
104       std::ostringstream ss;
105       ss << "No Feb 29th in given year of " << y << ".";
106       boost::throw_exception(std::invalid_argument(ss.str()));
107     }
108     return date_type(y, month_, day_);
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::ostringstream 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  //! Returns nth arg as string. 1 -> "first", 2 -> "second", max is 5.
158  BOOST_DATE_TIME_DECL const char* nth_as_str(int n);
159
160  //! Useful generator functor for finding holidays
161  /*! Based on the idea in Cal. Calc. for finding holidays that are
162   *  the 'first Monday of September'. When instantiated with
163   *  'fifth' kday of month, the result will be the last kday of month
164   *  which can be the fourth or fifth depending on the structure of
165   *  the month.
166   *
167   *  The algorithm here basically guesses for the first
168   *  day of the month.  Then finds the first day of the correct
169   *  type.  That is, if the first of the month is a Tuesday
170   *  and it needs Wenesday then we simply increment by a day
171   *  and then we can add the length of a week until we get
172   *  to the 'nth kday'.  There are probably more efficient
173   *  algorithms based on using a mod 7, but this one works
174   *  reasonably well for basic applications.
175   *  \ingroup date_alg
176   */
177  template<class date_type>
178  class nth_kday_of_month : public year_based_generator<date_type>
179  {
180  public:
181    typedef typename date_type::calendar_type calendar_type;
182    typedef typename calendar_type::day_of_week_type  day_of_week_type;
183    typedef typename calendar_type::month_type        month_type;
184    typedef typename calendar_type::year_type         year_type;
185    typedef typename date_type::duration_type        duration_type;
186    enum week_num {first=1, second, third, fourth, fifth};
187    nth_kday_of_month(week_num week_no,
188                      day_of_week_type dow,
189                      month_type m) :
190      month_(m),
191      wn_(week_no),
192      dow_(dow)
193    {}
194    //! Return a concrete date when provided with a year specific year.
195    date_type get_date(year_type y) const
196    {
197      date_type d(y, month_, 1); //first day of month
198      duration_type one_day(1);
199      duration_type one_week(7);
200      while (dow_ != d.day_of_week()) {
201        d = d + one_day;
202      }
203      int week = 1;
204      while (week < wn_) {
205        d = d + one_week;
206        week++;
207      }
208      // remove wrapping to next month behavior
209      if(d.month() != month_) {
210        d = d - one_week;
211      }
212      return d;
213    }
214    // added for streaming
215    month_type month() const
216    {
217      return month_;
218    }
219    week_num nth_week() const
220    {
221      return wn_;
222    }
223    day_of_week_type day_of_week() const
224    {
225      return dow_;
226    }
227    const char* nth_week_as_str() const
228    {
229      return nth_as_str(wn_);
230    }
231    //! Returns string suitable for use in POSIX time zone string
232    /*! Returns a string formatted as "M4.3.0" ==> 3rd Sunday in April. */
233    virtual std::string to_string() const
234    {
235     std::ostringstream ss;
236     ss << 'M' 
237       << static_cast<int>(month_) << '.'
238       << static_cast<int>(wn_) << '.'
239       << static_cast<int>(dow_);
240     return ss.str();
241    }
242  private:
243    month_type month_;
244    week_num wn_;
245    day_of_week_type dow_;
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::ostringstream 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::ostringstream 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
Note: See TracBrowser for help on using the repository browser.