summaryrefslogtreecommitdiff
path: root/boost/locale/date_time.hpp
blob: 71a92690a1af5e9900a51657c04ee53c2dae4046 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
//
//  Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
//
//  Distributed under the Boost Software License, Version 1.0. (See
//  accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_LOCALE_DATE_TIME_HPP_INCLUDED
#define BOOST_LOCALE_DATE_TIME_HPP_INCLUDED

#include <boost/locale/config.hpp>
#ifdef BOOST_MSVC
#  pragma warning(push)
#  pragma warning(disable : 4275 4251 4231 4660)
#endif

#include <boost/locale/hold_ptr.hpp>
#include <boost/locale/date_time_facet.hpp>
#include <boost/locale/formatting.hpp>
#include <boost/locale/time_zone.hpp>
#include <locale>
#include <vector>
#include <stdexcept>


namespace boost {
    namespace locale {
        ///
        /// \defgroup date_time Date, Time, Timezone and Calendar manipulations 
        ///
        /// This module provides various calendar, timezone and date time services
        ///
        /// @{


        ///
        /// \brief This error is thrown in case of invalid state that occurred
        ///
        class BOOST_SYMBOL_VISIBLE date_time_error : public std::runtime_error {
        public:
            ///
            /// Constructor of date_time_error class
            /// 
            date_time_error(std::string const &e) : std::runtime_error(e) {}
        };


        ///
        /// \brief This class represents a pair of period_type and the integer
        /// values that describes its amount. For example 3 days or 4 years.
        ///
        /// Usually obtained as product of period_type and integer or
        /// my calling a representative functions
        /// For example day()*3 == date_time_period(day(),3) == day(3)
        /// 
        struct date_time_period 
        {
            period::period_type type;   ///< The type of period, i.e. era, year, day etc.
            int value;                  ///< The value the actual number of \a periods
            ///
            /// Operator + returns copy of itself
            ///
            date_time_period operator+() const { return *this; }
            ///
            /// Operator -, switches the sign of period
            ///
            date_time_period operator-() const { return date_time_period(type,-value); }
            
            ///
            /// Constructor that creates date_time_period from period_type \a f and a value \a v -- default 1.
            ///
            date_time_period(period::period_type f=period::period_type(),int v=1) : type(f), value(v) {}
        };

        namespace period {
            ///
            ///  Get period_type for: special invalid value, should not be used directly
            ///
            inline period_type invalid(){ return period_type(marks::invalid); }
            ///
            ///  Get period_type for: Era i.e. AC, BC in Gregorian and Julian calendar, range [0,1]
            ///
            inline period_type era(){ return period_type(marks::era); }
            ///
            ///  Get period_type for: Year, it is calendar specific, for example 2011 in Gregorian calendar.
            ///
            inline period_type year(){ return period_type(marks::year); }
            ///
            ///  Get period_type for: Extended year for Gregorian/Julian calendars, where 1 BC == 0, 2 BC == -1.
            ///
            inline period_type extended_year(){ return period_type(marks::extended_year); }
            ///
            ///  Get period_type for: The month of year, calendar specific, in Gregorian [0..11]
            ///
            inline period_type month(){ return period_type(marks::month); }
            ///
            ///  Get period_type for: The day of month, calendar specific, in Gregorian [1..31]
            ///
            inline period_type day(){ return period_type(marks::day); }
            ///
            ///  Get period_type for: The number of day in year, starting from 1, in Gregorian  [1..366]
            ///
            inline period_type day_of_year(){ return period_type(marks::day_of_year); }
            ///
            ///  Get period_type for: Day of week, Sunday=1, Monday=2,..., Saturday=7.
            ///
            /// Note that updating this value respects local day of week, so for example,
            /// If first day of week is Monday and the current day is Tuesday then setting
            /// the value to Sunday (1) would forward the date by 5 days forward and not backward
            /// by two days as it could be expected if the numbers were taken as is.
            ///
            inline period_type day_of_week(){ return period_type(marks::day_of_week); }
            ///
            ///  Get period_type for: Original number of the day of the week in month. For example 1st Sunday, 
            /// 2nd Sunday, etc. in Gregorian [1..5]
            ///
            inline period_type day_of_week_in_month(){ return period_type(marks::day_of_week_in_month); }
            ///
            ///  Get period_type for: Local day of week, for example in France Monday is 1, in US Sunday is 1, [1..7]
            ///
            inline period_type day_of_week_local(){ return period_type(marks::day_of_week_local); }
            ///
            ///  Get period_type for: 24 clock hour [0..23]
            ///
            inline period_type hour(){ return period_type(marks::hour); }
            ///
            ///  Get period_type for: 12 clock hour [0..11]
            ///
            inline period_type hour_12(){ return period_type(marks::hour_12); }
            ///
            ///  Get period_type for: am or pm marker [0..1]
            ///
            inline period_type am_pm(){ return period_type(marks::am_pm); }
            ///
            ///  Get period_type for: minute [0..59]
            ///
            inline period_type minute(){ return period_type(marks::minute); }
            ///
            ///  Get period_type for: second [0..59]
            ///
            inline period_type second(){ return period_type(marks::second); }
            ///
            ///  Get period_type for: The week number in the year
            ///
            inline period_type week_of_year(){ return period_type(marks::week_of_year); }
            ///
            ///  Get period_type for: The week number within current month
            ///
            inline period_type week_of_month(){ return period_type(marks::week_of_month); }
            ///
            ///  Get period_type for: First day of week, constant, for example Sunday in US = 1, Monday in France = 2
            ///
            inline period_type first_day_of_week(){ return period_type(marks::first_day_of_week); }

