Add Catholic Feasts holiday authority class (US observances)

This includes a static function to calculate Easter that can be used for
other authorities.

Document the wxDateTimeWorkDays and wxDateTimeHolidayAuthority classes.

Closes #24094.
This commit is contained in:
Blake-Madden 2023-11-26 19:22:16 -05:00 committed by Vadim Zeitlin
parent 2c9fee3d6f
commit 5ba009e861
4 changed files with 912 additions and 13 deletions

View file

@ -17,6 +17,8 @@
#include <time.h>
#include <vector>
#include <limits.h> // for INT_MIN
#include "wx/longlong.h"
@ -44,7 +46,7 @@ struct _SYSTEMTIME;
* ? 2. getdate() function like under Solaris
* + 3. text conversion for wxDateSpan
* + 4. pluggable modules for the workdays calculations
* 5. wxDateTimeHolidayAuthority for Easter and other christian feasts
* 5. wxDateTimeHolidayAuthority Christian feasts outside of US
*/
/*
@ -1599,13 +1601,7 @@ protected:
virtual bool DoIsHoliday(const wxDateTime& dt) const = 0;
// this function should fill the array with all holidays between the two
// given dates - it is implemented in the base class, but in a very
// inefficient way (it just iterates over all days and uses IsHoliday() for
// each of them), so it must be overridden in the derived class where the
// base class version may be explicitly used if needed
//
// returns the number of holidays in the given range and fills holidays
// array
// given dates
virtual size_t DoGetHolidaysInRange(const wxDateTime& dtStart,
const wxDateTime& dtEnd,
wxDateTimeArray& holidays) const = 0;
@ -1625,6 +1621,85 @@ protected:
wxDateTimeArray& holidays) const override;
};
// https://marian.org/mary/feast-days
// https://www.omvusa.org/blog/catholic-holy-days-of-obligation/
class WXDLLIMPEXP_BASE wxDateTimeUSCatholicFeasts : public wxDateTimeHolidayAuthority
{
public:
// Easter for a given year.
// Based on https://www.geeksforgeeks.org/how-to-calculate-the-easter-date-for-a-given-year-using-gauss-algorithm/
// Validated against 1600 to 2099, using data from:
// https://www.assa.org.au/edm (Astronomical Society of South Australia)
// https://www.census.gov/data/software/x13as/genhol/easter-dates.html (US Census Bureau)
static wxDateTime GetEaster(int year);
// Ascension for a given year.
// Celebrated on the 40th day of Easter/
// the sixth Thursday after Easter Sunday.
static wxDateTime GetThursdayAscension(int year)
{
const wxDateTime ascension = GetEaster(year) + wxDateSpan::Days(39);
wxASSERT_MSG(
ascension.GetWeekDay() == wxDateTime::WeekDay::Thu,
"Error in Ascension calculation!");
return ascension;
}
// Ascension for a given year.
// Same as traditional Ascension, but moved to the following Sunday.
static wxDateTime GetSundayAscension(int year)
{
const wxDateTime ascension = GetEaster(year) + wxDateSpan::Weeks(6);
wxASSERT_MSG(
ascension.GetWeekDay() == wxDateTime::WeekDay::Sun,
"Error in Ascension calculation!");
return ascension;
}
protected:
bool DoIsHoliday(const wxDateTime& dt) const override
{
if (dt.IsSameDate(GetEaster(dt.GetYear())) ||
dt.IsSameDate(GetThursdayAscension(dt.GetYear())) )
{
return true;
}
for (const auto& feast : m_holyDaysOfObligation)
{
if (feast.GetMonth() == dt.GetMonth() &&
feast.GetDay() == dt.GetDay())
{
return true;
}
}
return false;
}
size_t DoGetHolidaysInRange(const wxDateTime& dtStart,
const wxDateTime& dtEnd,
wxDateTimeArray& holidays) const override;
private:
static std::vector<wxDateTime> m_holyDaysOfObligation;
};
// Christmas and Easter
class WXDLLIMPEXP_BASE wxDateTimeChristianHolidays : public wxDateTimeUSCatholicFeasts
{
protected:
bool DoIsHoliday(const wxDateTime& dt) const override
{
if (dt.IsSameDate(GetEaster(dt.GetYear())) ||
(dt.GetMonth() == 12 && dt.GetDay() == 25))
{
return true;
}
return false;
}
size_t DoGetHolidaysInRange(const wxDateTime& dtStart,
const wxDateTime& dtEnd,
wxDateTimeArray& holidays) const override;
};
// ============================================================================
// inline functions implementation
// ============================================================================

View file

@ -1679,18 +1679,111 @@ const wxDateTime wxDefaultDateTime;
/**
@class wxDateTimeWorkDays
@todo Write wxDateTimeWorkDays documentation.
Holiday authority that classifies all Saturdays and Sundays
as holidays.
@library{wxbase}
@category{data}
*/
class wxDateTimeWorkDays
class wxDateTimeWorkDays : public wxDateTimeHolidayAuthority
{
public:
protected:
/**
Override which returns @true if provided date is a Saturday and Sunday.
*/
virtual bool DoIsHoliday(const wxDateTime& dt) const override;
/**
Override which returns all Saturdays and Sundays from a provided range.
*/
virtual size_t DoGetHolidaysInRange(const wxDateTime& dtStart,
const wxDateTime& dtEnd,
wxDateTimeArray& holidays) const override;
};
/**
@class wxDateTimeUSCatholicFeasts
Holiday authority that returns Catholic holy days of obligation,
as observed in the United States. This includes:
- Solemnity of Mary, Mother of God
- Easter (moveable feast)
- Ascension (moveable feast)
- Assumption of the Blessed Virgin Mary
- All Saints Day
- Immaculate Conception of the Blessed Virgin Mary
- Christmas
@library{wxbase}
@category{data}
@since 3.3.0
*/
class wxDateTimeUSCatholicFeasts : public wxDateTimeHolidayAuthority
{
public:
/**
Returns the date for Easter for a given year.
*/
static wxDateTime GetEaster(int year);
/**
Returns the date for Ascension for a given year.
Celebrated on the 40th day of Easter/
sixth Thursday after Easter Sunday.
*/
static wxDateTime GetThursdayAscension(int year);
/**
Returns the date for Ascension for a given year.
This is the same as GetThursdayAscension(),
but moved to the Sunday following the traditional Ascension
that falls on a Thursday.
*/
static wxDateTime GetSundayAscension(int year);
protected:
/**
Override which returns @true if provided date is a holy day of obligation.
*/
bool DoIsHoliday(const wxDateTime& dt) const override;
/**
Override to determine the holy days of obligation within a date range.
*/
size_t DoGetHolidaysInRange(const wxDateTime& dtStart,
const wxDateTime& dtEnd,
wxDateTimeArray& holidays) const override;
};
/**
@class wxDateTimeChristianHolidays
Holiday authority that returns holidays common to all Christian religions.
This includes:
- Easter (moveable feast)
- Christmas
@library{wxbase}
@category{data}
@since 3.3.0
*/
class WXDLLIMPEXP_BASE wxDateTimeChristianHolidays : public wxDateTimeUSCatholicFeasts
{
protected:
/**
Override which returns @true if provided date is Easter or Christmas.
*/
bool DoIsHoliday(const wxDateTime& dt) const override;
/**
Override to determine the holidays within a date range.
*/
size_t DoGetHolidaysInRange(const wxDateTime& dtStart,
const wxDateTime& dtEnd,
wxDateTimeArray& holidays) const override;
};
/**
@class wxDateSpan
@ -2231,7 +2324,12 @@ public:
/**
@class wxDateTimeHolidayAuthority
@todo Write wxDateTimeHolidayAuthority documentation.
Class which decides whether a given
date is a holiday and is used by all functions working with "work days".
New classes can be derived from this to determine specific holidays.
These classes should override DoIsHoliday() and DoGetHolidaysInRange(),
and be passed to wxDateTimeHolidayAuthority::AddAuthority() to be used.
@library{wxbase}
@category{data}
@ -2239,6 +2337,40 @@ public:
class wxDateTimeHolidayAuthority
{
public:
/// Returns @true if the given date is a holiday.
static bool IsHoliday(const wxDateTime& dt);
/**
Fills the provided array with all holidays in the given range, returns
the number of them.
*/
static size_t GetHolidaysInRange(const wxDateTime& dtStart,
const wxDateTime& dtEnd,
wxDateTimeArray& holidays);
/// Clears the list of holiday authorities.
static void ClearAllAuthorities();
/**
Adds a new holiday authority.
The pointer will be deleted by wxDateTimeHolidayAuthority.
*/
static void AddAuthority(wxDateTimeHolidayAuthority* auth);
protected:
/**
This function should be overridden to determine whether
a given day is a holiday.
*/
virtual bool DoIsHoliday(const wxDateTime& dt) const = 0;
/**
This function should be overridden to fill an array with
all holidays between the two given dates.
*/
virtual size_t DoGetHolidaysInRange(const wxDateTime& dtStart,
const wxDateTime& dtEnd,
wxDateTimeArray& holidays) const = 0;
};

