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