            ///
            ///  Get date_time_period for: Era i.e. AC, BC in Gregorian and Julian calendar, range [0,1]
            ///
            inline date_time_period era(int v) { return date_time_period(era(),v); } 
            ///
            ///  Get date_time_period for: Year, it is calendar specific, for example 2011 in Gregorian calendar.
            ///
            inline date_time_period year(int v) { return date_time_period(year(),v); } 
            ///
            ///  Get date_time_period for: Extended year for Gregorian/Julian calendars, where 1 BC == 0, 2 BC == -1.
            ///
            inline date_time_period extended_year(int v) { return date_time_period(extended_year(),v); } 
            ///
            ///  Get date_time_period for: The month of year, calendar specific, in Gregorian [0..11]
            ///
            inline date_time_period month(int v) { return date_time_period(month(),v); } 
            ///
            ///  Get date_time_period for: The day of month, calendar specific, in Gregorian [1..31]
            ///
            inline date_time_period day(int v) { return date_time_period(day(),v); } 
            ///
            ///  Get date_time_period for: The number of day in year, starting from 1, in Gregorian  [1..366]
            ///
            inline date_time_period day_of_year(int v) { return date_time_period(day_of_year(),v); } 
            ///
            ///  Get date_time_period for: Day of week, Sunday=1, Monday=2,..., Saturday=7.
            ///
            /// Note that updating this value respects local day of week, so for example,
            /// If first day of week is Monday and the current day is Tuesday then setting
            /// the value to Sunday (1) would forward the date by 5 days forward and not backward
            /// by two days as it could be expected if the numbers were taken as is.
            ///
            inline date_time_period day_of_week(int v) { return date_time_period(day_of_week(),v); } 
            ///
            ///  Get date_time_period for: Original number of the day of the week in month. For example 1st Sunday, 
            /// 2nd Sunday, etc. in Gregorian [1..5]
            ///
            inline date_time_period day_of_week_in_month(int v) { return date_time_period(day_of_week_in_month(),v); } 
            ///
            ///  Get date_time_period for: Local day of week, for example in France Monday is 1, in US Sunday is 1, [1..7]
            ///
            inline date_time_period day_of_week_local(int v) { return date_time_period(day_of_week_local(),v); } 
            ///
            ///  Get date_time_period for: 24 clock hour [0..23]
            ///
            inline date_time_period hour(int v) { return date_time_period(hour(),v); } 
            ///
            ///  Get date_time_period for: 12 clock hour [0..11]
            ///
            inline date_time_period hour_12(int v) { return date_time_period(hour_12(),v); } 
            ///
            ///  Get date_time_period for: am or pm marker [0..1]
            ///
            inline date_time_period am_pm(int v) { return date_time_period(am_pm(),v); } 
            ///
            ///  Get date_time_period for: minute [0..59]
            ///
            inline date_time_period minute(int v) { return date_time_period(minute(),v); } 
            ///
            ///  Get date_time_period for: second [0..59]
            ///
            inline date_time_period second(int v) { return date_time_period(second(),v); } 
            ///
            ///  Get date_time_period for: The week number in the year
            ///
            inline date_time_period week_of_year(int v) { return date_time_period(week_of_year(),v); } 
            ///
            ///  Get date_time_period for: The week number within current month
            ///
            inline date_time_period week_of_month(int v) { return date_time_period(week_of_month(),v); } 
            ///
            ///  Get date_time_period for: First day of week, constant, for example Sunday in US = 1, Monday in France = 2
            ///
            inline date_time_period first_day_of_week(int v) { return date_time_period(first_day_of_week(),v); } 

