date_time_facet.hpp 8.8 KB

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