Coverage Report

Created: 2026-02-03 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/time/date.hpp
Line
Count
Source
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
 <https://www.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
49
namespace 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
    //! Microsecond 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
        //! first day of the month to which the given date belongs
211
        static Date startOfMonth(const Date& d);
212
        //! whether a date is the first day of its month
213
        static bool isStartOfMonth(const Date& d);
214
        //! last day of the month to which the given date belongs
215
        static Date endOfMonth(const Date& d);
216
        //! whether a date is the last day of its month
217
        static bool isEndOfMonth(const Date& d);
218
        //! next given weekday following or equal to the given date
219
        /*! E.g., the Friday following Tuesday, January 15th, 2002
220
            was January 18th, 2002.
221
222
            see http://www.cpearson.com/excel/DateTimeWS.htm
223
        */
224
        static Date nextWeekday(const Date& d,
225
                                Weekday w);
226
        //! n-th given weekday in the given month and year
227
        /*! E.g., the 4th Thursday of March, 1998 was March 26th,
228
            1998.
229
230
            see http://www.cpearson.com/excel/DateTimeWS.htm
231
        */
232
        static Date nthWeekday(Size n,
233
                               Weekday w,
234
                               Month m,
235
                               Year y);
236
237
#ifdef QL_HIGH_RESOLUTION_DATE
238
        //! local date time, based on the time zone settings of the computer
239
        static Date localDateTime();
240
        //! UTC date time
241
        static Date universalDateTime();
242
243
        //! underlying resolution of the  posix date time object
244
        static boost::posix_time::time_duration::tick_type ticksPerSecond();
245
#endif
246
247
        //@}
248
249
      private:
250
        static Date::serial_type minimumSerialNumber();
251
        static Date::serial_type maximumSerialNumber();
252
        static void checkSerialNumber(Date::serial_type serialNumber);
253
254
#ifdef QL_HIGH_RESOLUTION_DATE
255
        boost::posix_time::ptime dateTime_;
256
#else
257
        Date::serial_type serialNumber_;
258
        static Date advance(const Date& d, Integer units, TimeUnit);
259
        static Integer monthLength(Month m, bool leapYear);
260
        static Integer monthOffset(Month m, bool leapYear);
261
        static Date::serial_type yearOffset(Year y);
262
#endif
263
    };
264
265
    /*! \relates Date
266
        \brief Difference in days between dates
267
    */
268
    Date::serial_type operator-(const Date&, const Date&);
269
    /*! \relates Date
270
        \brief Difference in days (including fraction of days) between dates
271
    */
272
    Time daysBetween(const Date&, const Date&);
273
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
    /*! \relates Date */
283
    bool operator>(const Date&, const Date&);
284
    /*! \relates Date */
285
    bool operator>=(const Date&, const Date&);
286
287
    /*!
288
      Compute a hash value of @p d.
289
290
      This method makes Date hashable via <tt>boost::hash</tt>.
291
292
      Example:
293
294
      \code{.cpp}
295
      #include <unordered_set>
296
297
      std::unordered_set<Date> set;
298
      Date d = Date(1, Jan, 2020); 
299
300
      set.insert(d);
301
      assert(set.count(d)); // 'd' was added to 'set'
302
      \endcode
303
304
      \param [in] d Date to hash
305
      \return A hash value of @p d
306
      \relates Date
307
    */
308
    std::size_t hash_value(const Date& d);
309
310
    /*! \relates Date */
311
    std::ostream& operator<<(std::ostream&, const Date&);
312
313
    namespace detail {
314
315
        struct short_date_holder {
316
0
            explicit short_date_holder(const Date d) : d(d) {}
317
            Date d;
318
        };
319
        std::ostream& operator<<(std::ostream&, const short_date_holder&);
320
321
        struct long_date_holder {
322
692
            explicit long_date_holder(const Date& d) : d(d) {}
323
            Date d;
324
        };
325
        std::ostream& operator<<(std::ostream&, const long_date_holder&);
326
327
        struct iso_date_holder {
328
0
            explicit iso_date_holder(const Date& d) : d(d) {}
329
            Date d;
330
        };
331
        std::ostream& operator<<(std::ostream&, const iso_date_holder&);
332
333
        struct formatted_date_holder {
334
0
            formatted_date_holder(const Date& d, std::string f) : d(d), f(std::move(f)) {}
335
            Date d;
336
            std::string f;
337
        };
338
        std::ostream& operator<<(std::ostream&,
339
                                 const formatted_date_holder&);
340
341
#ifdef QL_HIGH_RESOLUTION_DATE
342
        struct iso_datetime_holder {
343
            explicit iso_datetime_holder(const Date& d) : d(d) {}
344
            Date d;
345
        };
346
        std::ostream& operator<<(std::ostream&, const iso_datetime_holder&);
347
#endif
348
    }