            ///
            /// Get predefined constant for January
            ///
            inline date_time_period january() { return date_time_period(month(),0); }
            ///
            /// Get predefined constant for February
            ///
            inline date_time_period february() { return date_time_period(month(),1); }
            ///
            /// Get predefined constant for March
            ///
            inline date_time_period march() { return date_time_period(month(),2); }
            ///
            /// Get predefined constant for April
            ///
            inline date_time_period april() { return date_time_period(month(),3); }
            ///
            /// Get predefined constant for May
            ///
            inline date_time_period may() { return date_time_period(month(),4); }
            ///
            /// Get predefined constant for June
            ///
            inline date_time_period june() { return date_time_period(month(),5); }
            ///
            /// Get predefined constant for July
            ///
            inline date_time_period july() { return date_time_period(month(),6); }
            ///
            /// Get predefined constant for August
            ///
            inline date_time_period august() { return date_time_period(month(),7); }
            ///
            /// Get predefined constant for September
            ///
            inline date_time_period september() { return date_time_period(month(),8); }
            ///
            /// Get predefined constant for October 
            ///
            inline date_time_period october() { return date_time_period(month(),9); }
            ///
            /// Get predefined constant for November
            ///
            inline date_time_period november() { return date_time_period(month(),10); }
            ///
            /// Get predefined constant for December
            ///
            inline date_time_period december() { return date_time_period(month(),11); }

            ///
            /// Get predefined constant for Sunday
            ///
            inline date_time_period sunday() { return date_time_period(day_of_week(),1); }
            ///
            /// Get predefined constant for Monday 
            ///
            inline date_time_period monday() { return date_time_period(day_of_week(),2); }
            ///
            /// Get predefined constant for Tuesday
            ///
            inline date_time_period tuesday() { return date_time_period(day_of_week(),3); }
            ///
            /// Get predefined constant for Wednesday
            ///
            inline date_time_period wednesday() { return date_time_period(day_of_week(),4); }
            ///
            /// Get predefined constant for Thursday
            ///
            inline date_time_period thursday() { return date_time_period(day_of_week(),5); }
            ///
            /// Get predefined constant for Friday
            ///
            inline date_time_period friday() { return date_time_period(day_of_week(),6); }
            ///
            /// Get predefined constant for Saturday
            ///
            inline date_time_period saturday() { return date_time_period(day_of_week(),7); }
            ///
            /// Get predefined constant for AM (Ante Meridiem)
            ///
            inline date_time_period am() { return date_time_period(am_pm(),0); }
            ///
            /// Get predefined constant for PM (Post Meridiem)
            ///
            inline date_time_period pm() { return date_time_period(am_pm(),1); }

            ///
            /// convert period_type to date_time_period(f,1)
            ///
            inline date_time_period operator+(period::period_type f) 
            {
                return date_time_period(f);
            }
            ///
            /// convert period_type to date_time_period(f,-1)
            ///
            inline date_time_period operator-(period::period_type f)
            {
                return date_time_period(f,-1);
            }

            ///
            /// Create date_time_period of type \a f with value \a v. 
            ///
            template<typename T>
            date_time_period operator*(period::period_type f,T v)
            {
                return date_time_period(f,v);
            }

            ///
            /// Create date_time_period of type \a f with value \a v. 
            ///
            template<typename T>
            date_time_period operator*(T v,period::period_type f)
            {
                return date_time_period(f,v);
            }
            ///
            /// Create date_time_period of type \a f with value \a v. 
            ///
            template<typename T>
            date_time_period operator*(T v,date_time_period f)
            {
                return date_time_period(f.type,f.value*v);
            }

            ///
            /// Create date_time_period of type \a f with value \a v. 
            ///
            template<typename T>
            date_time_period operator*(date_time_period f,T v)
            {
                return date_time_period(f.type,f.value*v);
            }


        } // period


        ///
        /// \brief this class that represents a set of periods, 
        ///
        /// It is generally created by operations on periods:
        /// 1995*year + 3*month + 1*day. Note: operations are not commutative.
        ///
        class date_time_period_set {
        public:
            