View file

@ -74,6 +74,7 @@
#include "wx/tokenzr.h"
#include <ctype.h>
#include <cmath>
#ifdef __WINDOWS__
#include <winnls.h>
@ -2271,6 +2272,133 @@ size_t wxDateTimeWorkDays::DoGetHolidaysInRange(const wxDateTime& dtStart,
return holidays.GetCount();
}
// ----------------------------------------------------------------------------
// wxDateTimeUSCatholicFeasts
// ----------------------------------------------------------------------------
std::vector<wxDateTime> wxDateTimeUSCatholicFeasts::m_holyDaysOfObligation =
{
// Feasts with fixed dates
{ wxDateTime(1, wxDateTime::Month::Jan, 0) }, // Solemnity of Mary, Mother of God
{ wxDateTime(15, wxDateTime::Month::Aug, 0) }, // Assumption of the Blessed Virgin Mary
{ wxDateTime(1, wxDateTime::Month::Nov, 0) }, // All Saints Day
{ wxDateTime(8, wxDateTime::Month::Dec, 0) }, // Immaculate Conception of the Blessed Virgin Mary
{ wxDateTime(25, wxDateTime::Month::Dec, 0) } // Christmas
};
wxDateTime wxDateTimeUSCatholicFeasts::GetEaster(int year)
{
// Adjust for miscalculation in Gauss formula
if (year == 1734 || year == 1886)
{
return wxDateTime(25, wxDateTime::Apr, year);
}
// All calculations done
// on the basis of
// Gauss Easter Algorithm
const float A = year % 19;
const float B = year % 4;
const float C = year % 7;
const float P = std::floor((float)year / 100.0);
const float Q = std::floor((float)(13 + 8 * P) / 25.0);
const float M = (int)(15 - Q + P - std::floor((float)P / 4)) % 30;
const float N = (int)(4 + P - std::floor((float)P / 4)) % 7;
const float D = (int)(19 * A + M) % 30;
const float E = (int)(2 * B + 4 * C + 6 * D + N) % 7;
const int days = (int)(22 + D + E);
// A corner case,
// when D is 29
if ((D == 29) && (E == 6))
{
wxASSERT_MSG(
wxDateTime(19, wxDateTime::Apr, year).GetWeekDay() ==
wxDateTime::WeekDay::Sun,
"Error in Easter calculation!");
return wxDateTime(19, wxDateTime::Apr, year);
}
// Another corner case,
// when D is 28
else if ((D == 28) && (E == 6))
{
wxASSERT_MSG(
wxDateTime(18, wxDateTime::Apr, year).GetWeekDay() ==
wxDateTime::WeekDay::Sun,
"Error in Easter calculation!");
return wxDateTime(18, wxDateTime::Apr, year);
}
else
{
// If days > 31, move to April
// April = 4th Month
if (days > 31)
{
wxASSERT_MSG(
wxDateTime((days - 31), wxDateTime::Apr, year).GetWeekDay() ==
wxDateTime::WeekDay::Sun,
"Error in Easter calculation!");
return wxDateTime((days - 31), wxDateTime::Apr, year);
}
else
{
// Otherwise, stay on March
// March = 3rd Month
wxASSERT_MSG(
wxDateTime(days, wxDateTime::Mar, year).GetWeekDay() ==
wxDateTime::WeekDay::Sun,
"Error in Easter calculation!");
return wxDateTime(days, wxDateTime::Mar, year);
}
}
}
size_t wxDateTimeUSCatholicFeasts::DoGetHolidaysInRange(const wxDateTime& dtStart,
const wxDateTime& dtEnd,
wxDateTimeArray& holidays) const
{
holidays.Clear();
for (wxDateTime dt = dtStart; dt <= dtEnd; dt += wxDateSpan::Day())
{
if (DoIsHoliday(dt) )
{
holidays.Add(dt);
continue;
}
}
return holidays.size();
}
// ----------------------------------------------------------------------------
// wxDateTimeChristianHolidays
// ----------------------------------------------------------------------------
size_t wxDateTimeChristianHolidays::DoGetHolidaysInRange(const wxDateTime& dtStart,
const wxDateTime& dtEnd,
wxDateTimeArray& holidays) const
{
holidays.Clear();
for (wxDateTime dt = dtStart; dt <= dtEnd; dt += wxDateSpan::Day())
{
if (DoIsHoliday(dt) )
{
holidays.Add(dt);
continue;
}
}
return holidays.size();
}
// ============================================================================
// other helper functions
// ============================================================================

