mirror of
https://github.com/wxWidgets/wxWidgets.git
synced 2026-08-18 01:19:45 +08:00
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:
committed by
Vadim Zeitlin
parent
2c9fee3d6f
commit
5ba009e861
+83
-8
@@ -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
|
||||
// ============================================================================
|
||||
|
||||
+137
-5
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
// ============================================================================
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user