            ///
            /// Default constructor - empty set
            ///
            date_time_period_set()
            {
            }
            ///
            /// Create a set of single period with value 1
            ///
            date_time_period_set(period::period_type f)
            {
                basic_[0]=date_time_period(f);
            }
            ///
            /// Create a set of single period \a fl
            ///
            date_time_period_set(date_time_period const &fl)
            {
                basic_[0]=fl;
            }
            ///
            /// Append date_time_period \a f to the set
            ///
            void add(date_time_period f)
            {
                size_t n=size();
                if(n < 4)
                    basic_[n]=f;
                else
                    periods_.push_back(f);
            }
            ///
            /// Get number if items in list
            ///
            size_t size() const
            {
                if(basic_[0].type == period::period_type())
                    return 0;
                if(basic_[1].type == period::period_type())
                    return 1;
                if(basic_[2].type == period::period_type())
                    return 2;
                if(basic_[3].type == period::period_type())
                    return 3;
                return 4+periods_.size();
            }
            ///
            /// Get item at position \a n the set, n should be in range [0,size)
            ///
            date_time_period const &operator[](size_t n) const 
            {
                if(n >= size())
                    throw std::out_of_range("Invalid index to date_time_period");
                if(n < 4)
                    return basic_[n];
                else
                    return periods_[n-4];
            }
        private:
            date_time_period basic_[4];
            std::vector<date_time_period> periods_;
        };

        
        ///
        /// Append two periods sets. Note this operator is not commutative 
        ///
        inline date_time_period_set operator+(date_time_period_set const &a,date_time_period_set const &b)
        {
            date_time_period_set s(a);
            for(unsigned i=0;i<b.size();i++)
                s.add(b[i]);
            return s;
        }
        
        ///
        /// Append two period sets when all periods of set \b change their sign
        ///
        inline date_time_period_set operator-(date_time_period_set const &a,date_time_period_set const &b)
        {
            date_time_period_set s(a);
            for(unsigned i=0;i<b.size();i++)
                s.add(-b[i]);
            return s;
        }


        ///
        /// \brief this class provides an access to general calendar information. 
        ///
        /// This information is not connected to specific date but generic to locale, and timezone.
        /// It is used in obtaining general information about calendar and is essential for creation of
        /// date_time objects.
        ///
        class BOOST_LOCALE_DECL calendar {
        public:

            ///
            /// Create calendar taking locale and timezone information from ios_base instance.
            /// 
            /// \note throws std::bad_cast if ios does not have a locale with installed \ref calendar_facet
            /// facet installed
            /// 
            calendar(std::ios_base &ios);
            ///
            /// Create calendar with locale \a l and time_zone \a zone
            ///
            /// \note throws std::bad_cast if loc does not have \ref calendar_facet facet installed
            /// 
            calendar(std::locale const &l,std::string const &zone);
            ///
            /// Create calendar with locale \a l and default timezone
            ///
            /// \note throws std::bad_cast if loc does not have \ref calendar_facet facet installed
            /// 
            calendar(std::locale const &l);
            ///
            /// Create calendar with default locale and timezone \a zone
            ///
            /// \note throws std::bad_cast if global locale does not have \ref calendar_facet facet installed
            /// 
            calendar(std::string const &zone);
            ///
            /// Create calendar with default locale and timezone 
            ///
            /// \note throws std::bad_cast if global locale does not have \ref calendar_facet facet installed
            /// 
            calendar();
            ~calendar();

            ///
            /// copy calendar
            ///
            calendar(calendar const &other);
            ///
            /// assign calendar
            ///
            calendar const &operator=(calendar const &other);

            ///
            /// Get minimum value for period f, For example for period::day it is 1.
            ///
            int minimum(period::period_type f) const;
            ///
            /// Get greatest possible minimum value for period f, For example for period::day it is 1, but may be different for other calendars.
            ///
            int greatest_minimum(period::period_type f) const;
            ///
            /// Get maximum value for period f, For example for Gregorian calendar's maximum period::day it is 31.
            ///
            int maximum(period::period_type f) const;
            ///
            /// Get least maximum value for period f, For example for Gregorian calendar's maximum period::day it is 28.
            ///
            int least_maximum(period::period_type f) const;

            ///
            /// Get first day of week for specific calendar, for example for US it is 1 - Sunday for France it is 2 - Monday
            int first_day_of_week() const;

