30#include <boost/date_time/gregorian/gregorian.hpp>
31#include <boost/date_time/posix_time/posix_time_types.hpp>
36#ifdef QL_HIGH_RESOLUTION_DATE
37#if BOOST_VERSION < 106700
38#include <boost/functional/hash.hpp>
40#include <boost/container_hash/hash.hpp>
44#if defined(BOOST_NO_STDC_NAMESPACE)
45 namespace std { using ::time; using ::time_t; using ::tm;
46 using ::gmtime; using ::localtime; }
49#ifdef QL_HIGH_RESOLUTION_DATE
50using boost::posix_time::ptime;
51using boost::posix_time::time_duration;
56#ifndef QL_HIGH_RESOLUTION_DATE
62 : serialNumber_(serialNumber) {
68 "year " <<
y <<
" out of bound. It must be in [1901,2199]");
71 <<
" outside January-December range [1,12]");
76 "day outside month (" <<
Integer(m) <<
") day-range "
77 <<
"[1," << len <<
"]");
159 "year " <<
y <<
" out of bounds. "
160 <<
"It must be in [1901,2199]");
174 "year " <<
y <<
" out of bounds. "
175 <<
"It must be in [1901,2199]");
183 QL_FAIL(
"undefined time units");
188 static const bool YearIsLeap[] = {
192 true,
false,
false,
false,
true,
false,
false,
false,
true,
false,
194 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
196 true,
false,
false,
false,
true,
false,
false,
false,
true,
false,
198 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
200 true,
false,
false,
false,
true,
false,
false,
false,
true,
false,
202 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
204 true,
false,
false,
false,
true,
false,
false,
false,
true,
false,
206 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
208 true,
false,
false,
false,
true,
false,
false,
false,
true,
false,
210 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
212 true,
false,
false,
false,
true,
false,
false,
false,
true,
false,
214 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
216 true,
false,
false,
false,
true,
false,
false,
false,
true,
false,
218 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
220 true,
false,
false,
false,
true,
false,
false,
false,
true,
false,
222 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
224 true,
false,
false,
false,
true,
false,
false,
false,
true,
false,
226 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
228 true,
false,
false,
false,
true,
false,
false,
false,
true,
false,
230 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
232 false,
false,
false,
false,
true,
false,
false,
false,
true,
false,
234 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
236 true,
false,
false,
false,
true,
false,
false,
false,
true,
false,
238 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
240 true,
false,
false,
false,
true,
false,
false,
false,
true,
false,
242 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
244 true,
false,
false,
false,
true,
false,
false,
false,
true,
false,
246 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
248 true,
false,
false,
false,
true,
false,
false,
false,
true,
false,
250 false,
false,
true,
false,
false,
false,
true,
false,
false,
false,
254 QL_REQUIRE(
y>=1900 &&
y<=2200,
"year outside valid range");
255 return YearIsLeap[
y-1900];
260 static const Integer MonthLength[] = {
261 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
263 static const Integer MonthLeapLength[] = {
264 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
266 return (leapYear? MonthLeapLength[m-1] : MonthLength[m-1]);
270 static const Integer MonthOffset[] = {
271 0, 31, 59, 90, 120, 151,
272 181, 212, 243, 273, 304, 334,
275 static const Integer MonthLeapOffset[] = {
276 0, 31, 60, 91, 121, 152,
277 182, 213, 244, 274, 305, 335,
280 return (leapYear? MonthLeapOffset[m-1] : MonthOffset[m-1]);
288 0, 366, 731, 1096, 1461, 1827, 2192, 2557, 2922, 3288,
290 3653, 4018, 4383, 4749, 5114, 5479, 5844, 6210, 6575, 6940,
292 7305, 7671, 8036, 8401, 8766, 9132, 9497, 9862,10227,10593,
294 10958,11323,11688,12054,12419,12784,13149,13515,13880,14245,
296 14610,14976,15341,15706,16071,16437,16802,17167,17532,17898,
298 18263,18628,18993,19359,19724,20089,20454,20820,21185,21550,
300 21915,22281,22646,23011,23376,23742,24107,24472,24837,25203,
302 25568,25933,26298,26664,27029,27394,27759,28125,28490,28855,
304 29220,29586,29951,30316,30681,31047,31412,31777,32142,32508,
306 32873,33238,33603,33969,34334,34699,35064,35430,35795,36160,
308 36525,36891,37256,37621,37986,38352,38717,39082,39447,39813,
310 40178,40543,40908,41274,41639,42004,42369,42735,43100,43465,
312 43830,44196,44561,44926,45291,45657,46022,46387,46752,47118,
314 47483,47848,48213,48579,48944,49309,49674,50040,50405,50770,
316 51135,51501,51866,52231,52596,52962,53327,53692,54057,54423,
318 54788,55153,55518,55884,56249,56614,56979,57345,57710,58075,
320 58440,58806,59171,59536,59901,60267,60632,60997,61362,61728,
322 62093,62458,62823,63189,63554,63919,64284,64650,65015,65380,
324 65745,66111,66476,66841,67206,67572,67937,68302,68667,69033,
326 69398,69763,70128,70494,70859,71224,71589,71955,72320,72685,
328 73050,73415,73780,74145,74510,74876,75241,75606,75971,76337,
330 76702,77067,77432,77798,78163,78528,78893,79259,79624,79989,
332 80354,80720,81085,81450,81815,82181,82546,82911,83276,83642,
334 84007,84372,84737,85103,85468,85833,86198,86564,86929,87294,
336 87659,88025,88390,88755,89120,89486,89851,90216,90581,90947,
338 91312,91677,92042,92408,92773,93138,93503,93869,94234,94599,
340 94964,95330,95695,96060,96425,96791,97156,97521,97886,98252,
342 98617,98982,99347,99713,100078,100443,100808,101174,101539,101904,
344 102269,102635,103000,103365,103730,104096,104461,104826,105191,105557,
346 105922,106287,106652,107018,107383,107748,108113,108479,108844,109209,
350 return YearOffset[
y-1900];
356 const boost::gregorian::date& serialNumberDateReference() {
357 static const boost::gregorian::date dateReference(
358 1899, boost::gregorian::Dec, 30);
359 return dateReference;
363#define compatibleEnums ( int(boost::date_time::Monday) +1 == Monday \
364 && int(boost::date_time::Tuesday) +1 == Tuesday \
365 && int(boost::date_time::Wednesday)+1 == Wednesday \
366 && int(boost::date_time::Thursday) +1 == Thursday \
367 && int(boost::date_time::Friday) +1 == Friday \
368 && int(boost::date_time::Saturday) +1 == Saturday \
369 && int(boost::date_time::Sunday) +1 == Sunday \
370 && int(boost::date_time::Jan) == January \
371 && int(boost::date_time::Feb) == February \
372 && int(boost::date_time::Mar) == March \
373 && int(boost::date_time::Apr) == April \
374 && int(boost::date_time::May) == May \
375 && int(boost::date_time::Jun) == June \
376 && int(boost::date_time::Jul) == July \
377 && int(boost::date_time::Aug) == August \
378 && int(boost::date_time::Sep) == September \
379 && int(boost::date_time::Oct) == October \
380 && int(boost::date_time::Nov) == November \
381 && int(boost::date_time::Dec) == December )
383 template <
bool compatible>
384 Weekday mapBoostDateType2QL(boost::gregorian::greg_weekday
d) {
390 case boost::date_time::Monday :
return Monday;
391 case boost::date_time::Tuesday :
return Tuesday;
392 case boost::date_time::Wednesday:
return Wednesday;
393 case boost::date_time::Thursday :
return Thursday;
394 case boost::date_time::Friday :
return Friday;
395 case boost::date_time::Saturday :
return Saturday;
396 case boost::date_time::Sunday :
return Sunday;
398 QL_FAIL(
"unknown boost date_time day of week given");
403 template <
bool compatible>
404 Month mapBoostDateType2QL(boost::gregorian::greg_month m) {
406 return Month(m.as_number());
410 case boost::date_time::Jan :
return January;
411 case boost::date_time::Feb :
return February;
412 case boost::date_time::Mar :
return March;
413 case boost::date_time::Apr :
return April;
414 case boost::date_time::May :
return May;
415 case boost::date_time::Jun :
return June;
416 case boost::date_time::Jul :
return July;
417 case boost::date_time::Aug :
return August;
418 case boost::date_time::Sep :
return September;
419 case boost::date_time::Oct :
return October;
420 case boost::date_time::Nov :
return November;
421 case boost::date_time::Dec :
return December;
423 QL_FAIL(
"unknown boost date_time month of week given");
429 template <
bool compatible>
430 boost::gregorian::greg_month mapQLDateType2Boost(
Month m) {
432 return boost::gregorian::greg_month(m);
436 case January :
return boost::date_time::Jan;
437 case February :
return boost::date_time::Feb;
438 case March :
return boost::date_time::Mar;
439 case April :
return boost::date_time::Apr;
440 case May :
return boost::date_time::May;
441 case June :
return boost::date_time::Jun;
442 case July :
return boost::date_time::Jul;
443 case August :
return boost::date_time::Aug;
444 case September:
return boost::date_time::Sep;
445 case October :
return boost::date_time::Oct;
446 case November :
return boost::date_time::Nov;
447 case December :
return boost::date_time::Dec;
449 QL_FAIL(
"unknown boost date_time month of week given");
455 using boost::gregorian::gregorian_calendar;
459 dt += boost::gregorian::days(
n);
462 dt += boost::gregorian::weeks(
n);
466 const boost::gregorian::date date = dt.date();
467 const Day eoM = gregorian_calendar::end_of_month_day(
468 date.year(), date.month());
471 dt += boost::gregorian::months(
n);
474 dt += boost::gregorian::years(
n);
477 if (date.day() == eoM) {
481 = gregorian_calendar::end_of_month_day(
482 dt.date().year(), dt.date().month());
485 dt -= boost::gregorian::days(newEoM - eoM);
491 dt += boost::posix_time::hours(
n);
494 dt += boost::posix_time::minutes(
n);
497 dt += boost::posix_time::seconds(
n);
500 dt += boost::posix_time::milliseconds(
n);
503 dt += boost::posix_time::microseconds(
n);
506 QL_FAIL(
"undefined time units");
512 "year " <<
y <<
" out of bound. It must be in [1901,2199]");
515 <<
" outside January-December range [1,12]");
517 const boost::gregorian::greg_month bM
518 = mapQLDateType2Boost<compatibleEnums>(m);
521 boost::gregorian::gregorian_calendar::end_of_month_day(
y, bM);
523 "day outside month (" <<
Integer(m) <<
") day-range "
524 <<
"[1," << len <<
"]");
526 return boost::gregorian::date(
y, bM,
d);
532 : dateTime_(serialNumberDateReference()) {}
535 : dateTime_(dateTime) {}
538 : dateTime_(gregorianDate(
y, m,
d)) {}
541 Hour hours, Minute minutes, Second seconds,
542 Millisecond millisec, Microsecond microsec)
544 gregorianDate(
y, m,
d),
545 boost::posix_time::time_duration(
546 hours, minutes, seconds,
547 millisec*(time_duration::ticks_per_second()/1000)
548 + microsec*(time_duration::ticks_per_second()/1000000))) {}
552 serialNumberDateReference() +
558 return mapBoostDateType2QL<compatibleEnums>(
559 dateTime_.date().day_of_week());
563 return dateTime_.date().day();
567 return dateTime_.date().day_of_year();
571 return mapBoostDateType2QL<compatibleEnums>(dateTime_.date().month());
575 return dateTime_.date().year();
578 Hour Date::hours()
const {
579 return dateTime_.time_of_day().hours();
582 Minute Date::minutes()
const {
583 return dateTime_.time_of_day().minutes();
586 Second Date::seconds()
const {
587 return dateTime_.time_of_day().seconds();
590 Time Date::fractionOfDay()
const {
591 const time_duration
t = dateTime().time_of_day();
594 = (
t.hours()*60.0 +
t.minutes())*60.0 +
t.seconds()
595 +
Real(
t.fractional_seconds())/ticksPerSecond();
597 return seconds/86400.0;
600 Time Date::fractionOfSecond()
const {
601 return dateTime_.time_of_day().fractional_seconds()
602 /
Real(ticksPerSecond());
605 Millisecond Date::milliseconds()
const {
606 return dateTime_.time_of_day().fractional_seconds()
607 /(ticksPerSecond()/1000);
610 Microsecond Date::microseconds()
const {
611 return (dateTime_.time_of_day().fractional_seconds()
612 - milliseconds()*(time_duration::ticks_per_second()/1000))
613 /(ticksPerSecond()/1000000);
616 time_duration::tick_type Date::ticksPerSecond() {
617 return time_duration::ticks_per_second();
622 - serialNumberDateReference()).
days();
628 const ptime& Date::dateTime()
const {
return dateTime_; }
631 dateTime_ += boost::gregorian::days(
d);
636 advance(dateTime_, p.length(), p.units());
641 dateTime_ -= boost::gregorian::days(
d);
645 advance(dateTime_, -p.length(), p.units());
650 dateTime_ +=boost::gregorian::days(1);
655 dateTime_ -=boost::gregorian::days(1);
687 Date Date::localDateTime() {
688 return Date(boost::posix_time::microsec_clock::local_time());
691 Date Date::universalDateTime() {
692 return Date(boost::posix_time::microsec_clock::universal_time());
696 return boost::gregorian::gregorian_calendar::is_leap_year(
y);
700 const Month m =
d.month();
702 const Day eoM = boost::gregorian::gregorian_calendar::end_of_month_day(
703 d.year(), mapQLDateType2Boost<compatibleEnums>(
d.month()));
705 return Date(eoM, m,
y);
709 return d.dayOfMonth() ==
710 boost::gregorian::gregorian_calendar::end_of_month_day(
711 d.year(), mapQLDateType2Boost<compatibleEnums>(
d.month()));
716 return (d1.dateTime().date() - d2.dateTime().date()).days();
721 return days + d2.fractionOfDay() - d1.fractionOfDay();
724 bool operator<(
const Date& d1,
const Date& d2) {
725 return (d1.dateTime() < d2.dateTime());
728 bool operator<=(
const Date& d1,
const Date& d2) {
729 return (d1.dateTime() <= d2.dateTime());
732 bool operator>(
const Date& d1,
const Date& d2) {
733 return (d1.dateTime() > d2.dateTime());
736 bool operator>=(
const Date& d1,
const Date& d2) {
737 return (d1.dateTime() >= d2.dateTime());
740 bool operator==(
const Date& d1,
const Date& d2) {
741 return (d1.dateTime() == d2.dateTime());
744 bool operator!=(
const Date& d1,
const Date& d2) {
745 return (d1.dateTime() != d2.dateTime());
760 "Date's serial number (" <<
serialNumber <<
") outside "
791 if (std::time(&
t) == std::time_t(-1))
793 std::tm *lt = std::localtime(&
t);
794 return {
Day(lt->tm_mday),
Month(lt->tm_mon + 1),
Year(lt->tm_year + 1900)};
799 return d + ((wd>dayOfWeek ? 7 : 0) - wd + dayOfWeek);
805 "zeroth day of week in a given (month, year) is undefined");
807 "no more than 5 weekday in a given (month, year)");
809 Size skip = nth - (dayOfWeek>=first ? 1 : 0);
810 return {
Day((1 + dayOfWeek + skip * 7) - first), m,
y};
818 return out <<
"January";
820 return out <<
"February";
822 return out <<
"March";
824 return out <<
"April";
828 return out <<
"June";
830 return out <<
"July";
832 return out <<
"August";
834 return out <<
"September";
836 return out <<
"October";
838 return out <<
"November";
840 return out <<
"December";
847#ifdef QL_HIGH_RESOLUTION_DATE
848 std::size_t seed = 0;
850 boost::hash_combine(seed,
d.dateTime().time_of_day().total_nanoseconds());
865 struct FormatResetter {
869 struct nopunct : std::numpunct<char> {
870 std::string do_grouping()
const override {
return ""; }
872 explicit FormatResetter(std::ostream &out)
873 : out_(&out), flags_(out.flags()), filler_(out.fill()),
875 std::locale loc (out.getloc(),
new nopunct);
877 out << std::resetiosflags(
878 std::ios_base::adjustfield | std::ios_base::basefield |
879 std::ios_base::floatfield | std::ios_base::showbase |
880 std::ios_base::showpos | std::ios_base::uppercase);
889 std::ios_base::fmtflags flags_;
900 FormatResetter resetter(out);
903 char filler = out.fill();
904 out << std::setw(2) << std::setfill(
'0') << mm <<
"/";
905 out << std::setw(2) << std::setfill(
'0') << dd <<
"/";
918 FormatResetter resetter(out);
919 out <<
d.month() <<
" ";
932 FormatResetter resetter(out);
936 out << std::setw(2) << std::setfill(
'0') << mm <<
"-";
937 out << std::setw(2) << std::setfill(
'0') << dd;
944 using namespace boost::gregorian;
949 FormatResetter resetter(out);
950 date boostDate(
d.year(),
d.month(),
d.dayOfMonth());
951 out.imbue(std::locale(std::locale(),
952 new date_facet(holder.
f.c_str())));
958#ifdef QL_HIGH_RESOLUTION_DATE
960 const iso_datetime_holder& holder) {
961 const Date&
d = holder.d;
964 FormatResetter resetter(out);
965 const Hour hh=
d.hours();
966 const Minute mm =
d.minutes();
967 const Second
s =
d.seconds();
968 const Millisecond millis =
d.milliseconds();
969 const Microsecond micros =
d.microseconds();
971 out << std::setw(2) << std::setfill(
'0') << hh <<
":"
972 << std::setw(2) << std::setfill(
'0') << mm <<
":"
973 << std::setw(2) << std::setfill(
'0') <<
s <<
","
974 << std::setw(3) << std::setfill(
'0') << millis
975 << std::setw(3) << std::setfill(
'0') << micros;
996 const std::string&
f) {
1000#ifdef QL_HIGH_RESOLUTION_DATE
1001 detail::iso_datetime_holder iso_datetime(
const Date&
d) {
1002 return detail::iso_datetime_holder(
d);
Date & operator-=(Date::serial_type days)
decrement date by the given number of days
static Date::serial_type yearOffset(Year y)
static Date minDate()
earliest allowed date
static Date todaysDate()
today's date.
static Date::serial_type maximumSerialNumber()
Date operator-(Date::serial_type days) const
returns a new date decremented by the given number of days
Date::serial_type serialNumber_
Date operator+(Date::serial_type days) const
returns a new date incremented by the given number of days
Date & operator+=(Date::serial_type days)
increments date by the given number of days
Date & operator--()
1-day pre-decrement
static Date endOfMonth(const Date &d)
last day of the month to which the given date belongs
static Integer monthOffset(Month m, bool leapYear)
Date & operator++()
1-day pre-increment
static Integer monthLength(Month m, bool leapYear)
Day dayOfYear() const
One-based (Jan 1st = 1)
static bool isEndOfMonth(const Date &d)
whether a date is the last day of its month
std::int_fast32_t serial_type
serial number type
Date::serial_type serialNumber() const
static Date advance(const Date &d, Integer units, TimeUnit)
static Date::serial_type minimumSerialNumber()
static void checkSerialNumber(Date::serial_type serialNumber)
static Date nthWeekday(Size n, Weekday w, Month m, Year y)
n-th given weekday in the given month and year
static bool isLeap(Year y)
whether the given year is a leap one
static Date nextWeekday(const Date &d, Weekday w)
next given weekday following or equal to the given date
static Date maxDate()
latest allowed date
Date()
Default constructor returning a null date.
date- and time-related classes, typedefs and enumerations
Classes and functions for error handling.
#define QL_ENSURE(condition, message)
throw an error if the given post-condition is not verified
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
#define QL_FAIL(message)
throw an error (possibly with file and line information)
TimeUnit
Units used to describe time periods.
detail::short_date_holder short_date(const Date &d)
output dates in short format (mm/dd/yyyy)
detail::long_date_holder long_date(const Date &d)
output dates in long format (Month ddth, yyyy)
detail::ordinal_holder ordinal(Size)
outputs naturals as 1st, 2nd, 3rd...
detail::formatted_date_holder formatted_date(const Date &d, const std::string &f)
output dates in user defined format using boost date functionality
detail::iso_date_holder iso_date(const Date &d)
output dates in ISO format (yyyy-mm-dd)
Real Time
continuous quantity with 1-year units
QL_INTEGER Integer
integer number
std::size_t Size
size of a container
std::ostream & operator<<(std::ostream &out, const short_date_holder &holder)
Quantity operator-(const Quantity &m1, const Quantity &m2)
bool operator==(const Currency &c1, const Currency &c2)
bool operator<(const Quantity &m1, const Quantity &m2)
bool operator>=(const Quantity &m1, const Quantity &m2)
std::ostream & operator<<(std::ostream &out, GFunctionFactory::YieldCurveModel type)
bool operator!=(const Currency &c1, const Currency &c2)
bool operator>(const Quantity &m1, const Quantity &m2)
Real days(const Period &p)
std::size_t hash_value(const Date &d)
bool operator<=(const Quantity &m1, const Quantity &m2)
Time daysBetween(const Date &d1, const Date &d2)