11 #include "internal.hpp"
17 inline Days ymdToDays(
int year,
int month,
int day)
20 auto const y =
static_cast<int>(year) - (month <= 2) + (year < 1);
21 auto const m =
static_cast<unsigned>(month);
22 auto const d =
static_cast<unsigned>(day);
23 auto const era = (y >= 0 ? y : y - 399) / 400;
24 auto const yoe =
static_cast<unsigned>(y - era * 400);
25 auto const doy = (153 * (m > 2 ? m - 3 : m + 9) + 2) / 5 + d - 1;
26 auto const doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
28 return Days { era * 146097 +
static_cast<long>(doe) - 719468 };
31 inline void daysToYmd(Days dys,
int* year,
int* month,
int* day)
34 auto const z = dys.count() + 719468;
35 auto const era = (z >= 0 ? z : z - 146096) / 146097;
36 auto const doe =
static_cast<unsigned long>(z - era * 146097);
37 auto const yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
38 auto const y =
static_cast<Days::rep
>(yoe) + era * 400;
39 auto const doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
40 auto const mp = (5 * doy + 2) / 153;
41 auto const m = mp < 10 ? mp + 3 : mp - 9;
42 auto const d = doy - (153 * mp + 2) / 5 + 1;
45 *year = *year - (*year < 1);
48 *month =
static_cast<int>(m);
50 *day =
static_cast<int>(d);
91 using Days = internal::Days;
92 using Weeks = std::chrono::duration<long, std::ratio_multiply<std::ratio<7>, Days::period>>;
158 internal::daysToYmd(days, &m_year, &m_month, &m_day);
250 return m_year != 0 && (m_month > 0 && m_month < 13) && (m_day > 0 && m_day < (
daysInMonthOfYear(m_year, m_month) + 1));
326 static auto getFirstWeekDate = [](
int year) {
331 Date currentDate = *
this;
332 Date firstWeekDate = getFirstWeekDate(y);
333 if (currentDate < firstWeekDate) {
336 firstWeekDate = getFirstWeekDate(y);
338 Date nextYearFirstWeekDate = getFirstWeekDate(y + 1);
339 if (currentDate >= nextYearFirstWeekDate) {
342 firstWeekDate = nextYearFirstWeekDate;
345 int week =
daysBetween(firstWeekDate, currentDate) / 7 + 1;
369 return shortName ? internal::getShortWeekdayName(
dayOfWeek()) : internal::getLongWeekdayName(
dayOfWeek());
395 return shortName ? internal::getShortMonthName(
month()) : internal::getLongMonthName(
month());
409 internal::daysToYmd(
Days(internal::ymdToDays(m_year, m_month, m_day) +
Days(days)), &y, &m, &d);
410 return Date(y, m, d);
417 internal::daysToYmd(
Days(internal::ymdToDays(m_year, m_month, m_day) -
Days(days)), &y, &m, &d);
418 return Date(y, m, d);
434 const int totalMonths = m_month + months - 1;
435 const int newYear = m_year + (totalMonths / 12);
436 const int newMonth = (totalMonths % 12) + 1;
438 const int newDays = newDaysInMonth < m_day ? newDaysInMonth : m_day;
440 return Date(newYear, newMonth, newDays);
456 const int newYear = m_year - (std::abs(m_month - months - 12) / 12);
457 const int newMonth = ((11 + m_month - (months % 12)) % 12) + 1;
459 const int newDays = newDaysInMonth < m_day ? newDaysInMonth : m_day;
461 return Date(newYear, newMonth, newDays);
467 const int newYear = m_year + years;
468 return Date(newYear > 0 ? newYear : newYear - 1, m_month, m_day);
474 const int newYear = m_year - years;
475 return Date(newYear > 0 ? newYear : newYear - 1, m_month, m_day);
488 return internal::ymdToDays(
year(),
month(),
day()).count();
532 std::string
toString(
const std::string& format)
const
535 return std::string();
537 std::stringstream output;
539 for (
size_t pos = 0; pos < format.size(); ++pos) {
544 char currChar = format[pos];
545 const int charCount = internal::countIdenticalCharsFrom(pos, format);
547 if (currChar ==
'#') {
548 output << (
year() < 0 ?
"-" :
"+");
549 }
else if (currChar ==
'y') {
550 if (charCount == 1) {
552 }
else if (charCount == 2) {
553 y = y - ((y / 100) * 100);
554 output << std::setfill(
'0') << std::setw(2) << y;
555 }
else if (charCount == 4) {
556 output << std::setfill(
'0') << std::setw(4) << y;
558 pos += charCount - 1;
559 }
else if (currChar ==
'M') {
560 if (charCount == 1) {
562 }
else if (charCount == 2) {
563 output << std::setfill(
'0') << std::setw(2) << m;
564 }
else if (charCount == 3) {
566 }
else if (charCount == 4) {
569 pos += charCount - 1;
570 }
else if (currChar ==
'd') {
571 if (charCount == 1) {
573 }
else if (charCount == 2) {
574 output << std::setfill(
'0') << std::setw(2) << d;
575 }
else if (charCount == 3) {
577 }
else if (charCount == 4) {
580 pos += charCount - 1;
581 }
else if (currChar ==
'E') {
582 output << (
year() < 0 ?
"BCE" :
"CE");
599 return Date(std::chrono::duration_cast<Days>(std::chrono::system_clock::now().time_since_epoch()));
614 int _year = 1, _month = 1, _day = 1;
616 for (
size_t fmtPos = 0, datPos = 0; fmtPos < format.size() && datPos < date.size(); ++fmtPos) {
617 const size_t charCount =
static_cast<size_t>(internal::countIdenticalCharsFrom(fmtPos, format));
619 if (format[fmtPos] ==
'#') {
620 if (date[datPos] ==
'+') {
623 }
else if (date[datPos] ==
'-') {
627 }
else if (format[fmtPos] ==
'y') {
628 if (charCount == 1) {
629 _year = _year * internal::readIntAndAdvancePos(date, datPos, 4);
630 }
else if (charCount == 2) {
631 _year = _year * std::stoi(date.substr(datPos, charCount));
634 }
else if (charCount == 4) {
635 _year = _year * std::stoi(date.substr(datPos, charCount));
638 fmtPos += charCount - 1;
639 }
else if (format[fmtPos] ==
'E') {
640 if (date.substr(datPos, 2) ==
"CE") {
641 _year = std::abs(_year);
643 }
else if (date.substr(datPos, 3) ==
"BCE") {
644 _year = -std::abs(_year);
647 }
else if (format[fmtPos] ==
'M') {
648 if (charCount == 1) {
649 _month = internal::readIntAndAdvancePos(date, datPos, 4);
650 }
else if (charCount == 2) {
651 _month = std::stoi(date.substr(datPos, charCount));
653 }
else if (charCount == 3) {
654 _month = internal::getShortMonthNumber(date.substr(datPos, charCount));
656 }
else if (charCount == 4) {
657 size_t newPos = datPos;
658 while (newPos < date.size() && std::isalpha(date[newPos]))
660 _month = internal::getLongMonthNumber(date.substr(datPos, newPos - datPos));
663 fmtPos += charCount - 1;
664 }
else if (format[fmtPos] ==
'd') {
665 if (charCount == 1) {
666 _day = internal::readIntAndAdvancePos(date, datPos, 2);
667 }
else if (charCount == 2) {
668 _day = std::stoi(date.substr(datPos, charCount));
670 }
else if (charCount == 3) {
673 }
else if (charCount == 4) {
674 while (datPos < date.size() && std::isalpha(date[datPos]))
677 fmtPos += charCount - 1;
684 return Date(_year, _month, _day);
690 return Date(
Days(julianDay - 2440588));
740 return (
year % 4 == 0) && (
year % 100 != 0 ||
year % 400 == 0);
805 const int DateFormatWidth = 10;
806 char result[DateFormatWidth];
807 is.read(result, DateFormatWidth);
Date is an immutable class representing a date without a time zone in the ISO-8601 calendar system,...
Definition: date.hpp:84
std::string monthName(bool shortName=false) const
Returns the name of the month of this date.
Definition: date.hpp:393
bool operator<(const Date &other) const
Returns whether this date is earlier than other.
Definition: date.hpp:193
Date subtractDays(int days) const
Returns the result of subtracting days from this date as a new Date object.
Definition: date.hpp:414
int dayOfWeek() const
Returns the weekday of this date as a number between 1 and 7, which corresponds to the enumeration We...
Definition: date.hpp:286
bool operator>(const Date &other) const
Returns whether this date is later than other.
Definition: date.hpp:205
long toDaysSinceEpoch() const
Returns the number of elapsed days since the epoch "1970-01-01".
Definition: date.hpp:486
std::string toString(const std::string &format) const
Returns this date as a string, formatted according to the format string format.
Definition: date.hpp:532
Month
Type of month.
Definition: date.hpp:119
Date(Date &&other)=default
Move-constructs a Date object from other.
int daysInYear() const
Returns the number of days in the year of this date. It is either 365 or 366.
Definition: date.hpp:304
bool isValid() const
Returns whether this date object represents a valid date.
Definition: date.hpp:248
static bool isLeapYear(int year)
Returns whether year is a leap year.
Definition: date.hpp:734
internal::Days Days
Day duration.
Definition: date.hpp:91
void getYearMonthDay(int *year, int *month, int *day) const
Set the year, month, and day of this date in the parameters year, month, and day, respectively.
Definition: date.hpp:254
Date subtractYears(int years) const
Returns the result of subtracting years from this date as a new Date object.
Definition: date.hpp:472
int year() const
Returns the year of this date as a number.
Definition: date.hpp:280
std::chrono::duration< long, std::ratio_multiply< std::ratio< 7 >, Days::period > > Weeks
Week duration.
Definition: date.hpp:92
Date(const Days &days)
Constructs a Date object from days elapsed since the epoch "1970-01-01".
Definition: date.hpp:156
int daysInMonth() const
Returns the number of days in the month of this date. It ranges between 28 and 31.
Definition: date.hpp:298
static int daysInMonthOfYear(int year, int month)
Returns the number of days in month of year. It ranges between 28 and 31.
Definition: date.hpp:744
bool operator<=(const Date &other) const
Returns whether this date is earlier than other or equal to it.
Definition: date.hpp:199
Date addYears(int years) const
Returns the result of adding years to this date as a new Date object.
Definition: date.hpp:465
bool operator==(const Date &other) const
Returns whether this date is equal to other.
Definition: date.hpp:217
Date subtractMonths(int months) const
Returns the result of subtracting months from this date as a new Date object.
Definition: date.hpp:451
Weekday
Type of weekday.
Definition: date.hpp:105
Date addDays(int days) const
Returns the result of adding days to this date as a new Date object.
Definition: date.hpp:406
bool operator>=(const Date &other) const
Returns whether this date is later than other or equal to it.
Definition: date.hpp:211
static Date fromJulianDay(long julianDay)
Returns a Date object corresponding to the Julian day julianDay.
Definition: date.hpp:688
std::string dayOfWeekName(bool shortName=false) const
Returns the name of the weekday of this date.
Definition: date.hpp:367
static Date current()
Returns a Date object set to the current date obtained from the system clock.
Definition: date.hpp:597
Date(int year, int month, int day)
Constructs a Date object from the given year, month and day.
Definition: date.hpp:162
int month() const
Returns the month of the year of this date as a number between 1 and 12, which corresponds to the enu...
Definition: date.hpp:271
Date()
Constructs an invalid Date object with every field is set to zero.
Definition: date.hpp:142
Date & operator=(Date &&other)=default
Move assignment operator.
bool operator!=(const Date &other) const
Returns whether this date is different from other.
Definition: date.hpp:223
std::istream & operator>>(std::istream &is, Date &d)
Reads a date in ISO-8601 date format "yyyy-MM-dd" from stream is and stores it in date d.
Definition: date.hpp:803
static Date epoch()
Returns a Date object set to the epoch "1970-01-01".
Definition: date.hpp:603
int day() const
Returns the day of the month of this date as a number between 1 and 31.
Definition: date.hpp:265
Days toStdDurationSinceEpoch() const
Returns the elapsed time since the epoch "1970-01-01" as a Days duration.
Definition: date.hpp:492
static long weeksBetween(const Date &from, const Date &to)
Returns the number of weeks between from and to.
Definition: date.hpp:719
long toJulianDay() const
Returns the corresponding Julian Day Number (JDN) of this date.
Definition: date.hpp:503
static long daysBetween(const Date &from, const Date &to)
Returns the number of days between from and to.
Definition: date.hpp:707
static Date fromString(const std::string &date, const std::string &format)
Returns a Date object from the date string date according to the format string format.
Definition: date.hpp:612
Date(const Date &other)=default
Copy-constructs a Date object from other.
int weekOfYear(int *weekYear=nullptr) const
Returns the week of the year of this date, and optionally stores the year in weekYear.
Definition: date.hpp:324
int dayOfYear() const
Returns the day of year of this date as a number between 1 and 365 (1 to 366 on leap years).
Definition: date.hpp:292
~Date()=default
Default destructor.
Date addMonths(int months) const
Returns the result of adding months to this date as a new Date object.
Definition: date.hpp:429
std::ostream & operator<<(std::ostream &os, const Date &d)
Writes date d to stream os in ISO-8601 date format, "yyyy-MM-dd".
Definition: date.hpp:793
Date & operator=(const Date &other)=default
Copy assignment operator.
bool isLeapYear() const
Returns whether the year of this date is a leap year.
Definition: date.hpp:310