            ///
            /// get calendar's locale
            ///
            std::locale get_locale() const;
            ///
            /// get calendar's time zone
            ///
            std::string get_time_zone() const;

            ///
            /// Check if the calendar is Gregorian
            ///
            bool is_gregorian() const;

            ///
            /// Compare calendars for equivalence: i.e. calendar types, time zones etc.
            ///
            bool operator==(calendar const &other) const;
            ///
            /// Opposite of ==
            ///
            bool operator!=(calendar const &other) const;

        private:
            friend class date_time;
            std::locale locale_;
            std::string tz_;
            hold_ptr<abstract_calendar> impl_;
        };

        ///
        /// \brief this class represents a date time and allows to perform various operation according to the
        /// locale settings.
        ///
        /// This class allows to manipulate various aspects of dates and times easily using arithmetic operations with
        /// periods.
        ///
        /// General arithmetic functions:
        ///
        /// - date_time + date_time_period_set = date_time: move time point forward by specific periods like date_time + month;
        /// - date_time - date_time_period_set = date_time: move time point backward by specific periods like date_time - month;
        /// - 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"
        /// - 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"
        /// - date_time / period_type = int - current period value: like "2010-12-21" / month == 12. "2010-12-21" / year = 2010
        /// - (date_time - date_time) / period_type = int: distance between dates in period_type. Like ("2010-12-01" - "2008-12-01") / month = 24.
        ///
        /// You can also assign specific periods using assignment operator like:
        /// some_time = year * 1995 that sets the year to 1995.
        ///
        ///
        
        class BOOST_LOCALE_DECL date_time {
        public:

            ///
            /// Dafault constructor, uses default calendar initialized date_time object to current time.
            ///
            /// \note throws std::bad_cast if the global locale does not have \ref calendar_facet facet installed
            /// 
            date_time();
            ///
            /// copy date_time
            ///
            date_time(date_time const &other);
            ///
            /// copy date_time and change some fields according to the \a set
            ///
            date_time(date_time const &other,date_time_period_set const &set);
            ///
            /// assign the date_time
            ///
            date_time const &operator=(date_time const &other);
            ~date_time();

            ///
            /// Create a date_time object using POSIX time \a time and default calendar
            ///
            /// \note throws std::bad_cast if the global locale does not have \ref calendar_facet facet installed
            /// 
            date_time(double time);
            ///
            /// Create a date_time object using POSIX time \a time and calendar \a cal
            ///
            date_time(double time,calendar const &cal);
            ///
            /// Create a date_time object using calendar \a cal and initializes it to current time.
            ///
            date_time(calendar const &cal);
            
            ///
            /// Create a date_time object using default calendar and define values given in \a set
            ///
            /// \note throws std::bad_cast if the global locale does not have \ref calendar_facet facet installed
            /// 
            date_time(date_time_period_set const &set);
            ///
            /// Create a date_time object using calendar \a cal and define values given in \a set
            ///
            date_time(date_time_period_set const &set,calendar const &cal);

           
            ///
            /// assign values to various periods in set \a f  
            ///
            date_time const &operator=(date_time_period_set const &f);

            ///
            /// set specific period \a f value to \a v
            ///
            void set(period::period_type f,int v);
            ///
            /// get specific period \a f value
            ///
            int get(period::period_type f) const;

            ///
            /// syntactic sugar for get(f)
            ///
            int operator/(period::period_type f) const
            {
                return get(f);
            }

            ///
            /// add single period f to the current date_time
            ///
            date_time operator+(period::period_type f) const
            {
                return *this+date_time_period(f);
            }

            ///
            /// subtract single period f from the current date_time
            ///
            date_time operator-(period::period_type f) const
            {
                return *this-date_time_period(f);
            }

            ///
            /// add single period f to the current date_time
            ///
            date_time const &operator+=(period::period_type f)
            {
                return *this+=date_time_period(f);
            }
            ///
            /// subtract single period f from the current date_time
            ///
            date_time const &operator-=(period::period_type f)
            {
                return *this-=date_time_period(f);
            }

            ///
            /// roll forward a date by single period f.
            ///
            date_time operator<<(period::period_type f) const
            {
                return *this<<date_time_period(f);
            }

            ///
            /// roll backward a date by single period f.
            ///
            date_time operator>>(period::period_type f) const
            {
                return *this>>date_time_period(f);
            }

