| 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_FACET_HPP_INCLUDED |
| 8 | #define BOOST_LOCALE_DATE_TIME_FACET_HPP_INCLUDED |
| 9 | |
| 10 | #include <boost/locale/config.hpp> |
| 11 | #include <boost/locale/detail/facet_id.hpp> |
| 12 | #include <cstdint> |
| 13 | #include <locale> |
| 14 | |
| 15 | #ifdef BOOST_MSVC |
| 16 | # pragma warning(push) |
| 17 | # pragma warning(disable : 4275 4251 4231 4660) |
| 18 | #endif |
| 19 | |
| 20 | namespace boost { namespace locale { |
| 21 | |
| 22 | /// \brief Namespace that contains various types for manipulation with dates |
| 23 | namespace period { |
| 24 | |
| 25 | /// \brief This namespace holds a enum of various period types like era, year, month, etc.. |
| 26 | namespace marks { |
| 27 | |
| 28 | /// \brief the type that defines a flag that holds a period identifier |
| 29 | enum period_mark { |
| 30 | invalid, ///< Special invalid value, should not be used directly |
| 31 | era, ///< Era i.e. AC, BC in Gregorian and Julian calendar, range [0,1] |
| 32 | year, ///< Year, it is calendar specific, for example 2011 in Gregorian calendar. |
| 33 | extended_year, ///< Extended year for Gregorian/Julian calendars, where 1 BC == 0, 2 BC == -1. |
| 34 | month, ///< The month of year, calendar specific, in Gregorian [0..11] |
| 35 | day, ///< The day of month, calendar specific, in Gregorian [1..31] |
| 36 | day_of_year, ///< The number of day in year, starting from 1, in Gregorian [1..366] |
| 37 | day_of_week, ///< Day of week, Sunday=1, Monday=2,..., Saturday=7. |
| 38 | ///< Note that updating this value respects local day of week, so for example, |
| 39 | ///< If first day of week is Monday and the current day is Tuesday then setting |
| 40 | ///< the value to Sunday (1) would forward the date by 5 days forward and not backward |
| 41 | ///< by two days as it could be expected if the numbers were taken as is. |
| 42 | day_of_week_in_month, ///< Original number of the day of the week in month. For example 1st Sunday, |
| 43 | ///< 2nd Sunday, etc. in Gregorian [1..5] |
| 44 | day_of_week_local, ///< Local day of week, for example in France Monday is 1, in US Sunday is 1, [1..7] |
| 45 | hour, ///< 24 clock hour [0..23] |
| 46 | hour_12, ///< 12 clock hour [0..11] |
| 47 | am_pm, ///< am or pm marker [0..1] |
| 48 | minute, ///< minute [0..59] |
| 49 | second, ///< second [0..59] |
| 50 | week_of_year, ///< The week number in the year |
| 51 | week_of_month, ///< The week number within current month |
| 52 | first_day_of_week, ///< First day of week, constant, for example Sunday in US = 1, Monday in France = 2 |
| 53 | }; |
| 54 | |
| 55 | } // namespace marks |
| 56 | |
| 57 | /// \brief This class holds a type that represents certain period of time like |
| 58 | /// year, hour, second and so on. |
| 59 | /// |
| 60 | /// It can be created from either marks::period_mark type or by using shortcuts in period |
| 61 | /// namespace - calling functions like period::year(), period::hour() and so on. |
| 62 | /// |
| 63 | /// Basically it represents the same object as enum marks::period_mark but allows to |
| 64 | /// provide save operator overloading that would not collide with casing of enum to |
| 65 | /// numeric values. |
| 66 | class period_type { |
| 67 | public: |
| 68 | /// Create a period of specific type, default is invalid. |
| 69 | period_type(marks::period_mark m = marks::invalid) : mark_(m) {} |
| 70 | |
| 71 | /// Get the value of marks::period_mark it was created with. |
| 72 | marks::period_mark mark() const { return mark_; } |
| 73 | |
| 74 | /// Check if two periods are the same |
| 75 | bool operator==(const period_type& other) const { return mark() == other.mark(); } |
| 76 | /// Check if two periods are different |
| 77 | bool operator!=(const period_type& other) const { return mark() != other.mark(); } |
| 78 | |
| 79 | private: |
| 80 | marks::period_mark mark_; |
| 81 | }; |
| 82 | |
| 83 | } // namespace period |
| 84 | |
| 85 | /// Structure that define POSIX time, seconds and milliseconds |
| 86 | /// since Jan 1, 1970, 00:00 not including leap seconds. |
| 87 | struct posix_time { |
| 88 | int64_t seconds; ///< Seconds since epoch |
| 89 | uint32_t nanoseconds; ///< Nanoseconds resolution |
| 90 | }; |
| 91 | |
| 92 | /// This class defines generic calendar class, it is used by date_time and calendar |
| 93 | /// objects internally. It is less useful for end users, but it is build for localization |
| 94 | /// backend implementation |
| 95 | class BOOST_SYMBOL_VISIBLE abstract_calendar { |
| 96 | public: |
| 97 | /// Type that defines how to fetch the value |
| 98 | enum value_type { |
| 99 | absolute_minimum, ///< Absolute possible minimum for the value, for example for day is 1 |
| 100 | actual_minimum, ///< Actual minimal value for this period. |
| 101 | greatest_minimum, ///< Maximal minimum value that can be for this period |
| 102 | current, ///< Current value of this period |
| 103 | least_maximum, ///< The last maximal value for this period, For example for Gregorian calendar |
| 104 | ///< day it is 28 |
| 105 | actual_maximum, ///< Actual maximum, for it can be 28, 29, 30, 31 for day according to current month |
| 106 | absolute_maximum, ///< Maximal value, for Gregorian day it would be 31. |
| 107 | }; |
| 108 | |
| 109 | /// A way to update the value |
| 110 | enum update_type { |
| 111 | move, ///< Change the value up or down effecting others for example 1990-12-31 + 1 day = 1991-01-01 |
| 112 | roll, ///< Change the value up or down not effecting others for example 1990-12-31 + 1 day = 1990-12-01 |
| 113 | }; |
| 114 | |
| 115 | /// Information about calendar |
| 116 | enum calendar_option_type { |
| 117 | is_gregorian, ///< Check if the calendar is Gregorian |
| 118 | is_dst ///< Check if the current time is in daylight time savings |
| 119 | }; |
| 120 | |
| 121 | /// Make a polymorphic copy of the calendar |
| 122 | virtual abstract_calendar* clone() const = 0; |
| 123 | |
| 124 | /// Set specific \a value for period \a p, note not all values are settable. |
| 125 | /// |
| 126 | /// After calling set_value you may want to call normalize() function to make sure |
| 127 | /// all periods are updated, if you set several fields that are part of a single |
| 128 | /// date/time representation you should call set_value several times and then |
| 129 | /// call normalize(). |
| 130 | /// |
| 131 | /// If normalize() is not called after set_value, the behavior is undefined |
| 132 | virtual void set_value(period::marks::period_mark m, int value) = 0; |
| 133 | |
| 134 | /// Recalculate all periods after setting them, should be called after use of set_value() function. |
| 135 | virtual void normalize() = 0; |
| 136 | |
| 137 | /// Get specific value for period \a p according to a value_type \a v |
| 138 | virtual int get_value(period::marks::period_mark m, value_type v) const = 0; |
| 139 | |
| 140 | /// Set current time point |
| 141 | virtual void set_time(const posix_time& p) = 0; |
| 142 | /// Get current time point |
| 143 | virtual posix_time get_time() const = 0; |
| 144 | /// Get current time since epoch in milliseconds |
| 145 | virtual double get_time_ms() const = 0; |
| 146 | |
| 147 | /// Set option for calendar, for future use |
| 148 | virtual void set_option(calendar_option_type opt, int v) = 0; |
| 149 | /// Get option for calendar, currently only check if it is Gregorian calendar |
| 150 | virtual int get_option(calendar_option_type opt) const = 0; |
| 151 | |
| 152 | /// Adjust period's \a p value by \a difference items using a update_type \a u. |
| 153 | /// Note: not all values are adjustable |
| 154 | virtual void adjust_value(period::marks::period_mark m, update_type u, int difference) = 0; |
| 155 | |
| 156 | /// Calculate the difference between this calendar and \a other in \a p units |
| 157 | virtual int difference(const abstract_calendar& other, period::marks::period_mark m) const = 0; |
| 158 | |
| 159 | /// Set time zone, empty - use system |
| 160 | virtual void set_timezone(const std::string& tz) = 0; |
| 161 | /// Get current time zone, empty - system one |
| 162 | virtual std::string get_timezone() const = 0; |
| 163 | |
| 164 | /// Check of two calendars have same rules |
| 165 | virtual bool same(const abstract_calendar* other) const = 0; |
| 166 | |
| 167 | virtual ~abstract_calendar() = default; |
| 168 | }; |
| 169 | |
| 170 | /// \brief the facet that generates calendar for specific locale |
| 171 | class BOOST_SYMBOL_VISIBLE calendar_facet : public std::locale::facet, public detail::facet_id<calendar_facet> { |
| 172 | public: |
| 173 | /// Basic constructor |
| 174 | calendar_facet(size_t refs = 0) : std::locale::facet(refs) {} |
| 175 | /// Create a new calendar that points to current point of time. |
| 176 | virtual abstract_calendar* create_calendar() const = 0; |
| 177 | }; |
| 178 | |
| 179 | }} // namespace boost::locale |
| 180 | |
| 181 | #ifdef BOOST_MSVC |
| 182 | # pragma warning(pop) |
| 183 | #endif |
| 184 | |
| 185 | #endif |
| 186 | |