349
350
    namespace io {
351
352
        //! output dates in short format (mm/dd/yyyy)
353
        /*! \ingroup manips */
354
        detail::short_date_holder short_date(const Date&);
355
356
        //! output dates in long format (Month ddth, yyyy)
357
        /*! \ingroup manips */
358
        detail::long_date_holder long_date(const Date&);
359
360
        //! output dates in ISO format (yyyy-mm-dd)
361
        /*! \ingroup manips */
362
        detail::iso_date_holder iso_date(const Date&);
363
364
        //! output dates in user defined format using boost date functionality
365
        /*! \ingroup manips */
366
        detail::formatted_date_holder formatted_date(const Date&,
367
                                                     const std::string& fmt);
368
369
#ifdef QL_HIGH_RESOLUTION_DATE
370
        //! output datetimes in ISO format (YYYY-MM-DDThh:mm:ss,SSSSSS)
371
        /*! \ingroup manips */
372
        detail::iso_datetime_holder iso_datetime(const Date&);
373
#endif
374
375
    }
376
377
378
    // inline definitions
379
380
0
    inline Date Date::startOfMonth(const Date& d) {
381
0
        Month m = d.month();
382
0
        Year y = d.year();
383
0
        return Date(1, m, y);
384
0
    }
385
386
0
    inline bool Date::isStartOfMonth(const Date& d) {
387
0
       return (d.dayOfMonth() == 1);
388
0
    }
389
390
#ifndef QL_HIGH_RESOLUTION_DATE
391
0
    inline Weekday Date::weekday() const {
392
0
        Integer w = serialNumber_ % 7;
393
0
        return Weekday(w == 0 ? 7 : w);
394
0
    }
395
396
27.7M
    inline Day Date::dayOfMonth() const {
397
27.7M
        return dayOfYear() - monthOffset(month(),isLeap(year()));
398
27.7M
    }
399
400
83.2M
    inline Day Date::dayOfYear() const {
401
83.2M
        return serialNumber_ - yearOffset(year());
402
83.2M
    }
403
404
1.85G
    inline Date::serial_type Date::serialNumber() const {
405
1.85G
        return serialNumber_;
406
1.85G
    }
407
408
463k
    inline Date Date::operator+(Date::serial_type days) const {
409
463k
        return Date(serialNumber_+days);
410
463k
    }
411
412
0
    inline Date Date::operator-(Date::serial_type days) const {
413
0
        return Date(serialNumber_-days);
414
0
    }
415
416
27.7M
    inline Date Date::operator+(const Period& p) const {
417
27.7M
        return advance(*this,p.length(),p.units());
418
27.7M
    }
419
420
0
    inline Date Date::operator-(const Period& p) const {
421
0
        return advance(*this,-p.length(),p.units());
422
0
    }
423
424
0
    inline Date Date::endOfMonth(const Date& d) {
425
0
        Month m = d.month();
426
0
        Year y = d.year();
427
0
        return {monthLength(m, isLeap(y)), m, y};
428
0
    }
429
430
0
    inline bool Date::isEndOfMonth(const Date& d) {
431
0
       return (d.dayOfMonth() == monthLength(d.month(), isLeap(d.year())));
432
0
    }
433
434
82.8M
    inline Date::serial_type operator-(const Date& d1, const Date& d2) {
435
82.8M
        return d1.serialNumber()-d2.serialNumber();
436
82.8M
    }
437
438
55.2M
    inline Time daysBetween(const Date& d1, const Date& d2) {
439
55.2M
        return Time(d2-d1);
440
55.2M
    }
441
442
83.5M
    inline bool operator==(const Date& d1, const Date& d2) {
443
83.5M
        return (d1.serialNumber() == d2.serialNumber());
444
83.5M
    }
445
446
305M
    inline bool operator!=(const Date& d1, const Date& d2) {
447
305M
        return (d1.serialNumber() != d2.serialNumber());
448
305M
    }
449
450
290M
    inline bool operator<(const Date& d1, const Date& d2) {
451
290M
        return (d1.serialNumber() < d2.serialNumber());
452
290M
    }
453
454
28.6M
    inline bool operator<=(const Date& d1, const Date& d2) {
455
28.6M
        return (d1.serialNumber() <= d2.serialNumber());
456
28.6M
    }
457
458
82.8M
    inline bool operator>(const Date& d1, const Date& d2) {
459
82.8M
        return (d1.serialNumber() > d2.serialNumber());
460
82.8M
    }
461
462
55.2M
    inline bool operator>=(const Date& d1, const Date& d2) {
463
55.2M
        return (d1.serialNumber() >= d2.serialNumber());
464
55.2M
    }
465
#endif
466
}
467
468
namespace std {
469
    template<>
470
    struct hash<QuantLib::Date> {
471
0
        std::size_t operator()(const QuantLib::Date& d) const {
472
0
            return QuantLib::hash_value(d);
473
0
        }
474
    };
475
}
476
477
#endif