            ///
            /// roll forward a date by single period f.
            ///
            date_time const &operator<<=(period::period_type f)
            {
                return *this<<=date_time_period(f);
            }
            ///
            /// roll backward a date by single period f.
            ///
            date_time const &operator>>=(period::period_type f)
            {
                return *this>>=date_time_period(f);
            }

            ///
            /// add date_time_period to the current date_time
            ///
            date_time operator+(date_time_period const &v) const;
            ///
            /// subtract date_time_period from the current date_time
            ///
            date_time operator-(date_time_period const &v) const;
            ///
            /// add date_time_period to the current date_time
            ///
            date_time const &operator+=(date_time_period const &v);
            ///
            /// subtract date_time_period from the current date_time
            ///
            date_time const &operator-=(date_time_period const &v);

            ///
            /// roll current date_time forward by date_time_period v
            ///
            date_time operator<<(date_time_period const &v) const;
            ///
            /// roll current date_time backward by date_time_period v
            ///
            date_time operator>>(date_time_period const &v) const ;
            ///
            /// roll current date_time forward by date_time_period v
            ///
            date_time const &operator<<=(date_time_period const &v);
            ///
            /// roll current date_time backward by date_time_period v
            ///
            date_time const &operator>>=(date_time_period const &v);

            ///
            /// add date_time_period_set v to the current date_time
            ///
            date_time operator+(date_time_period_set const &v) const;
            ///
            /// subtract date_time_period_set v from the current date_time
            ///
            date_time operator-(date_time_period_set const &v) const;
            ///
            /// add date_time_period_set v to the current date_time
            ///
            date_time const &operator+=(date_time_period_set const &v);
            ///
            /// subtract date_time_period_set v from the current date_time
            ///
            date_time const &operator-=(date_time_period_set const &v);

            ///
            /// roll current date_time forward by date_time_period_set v
            ///
            date_time operator<<(date_time_period_set const &v) const;
            ///
            /// roll current date_time backward by date_time_period_set v
            ///
            date_time operator>>(date_time_period_set const &v) const ;
            ///
            /// roll current date_time forward by date_time_period_set v
            ///
            date_time const &operator<<=(date_time_period_set const &v);
            ///
            /// roll current date_time backward by date_time_period_set v
            ///
            date_time const &operator>>=(date_time_period_set const &v);

            ///
            /// Get POSIX time
            ///
            /// The POSIX time is number of seconds since January 1st, 1970 00:00 UTC, ignoring leap seconds.
            ///
            double time() const;
            ///
            /// set POSIX time
            ///
            /// The POSIX time is number of seconds since January 1st, 1970 00:00 UTC, ignoring leap seconds.
            /// This time can be fetched from Operating system clock using C function time, gettimeofday and others.
            ///
            void time(double v);

            ///
            /// compare date_time in the timeline (ignores difference in calendar, timezone etc)
            ///
            bool operator==(date_time const &other) const;
            ///
            /// compare date_time in the timeline (ignores difference in calendar, timezone etc)
            ///
            bool operator!=(date_time const &other) const;
            ///
            /// compare date_time in the timeline (ignores difference in calendar, timezone etc)
            ///
            bool operator<(date_time const &other) const;
            ///
            /// compare date_time in the timeline (ignores difference in calendar, timezone etc)
            ///
            bool operator>(date_time const &other) const;
            ///
            /// compare date_time in the timeline (ignores difference in calendar, timezone etc)
            ///
            bool operator<=(date_time const &other) const;
            ///
            /// compare date_time in the timeline (ignores difference in calendar, timezone etc)
            ///
            bool operator>=(date_time const &other) const;

            ///
            /// swaps two dates - efficient, does not throw
            ///
            void swap(date_time &other);

            ///
            /// calculate the distance from this date_time to \a other in terms of perios \a f
            ///
            int difference(date_time const &other,period::period_type f) const;

            ///
            /// Get minimal possible value for *this time point for a period \a f.
            ///
            int minimum(period::period_type f) const;
            ///
            /// Get minimal possible value for *this time point for a period \a f. For example
            /// in February maximum(day) may be 28 or 29, in January maximum(day)==31
            ///
            int maximum(period::period_type f) const;

            ///
            /// Check if *this time point is in daylight saving time 
            ///
            bool is_in_daylight_saving_time() const;

        private:
            hold_ptr<abstract_calendar> impl_;
        };

