1 //
2 //  Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
3 //
4 //  Distributed under the Boost Software License, Version 1.0. (See
5 //  accompanying file LICENSE_1_0.txt or copy at
6 //  http://www.boost.org/LICENSE_1_0.txt)
7 //
8 #ifndef BOOST_LOCALE_DATE_TIME_HPP_INCLUDED
9 #define BOOST_LOCALE_DATE_TIME_HPP_INCLUDED
10 
11 #include <boost/locale/config.hpp>
12 #ifdef BOOST_MSVC
13 #  pragma warning(push)
14 #  pragma warning(disable : 4275 4251 4231 4660)
15 #endif
16 
17 #include <boost/locale/hold_ptr.hpp>
18 #include <boost/locale/date_time_facet.hpp>
19 #include <boost/locale/formatting.hpp>
20 #include <boost/locale/time_zone.hpp>
21 #include <locale>
22 #include <vector>
23 #include <stdexcept>
24 
25 
26 namespace boost {
27     namespace locale {
28         ///
29         /// \defgroup date_time Date, Time, Timezone and Calendar manipulations
30         ///
31         /// This module provides various calendar, timezone and date time services
32         ///
33         /// @{
34 
35 
36         ///
37         /// \brief This error is thrown in case of invalid state that occurred
38         ///
39         class BOOST_SYMBOL_VISIBLE date_time_error : public std::runtime_error {
40         public:
41             ///
42             /// Constructor of date_time_error class
43             ///
date_time_error(std::string const & e)44             date_time_error(std::string const &e) : std::runtime_error(e) {}
45         };
46 
47 
48         ///
49         /// \brief This class represents a pair of period_type and the integer
50         /// values that describes its amount. For example 3 days or 4 years.
51         ///
52         /// Usually obtained as product of period_type and integer or
53         /// my calling a representative functions
54         /// For example day()*3 == date_time_period(day(),3) == day(3)
55         ///
56         struct date_time_period
57         {
58             period::period_type type;   ///< The type of period, i.e. era, year, day etc.
59             int value;                  ///< The value the actual number of \a periods
60             ///
61             /// Operator + returns copy of itself
62             ///
operator +boost::locale::date_time_period63             date_time_period operator+() const { return *this; }
64             ///
65             /// Operator -, switches the sign of period
66             ///
operator -boost::locale::date_time_period67             date_time_period operator-() const { return date_time_period(type,-value); }
68 
69             ///
70             /// Constructor that creates date_time_period from period_type \a f and a value \a v -- default 1.
71             ///
date_time_periodboost::locale::date_time_period72             date_time_period(period::period_type f=period::period_type(),int v=1) : type(f), value(v) {}
73         };
74 
75         namespace period {
76             ///
77             ///  Get period_type for: special invalid value, should not be used directly
78             ///
invalid()79             inline period_type invalid(){ return period_type(marks::invalid); }
80             ///
81             ///  Get period_type for: Era i.e. AC, BC in Gregorian and Julian calendar, range [0,1]
82             ///
era()83             inline period_type era(){ return period_type(marks::era); }
84             ///
85             ///  Get period_type for: Year, it is calendar specific, for example 2011 in Gregorian calendar.
86             ///
year()87             inline period_type year(){ return period_type(marks::year); }
88             ///
89             ///  Get period_type for: Extended year for Gregorian/Julian calendars, where 1 BC == 0, 2 BC == -1.
90             ///
extended_year()91             inline period_type extended_year(){ return period_type(marks::extended_year); }
92             ///
93             ///  Get period_type for: The month of year, calendar specific, in Gregorian [0..11]
94             ///
month()95             inline period_type month(){ return period_type(marks::month); }
96             ///
97             ///  Get period_type for: The day of month, calendar specific, in Gregorian [1..31]
98             ///
day()99             inline period_type day(){ return period_type(marks::day); }
100             ///
101             ///  Get period_type for: The number of day in year, starting from 1, in Gregorian  [1..366]
102             ///
day_of_year()103             inline period_type day_of_year(){ return period_type(marks::day_of_year); }
104             ///
105             ///  Get period_type for: Day of week, Sunday=1, Monday=2,..., Saturday=7.
106             ///
107             /// Note that updating this value respects local day of week, so for example,
108             /// If first day of week is Monday and the current day is Tuesday then setting
109             /// the value to Sunday (1) would forward the date by 5 days forward and not backward
110             /// by two days as it could be expected if the numbers were taken as is.
111             ///
day_of_week()112             inline period_type day_of_week(){ return period_type(marks::day_of_week); }
113             ///
114             ///  Get period_type for: Original number of the day of the week in month. For example 1st Sunday,
115             /// 2nd Sunday, etc. in Gregorian [1..5]
116             ///
day_of_week_in_month()117             inline period_type day_of_week_in_month(){ return period_type(marks::day_of_week_in_month); }
118             ///
119             ///  Get period_type for: Local day of week, for example in France Monday is 1, in US Sunday is 1, [1..7]
120             ///
day_of_week_local()121             inline period_type day_of_week_local(){ return period_type(marks::day_of_week_local); }
122             ///
123             ///  Get period_type for: 24 clock hour [0..23]
124             ///
hour()125             inline period_type hour(){ return period_type(marks::hour); }
126             ///
127             ///  Get period_type for: 12 clock hour [0..11]
128             ///
hour_12()129             inline period_type hour_12(){ return period_type(marks::hour_12); }
130             ///
131             ///  Get period_type for: am or pm marker [0..1]
132             ///
am_pm()133             inline period_type am_pm(){ return period_type(marks::am_pm); }
134             ///
135             ///  Get period_type for: minute [0..59]
136             ///
minute()137             inline period_type minute(){ return period_type(marks::minute); }
138             ///
139             ///  Get period_type for: second [0..59]
140             ///
second()141             inline period_type second(){ return period_type(marks::second); }
142             ///
143             ///  Get period_type for: The week number in the year
144             ///
week_of_year()145             inline period_type week_of_year(){ return period_type(marks::week_of_year); }
146             ///
147             ///  Get period_type for: The week number within current month
148             ///
week_of_month()149             inline period_type week_of_month(){ return period_type(marks::week_of_month); }
150             ///
151             ///  Get period_type for: First day of week, constant, for example Sunday in US = 1, Monday in France = 2
152             ///
first_day_of_week()153             inline period_type first_day_of_week(){ return period_type(marks::first_day_of_week); }
154 
155             ///
156             ///  Get date_time_period for: Era i.e. AC, BC in Gregorian and Julian calendar, range [0,1]
157             ///
era(int v)158             inline date_time_period era(int v) { return date_time_period(era(),v); }
159             ///
160             ///  Get date_time_period for: Year, it is calendar specific, for example 2011 in Gregorian calendar.
161             ///
year(int v)162             inline date_time_period year(int v) { return date_time_period(year(),v); }
163             ///
164             ///  Get date_time_period for: Extended year for Gregorian/Julian calendars, where 1 BC == 0, 2 BC == -1.
165             ///
extended_year(int v)166             inline date_time_period extended_year(int v) { return date_time_period(extended_year(),v); }
167             ///
168             ///  Get date_time_period for: The month of year, calendar specific, in Gregorian [0..11]
169             ///
month(int v)170             inline date_time_period month(int v) { return date_time_period(month(),v); }
171             ///
172             ///  Get date_time_period for: The day of month, calendar specific, in Gregorian [1..31]
173             ///
day(int v)174             inline date_time_period day(int v) { return date_time_period(day(),v); }
175             ///
176             ///  Get date_time_period for: The number of day in year, starting from 1, in Gregorian  [1..366]
177             ///
day_of_year(int v)178             inline date_time_period day_of_year(int v) { return date_time_period(day_of_year(),v); }
179             ///
180             ///  Get date_time_period for: Day of week, Sunday=1, Monday=2,..., Saturday=7.
181             ///
182             /// Note that updating this value respects local day of week, so for example,
183             /// If first day of week is Monday and the current day is Tuesday then setting
184             /// the value to Sunday (1) would forward the date by 5 days forward and not backward
185             /// by two days as it could be expected if the numbers were taken as is.
186             ///
day_of_week(int v)187             inline date_time_period day_of_week(int v) { return date_time_period(day_of_week(),v); }
188             ///
189             ///  Get date_time_period for: Original number of the day of the week in month. For example 1st Sunday,
190             /// 2nd Sunday, etc. in Gregorian [1..5]
191             ///
day_of_week_in_month(int v)192             inline date_time_period day_of_week_in_month(int v) { return date_time_period(day_of_week_in_month(),v); }
193             ///
194             ///  Get date_time_period for: Local day of week, for example in France Monday is 1, in US Sunday is 1, [1..7]
195             ///
day_of_week_local(int v)196             inline date_time_period day_of_week_local(int v) { return date_time_period(day_of_week_local(),v); }
197             ///
198             ///  Get date_time_period for: 24 clock hour [0..23]
199             ///
hour(int v)200             inline date_time_period hour(int v) { return date_time_period(hour(),v); }
201             ///
202             ///  Get date_time_period for: 12 clock hour [0..11]
203             ///
hour_12(int v)204             inline date_time_period hour_12(int v) { return date_time_period(hour_12(),v); }
205             ///
206             ///  Get date_time_period for: am or pm marker [0..1]
207             ///
am_pm(int v)208             inline date_time_period am_pm(int v) { return date_time_period(am_pm(),v); }
209             ///
210             ///  Get date_time_period for: minute [0..59]
211             ///
minute(int v)212             inline date_time_period minute(int v) { return date_time_period(minute(),v); }
213             ///
214             ///  Get date_time_period for: second [0..59]
215             ///
second(int v)216             inline date_time_period second(int v) { return date_time_period(second(),v); }
217             ///
218             ///  Get date_time_period for: The week number in the year
219             ///
week_of_year(int v)220             inline date_time_period week_of_year(int v) { return date_time_period(week_of_year(),v); }
221             ///
222             ///  Get date_time_period for: The week number within current month
223             ///
week_of_month(int v)224             inline date_time_period week_of_month(int v) { return date_time_period(week_of_month(),v); }
225             ///
226             ///  Get date_time_period for: First day of week, constant, for example Sunday in US = 1, Monday in France = 2
227             ///
first_day_of_week(int v)228             inline date_time_period first_day_of_week(int v) { return date_time_period(first_day_of_week(),v); }
229 
230             ///
231             /// Get predefined constant for January
232             ///
january()233             inline date_time_period january() { return date_time_period(month(),0); }
234             ///
235             /// Get predefined constant for February
236             ///
february()237             inline date_time_period february() { return date_time_period(month(),1); }
238             ///
239             /// Get predefined constant for March
240             ///
march()241             inline date_time_period march() { return date_time_period(month(),2); }
242             ///
243             /// Get predefined constant for April
244             ///
april()245             inline date_time_period april() { return date_time_period(month(),3); }
246             ///
247             /// Get predefined constant for May
248             ///
may()249             inline date_time_period may() { return date_time_period(month(),4); }
250             ///
251             /// Get predefined constant for June
252             ///
june()253             inline date_time_period june() { return date_time_period(month(),5); }
254             ///
255             /// Get predefined constant for July
256             ///
july()257             inline date_time_period july() { return date_time_period(month(),6); }
258             ///
259             /// Get predefined constant for August
260             ///
august()261             inline date_time_period august() { return date_time_period(month(),7); }
262             ///
263             /// Get predefined constant for September
264             ///
september()265             inline date_time_period september() { return date_time_period(month(),8); }
266             ///
267             /// Get predefined constant for October
268             ///
october()269             inline date_time_period october() { return date_time_period(month(),9); }
270             ///
271             /// Get predefined constant for November
272             ///
november()273             inline date_time_period november() { return date_time_period(month(),10); }
274             ///
275             /// Get predefined constant for December
276             ///
december()277             inline date_time_period december() { return date_time_period(month(),11); }
278 
279             ///
280             /// Get predefined constant for Sunday
281             ///
sunday()282             inline date_time_period sunday() { return date_time_period(day_of_week(),1); }
283             ///
284             /// Get predefined constant for Monday
285             ///
monday()286             inline date_time_period monday() { return date_time_period(day_of_week(),2); }
287             ///
288             /// Get predefined constant for Tuesday
289             ///
tuesday()290             inline date_time_period tuesday() { return date_time_period(day_of_week(),3); }
291             ///
292             /// Get predefined constant for Wednesday
293             ///
wednesday()294             inline date_time_period wednesday() { return date_time_period(day_of_week(),4); }
295             ///
296             /// Get predefined constant for Thursday
297             ///
thursday()298             inline date_time_period thursday() { return date_time_period(day_of_week(),5); }
299             ///
300             /// Get predefined constant for Friday
301             ///
friday()302             inline date_time_period friday() { return date_time_period(day_of_week(),6); }
303             ///
304             /// Get predefined constant for Saturday
305             ///
saturday()306             inline date_time_period saturday() { return date_time_period(day_of_week(),7); }
307             ///
308             /// Get predefined constant for AM (Ante Meridiem)
309             ///
am()310             inline date_time_period am() { return date_time_period(am_pm(),0); }
311             ///
312             /// Get predefined constant for PM (Post Meridiem)
313             ///
pm()314             inline date_time_period pm() { return date_time_period(am_pm(),1); }
315 
316             ///
317             /// convert period_type to date_time_period(f,1)
318             ///
operator +(period::period_type f)319             inline date_time_period operator+(period::period_type f)
320             {
321                 return date_time_period(f);
322             }
323             ///
324             /// convert period_type to date_time_period(f,-1)
325             ///
operator -(period::period_type f)326             inline date_time_period operator-(period::period_type f)
327             {
328                 return date_time_period(f,-1);
329             }
330 
331             ///
332             /// Create date_time_period of type \a f with value \a v.
333             ///
334             template<typename T>
operator *(period::period_type f,T v)335             date_time_period operator*(period::period_type f,T v)
336             {
337                 return date_time_period(f,v);
338             }
339 
340             ///
341             /// Create date_time_period of type \a f with value \a v.
342             ///
343             template<typename T>
operator *(T v,period::period_type f)344             date_time_period operator*(T v,period::period_type f)
345             {
346                 return date_time_period(f,v);
347             }
348             ///
349             /// Create date_time_period of type \a f with value \a v.
350             ///
351             template<typename T>
operator *(T v,date_time_period f)352             date_time_period operator*(T v,date_time_period f)
353             {
354                 return date_time_period(f.type,f.value*v);
355             }
356 
357             ///
358             /// Create date_time_period of type \a f with value \a v.
359             ///
360             template<typename T>
operator *(date_time_period f,T v)361             date_time_period operator*(date_time_period f,T v)
362             {
363                 return date_time_period(f.type,f.value*v);
364             }
365 
366 
367         } // period
368 
369 
370         ///
371         /// \brief this class that represents a set of periods,
372         ///
373         /// It is generally created by operations on periods:
374         /// 1995*year + 3*month + 1*day. Note: operations are not commutative.
375         ///
376         class date_time_period_set {
377         public:
378 
379             ///
380             /// Default constructor - empty set
381             ///
date_time_period_set()382             date_time_period_set()
383             {
384             }
385             ///
386             /// Create a set of single period with value 1
387             ///
date_time_period_set(period::period_type f)388             date_time_period_set(period::period_type f)
389             {
390                 basic_[0]=date_time_period(f);
391             }
392             ///
393             /// Create a set of single period \a fl
394             ///
date_time_period_set(date_time_period const & fl)395             date_time_period_set(date_time_period const &fl)
396             {
397                 basic_[0]=fl;
398             }
399             ///
400             /// Append date_time_period \a f to the set
401             ///
add(date_time_period f)402             void add(date_time_period f)
403             {
404                 size_t n=size();
405                 if(n < 4)
406                     basic_[n]=f;
407                 else
408                     periods_.push_back(f);
409             }
410             ///
411             /// Get number if items in list
412             ///
size() const413             size_t size() const
414             {
415                 if(basic_[0].type == period::period_type())
416                     return 0;
417                 if(basic_[1].type == period::period_type())
418                     return 1;
419                 if(basic_[2].type == period::period_type())
420                     return 2;
421                 if(basic_[3].type == period::period_type())
422                     return 3;
423                 return 4+periods_.size();
424             }
425             ///
426             /// Get item at position \a n the set, n should be in range [0,size)
427             ///
operator [](size_t n) const428             date_time_period const &operator[](size_t n) const
429             {
430                 if(n >= size())
431                     throw std::out_of_range("Invalid index to date_time_period");
432                 if(n < 4)
433                     return basic_[n];
434                 else
435                     return periods_[n-4];
436             }
437         private:
438             date_time_period basic_[4];
439             std::vector<date_time_period> periods_;
440         };
441 
442 
443         ///
444         /// Append two periods sets. Note this operator is not commutative
445         ///
operator +(date_time_period_set const & a,date_time_period_set const & b)446         inline date_time_period_set operator+(date_time_period_set const &a,date_time_period_set const &b)
447         {
448             date_time_period_set s(a);
449             for(unsigned i=0;i<b.size();i++)
450                 s.add(b[i]);
451             return s;
452         }
453 
454         ///
455         /// Append two period sets when all periods of set \b change their sign
456         ///
operator -(date_time_period_set const & a,date_time_period_set const & b)457         inline date_time_period_set operator-(date_time_period_set const &a,date_time_period_set const &b)
458         {
459             date_time_period_set s(a);
460             for(unsigned i=0;i<b.size();i++)
461                 s.add(-b[i]);
462             return s;
463         }
464 
465 
466         ///
467         /// \brief this class provides an access to general calendar information.
468         ///
469         /// This information is not connected to specific date but generic to locale, and timezone.
470         /// It is used in obtaining general information about calendar and is essential for creation of
471         /// date_time objects.
472         ///
473         class BOOST_LOCALE_DECL calendar {
474         public:
475 
476             ///
477             /// Create calendar taking locale and timezone information from ios_base instance.
478             ///
479             /// \note throws std::bad_cast if ios does not have a locale with installed \ref calendar_facet
480             /// facet installed
481             ///
482             calendar(std::ios_base &ios);
483             ///
484             /// Create calendar with locale \a l and time_zone \a zone
485             ///
486             /// \note throws std::bad_cast if loc does not have \ref calendar_facet facet installed
487             ///
488             calendar(std::locale const &l,std::string const &zone);
489             ///
490             /// Create calendar with locale \a l and default timezone
491             ///
492             /// \note throws std::bad_cast if loc does not have \ref calendar_facet facet installed
493             ///
494             calendar(std::locale const &l);
495             ///
496             /// Create calendar with default locale and timezone \a zone
497             ///
498             /// \note throws std::bad_cast if global locale does not have \ref calendar_facet facet installed
499             ///
500             calendar(std::string const &zone);
501             ///
502             /// Create calendar with default locale and timezone
503             ///
504             /// \note throws std::bad_cast if global locale does not have \ref calendar_facet facet installed
505             ///
506             calendar();
507             ~calendar();
508 
509             ///
510             /// copy calendar
511             ///
512             calendar(calendar const &other);
513             ///
514             /// assign calendar
515             ///
516             calendar const &operator=(calendar const &other);
517 
518             ///
519             /// Get minimum value for period f, For example for period::day it is 1.
520             ///
521             int minimum(period::period_type f) const;
522             ///
523             /// Get greatest possible minimum value for period f, For example for period::day it is 1, but may be different for other calendars.
524             ///
525             int greatest_minimum(period::period_type f) const;
526             ///
527             /// Get maximum value for period f, For example for Gregorian calendar's maximum period::day it is 31.
528             ///
529             int maximum(period::period_type f) const;
530             ///
531             /// Get least maximum value for period f, For example for Gregorian calendar's maximum period::day it is 28.
532             ///
533             int least_maximum(period::period_type f) const;
534 
535             ///
536             /// Get first day of week for specific calendar, for example for US it is 1 - Sunday for France it is 2 - Monday
537             int first_day_of_week() const;
538 
539             ///
540             /// get calendar's locale
541             ///
542             std::locale get_locale() const;
543             ///
544             /// get calendar's time zone
545             ///
546             std::string get_time_zone() const;
547 
548             ///
549             /// Check if the calendar is Gregorian
550             ///
551             bool is_gregorian() const;
552 
553             ///
554             /// Compare calendars for equivalence: i.e. calendar types, time zones etc.
555             ///
556             bool operator==(calendar const &other) const;
557             ///
558             /// Opposite of ==
559             ///
560             bool operator!=(calendar const &other) const;
561 
562         private:
563             friend class date_time;
564             std::locale locale_;
565             std::string tz_;
566             hold_ptr<abstract_calendar> impl_;
567         };
568 
569         ///
570         /// \brief this class represents a date time and allows to perform various operation according to the
571         /// locale settings.
572         ///
573         /// This class allows to manipulate various aspects of dates and times easily using arithmetic operations with
574         /// periods.
575         ///
576         /// General arithmetic functions:
577         ///
578         /// - date_time + date_time_period_set = date_time: move time point forward by specific periods like date_time + month;
579         /// - date_time - date_time_period_set = date_time: move time point backward by specific periods like date_time - month;
580         /// - date_time << date_time_period_set  = date_time: roll time point forward by specific periods with rolling to begin if overflows: like "2010-01-31" << 2* day == "2010-01-02" instead of "2010-02-02"
581         /// - date_time >> date_time_period_set  = date_time: roll time point backward by specific periods with rolling to end if overflows: like "2010-01-02" >> 2* day == "2010-01-31" instead of "2009-12-30"
582         /// - date_time / period_type = int - current period value: like "2010-12-21" / month == 12. "2010-12-21" / year = 2010
583         /// - (date_time - date_time) / period_type = int: distance between dates in period_type. Like ("2010-12-01" - "2008-12-01") / month = 24.
584         ///
585         /// You can also assign specific periods using assignment operator like:
586         /// some_time = year * 1995 that sets the year to 1995.
587         ///
588         ///
589 
590         class BOOST_LOCALE_DECL date_time {
591         public:
592 
593             ///
594             /// Dafault constructor, uses default calendar initialized date_time object to current time.
595             ///
596             /// \note throws std::bad_cast if the global locale does not have \ref calendar_facet facet installed
597             ///
598             date_time();
599             ///
600             /// copy date_time
601             ///
602             date_time(date_time const &other);
603             ///
604             /// copy date_time and change some fields according to the \a set
605             ///
606             date_time(date_time const &other,date_time_period_set const &set);
607             ///
608             /// assign the date_time
609             ///
610             date_time const &operator=(date_time const &other);
611             ~date_time();
612 
613             ///
614             /// Create a date_time object using POSIX time \a time and default calendar
615             ///
616             /// \note throws std::bad_cast if the global locale does not have \ref calendar_facet facet installed
617             ///
618             date_time(double time);
619             ///
620             /// Create a date_time object using POSIX time \a time and calendar \a cal
621             ///
622             date_time(double time,calendar const &cal);
623             ///
624             /// Create a date_time object using calendar \a cal and initializes it to current time.
625             ///
626             date_time(calendar const &cal);
627 
628             ///
629             /// Create a date_time object using default calendar and define values given in \a set
630             ///
631             /// \note throws std::bad_cast if the global locale does not have \ref calendar_facet facet installed
632             ///
633             date_time(date_time_period_set const &set);
634             ///
635             /// Create a date_time object using calendar \a cal and define values given in \a set
636             ///
637             date_time(date_time_period_set const &set,calendar const &cal);
638 
639 
640             ///
641             /// assign values to various periods in set \a f
642             ///
643             date_time const &operator=(date_time_period_set const &f);
644 
645             ///
646             /// set specific period \a f value to \a v
647             ///
648             void set(period::period_type f,int v);
649             ///
650             /// get specific period \a f value
651             ///
652             int get(period::period_type f) const;
653 
654             ///
655             /// syntactic sugar for get(f)
656             ///
operator /(period::period_type f) const657             int operator/(period::period_type f) const
658             {
659                 return get(f);
660             }
661 
662             ///
663             /// add single period f to the current date_time
664             ///
operator +(period::period_type f) const665             date_time operator+(period::period_type f) const
666             {
667                 return *this+date_time_period(f);
668             }
669 
670             ///
671             /// subtract single period f from the current date_time
672             ///
operator -(period::period_type f) const673             date_time operator-(period::period_type f) const
674             {
675                 return *this-date_time_period(f);
676             }
677 
678             ///
679             /// add single period f to the current date_time
680             ///
operator +=(period::period_type f)681             date_time const &operator+=(period::period_type f)
682             {
683                 return *this+=date_time_period(f);
684             }
685             ///
686             /// subtract single period f from the current date_time
687             ///
operator -=(period::period_type f)688             date_time const &operator-=(period::period_type f)
689             {
690                 return *this-=date_time_period(f);
691             }
692 
693             ///
694             /// roll forward a date by single period f.
695             ///
operator <<(period::period_type f) const696             date_time operator<<(period::period_type f) const
697             {
698                 return *this<<date_time_period(f);
699             }
700 
701             ///
702             /// roll backward a date by single period f.
703             ///
operator >>(period::period_type f) const704             date_time operator>>(period::period_type f) const
705             {
706                 return *this>>date_time_period(f);
707             }
708 
709             ///
710             /// roll forward a date by single period f.
711             ///
operator <<=(period::period_type f)712             date_time const &operator<<=(period::period_type f)
713             {
714                 return *this<<=date_time_period(f);
715             }
716             ///
717             /// roll backward a date by single period f.
718             ///
operator >>=(period::period_type f)719             date_time const &operator>>=(period::period_type f)
720             {
721                 return *this>>=date_time_period(f);
722             }
723 
724             ///
725             /// add date_time_period to the current date_time
726             ///
727             date_time operator+(date_time_period const &v) const;
728             ///
729             /// subtract date_time_period from the current date_time
730             ///
731             date_time operator-(date_time_period const &v) const;
732             ///
733             /// add date_time_period to the current date_time
734             ///
735             date_time const &operator+=(date_time_period const &v);
736             ///
737             /// subtract date_time_period from the current date_time
738             ///
739             date_time const &operator-=(date_time_period const &v);
740 
741             ///
742             /// roll current date_time forward by date_time_period v
743             ///
744             date_time operator<<(date_time_period const &v) const;
745             ///
746             /// roll current date_time backward by date_time_period v
747             ///
748             date_time operator>>(date_time_period const &v) const ;
749             ///
750             /// roll current date_time forward by date_time_period v
751             ///
752             date_time const &operator<<=(date_time_period const &v);
753             ///
754             /// roll current date_time backward by date_time_period v
755             ///
756             date_time const &operator>>=(date_time_period const &v);
757 
758             ///
759             /// add date_time_period_set v to the current date_time
760             ///
761             date_time operator+(date_time_period_set const &v) const;
762             ///
763             /// subtract date_time_period_set v from the current date_time
764             ///
765             date_time operator-(date_time_period_set const &v) const;
766             ///
767             /// add date_time_period_set v to the current date_time
768             ///
769             date_time const &operator+=(date_time_period_set const &v);
770             ///
771             /// subtract date_time_period_set v from the current date_time
772             ///
773             date_time const &operator-=(date_time_period_set const &v);
774 
775             ///
776             /// roll current date_time forward by date_time_period_set v
777             ///
778             date_time operator<<(date_time_period_set const &v) const;
779             ///
780             /// roll current date_time backward by date_time_period_set v
781             ///
782             date_time operator>>(date_time_period_set const &v) const ;
783             ///
784             /// roll current date_time forward by date_time_period_set v
785             ///
786             date_time const &operator<<=(date_time_period_set const &v);
787             ///
788             /// roll current date_time backward by date_time_period_set v
789             ///
790             date_time const &operator>>=(date_time_period_set const &v);
791 
792             ///
793             /// Get POSIX time
794             ///
795             /// The POSIX time is number of seconds since January 1st, 1970 00:00 UTC, ignoring leap seconds.
796             ///
797             double time() const;
798             ///
799             /// set POSIX time
800             ///
801             /// The POSIX time is number of seconds since January 1st, 1970 00:00 UTC, ignoring leap seconds.
802             /// This time can be fetched from Operating system clock using C function time, gettimeofday and others.
803             ///
804             void time(double v);
805 
806             ///
807             /// compare date_time in the timeline (ignores difference in calendar, timezone etc)
808             ///
809             bool operator==(date_time const &other) const;
810             ///
811             /// compare date_time in the timeline (ignores difference in calendar, timezone etc)
812             ///
813             bool operator!=(date_time const &other) const;
814             ///
815             /// compare date_time in the timeline (ignores difference in calendar, timezone etc)
816             ///
817             bool operator<(date_time const &other) const;
818             ///
819             /// compare date_time in the timeline (ignores difference in calendar, timezone etc)
820             ///
821             bool operator>(date_time const &other) const;
822             ///
823             /// compare date_time in the timeline (ignores difference in calendar, timezone etc)
824             ///
825             bool operator<=(date_time const &other) const;
826             ///
827             /// compare date_time in the timeline (ignores difference in calendar, timezone etc)
828             ///
829             bool operator>=(date_time const &other) const;
830 
831             ///
832             /// swaps two dates - efficient, does not throw
833             ///
834             void swap(date_time &other);
835 
836             ///
837             /// calculate the distance from this date_time to \a other in terms of perios \a f
838             ///
839             int difference(date_time const &other,period::period_type f) const;
840 
841             ///
842             /// Get minimal possible value for *this time point for a period \a f.
843             ///
844             int minimum(period::period_type f) const;
845             ///
846             /// Get minimal possible value for *this time point for a period \a f. For example
847             /// in February maximum(day) may be 28 or 29, in January maximum(day)==31
848             ///
849             int maximum(period::period_type f) const;
850 
851             ///
852             /// Check if *this time point is in daylight saving time
853             ///
854             bool is_in_daylight_saving_time() const;
855 
856         private:
857             hold_ptr<abstract_calendar> impl_;
858         };
859 
860         ///
861         /// Writes date_time \a t to output stream \a out.
862         ///
863         /// This function uses locale, calendar and time zone of the target stream \a in.
864         ///
865         /// For example:
866         /// \code
867         ///  date_time now(time(0),hebrew_calendar)
868         ///  cout << "Year: " << period::year(now) <<" Full Date:"<< now;
869         /// \endcode
870         ///
871         /// The output may be Year:5770 Full Date:Jan 1, 2010
872         ///
873         template<typename CharType>
operator <<(std::basic_ostream<CharType> & out,date_time const & t)874         std::basic_ostream<CharType> &operator<<(std::basic_ostream<CharType> &out,date_time const &t)
875         {
876             double time_point = t.time();
877             uint64_t display_flags = ios_info::get(out).display_flags();
878             if  (
879                     display_flags == flags::date
880                     || display_flags == flags::time
881                     || display_flags == flags::datetime
882                     || display_flags == flags::strftime
883                 )
884             {
885                 out << time_point;
886             }
887             else {
888                 ios_info::get(out).display_flags(flags::datetime);
889                 out << time_point;
890                 ios_info::get(out).display_flags(display_flags);
891             }
892             return out;
893         }
894 
895         ///
896         /// Reads date_time \a t from output stream \a in
897         ///
898         /// This function uses locale, calendar and time zone of the source stream \a in.
899         ///
900         template<typename CharType>
operator >>(std::basic_istream<CharType> & in,date_time & t)901         std::basic_istream<CharType> &operator>>(std::basic_istream<CharType> &in,date_time &t)
902         {
903             double v;
904             uint64_t display_flags = ios_info::get(in).display_flags();
905             if  (
906                     display_flags == flags::date
907                     || display_flags == flags::time
908                     || display_flags == flags::datetime
909                     || display_flags == flags::strftime
910                 )
911             {
912                 in >> v;
913             }
914             else {
915                 ios_info::get(in).display_flags(flags::datetime);
916                 in >> v;
917                 ios_info::get(in).display_flags(display_flags);
918             }
919             if(!in.fail())
920                 t.time(v);
921             return in;
922         }
923 
924         ///
925         /// \brief This class represents a period: a pair of two date_time objects.
926         ///
927         /// It is generally used as syntactic sugar to calculate difference between two dates.
928         ///
929         /// Note: it stores references to the original objects, so it is not recommended to be used
930         /// outside of the equation you calculate the difference in.
931         ///
932         class date_time_duration {
933         public:
934 
935             ///
936             /// Create an object were \a first represents earlier point on time line and \a second is later
937             /// point.
938             ///
date_time_duration(date_time const & first,date_time const & second)939             date_time_duration(date_time const &first,date_time const &second) :
940                 s_(first),
941                 e_(second)
942             {
943             }
944 
945             ///
946             /// find a difference in terms of period_type \a f
947             ///
get(period::period_type f) const948             int get(period::period_type f) const
949             {
950                 return start().difference(end(),f);
951             }
952 
953             ///
954             /// Syntactic sugar for get(f)
955             ///
operator /(period::period_type f) const956             int operator / (period::period_type f) const
957             {
958                 return start().difference(end(),f);
959             }
960 
961             ///
962             /// Get starting point
963             ///
start() const964             date_time const &start() const { return s_; }
965             ///
966             /// Get ending point
967             ///
end() const968             date_time const &end() const { return e_; }
969         private:
970             date_time const &s_;
971             date_time const &e_;
972         };
973 
974         ///
975         /// Calculates the difference between two dates, the left operand is a later point on time line.
976         /// Returns date_time_duration object.
977         ///
operator -(date_time const & later,date_time const & earlier)978         inline date_time_duration operator-(date_time const &later,date_time const &earlier)
979         {
980             return date_time_duration(earlier,later);
981         }
982 
983 
984         namespace period {
985             ///
986             ///  Extract from date_time numerical value of Era i.e. AC, BC in Gregorian and Julian calendar, range [0,1]
987             ///
era(date_time const & dt)988             inline int era(date_time const &dt) { return dt.get(era()); }
989             ///
990             ///  Extract from date_time numerical value of Year, it is calendar specific, for example 2011 in Gregorian calendar.
991             ///
year(date_time const & dt)992             inline int year(date_time const &dt) { return dt.get(year()); }
993             ///
994             ///  Extract from date_time numerical value of Extended year for Gregorian/Julian calendars, where 1 BC == 0, 2 BC == -1.
995             ///
extended_year(date_time const & dt)996             inline int extended_year(date_time const &dt) { return dt.get(extended_year()); }
997             ///
998             ///  Extract from date_time numerical value of The month of year, calendar specific, in Gregorian [0..11]
999             ///
month(date_time const & dt)1000             inline int month(date_time const &dt) { return dt.get(month()); }
1001             ///
1002             ///  Extract from date_time numerical value of The day of month, calendar specific, in Gregorian [1..31]
1003             ///
day(date_time const & dt)1004             inline int day(date_time const &dt) { return dt.get(day()); }
1005             ///
1006             ///  Extract from date_time numerical value of The number of day in year, starting from 1, in Gregorian  [1..366]
1007             ///
day_of_year(date_time const & dt)1008             inline int day_of_year(date_time const &dt) { return dt.get(day_of_year()); }
1009             ///
1010             ///  Extract from date_time numerical value of Day of week, Sunday=1, Monday=2,..., Saturday=7.
1011             ///
1012             /// Note that updating this value respects local day of week, so for example,
1013             /// If first day of week is Monday and the current day is Tuesday then setting
1014             /// the value to Sunday (1) would forward the date by 5 days forward and not backward
1015             /// by two days as it could be expected if the numbers were taken as is.
1016             ///
day_of_week(date_time const & dt)1017             inline int day_of_week(date_time const &dt) { return dt.get(day_of_week()); }
1018             ///
1019             ///  Extract from date_time numerical value of Original number of the day of the week in month. For example 1st Sunday,
1020             /// 2nd Sunday, etc. in Gregorian [1..5]
1021             ///
day_of_week_in_month(date_time const & dt)1022             inline int day_of_week_in_month(date_time const &dt) { return dt.get(day_of_week_in_month()); }
1023             ///
1024             ///  Extract from date_time numerical value of Local day of week, for example in France Monday is 1, in US Sunday is 1, [1..7]
1025             ///
day_of_week_local(date_time const & dt)1026             inline int day_of_week_local(date_time const &dt) { return dt.get(day_of_week_local()); }
1027             ///
1028             ///  Extract from date_time numerical value of 24 clock hour [0..23]
1029             ///
hour(date_time const & dt)1030             inline int hour(date_time const &dt) { return dt.get(hour()); }
1031             ///
1032             ///  Extract from date_time numerical value of 12 clock hour [0..11]
1033             ///
hour_12(date_time const & dt)1034             inline int hour_12(date_time const &dt) { return dt.get(hour_12()); }
1035             ///
1036             ///  Extract from date_time numerical value of am or pm marker [0..1]
1037             ///
am_pm(date_time const & dt)1038             inline int am_pm(date_time const &dt) { return dt.get(am_pm()); }
1039             ///
1040             ///  Extract from date_time numerical value of minute [0..59]
1041             ///
minute(date_time const & dt)1042             inline int minute(date_time const &dt) { return dt.get(minute()); }
1043             ///
1044             ///  Extract from date_time numerical value of second [0..59]
1045             ///
second(date_time const & dt)1046             inline int second(date_time const &dt) { return dt.get(second()); }
1047             ///
1048             ///  Extract from date_time numerical value of The week number in the year
1049             ///
week_of_year(date_time const & dt)1050             inline int week_of_year(date_time const &dt) { return dt.get(week_of_year()); }
1051             ///
1052             ///  Extract from date_time numerical value of The week number within current month
1053             ///
week_of_month(date_time const & dt)1054             inline int week_of_month(date_time const &dt) { return dt.get(week_of_month()); }
1055             ///
1056             ///  Extract from date_time numerical value of First day of week, constant, for example Sunday in US = 1, Monday in France = 2
1057             ///
first_day_of_week(date_time const & dt)1058             inline int first_day_of_week(date_time const &dt) { return dt.get(first_day_of_week()); }
1059 
1060             ///
1061             ///  Extract from date_time_duration numerical value of duration in  Era i.e. AC, BC in Gregorian and Julian calendar, range [0,1]
1062             ///
era(date_time_duration const & dt)1063             inline int era(date_time_duration const &dt) { return dt.get(era()); }
1064             ///
1065             ///  Extract from date_time_duration numerical value of duration in years
1066             ///
year(date_time_duration const & dt)1067             inline int year(date_time_duration const &dt) { return dt.get(year()); }
1068             ///
1069             ///  Extract from date_time_duration numerical value of duration in extended years (for Gregorian/Julian calendars, where 1 BC == 0, 2 BC == -1).
1070             ///
extended_year(date_time_duration const & dt)1071             inline int extended_year(date_time_duration const &dt) { return dt.get(extended_year()); }
1072             ///
1073             ///  Extract from date_time_duration numerical value of duration in months
1074             ///
month(date_time_duration const & dt)1075             inline int month(date_time_duration const &dt) { return dt.get(month()); }
1076             ///
1077             ///  Extract from date_time_duration numerical value of duration in days of month
1078             ///
day(date_time_duration const & dt)1079             inline int day(date_time_duration const &dt) { return dt.get(day()); }
1080             ///
1081             ///  Extract from date_time_duration numerical value of duration in days of year
1082             ///
day_of_year(date_time_duration const & dt)1083             inline int day_of_year(date_time_duration const &dt) { return dt.get(day_of_year()); }
1084             ///
1085             ///  Extract from date_time_duration numerical value of duration in days of week
1086             ///
day_of_week(date_time_duration const & dt)1087             inline int day_of_week(date_time_duration const &dt) { return dt.get(day_of_week()); }
1088             ///
1089             ///  Extract from date_time_duration numerical value of duration in original number of the day of the week in month
1090             ///
day_of_week_in_month(date_time_duration const & dt)1091             inline int day_of_week_in_month(date_time_duration const &dt) { return dt.get(day_of_week_in_month()); }
1092             ///
1093             ///  Extract from date_time_duration numerical value of duration in local day of week
1094             ///
day_of_week_local(date_time_duration const & dt)1095             inline int day_of_week_local(date_time_duration const &dt) { return dt.get(day_of_week_local()); }
1096             ///
1097             ///  Extract from date_time_duration numerical value of duration in hours
1098             ///
hour(date_time_duration const & dt)1099             inline int hour(date_time_duration const &dt) { return dt.get(hour()); }
1100             ///
1101             ///  Extract from date_time_duration numerical value of duration in  12 clock hours
1102             ///
hour_12(date_time_duration const & dt)1103             inline int hour_12(date_time_duration const &dt) { return dt.get(hour_12()); }
1104             ///
1105             ///  Extract from date_time_duration numerical value of duration in  am or pm markers
1106             ///
am_pm(date_time_duration const & dt)1107             inline int am_pm(date_time_duration const &dt) { return dt.get(am_pm()); }
1108             ///
1109             ///  Extract from date_time_duration numerical value of duration in  minutes
1110             ///
minute(date_time_duration const & dt)1111             inline int minute(date_time_duration const &dt) { return dt.get(minute()); }
1112             ///
1113             ///  Extract from date_time_duration numerical value of duration in  seconds
1114             ///
second(date_time_duration const & dt)1115             inline int second(date_time_duration const &dt) { return dt.get(second()); }
1116             ///
1117             ///  Extract from date_time_duration numerical value of duration in the week number in the year
1118             ///
week_of_year(date_time_duration const & dt)1119             inline int week_of_year(date_time_duration const &dt) { return dt.get(week_of_year()); }
1120             ///
1121             ///  Extract from date_time_duration numerical value of duration in  The week number within current month
1122             ///
week_of_month(date_time_duration const & dt)1123             inline int week_of_month(date_time_duration const &dt) { return dt.get(week_of_month()); }
1124             ///
1125             ///  Extract from date_time_duration numerical value of duration in the first day of week
1126             ///
first_day_of_week(date_time_duration const & dt)1127             inline int first_day_of_week(date_time_duration const &dt) { return dt.get(first_day_of_week()); }
1128 
1129 
1130         }
1131 
1132         /// @}
1133 
1134 
1135     } // locale
1136 } // boost
1137 
1138 #ifdef BOOST_MSVC
1139 #pragma warning(pop)
1140 #endif
1141 
1142 
1143 #endif
1144 ///
1145 /// \example calendar.cpp
1146 ///
1147 /// Example of using date_time functions for generating calendar for current year.
1148 ///
1149 
1150 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
1151