View file

@ -2025,4 +2025,568 @@ TEST_CASE("wxDateTime::UNow", "[datetime][now][unow]")
CHECK( gotMS );
}
TEST_CASE("Easter", "[datetime][holiday][easter]")
{
std::vector<wxDateTime> easters =
{
wxDateTime( 2, wxDateTime::Apr, 1600),
wxDateTime(22, wxDateTime::Apr, 1601),
wxDateTime( 7, wxDateTime::Apr, 1602),
wxDateTime(30, wxDateTime::Mar, 1603),
wxDateTime(18, wxDateTime::Apr, 1604),
wxDateTime(10, wxDateTime::Apr, 1605),
wxDateTime(26, wxDateTime::Mar, 1606),
wxDateTime(15, wxDateTime::Apr, 1607),
wxDateTime( 6, wxDateTime::Apr, 1608),
wxDateTime(19, wxDateTime::Apr, 1609),
wxDateTime(11, wxDateTime::Apr, 1610),
wxDateTime( 3, wxDateTime::Apr, 1611),
wxDateTime(22, wxDateTime::Apr, 1612),
wxDateTime( 7, wxDateTime::Apr, 1613),
wxDateTime(30, wxDateTime::Mar, 1614),
wxDateTime(19, wxDateTime::Apr, 1615),
wxDateTime( 3, wxDateTime::Apr, 1616),
wxDateTime(26, wxDateTime::Mar, 1617),
wxDateTime(15, wxDateTime::Apr, 1618),
wxDateTime(31, wxDateTime::Mar, 1619),
wxDateTime(19, wxDateTime::Apr, 1620),
wxDateTime(11, wxDateTime::Apr, 1621),
wxDateTime(27, wxDateTime::Mar, 1622),
wxDateTime(16, wxDateTime::Apr, 1623),
wxDateTime( 7, wxDateTime::Apr, 1624),
wxDateTime(30, wxDateTime::Mar, 1625),
wxDateTime(12, wxDateTime::Apr, 1626),
wxDateTime( 4, wxDateTime::Apr, 1627),
wxDateTime(23, wxDateTime::Apr, 1628),
wxDateTime(15, wxDateTime::Apr, 1629),
wxDateTime(31, wxDateTime::Mar, 1630),
wxDateTime(20, wxDateTime::Apr, 1631),
wxDateTime(11, wxDateTime::Apr, 1632),
wxDateTime(27, wxDateTime::Mar, 1633),
wxDateTime(16, wxDateTime::Apr, 1634),
wxDateTime( 8, wxDateTime::Apr, 1635),
wxDateTime(23, wxDateTime::Mar, 1636),
wxDateTime(12, wxDateTime::Apr, 1637),
wxDateTime( 4, wxDateTime::Apr, 1638),
wxDateTime(24, wxDateTime::Apr, 1639),
wxDateTime( 8, wxDateTime::Apr, 1640),
wxDateTime(31, wxDateTime::Mar, 1641),
wxDateTime(20, wxDateTime::Apr, 1642),
wxDateTime( 5, wxDateTime::Apr, 1643),
wxDateTime(27, wxDateTime::Mar, 1644),
wxDateTime(16, wxDateTime::Apr, 1645),
wxDateTime( 1, wxDateTime::Apr, 1646),
wxDateTime(21, wxDateTime::Apr, 1647),
wxDateTime(12, wxDateTime::Apr, 1648),
wxDateTime( 4, wxDateTime::Apr, 1649),
wxDateTime(17, wxDateTime::Apr, 1650),
wxDateTime( 9, wxDateTime::Apr, 1651),
wxDateTime(31, wxDateTime::Mar, 1652),
wxDateTime(13, wxDateTime::Apr, 1653),
wxDateTime( 5, wxDateTime::Apr, 1654),
wxDateTime(28, wxDateTime::Mar, 1655),
wxDateTime(16, wxDateTime::Apr, 1656),
wxDateTime( 1, wxDateTime::Apr, 1657),
wxDateTime(21, wxDateTime::Apr, 1658),
wxDateTime(13, wxDateTime::Apr, 1659),
wxDateTime(28, wxDateTime::Mar, 1660),
wxDateTime(17, wxDateTime::Apr, 1661),
wxDateTime( 9, wxDateTime::Apr, 1662),
wxDateTime(25, wxDateTime::Mar, 1663),
wxDateTime(13, wxDateTime::Apr, 1664),
wxDateTime( 5, wxDateTime::Apr, 1665),
wxDateTime(25, wxDateTime::Apr, 1666),
wxDateTime(10, wxDateTime::Apr, 1667),
wxDateTime( 1, wxDateTime::Apr, 1668),
wxDateTime(21, wxDateTime::Apr, 1669),
wxDateTime( 6, wxDateTime::Apr, 1670),
wxDateTime(29, wxDateTime::Mar, 1671),
wxDateTime(17, wxDateTime::Apr, 1672),
wxDateTime( 2, wxDateTime::Apr, 1673),
wxDateTime(25, wxDateTime::Mar, 1674),
wxDateTime(14, wxDateTime::Apr, 1675),
wxDateTime( 5, wxDateTime::Apr, 1676),
wxDateTime(18, wxDateTime::Apr, 1677),
wxDateTime(10, wxDateTime::Apr, 1678),
wxDateTime( 2, wxDateTime::Apr, 1679),
wxDateTime(21, wxDateTime::Apr, 1680),
wxDateTime( 6, wxDateTime::Apr, 1681),
wxDateTime(29, wxDateTime::Mar, 1682),
wxDateTime(18, wxDateTime::Apr, 1683),
wxDateTime( 2, wxDateTime::Apr, 1684),
wxDateTime(22, wxDateTime::Apr, 1685),
wxDateTime(14, wxDateTime::Apr, 1686),
wxDateTime(30, wxDateTime::Mar, 1687),
wxDateTime(18, wxDateTime::Apr, 1688),
wxDateTime(10, wxDateTime::Apr, 1689),
wxDateTime(26, wxDateTime::Mar, 1690),
wxDateTime(15, wxDateTime::Apr, 1691),
wxDateTime( 6, wxDateTime::Apr, 1692),
wxDateTime(22, wxDateTime::Mar, 1693),
wxDateTime(11, wxDateTime::Apr, 1694),
wxDateTime( 3, wxDateTime::Apr, 1695),
wxDateTime(22, wxDateTime::Apr, 1696),
wxDateTime( 7, wxDateTime::Apr, 1697),
wxDateTime(30, wxDateTime::Mar, 1698),
wxDateTime(19, wxDateTime::Apr, 1699),
wxDateTime(11, wxDateTime::Apr, 1700),
wxDateTime(27, wxDateTime::Mar, 1701),
wxDateTime(16, wxDateTime::Apr, 1702),
wxDateTime( 8, wxDateTime::Apr, 1703),
wxDateTime(23, wxDateTime::Mar, 1704),
wxDateTime(12, wxDateTime::Apr, 1705),
wxDateTime( 4, wxDateTime::Apr, 1706),
wxDateTime(24, wxDateTime::Apr, 1707),
wxDateTime( 8, wxDateTime::Apr, 1708),
wxDateTime(31, wxDateTime::Mar, 1709),
wxDateTime(20, wxDateTime::Apr, 1710),
wxDateTime( 5, wxDateTime::Apr, 1711),
wxDateTime(27, wxDateTime::Mar, 1712),
wxDateTime(16, wxDateTime::Apr, 1713),
wxDateTime( 1, wxDateTime::Apr, 1714),
wxDateTime(21, wxDateTime::Apr, 1715),
wxDateTime(12, wxDateTime::Apr, 1716),
wxDateTime(28, wxDateTime::Mar, 1717),
wxDateTime(17, wxDateTime::Apr, 1718),
wxDateTime( 9, wxDateTime::Apr, 1719),
wxDateTime(31, wxDateTime::Mar, 1720),
wxDateTime(13, wxDateTime::Apr, 1721),
wxDateTime( 5, wxDateTime::Apr, 1722),
wxDateTime(28, wxDateTime::Mar, 1723),
wxDateTime(16, wxDateTime::Apr, 1724),
wxDateTime( 1, wxDateTime::Apr, 1725),
wxDateTime(21, wxDateTime::Apr, 1726),
wxDateTime(13, wxDateTime::Apr, 1727),
wxDateTime(28, wxDateTime::Mar, 1728),
wxDateTime(17, wxDateTime::Apr, 1729),
wxDateTime( 9, wxDateTime::Apr, 1730),
wxDateTime(25, wxDateTime::Mar, 1731),
wxDateTime(13, wxDateTime::Apr, 1732),
wxDateTime( 5, wxDateTime::Apr, 1733),
wxDateTime(25, wxDateTime::Apr, 1734),
wxDateTime(10, wxDateTime::Apr, 1735),
wxDateTime( 1, wxDateTime::Apr, 1736),
wxDateTime(21, wxDateTime::Apr, 1737),
wxDateTime( 6, wxDateTime::Apr, 1738),
wxDateTime(29, wxDateTime::Mar, 1739),
wxDateTime(17, wxDateTime::Apr, 1740),
wxDateTime( 2, wxDateTime::Apr, 1741),
wxDateTime(25, wxDateTime::Mar, 1742),
wxDateTime(14, wxDateTime::Apr, 1743),
wxDateTime( 5, wxDateTime::Apr, 1744),
wxDateTime(18, wxDateTime::Apr, 1745),
wxDateTime(10, wxDateTime::Apr, 1746),
wxDateTime( 2, wxDateTime::Apr, 1747),
wxDateTime(14, wxDateTime::Apr, 1748),
wxDateTime( 6, wxDateTime::Apr, 1749),
wxDateTime(29, wxDateTime::Mar, 1750),
wxDateTime(11, wxDateTime::Apr, 1751),
wxDateTime( 2, wxDateTime::Apr, 1752),
wxDateTime(22, wxDateTime::Apr, 1753),
wxDateTime(14, wxDateTime::Apr, 1754),
wxDateTime(30, wxDateTime::Mar, 1755),
wxDateTime(18, wxDateTime::Apr, 1756),
wxDateTime(10, wxDateTime::Apr, 1757),
wxDateTime(26, wxDateTime::Mar, 1758),
wxDateTime(15, wxDateTime::Apr, 1759),
wxDateTime( 6, wxDateTime::Apr, 1760),
wxDateTime(22, wxDateTime::Mar, 1761),
wxDateTime(11, wxDateTime::Apr, 1762),
wxDateTime( 3, wxDateTime::Apr, 1763),
wxDateTime(22, wxDateTime::Apr, 1764),
wxDateTime( 7, wxDateTime::Apr, 1765),
wxDateTime(30, wxDateTime::Mar, 1766),
wxDateTime(19, wxDateTime::Apr, 1767),
wxDateTime( 3, wxDateTime::Apr, 1768),
wxDateTime(26, wxDateTime::Mar, 1769),
wxDateTime(15, wxDateTime::Apr, 1770),
wxDateTime(31, wxDateTime::Mar, 1771),
wxDateTime(19, wxDateTime::Apr, 1772),
wxDateTime(11, wxDateTime::Apr, 1773),
wxDateTime( 3, wxDateTime::Apr, 1774),
wxDateTime(16, wxDateTime::Apr, 1775),
wxDateTime( 7, wxDateTime::Apr, 1776),
wxDateTime(30, wxDateTime::Mar, 1777),
wxDateTime(19, wxDateTime::Apr, 1778),
wxDateTime( 4, wxDateTime::Apr, 1779),
wxDateTime(26, wxDateTime::Mar, 1780),
wxDateTime(15, wxDateTime::Apr, 1781),
wxDateTime(31, wxDateTime::Mar, 1782),
wxDateTime(20, wxDateTime::Apr, 1783),
wxDateTime(11, wxDateTime::Apr, 1784),
wxDateTime(27, wxDateTime::Mar, 1785),
wxDateTime(16, wxDateTime::Apr, 1786),
wxDateTime( 8, wxDateTime::Apr, 1787),
wxDateTime(23, wxDateTime::Mar, 1788),
wxDateTime(12, wxDateTime::Apr, 1789),
wxDateTime( 4, wxDateTime::Apr, 1790),
wxDateTime(24, wxDateTime::Apr, 1791),
wxDateTime( 8, wxDateTime::Apr, 1792),
wxDateTime(31, wxDateTime::Mar, 1793),
wxDateTime(20, wxDateTime::Apr, 1794),
wxDateTime( 5, wxDateTime::Apr, 1795),
wxDateTime(27, wxDateTime::Mar, 1796),
wxDateTime(16, wxDateTime::Apr, 1797),
wxDateTime( 8, wxDateTime::Apr, 1798),
wxDateTime(24, wxDateTime::Mar, 1799),
wxDateTime(13, wxDateTime::Apr, 1800),
wxDateTime( 5, wxDateTime::Apr, 1801),
wxDateTime(18, wxDateTime::Apr, 1802),
wxDateTime(10, wxDateTime::Apr, 1803),
wxDateTime( 1, wxDateTime::Apr, 1804),
wxDateTime(14, wxDateTime::Apr, 1805),
wxDateTime( 6, wxDateTime::Apr, 1806),
wxDateTime(29, wxDateTime::Mar, 1807),
wxDateTime(17, wxDateTime::Apr, 1808),
wxDateTime( 2, wxDateTime::Apr, 1809),
wxDateTime(22, wxDateTime::Apr, 1810),
wxDateTime(14, wxDateTime::Apr, 1811),
wxDateTime(29, wxDateTime::Mar, 1812),
wxDateTime(18, wxDateTime::Apr, 1813),
wxDateTime(10, wxDateTime::Apr, 1814),
wxDateTime(26, wxDateTime::Mar, 1815),
wxDateTime(14, wxDateTime::Apr, 1816),
wxDateTime( 6, wxDateTime::Apr, 1817),
wxDateTime(22, wxDateTime::Mar, 1818),
wxDateTime(11, wxDateTime::Apr, 1819),
wxDateTime( 2, wxDateTime::Apr, 1820),
wxDateTime(22, wxDateTime::Apr, 1821),
wxDateTime( 7, wxDateTime::Apr, 1822),
wxDateTime(30, wxDateTime::Mar, 1823),
wxDateTime(18, wxDateTime::Apr, 1824),
wxDateTime( 3, wxDateTime::Apr, 1825),
wxDateTime(26, wxDateTime::Mar, 1826),
wxDateTime(15, wxDateTime::Apr, 1827),
wxDateTime( 6, wxDateTime::Apr, 1828),
wxDateTime(19, wxDateTime::Apr, 1829),
wxDateTime(11, wxDateTime::Apr, 1830),
wxDateTime( 3, wxDateTime::Apr, 1831),
wxDateTime(22, wxDateTime::Apr, 1832),
wxDateTime( 7, wxDateTime::Apr, 1833),
wxDateTime(30, wxDateTime::Mar, 1834),
wxDateTime(19, wxDateTime::Apr, 1835),
wxDateTime( 3, wxDateTime::Apr, 1836),
wxDateTime(26, wxDateTime::Mar, 1837),
wxDateTime(15, wxDateTime::Apr, 1838),
wxDateTime(31, wxDateTime::Mar, 1839),
wxDateTime(19, wxDateTime::Apr, 1840),
wxDateTime(11, wxDateTime::Apr, 1841),
wxDateTime(27, wxDateTime::Mar, 1842),
wxDateTime(16, wxDateTime::Apr, 1843),
wxDateTime( 7, wxDateTime::Apr, 1844),
wxDateTime(23, wxDateTime::Mar, 1845),
wxDateTime(12, wxDateTime::Apr, 1846),
wxDateTime( 4, wxDateTime::Apr, 1847),
wxDateTime(23, wxDateTime::Apr, 1848),
wxDateTime( 8, wxDateTime::Apr, 1849),
wxDateTime(31, wxDateTime::Mar, 1850),
wxDateTime(20, wxDateTime::Apr, 1851),
wxDateTime(11, wxDateTime::Apr, 1852),
wxDateTime(27, wxDateTime::Mar, 1853),
wxDateTime(16, wxDateTime::Apr, 1854),
wxDateTime( 8, wxDateTime::Apr, 1855),
wxDateTime(23, wxDateTime::Mar, 1856),
wxDateTime(12, wxDateTime::Apr, 1857),
wxDateTime( 4, wxDateTime::Apr, 1858),
wxDateTime(24, wxDateTime::Apr, 1859),
wxDateTime( 8, wxDateTime::Apr, 1860),
wxDateTime(31, wxDateTime::Mar, 1861),
wxDateTime(20, wxDateTime::Apr, 1862),
wxDateTime( 5, wxDateTime::Apr, 1863),
wxDateTime(27, wxDateTime::Mar, 1864),
wxDateTime(16, wxDateTime::Apr, 1865),
wxDateTime( 1, wxDateTime::Apr, 1866),
wxDateTime(21, wxDateTime::Apr, 1867),
wxDateTime(12, wxDateTime::Apr, 1868),
wxDateTime(28, wxDateTime::Mar, 1869),
wxDateTime(17, wxDateTime::Apr, 1870),
wxDateTime( 9, wxDateTime::Apr, 1871),
wxDateTime(31, wxDateTime::Mar, 1872),
wxDateTime(13, wxDateTime::Apr, 1873),
wxDateTime( 5, wxDateTime::Apr, 1874),
wxDateTime(28, wxDateTime::Mar, 1875),
wxDateTime(16, wxDateTime::Apr, 1876),
wxDateTime( 1, wxDateTime::Apr, 1877),
wxDateTime(21, wxDateTime::Apr, 1878),
wxDateTime(13, wxDateTime::Apr, 1879),
wxDateTime(28, wxDateTime::Mar, 1880),
wxDateTime(17, wxDateTime::Apr, 1881),
wxDateTime( 9, wxDateTime::Apr, 1882),
wxDateTime(25, wxDateTime::Mar, 1883),
wxDateTime(13, wxDateTime::Apr, 1884),
wxDateTime( 5, wxDateTime::Apr, 1885),
wxDateTime(25, wxDateTime::Apr, 1886),
wxDateTime(10, wxDateTime::Apr, 1887),
wxDateTime( 1, wxDateTime::Apr, 1888),
wxDateTime(21, wxDateTime::Apr, 1889),
wxDateTime( 6, wxDateTime::Apr, 1890),
wxDateTime(29, wxDateTime::Mar, 1891),
wxDateTime(17, wxDateTime::Apr, 1892),
wxDateTime( 2, wxDateTime::Apr, 1893),
wxDateTime(25, wxDateTime::Mar, 1894),
wxDateTime(14, wxDateTime::Apr, 1895),
wxDateTime( 5, wxDateTime::Apr, 1896),
wxDateTime(18, wxDateTime::Apr, 1897),
wxDateTime(10, wxDateTime::Apr, 1898),
wxDateTime( 2, wxDateTime::Apr, 1899),
wxDateTime(15, wxDateTime::Apr, 1900),
wxDateTime( 7, wxDateTime::Apr, 1901),
wxDateTime(30, wxDateTime::Mar, 1902),
wxDateTime(12, wxDateTime::Apr, 1903),
wxDateTime( 3, wxDateTime::Apr, 1904),
wxDateTime(23, wxDateTime::Apr, 1905),
wxDateTime(15, wxDateTime::Apr, 1906),
wxDateTime(31, wxDateTime::Mar, 1907),
wxDateTime(19, wxDateTime::Apr, 1908),
wxDateTime(11, wxDateTime::Apr, 1909),
wxDateTime(27, wxDateTime::Mar, 1910),
wxDateTime(16, wxDateTime::Apr, 1911),
wxDateTime( 7, wxDateTime::Apr, 1912),
wxDateTime(23, wxDateTime::Mar, 1913),
wxDateTime(12, wxDateTime::Apr, 1914),
wxDateTime( 4, wxDateTime::Apr, 1915),
wxDateTime(23, wxDateTime::Apr, 1916),
wxDateTime( 8, wxDateTime::Apr, 1917),
wxDateTime(31, wxDateTime::Mar, 1918),
wxDateTime(20, wxDateTime::Apr, 1919),
wxDateTime( 4, wxDateTime::Apr, 1920),
wxDateTime(27, wxDateTime::Mar, 1921),
wxDateTime(16, wxDateTime::Apr, 1922),
wxDateTime( 1, wxDateTime::Apr, 1923),
wxDateTime(20, wxDateTime::Apr, 1924),
wxDateTime(12, wxDateTime::Apr, 1925),
wxDateTime( 4, wxDateTime::Apr, 1926),
wxDateTime(17, wxDateTime::Apr, 1927),
wxDateTime( 8, wxDateTime::Apr, 1928),
wxDateTime(31, wxDateTime::Mar, 1929),
wxDateTime(20, wxDateTime::Apr, 1930),
wxDateTime( 5, wxDateTime::Apr, 1931),
wxDateTime(27, wxDateTime::Mar, 1932),
wxDateTime(16, wxDateTime::Apr, 1933),
wxDateTime( 1, wxDateTime::Apr, 1934),
wxDateTime(21, wxDateTime::Apr, 1935),
wxDateTime(12, wxDateTime::Apr, 1936),
wxDateTime(28, wxDateTime::Mar, 1937),
wxDateTime(17, wxDateTime::Apr, 1938),
wxDateTime( 9, wxDateTime::Apr, 1939),
wxDateTime(24, wxDateTime::Mar, 1940),
wxDateTime(13, wxDateTime::Apr, 1941),
wxDateTime( 5, wxDateTime::Apr, 1942),
wxDateTime(25, wxDateTime::Apr, 1943),
wxDateTime( 9, wxDateTime::Apr, 1944),
wxDateTime( 1, wxDateTime::Apr, 1945),
wxDateTime(21, wxDateTime::Apr, 1946),
wxDateTime( 6, wxDateTime::Apr, 1947),
wxDateTime(28, wxDateTime::Mar, 1948),
wxDateTime(17, wxDateTime::Apr, 1949),
wxDateTime( 9, wxDateTime::Apr, 1950),
wxDateTime(25, wxDateTime::Mar, 1951),
wxDateTime(13, wxDateTime::Apr, 1952),
wxDateTime( 5, wxDateTime::Apr, 1953),
wxDateTime(18, wxDateTime::Apr, 1954),
wxDateTime(10, wxDateTime::Apr, 1955),
wxDateTime( 1, wxDateTime::Apr, 1956),
wxDateTime(21, wxDateTime::Apr, 1957),
wxDateTime( 6, wxDateTime::Apr, 1958),
wxDateTime(29, wxDateTime::Mar, 1959),
wxDateTime(17, wxDateTime::Apr, 1960),
wxDateTime( 2, wxDateTime::Apr, 1961),
wxDateTime(22, wxDateTime::Apr, 1962),
wxDateTime(14, wxDateTime::Apr, 1963),
wxDateTime(29, wxDateTime::Mar, 1964),
wxDateTime(18, wxDateTime::Apr, 1965),
wxDateTime(10, wxDateTime::Apr, 1966),
wxDateTime(26, wxDateTime::Mar, 1967),
wxDateTime(14, wxDateTime::Apr, 1968),
wxDateTime( 6, wxDateTime::Apr, 1969),
wxDateTime(29, wxDateTime::Mar, 1970),
wxDateTime(11, wxDateTime::Apr, 1971),
wxDateTime( 2, wxDateTime::Apr, 1972),
wxDateTime(22, wxDateTime::Apr, 1973),
wxDateTime(14, wxDateTime::Apr, 1974),
wxDateTime(30, wxDateTime::Mar, 1975),
wxDateTime(18, wxDateTime::Apr, 1976),
wxDateTime(10, wxDateTime::Apr, 1977),
wxDateTime(26, wxDateTime::Mar, 1978),
wxDateTime(15, wxDateTime::Apr, 1979),
wxDateTime( 6, wxDateTime::Apr, 1980),
wxDateTime(19, wxDateTime::Apr, 1981),
wxDateTime(11, wxDateTime::Apr, 1982),
wxDateTime( 3, wxDateTime::Apr, 1983),
wxDateTime(22, wxDateTime::Apr, 1984),
wxDateTime( 7, wxDateTime::Apr, 1985),
wxDateTime(30, wxDateTime::Mar, 1986),
wxDateTime(19, wxDateTime::Apr, 1987),
wxDateTime( 3, wxDateTime::Apr, 1988),
wxDateTime(26, wxDateTime::Mar, 1989),
wxDateTime(15, wxDateTime::Apr, 1990),
wxDateTime(31, wxDateTime::Mar, 1991),
wxDateTime(19, wxDateTime::Apr, 1992),
wxDateTime(11, wxDateTime::Apr, 1993),
wxDateTime( 3, wxDateTime::Apr, 1994),
wxDateTime(16, wxDateTime::Apr, 1995),
wxDateTime( 7, wxDateTime::Apr, 1996),
wxDateTime(30, wxDateTime::Mar, 1997),
wxDateTime(12, wxDateTime::Apr, 1998),
wxDateTime( 4, wxDateTime::Apr, 1999),
wxDateTime(23, wxDateTime::Apr, 2000),
wxDateTime(15, wxDateTime::Apr, 2001),
wxDateTime(31, wxDateTime::Mar, 2002),
wxDateTime(20, wxDateTime::Apr, 2003),
wxDateTime(11, wxDateTime::Apr, 2004),
wxDateTime(27, wxDateTime::Mar, 2005),
wxDateTime(16, wxDateTime::Apr, 2006),
wxDateTime( 8, wxDateTime::Apr, 2007),
wxDateTime(23, wxDateTime::Mar, 2008),
wxDateTime(12, wxDateTime::Apr, 2009),
wxDateTime( 4, wxDateTime::Apr, 2010),
wxDateTime(24, wxDateTime::Apr, 2011),
wxDateTime( 8, wxDateTime::Apr, 2012),
wxDateTime(31, wxDateTime::Mar, 2013),
wxDateTime(20, wxDateTime::Apr, 2014),
wxDateTime( 5, wxDateTime::Apr, 2015),
wxDateTime(27, wxDateTime::Mar, 2016),
wxDateTime(16, wxDateTime::Apr, 2017),
wxDateTime( 1, wxDateTime::Apr, 2018),
wxDateTime(21, wxDateTime::Apr, 2019),
wxDateTime(12, wxDateTime::Apr, 2020),
wxDateTime( 4, wxDateTime::Apr, 2021),
wxDateTime(17, wxDateTime::Apr, 2022),
wxDateTime( 9, wxDateTime::Apr, 2023),
wxDateTime(31, wxDateTime::Mar, 2024),
wxDateTime(20, wxDateTime::Apr, 2025),
wxDateTime( 5, wxDateTime::Apr, 2026),
wxDateTime(28, wxDateTime::Mar, 2027),
wxDateTime(16, wxDateTime::Apr, 2028),
wxDateTime( 1, wxDateTime::Apr, 2029),
wxDateTime(21, wxDateTime::Apr, 2030),
wxDateTime(13, wxDateTime::Apr, 2031),
wxDateTime(28, wxDateTime::Mar, 2032),
wxDateTime(17, wxDateTime::Apr, 2033),
wxDateTime( 9, wxDateTime::Apr, 2034),
wxDateTime(25, wxDateTime::Mar, 2035),
wxDateTime(13, wxDateTime::Apr, 2036),
wxDateTime( 5, wxDateTime::Apr, 2037),
wxDateTime(25, wxDateTime::Apr, 2038),
wxDateTime(10, wxDateTime::Apr, 2039),
wxDateTime( 1, wxDateTime::Apr, 2040),
wxDateTime(21, wxDateTime::Apr, 2041),
wxDateTime( 6, wxDateTime::Apr, 2042),
wxDateTime(29, wxDateTime::Mar, 2043),
wxDateTime(17, wxDateTime::Apr, 2044),
wxDateTime( 9, wxDateTime::Apr, 2045),
wxDateTime(25, wxDateTime::Mar, 2046),
wxDateTime(14, wxDateTime::Apr, 2047),
wxDateTime( 5, wxDateTime::Apr, 2048),
wxDateTime(18, wxDateTime::Apr, 2049),
wxDateTime(10, wxDateTime::Apr, 2050),
wxDateTime( 2, wxDateTime::Apr, 2051),
wxDateTime(21, wxDateTime::Apr, 2052),
wxDateTime( 6, wxDateTime::Apr, 2053),
wxDateTime(29, wxDateTime::Mar, 2054),
wxDateTime(18, wxDateTime::Apr, 2055),
wxDateTime( 2, wxDateTime::Apr, 2056),
wxDateTime(22, wxDateTime::Apr, 2057),
wxDateTime(14, wxDateTime::Apr, 2058),
wxDateTime(30, wxDateTime::Mar, 2059),
wxDateTime(18, wxDateTime::Apr, 2060),
wxDateTime(10, wxDateTime::Apr, 2061),
wxDateTime(26, wxDateTime::Mar, 2062),
wxDateTime(15, wxDateTime::Apr, 2063),
wxDateTime( 6, wxDateTime::Apr, 2064),
wxDateTime(29, wxDateTime::Mar, 2065),
wxDateTime(11, wxDateTime::Apr, 2066),
wxDateTime( 3, wxDateTime::Apr, 2067),
wxDateTime(22, wxDateTime::Apr, 2068),
wxDateTime(14, wxDateTime::Apr, 2069),
wxDateTime(30, wxDateTime::Mar, 2070),
wxDateTime(19, wxDateTime::Apr, 2071),
wxDateTime(10, wxDateTime::Apr, 2072),
wxDateTime(26, wxDateTime::Mar, 2073),
wxDateTime(15, wxDateTime::Apr, 2074),
wxDateTime( 7, wxDateTime::Apr, 2075),
wxDateTime(19, wxDateTime::Apr, 2076),
wxDateTime(11, wxDateTime::Apr, 2077),
wxDateTime( 3, wxDateTime::Apr, 2078),
wxDateTime(23, wxDateTime::Apr, 2079),
wxDateTime( 7, wxDateTime::Apr, 2080),
wxDateTime(30, wxDateTime::Mar, 2081),
wxDateTime(19, wxDateTime::Apr, 2082),
wxDateTime( 4, wxDateTime::Apr, 2083),
wxDateTime(26, wxDateTime::Mar, 2084),
wxDateTime(15, wxDateTime::Apr, 2085),
wxDateTime(31, wxDateTime::Mar, 2086),
wxDateTime(20, wxDateTime::Apr, 2087),
wxDateTime(11, wxDateTime::Apr, 2088),
wxDateTime( 3, wxDateTime::Apr, 2089),
wxDateTime(16, wxDateTime::Apr, 2090),
wxDateTime( 8, wxDateTime::Apr, 2091),
wxDateTime(30, wxDateTime::Mar, 2092),
wxDateTime(12, wxDateTime::Apr, 2093),
wxDateTime( 4, wxDateTime::Apr, 2094),
wxDateTime(24, wxDateTime::Apr, 2095),
wxDateTime(15, wxDateTime::Apr, 2096),
wxDateTime(31, wxDateTime::Mar, 2097),
wxDateTime(20, wxDateTime::Apr, 2098),
wxDateTime(12, wxDateTime::Apr, 2099)
};
for (const auto& easter : easters)
{
INFO("Checking year " << easter.GetYear());
CHECK(wxDateTimeUSCatholicFeasts::GetEaster(easter.GetYear()).IsSameDate(easter));
}
}
TEST_CASE("US Catholic Holidays", "[datetime][holiday]")
{
SECTION("Ascension")
{
wxDateTime ascension = wxDateTimeUSCatholicFeasts::GetThursdayAscension(2023);
CHECK(ascension.GetMonth() == wxDateTime::Month::May);
CHECK(ascension.GetDay() == 18);
ascension = wxDateTimeUSCatholicFeasts::GetSundayAscension(2023);
CHECK(ascension.GetMonth() == wxDateTime::Month::May);
CHECK(ascension.GetDay() == 21);
}
SECTION("Fixed date feasts")
{
wxDateTimeHolidayAuthority::AddAuthority(new wxDateTimeUSCatholicFeasts);
CHECK(wxDateTimeHolidayAuthority::IsHoliday(wxDateTime( 1, wxDateTime::Month::Jan, 2024)));
CHECK(wxDateTimeHolidayAuthority::IsHoliday(wxDateTime(15, wxDateTime::Month::Aug, 2023)));
CHECK(wxDateTimeHolidayAuthority::IsHoliday(wxDateTime( 1, wxDateTime::Month::Nov, 2023)));
CHECK(wxDateTimeHolidayAuthority::IsHoliday(wxDateTime( 8, wxDateTime::Month::Dec, 2023)));
CHECK(wxDateTimeHolidayAuthority::IsHoliday(wxDateTime(25, wxDateTime::Month::Dec, 2023)));
// random days that should not be feasts of obligation
CHECK_FALSE(wxDateTimeHolidayAuthority::IsHoliday(wxDateTime( 1, wxDateTime::Month::Dec, 2023)));
CHECK_FALSE(wxDateTimeHolidayAuthority::IsHoliday(wxDateTime(31, wxDateTime::Month::Oct, 2023)));
CHECK_FALSE(wxDateTimeHolidayAuthority::IsHoliday(wxDateTime(14, wxDateTime::Month::Feb, 2023)));
}
}
TEST_CASE("Christian Holidays", "[datetime][holiday][christian]")
{
SECTION("Easter")
{
wxDateTime easter = wxDateTimeChristianHolidays::GetEaster(2023);
CHECK(easter.GetMonth() == wxDateTime::Month::Apr);
CHECK(easter.GetDay() == 9);
easter = wxDateTimeChristianHolidays::GetEaster(2010);
CHECK(easter.GetMonth() == wxDateTime::Month::Apr);
CHECK(easter.GetDay() == 4);
}
SECTION("Christmas")
{
wxDateTimeHolidayAuthority::AddAuthority(new wxDateTimeChristianHolidays);
CHECK(wxDateTimeHolidayAuthority::IsHoliday(wxDateTime(25, wxDateTime::Month::Dec, 1990)));
CHECK(wxDateTimeHolidayAuthority::IsHoliday(wxDateTime(25, wxDateTime::Month::Dec, 1700)));
CHECK(wxDateTimeHolidayAuthority::IsHoliday(wxDateTime(25, wxDateTime::Month::Dec, 2023)));
// random days that are not Christmas or weekends
CHECK_FALSE(wxDateTimeHolidayAuthority::IsHoliday(wxDateTime(1, wxDateTime::Month::Dec, 2023)));
CHECK_FALSE(wxDateTimeHolidayAuthority::IsHoliday(wxDateTime(29, wxDateTime::Month::Dec, 2023)));
}
}
#endif // wxUSE_DATETIME