1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
5 Copyright (C) 2003, 2004, 2005, 2006 StatPro Italia srl
6 Copyright (C) 2004, 2005, 2006 Ferdinando Ametrano
7 Copyright (C) 2006 Katiuscia Manzoni
8 Copyright (C) 2006 Toyin Akin
9 Copyright (C) 2015 Klaus Spanderen
10 Copyright (C) 2020 Leonardo Arcari
11 Copyright (C) 2020 Kline s.r.l.
12
13 This file is part of QuantLib, a free-software/open-source library
14 for financial quantitative analysts and developers - http://quantlib.org/
15
16 QuantLib is free software: you can redistribute it and/or modify it
17 under the terms of the QuantLib license. You should have received a
18 copy of the license along with this program; if not, please email
19 <quantlib-dev@lists.sf.net>. The license is also available online at
20 <http://quantlib.org/license.shtml>.
21
22 This program is distributed in the hope that it will be useful, but WITHOUT
23 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
24 FOR A PARTICULAR PURPOSE. See the license for more details.
25*/
26
27/*! \file date.hpp
28 \brief date- and time-related classes, typedefs and enumerations
29*/
30
31#ifndef quantlib_date_hpp
32#define quantlib_date_hpp
33
34#include <ql/time/period.hpp>
35#include <ql/time/weekday.hpp>
36#include <ql/utilities/null.hpp>
37
38#ifdef QL_HIGH_RESOLUTION_DATE
39#include <boost/date_time/posix_time/ptime.hpp>
40#include <boost/date_time/posix_time/posix_time_duration.hpp>
41#endif
42
43#include <cstdint>
44#include <utility>
45#include <functional>
46#include <string>
47
48
49namespace QuantLib {
50
51 //! Day number
52 /*! \ingroup datetime */
53 typedef Integer Day;
54
55 //! Month names
56 /*! \ingroup datetime */
57 enum Month { January = 1,
58 February = 2,
59 March = 3,
60 April = 4,
61 May = 5,
62 June = 6,
63 July = 7,
64 August = 8,
65 September = 9,
66 October = 10,
67 November = 11,
68 December = 12,
69 Jan = 1,
70 Feb = 2,
71 Mar = 3,
72 Apr = 4,
73 Jun = 6,
74 Jul = 7,
75 Aug = 8,
76 Sep = 9,
77 Oct = 10,
78 Nov = 11,
79 Dec = 12
80 };
81
82 /*! \relates Month */
83 std::ostream& operator<<(std::ostream&, Month);
84
85 //! Year number
86 /*! \ingroup datetime */
87 typedef Integer Year;
88
89#ifdef QL_HIGH_RESOLUTION_DATE
90 //! Hour number
91 /*! \ingroup datetime */
92 typedef boost::posix_time::hours::hour_type Hour;
93
94 //! Minute number
95 /*! \ingroup datetime */
96 typedef boost::posix_time::minutes::min_type Minute;
97
98 //! Second number
99 /*! \ingroup datetime */
100 typedef boost::posix_time::minutes::sec_type Second;
101
102 //! Millisecond number
103 /*! \ingroup datetime */
104 typedef boost::posix_time::time_duration::fractional_seconds_type
105 Millisecond;
106
107 //! Millisecond number
108 /*! \ingroup datetime */
109 typedef boost::posix_time::time_duration::fractional_seconds_type
110 Microsecond;
111#endif
112
113 //! Concrete date class
114 /*! This class provides methods to inspect dates as well as methods and
115 operators which implement a limited date algebra (increasing and
116 decreasing dates, and calculating their difference).
117
118 \ingroup datetime
119
120 \test self-consistency of dates, serial numbers, days of
121 month, months, and weekdays is checked over the whole
122 date range.
123 */
124
125 class Date {
126 public:
127 //! serial number type
128 typedef std::int_fast32_t serial_type;
129 //! \name constructors
130 //@{
131 //! Default constructor returning a null date.
132 Date();
133 //! Constructor taking a serial number as given by Applix or Excel.
134 explicit Date(Date::serial_type serialNumber);
135 //! More traditional constructor.
136 Date(Day d, Month m, Year y);
137
138#ifdef QL_HIGH_RESOLUTION_DATE
139 //! Constructor taking boost posix date time object
140 explicit Date(const boost::posix_time::ptime& localTime);
141 //! More traditional constructor.
142 Date(Day d, Month m, Year y,
143 Hour hours, Minute minutes, Second seconds,
144 Millisecond millisec = 0, Microsecond microsec = 0);
145#endif
146 //@}
147
148 //! \name inspectors
149 //@{
150 Weekday weekday() const;
151 Day dayOfMonth() const;
152 //! One-based (Jan 1st = 1)
153 Day dayOfYear() const;
154 Month month() const;
155 Year year() const;
156 Date::serial_type serialNumber() const;
157
158#ifdef QL_HIGH_RESOLUTION_DATE
159 Hour hours() const;
160 Minute minutes() const;
161 Second seconds() const;
162 Millisecond milliseconds() const;
163 Microsecond microseconds() const;
164
165 Time fractionOfDay() const;
166 Time fractionOfSecond() const;
167
168 const boost::posix_time::ptime& dateTime() const;
169#endif
170 //@}
171
172 //! \name date algebra
173 //@{
174 //! increments date by the given number of days
175 Date& operator+=(Date::serial_type days);
176 //! increments date by the given period
177 Date& operator+=(const Period&);
178 //! decrement date by the given number of days
179 Date& operator-=(Date::serial_type days);
180 //! decrements date by the given period
181 Date& operator-=(const Period&);
182 //! 1-day pre-increment
183 Date& operator++();
184 //! 1-day post-increment
185 Date operator++(int );
186 //! 1-day pre-decrement
187 Date& operator--();
188 //! 1-day post-decrement
189 Date operator--(int );
190 //! returns a new date incremented by the given number of days
191 Date operator+(Date::serial_type days) const;
192 //! returns a new date incremented by the given period
193 Date operator+(const Period&) const;
194 //! returns a new date decremented by the given number of days
195 Date operator-(Date::serial_type days) const;
196 //! returns a new date decremented by the given period
197 Date operator-(const Period&) const;
198 //@}
199
200 //! \name static methods
201 //@{
202 //! today's date.
203 static Date todaysDate();
204 //! earliest allowed date
205 static Date minDate();
206 //! latest allowed date
207 static Date maxDate();
208 //! whether the given year is a leap one
209 static bool isLeap(Year y);
210 //! last day of the month to which the given date belongs
211 static Date endOfMonth(const Date& d);
212 //! whether a date is the last day of its month
213 static bool isEndOfMonth(const Date& d);
214 //! next given weekday following or equal to the given date
215 /*! E.g., the Friday following Tuesday, January 15th, 2002
216 was January 18th, 2002.
217
218 see http://www.cpearson.com/excel/DateTimeWS.htm
219 */
220 static Date nextWeekday(const Date& d,
221 Weekday w);
222 //! n-th given weekday in the given month and year
223 /*! E.g., the 4th Thursday of March, 1998 was March 26th,
224 1998.
225
226 see http://www.cpearson.com/excel/DateTimeWS.htm
227 */
228 static Date nthWeekday(Size n,
229 Weekday w,
230 Month m,
231 Year y);
232
233#ifdef QL_HIGH_RESOLUTION_DATE
234 //! local date time, based on the time zone settings of the computer
235 static Date localDateTime();
236 //! UTC date time
237 static Date universalDateTime();
238
239 //! underlying resolution of the posix date time object
240 static boost::posix_time::time_duration::tick_type ticksPerSecond();
241#endif
242
243 //@}
244
245 private:
246 static Date::serial_type minimumSerialNumber();
247 static Date::serial_type maximumSerialNumber();
248 static void checkSerialNumber(Date::serial_type serialNumber);
249
250#ifdef QL_HIGH_RESOLUTION_DATE
251 boost::posix_time::ptime dateTime_;
252#else
253 Date::serial_type serialNumber_;
254 static Date advance(const Date& d, Integer units, TimeUnit);
255 static Integer monthLength(Month m, bool leapYear);
256 static Integer monthOffset(Month m, bool leapYear);
257 static Date::serial_type yearOffset(Year y);
258#endif
259 };
260
261 /*! \relates Date
262 \brief Difference in days between dates
263 */
264 Date::serial_type operator-(const Date&, const Date&);
265 /*! \relates Date
266 \brief Difference in days (including fraction of days) between dates
267 */
268 Time daysBetween(const Date&, const Date&);
269
270 /*! \relates Date */
271 bool operator==(const Date&, const Date&);
272 /*! \relates Date */
273 bool operator!=(const Date&, const Date&);
274 /*! \relates Date */
275 bool operator<(const Date&, const Date&);
276 /*! \relates Date */
277 bool operator<=(const Date&, const Date&);
278 /*! \relates Date */
279 bool operator>(const Date&, const Date&);
280 /*! \relates Date */
281 bool operator>=(const Date&, const Date&);
282
283 /*!
284 Compute a hash value of @p d.
285
286 This method makes Date hashable via <tt>boost::hash</tt>.
287
288 Example:
289
290 \code{.cpp}
291 #include <unordered_set>
292
293 std::unordered_set<Date> set;
294 Date d = Date(1, Jan, 2020);
295
296 set.insert(d);
297 assert(set.count(d)); // 'd' was added to 'set'
298 \endcode
299
300 \param [in] d Date to hash
301 \return A hash value of @p d
302 \relates Date
303 */
304 std::size_t hash_value(const Date& d);
305
306 /*! \relates Date */
307 std::ostream& operator<<(std::ostream&, const Date&);
308
309 namespace detail {
310
311 struct short_date_holder {
312 explicit short_date_holder(const Date d) : d(d) {}
313 Date d;
314 };
315 std::ostream& operator<<(std::ostream&, const short_date_holder&);
316
317 struct long_date_holder {
318 explicit long_date_holder(const Date& d) : d(d) {}
319 Date d;
320 };
321 std::ostream& operator<<(std::ostream&, const long_date_holder&);
322
323 struct iso_date_holder {
324 explicit iso_date_holder(const Date& d) : d(d) {}
325 Date d;
326 };
327 std::ostream& operator<<(std::ostream&, const iso_date_holder&);
328
329 struct formatted_date_holder {
330 formatted_date_holder(const Date& d, std::string f) : d(d), f(std::move(f)) {}
331 Date d;
332 std::string f;
333 };
334 std::ostream& operator<<(std::ostream&,
335 const formatted_date_holder&);
336
337#ifdef QL_HIGH_RESOLUTION_DATE
338 struct iso_datetime_holder {
339 explicit iso_datetime_holder(const Date& d) : d(d) {}
340 Date d;
341 };
342 std::ostream& operator<<(std::ostream&, const iso_datetime_holder&);
343#endif
344 }
345
346 namespace io {
347
348 //! output dates in short format (mm/dd/yyyy)
349 /*! \ingroup manips */
350 detail::short_date_holder short_date(const Date&);
351
352 //! output dates in long format (Month ddth, yyyy)
353 /*! \ingroup manips */
354 detail::long_date_holder long_date(const Date&);
355
356 //! output dates in ISO format (yyyy-mm-dd)
357 /*! \ingroup manips */
358 detail::iso_date_holder iso_date(const Date&);
359
360 //! output dates in user defined format using boost date functionality
361 /*! \ingroup manips */
362 detail::formatted_date_holder formatted_date(const Date&,
363 const std::string& fmt);
364
365#ifdef QL_HIGH_RESOLUTION_DATE
366 //! output datetimes in ISO format (YYYY-MM-DDThh:mm:ss,SSSSSS)
367 /*! \ingroup manips */
368 detail::iso_datetime_holder iso_datetime(const Date&);
369#endif
370
371 }
372
373 #ifdef QL_NULL_AS_FUNCTIONS
374
375 //! specialization of Null template for the Date class
376 template <>
377 inline Date Null<Date>() {
378 return {};
379 }
380
381 #else
382
383 template <>
384 class Null<Date> {
385 public:
386 Null() = default;
387 operator Date() const { return {}; }
388 };
389
390 #endif
391
392#ifndef QL_HIGH_RESOLUTION_DATE
393 // inline definitions
394
395 inline Weekday Date::weekday() const {
396 Integer w = serialNumber_ % 7;
397 return Weekday(w == 0 ? 7 : w);
398 }
399
400 inline Day Date::dayOfMonth() const {
401 return dayOfYear() - monthOffset(m: month(),leapYear: isLeap(y: year()));
402 }
403
404 inline Day Date::dayOfYear() const {
405 return serialNumber_ - yearOffset(y: year());
406 }
407
408 inline Date::serial_type Date::serialNumber() const {
409 return serialNumber_;
410 }
411
412 inline Date Date::operator+(Date::serial_type days) const {
413 return Date(serialNumber_+days);
414 }
415
416 inline Date Date::operator-(Date::serial_type days) const {
417 return Date(serialNumber_-days);
418 }
419
420 inline Date Date::operator+(const Period& p) const {
421 return advance(d: *this,units: p.length(),p.units());
422 }
423
424 inline Date Date::operator-(const Period& p) const {
425 return advance(d: *this,units: -p.length(),p.units());
426 }
427
428 inline Date Date::endOfMonth(const Date& d) {
429 Month m = d.month();
430 Year y = d.year();
431 return {monthLength(m, leapYear: isLeap(y)), m, y};
432 }
433
434 inline bool Date::isEndOfMonth(const Date& d) {
435 return (d.dayOfMonth() == monthLength(m: d.month(), leapYear: isLeap(y: d.year())));
436 }
437
438 inline Date::serial_type operator-(const Date& d1, const Date& d2) {
439 return d1.serialNumber()-d2.serialNumber();
440 }
441
442 inline Time daysBetween(const Date& d1, const Date& d2) {
443 return Time(d2-d1);
444 }
445
446 inline bool operator==(const Date& d1, const Date& d2) {
447 return (d1.serialNumber() == d2.serialNumber());
448 }
449
450 inline bool operator!=(const Date& d1, const Date& d2) {
451 return (d1.serialNumber() != d2.serialNumber());
452 }
453
454 inline bool operator<(const Date& d1, const Date& d2) {
455 return (d1.serialNumber() < d2.serialNumber());
456 }
457
458 inline bool operator<=(const Date& d1, const Date& d2) {
459 return (d1.serialNumber() <= d2.serialNumber());
460 }
461
462 inline bool operator>(const Date& d1, const Date& d2) {
463 return (d1.serialNumber() > d2.serialNumber());
464 }
465
466 inline bool operator>=(const Date& d1, const Date& d2) {
467 return (d1.serialNumber() >= d2.serialNumber());
468 }
469#endif
470}
471
472namespace std {
473 template<>
474 struct hash<QuantLib::Date> {
475 std::size_t operator()(const QuantLib::Date& d) const {
476 return QuantLib::hash_value(d);
477 }
478 };
479}
480
481#endif
482

source code of quantlib/ql/time/date.hpp