period.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. #ifndef DATE_TIME_PERIOD_HPP___
  2. #define DATE_TIME_PERIOD_HPP___
  3. /* Copyright (c) 2002,2003 CrystalClear Software, Inc.
  4. * Use, modification and distribution is subject to the
  5. * Boost Software License, Version 1.0. (See accompanying
  6. * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
  7. * Author: Jeff Garland, Bart Garst
  8. * $Date$
  9. */
  10. /*! \file period.hpp
  11. This file contain the implementation of the period abstraction. This is
  12. basically the same idea as a range. Although this class is intended for
  13. use in the time library, it is pretty close to general enough for other
  14. numeric uses.
  15. */
  16. #include <boost/operators.hpp>
  17. #include <boost/date_time/compiler_config.hpp>
  18. namespace boost {
  19. namespace date_time {
  20. //!Provides generalized period type useful in date-time systems
  21. /*!This template uses a class to represent a time point within the period
  22. and another class to represent a duration. As a result, this class is
  23. not appropriate for use when the number and duration representation
  24. are the same (eg: in the regular number domain).
  25. A period can be specified by providing either the begining point and
  26. a duration or the begining point and the end point( end is NOT part
  27. of the period but 1 unit past it. A period will be "invalid" if either
  28. end_point <= begin_point or the given duration is <= 0. Any valid period
  29. will return false for is_null().
  30. Zero length periods are also considered invalid. Zero length periods are
  31. periods where the begining and end points are the same, or, the given
  32. duration is zero. For a zero length period, the last point will be one
  33. unit less than the begining point.
  34. In the case that the begin and last are the same, the period has a
  35. length of one unit.
  36. The best way to handle periods is usually to provide a begining point and
  37. a duration. So, day1 + 7 days is a week period which includes all of the
  38. first day and 6 more days (eg: Sun to Sat).
  39. */
  40. template<class point_rep, class duration_rep>
  41. class BOOST_SYMBOL_VISIBLE period : private
  42. boost::less_than_comparable<period<point_rep, duration_rep>
  43. , boost::equality_comparable< period<point_rep, duration_rep>
  44. > >
  45. {
  46. public:
  47. typedef point_rep point_type;
  48. typedef duration_rep duration_type;
  49. period(point_rep first_point, point_rep end_point);
  50. period(point_rep first_point, duration_rep len);
  51. point_rep begin() const;
  52. point_rep end() const;
  53. point_rep last() const;
  54. duration_rep length() const;
  55. bool is_null() const;
  56. bool operator==(const period& rhs) const;
  57. bool operator<(const period& rhs) const;
  58. void shift(const duration_rep& d);
  59. void expand(const duration_rep& d);
  60. bool contains(const point_rep& point) const;
  61. bool contains(const period& other) const;
  62. bool intersects(const period& other) const;
  63. bool is_adjacent(const period& other) const;
  64. bool is_before(const point_rep& point) const;
  65. bool is_after(const point_rep& point) const;
  66. period intersection(const period& other) const;
  67. period merge(const period& other) const;
  68. period span(const period& other) const;
  69. private:
  70. point_rep begin_;
  71. point_rep last_;
  72. };
  73. //! create a period from begin to last eg: [begin,end)
  74. /*! If end <= begin then the period will be invalid
  75. */
  76. template<class point_rep, class duration_rep>
  77. inline
  78. period<point_rep,duration_rep>::period(point_rep first_point,
  79. point_rep end_point) :
  80. begin_(first_point),
  81. last_(end_point - duration_rep::unit())
  82. {}
  83. //! create a period as [begin, begin+len)
  84. /*! If len is <= 0 then the period will be invalid
  85. */
  86. template<class point_rep, class duration_rep>
  87. inline
  88. period<point_rep,duration_rep>::period(point_rep first_point, duration_rep len) :
  89. begin_(first_point),
  90. last_(first_point + len-duration_rep::unit())
  91. { }
  92. //! Return the first element in the period
  93. template<class point_rep, class duration_rep>
  94. inline
  95. point_rep period<point_rep,duration_rep>::begin() const
  96. {
  97. return begin_;
  98. }
  99. //! Return one past the last element
  100. template<class point_rep, class duration_rep>
  101. inline
  102. point_rep period<point_rep,duration_rep>::end() const
  103. {
  104. return last_ + duration_rep::unit();
  105. }
  106. //! Return the last item in the period
  107. template<class point_rep, class duration_rep>
  108. inline
  109. point_rep period<point_rep,duration_rep>::last() const
  110. {
  111. return last_;
  112. }
  113. //! True if period is ill formed (length is zero or less)
  114. template<class point_rep, class duration_rep>
  115. inline
  116. bool period<point_rep,duration_rep>::is_null() const
  117. {
  118. return end() <= begin_;
  119. }
  120. //! Return the length of the period
  121. template<class point_rep, class duration_rep>
  122. inline
  123. duration_rep period<point_rep,duration_rep>::length() const
  124. {
  125. if(last_ < begin_){ // invalid period
  126. return last_+duration_rep::unit() - begin_;
  127. }
  128. else{
  129. return end() - begin_; // normal case
  130. }
  131. }
  132. //! Equality operator
  133. template<class point_rep, class duration_rep>
  134. inline
  135. bool period<point_rep,duration_rep>::operator==(const period& rhs) const
  136. {
  137. return ((begin_ == rhs.begin_) &&
  138. (last_ == rhs.last_));
  139. }
  140. //! Strict as defined by rhs.last <= lhs.last
  141. template<class point_rep, class duration_rep>
  142. inline
  143. bool period<point_rep,duration_rep>::operator<(const period& rhs) const
  144. {
  145. return (last_ < rhs.begin_);
  146. }
  147. //! Shift the start and end by the specified amount
  148. template<class point_rep, class duration_rep>
  149. inline
  150. void period<point_rep,duration_rep>::shift(const duration_rep& d)
  151. {
  152. begin_ = begin_ + d;
  153. last_ = last_ + d;
  154. }
  155. /** Expands the size of the period by the duration on both ends.
  156. *
  157. *So before expand
  158. *@code
  159. *
  160. * [-------]
  161. * ^ ^ ^ ^ ^ ^ ^
  162. * 1 2 3 4 5 6 7
  163. *
  164. *@endcode
  165. * After expand(2)
  166. *@code
  167. *
  168. * [----------------------]
  169. * ^ ^ ^ ^ ^ ^ ^
  170. * 1 2 3 4 5 6 7
  171. *
  172. *@endcode
  173. */
  174. template<class point_rep, class duration_rep>
  175. inline
  176. void period<point_rep,duration_rep>::expand(const duration_rep& d)
  177. {
  178. begin_ = begin_ - d;
  179. last_ = last_ + d;
  180. }
  181. //! True if the point is inside the period, zero length periods contain no points
  182. template<class point_rep, class duration_rep>
  183. inline
  184. bool period<point_rep,duration_rep>::contains(const point_rep& point) const
  185. {
  186. return ((point >= begin_) &&
  187. (point <= last_));
  188. }
  189. //! True if this period fully contains (or equals) the other period
  190. template<class point_rep, class duration_rep>
  191. inline
  192. bool period<point_rep,duration_rep>::contains(const period<point_rep,duration_rep>& other) const
  193. {
  194. return ((begin_ <= other.begin_) && (last_ >= other.last_));
  195. }
  196. //! True if periods are next to each other without a gap.
  197. /* In the example below, p1 and p2 are adjacent, but p3 is not adjacent
  198. * with either of p1 or p2.
  199. *@code
  200. * [-p1-)
  201. * [-p2-)
  202. * [-p3-)
  203. *@endcode
  204. */
  205. template<class point_rep, class duration_rep>
  206. inline
  207. bool
  208. period<point_rep,duration_rep>::is_adjacent(const period<point_rep,duration_rep>& other) const
  209. {
  210. return (other.begin() == end() ||
  211. begin_ == other.end());
  212. }
  213. //! True if all of the period is prior or t < start
  214. /* In the example below only point 1 would evaluate to true.
  215. *@code
  216. * [---------])
  217. * ^ ^ ^ ^ ^
  218. * 1 2 3 4 5
  219. *
  220. *@endcode
  221. */
  222. template<class point_rep, class duration_rep>
  223. inline
  224. bool
  225. period<point_rep,duration_rep>::is_after(const point_rep& t) const
  226. {
  227. if (is_null())
  228. {
  229. return false; //null period isn't after
  230. }
  231. return t < begin_;
  232. }
  233. //! True if all of the period is prior to the passed point or end <= t
  234. /* In the example below points 4 and 5 return true.
  235. *@code
  236. * [---------])
  237. * ^ ^ ^ ^ ^
  238. * 1 2 3 4 5
  239. *
  240. *@endcode
  241. */
  242. template<class point_rep, class duration_rep>
  243. inline
  244. bool
  245. period<point_rep,duration_rep>::is_before(const point_rep& t) const
  246. {
  247. if (is_null())
  248. {
  249. return false; //null period isn't before anything
  250. }
  251. return last_ < t;
  252. }
  253. //! True if the periods overlap in any way
  254. /* In the example below p1 intersects with p2, p4, and p6.
  255. *@code
  256. * [---p1---)
  257. * [---p2---)
  258. * [---p3---)
  259. * [---p4---)
  260. * [-p5-)
  261. * [-p6-)
  262. *@endcode
  263. */
  264. template<class point_rep, class duration_rep>
  265. inline
  266. bool period<point_rep,duration_rep>::intersects(const period<point_rep,duration_rep>& other) const
  267. {
  268. return ( contains(other.begin_) ||
  269. other.contains(begin_) ||
  270. ((other.begin_ < begin_) && (other.last_ >= begin_)));
  271. }
  272. //! Returns the period of intersection or invalid range no intersection
  273. template<class point_rep, class duration_rep>
  274. inline
  275. period<point_rep,duration_rep>
  276. period<point_rep,duration_rep>::intersection(const period<point_rep,duration_rep>& other) const
  277. {
  278. if (begin_ > other.begin_) {
  279. if (last_ <= other.last_) { //case2
  280. return *this;
  281. }
  282. //case 1
  283. return period<point_rep,duration_rep>(begin_, other.end());
  284. }
  285. else {
  286. if (last_ <= other.last_) { //case3
  287. return period<point_rep,duration_rep>(other.begin_, this->end());
  288. }
  289. //case4
  290. return other;
  291. }
  292. //unreachable
  293. }
  294. //! Returns the union of intersecting periods -- or null period
  295. /*!
  296. */
  297. template<class point_rep, class duration_rep>
  298. inline
  299. period<point_rep,duration_rep>
  300. period<point_rep,duration_rep>::merge(const period<point_rep,duration_rep>& other) const
  301. {
  302. if (this->intersects(other)) {
  303. if (begin_ < other.begin_) {
  304. return period<point_rep,duration_rep>(begin_, last_ > other.last_ ? this->end() : other.end());
  305. }
  306. return period<point_rep,duration_rep>(other.begin_, last_ > other.last_ ? this->end() : other.end());
  307. }
  308. return period<point_rep,duration_rep>(begin_,begin_); // no intersect return null
  309. }
  310. //! Combine two periods with earliest start and latest end.
  311. /*! Combines two periods and any gap between them such that
  312. * start = min(p1.start, p2.start)
  313. * end = max(p1.end , p2.end)
  314. *@code
  315. * [---p1---)
  316. * [---p2---)
  317. * result:
  318. * [-----------p3----------)
  319. *@endcode
  320. */
  321. template<class point_rep, class duration_rep>
  322. inline
  323. period<point_rep,duration_rep>
  324. period<point_rep,duration_rep>::span(const period<point_rep,duration_rep>& other) const
  325. {
  326. point_rep start((begin_ < other.begin_) ? begin() : other.begin());
  327. point_rep newend((last_ < other.last_) ? other.end() : this->end());
  328. return period<point_rep,duration_rep>(start, newend);
  329. }
  330. } } //namespace date_time
  331. #endif