        ///
        /// Writes date_time \a t to output stream \a out.
        ///
        /// This function uses locale, calendar and time zone of the target stream \a in.
        ///
        /// For example:
        /// \code
        ///  date_time now(time(0),hebrew_calendar)
        ///  cout << "Year: " << period::year(now) <<" Full Date:"<< now;
        /// \endcode
        ///
        /// The output may be Year:5770 Full Date:Jan 1, 2010
        /// 
        template<typename CharType>
        std::basic_ostream<CharType> &operator<<(std::basic_ostream<CharType> &out,date_time const &t)
        {
            double time_point = t.time();
            uint64_t display_flags = ios_info::get(out).display_flags();
            if  (
                    display_flags == flags::date 
                    || display_flags == flags::time 
                    || display_flags == flags::datetime 
                    || display_flags == flags::strftime
                ) 
            {
                out << time_point;
            }
            else {
                ios_info::get(out).display_flags(flags::datetime);
                out << time_point;
                ios_info::get(out).display_flags(display_flags);
            }
            return out;
        }

        ///
        /// Reads date_time \a t from output stream \a in
        ///
        /// This function uses locale, calendar and time zone of the source stream \a in.
        ///
        template<typename CharType>
        std::basic_istream<CharType> &operator>>(std::basic_istream<CharType> &in,date_time &t)
        {
            double v;
            uint64_t display_flags = ios_info::get(in).display_flags();
            if  (
                    display_flags == flags::date 
                    || display_flags == flags::time 
                    || display_flags == flags::datetime 
                    || display_flags == flags::strftime
                ) 
            {
                in >> v;
            }
            else {
                ios_info::get(in).display_flags(flags::datetime);
                in >> v;
                ios_info::get(in).display_flags(display_flags);
            }
            if(!in.fail())
                t.time(v);
            return in;
        }

        ///
        /// \brief This class represents a period: a pair of two date_time objects.
        /// 
        /// It is generally used as syntactic sugar to calculate difference between two dates.
        ///
        /// Note: it stores references to the original objects, so it is not recommended to be used
        /// outside of the equation you calculate the difference in.
        ///
        class date_time_duration {
        public:

            ///
            /// Create an object were \a first represents earlier point on time line and \a second is later
            /// point.
            /// 
            date_time_duration(date_time const &first,date_time const &second) :
                s_(first),
                e_(second)
            {
            }
            
            ///
            /// find a difference in terms of period_type \a f
            ///
            int get(period::period_type f) const
            {
                return start().difference(end(),f);
            }

            ///
            /// Syntactic sugar for get(f)
            ///
            int operator / (period::period_type f) const
            {
                return start().difference(end(),f);
            }

            ///
            /// Get starting point
            ///
            date_time const &start() const { return s_; }
            ///
            /// Get ending point
            ///
            date_time const &end() const { return e_; }
        private:
            date_time const &s_;
            date_time const &e_;
        };

        ///
        /// Calculates the difference between two dates, the left operand is a later point on time line.
        /// Returns date_time_duration object.
        ///
        inline date_time_duration operator-(date_time const &later,date_time const &earlier)
        {
            return date_time_duration(earlier,later);
        }

        
        namespace period {
            ///
            ///  Extract from date_time numerical value of Era i.e. AC, BC in Gregorian and Julian calendar, range [0,1]
            ///
            inline int era(date_time const &dt) { return dt.get(era()); } 
            ///
            ///  Extract from date_time numerical value of Year, it is calendar specific, for example 2011 in Gregorian calendar.
            ///
            inline int year(date_time const &dt) { return dt.get(year()); } 
            ///
            ///  Extract from date_time numerical value of Extended year for Gregorian/Julian calendars, where 1 BC == 0, 2 BC == -1.
            ///
            inline int extended_year(date_time const &dt) { return dt.get(extended_year()); } 
            ///
            ///  Extract from date_time numerical value of The month of year, calendar specific, in Gregorian [0..11]
            ///
            inline int month(date_time const &dt) { return dt.get(month()); } 
            ///
            ///  Extract from date_time numerical value of The day of month, calendar specific, in Gregorian [1..31]
            ///
            inline int day(date_time const &dt) { return dt.get(day()); } 
            ///
            ///  Extract from date_time numerical value of The number of day in year, starting from 1, in Gregorian  [1..366]
            ///
            inline int day_of_year(date_time const &dt) { return dt.get(day_of_year()); } 
            ///
            ///  Extract from date_time numerical value of Day of week, Sunday=1, Monday=2,..., Saturday=7.
            ///
            /// Note that updating this value respects local day of week, so for example,
            /// If first day of week is Monday and the current day is Tuesday then setting
            /// the value to Sunday (1) would forward the date by 5 days forward and not backward
            /// by two days as it could be expected if the numbers were taken as is.
            ///
            inline int day_of_week(date_time const &dt) { return dt.get(day_of_week()); } 
            ///
            ///  Extract from date_time numerical value of Original number of the day of the week in month. For example 1st Sunday, 
            /// 2nd Sunday, etc. in Gregorian [1..5]
            ///
            inline int day_of_week_in_month(date_time const &dt) { return dt.get(day_of_week_in_month()); } 
            ///
            ///  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]
            ///
            inline int day_of_week_local(date_time const &dt) { return dt.get(day_of_week_local()); } 
            ///
            ///  Extract from date_time numerical value of 24 clock hour [0..23]
            ///
            inline int hour(date_time const &dt) { return dt.get(hour()); } 
            ///
            ///  Extract from date_time numerical value of 12 clock hour [0..11]
            ///
            inline int hour_12(date_time const &dt) { return dt.get(hour_12()); } 
            ///
            ///  Extract from date_time numerical value of am or pm marker [0..1]
            ///
            inline int am_pm(date_time const &dt) { return dt.get(am_pm()); } 
            ///
            ///  Extract from date_time numerical value of minute [0..59]
            ///
            inline int minute(date_time const &dt) { return dt.get(minute()); } 
            ///
            ///  Extract from date_time numerical value of second [0..59]
            ///
            inline int second(date_time const &dt) { return dt.get(second()); } 
            ///
            ///  Extract from date_time numerical value of The week number in the year
            ///
            inline int week_of_year(date_time const &dt) { return dt.get(week_of_year()); } 
            ///
            ///  Extract from date_time numerical value of The week number within current month
            ///
            inline int week_of_month(date_time const &dt) { return dt.get(week_of_month()); } 
            ///
            ///  Extract from date_time numerical value of First day of week, constant, for example Sunday in US = 1, Monday in France = 2
            ///
            inline int first_day_of_week(date_time const &dt) { return dt.get(first_day_of_week()); } 
            
            ///
            ///  Extract from date_time_duration numerical value of duration in  Era i.e. AC, BC in Gregorian and Julian calendar, range [0,1]
            ///
            inline int era(date_time_duration const &dt) { return dt.get(era()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in years
            ///
            inline int year(date_time_duration const &dt) { return dt.get(year()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in extended years (for Gregorian/Julian calendars, where 1 BC == 0, 2 BC == -1).
            ///
            inline int extended_year(date_time_duration const &dt) { return dt.get(extended_year()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in months
            ///
            inline int month(date_time_duration const &dt) { return dt.get(month()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in days of month
            ///
            inline int day(date_time_duration const &dt) { return dt.get(day()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in days of year
            ///
            inline int day_of_year(date_time_duration const &dt) { return dt.get(day_of_year()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in days of week
            ///
            inline int day_of_week(date_time_duration const &dt) { return dt.get(day_of_week()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in original number of the day of the week in month
            ///
            inline int day_of_week_in_month(date_time_duration const &dt) { return dt.get(day_of_week_in_month()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in local day of week
            ///
            inline int day_of_week_local(date_time_duration const &dt) { return dt.get(day_of_week_local()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in hours
            ///
            inline int hour(date_time_duration const &dt) { return dt.get(hour()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in  12 clock hours
            ///
            inline int hour_12(date_time_duration const &dt) { return dt.get(hour_12()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in  am or pm markers
            ///
            inline int am_pm(date_time_duration const &dt) { return dt.get(am_pm()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in  minutes
            ///
            inline int minute(date_time_duration const &dt) { return dt.get(minute()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in  seconds
            ///
            inline int second(date_time_duration const &dt) { return dt.get(second()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in the week number in the year
            ///
            inline int week_of_year(date_time_duration const &dt) { return dt.get(week_of_year()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in  The week number within current month
            ///
            inline int week_of_month(date_time_duration const &dt) { return dt.get(week_of_month()); } 
            ///
            ///  Extract from date_time_duration numerical value of duration in the first day of week
            ///
            inline int first_day_of_week(date_time_duration const &dt) { return dt.get(first_day_of_week()); } 


        }
        
        /// @}


    } // locale
} // boost

#ifdef BOOST_MSVC
#pragma warning(pop)
#endif


#endif
///
/// \example calendar.cpp
///
/// Example of using date_time functions for generating calendar for current year.
///

// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4