File indexing completed on 2024-06-02 05:19:07
0001 /* 0002 * holidays.cpp - holiday checker 0003 * This file is part of kalarmcalendar library, which provides access to KAlarm 0004 * calendar data. 0005 * Program: kalarm 0006 * SPDX-FileCopyrightText: 2023 David Jarvie <djarvie@kde.org> 0007 * 0008 * SPDX-License-Identifier: LGPL-2.0-or-later 0009 */ 0010 0011 #include "holidays.h" 0012 0013 #include <KHolidays/HolidayRegion> 0014 0015 namespace KAlarmCal 0016 { 0017 0018 Holidays::Holidays(const KHolidays::HolidayRegion& holidayRegion) 0019 { 0020 initialise(holidayRegion.regionCode()); 0021 } 0022 0023 Holidays::Holidays(const QString& regionCode) 0024 { 0025 initialise(regionCode); 0026 } 0027 0028 /****************************************************************************** 0029 * Set a new holiday region. 0030 */ 0031 void Holidays::setRegion(const KHolidays::HolidayRegion& holidayRegion) 0032 { 0033 if (holidayRegion.regionCode() == mRegion->regionCode()) 0034 return; 0035 mTypes.clear(); 0036 mNames.clear(); 0037 initialise(holidayRegion.regionCode()); 0038 } 0039 0040 /****************************************************************************** 0041 * Set a new holiday region. 0042 */ 0043 void Holidays::setRegion(const QString& regionCode) 0044 { 0045 if (regionCode == mRegion->regionCode()) 0046 return; 0047 mTypes.clear(); 0048 mNames.clear(); 0049 initialise(regionCode); 0050 } 0051 0052 /****************************************************************************** 0053 * Set a new holiday region. 0054 */ 0055 void Holidays::initialise(const QString& regionCode) 0056 { 0057 mRegion.reset(new KHolidays::HolidayRegion(regionCode)); 0058 mCacheStartDate = QDate::currentDate().addDays(-1); // in case KAlarm time zone is different 0059 mNoCacheDate = mCacheStartDate; 0060 0061 if (mRegion->isValid()) 0062 { 0063 // Initially cache holiday data up to a year from today 0064 const int COUNT = 366; 0065 extendCache(mCacheStartDate.addDays(COUNT - 1)); 0066 } 0067 } 0068 0069 /****************************************************************************** 0070 * Return the holiday region code. 0071 */ 0072 QString Holidays::regionCode() const 0073 { 0074 return mRegion ? mRegion->regionCode() : QString(); 0075 } 0076 0077 /****************************************************************************** 0078 * Return whether the holiday data is valid. 0079 */ 0080 bool Holidays::isValid() const 0081 { 0082 return mRegion && mRegion->isValid(); 0083 } 0084 0085 /****************************************************************************** 0086 * Determine whether a date is a non-working holiday. 0087 */ 0088 bool Holidays::isHoliday(const QDate& date) const 0089 { 0090 return holidayType(date) == NonWorking; 0091 } 0092 0093 /****************************************************************************** 0094 * Determine the holiday type for a date. 0095 */ 0096 Holidays::Type Holidays::holidayType(const QDate& date) const 0097 { 0098 if (date < QDate::currentDate().addDays(-1)) 0099 return None; 0100 const int offset = mCacheStartDate.daysTo(date); 0101 if (date < mNoCacheDate) 0102 return mTypes[offset*2] ? NonWorking : mTypes[offset*2 + 1] ? Working : None; 0103 // The date is past the end of the cache. Fill the cache. 0104 extendCache(QDate(date.year(), 12, 31)); 0105 if (date < mNoCacheDate) 0106 return mTypes[offset*2] ? NonWorking : mTypes[offset*2 + 1] ? Working : None; 0107 0108 // The date is past the maximum cache limit. 0109 const KHolidays::Holiday::List hols = mRegion->rawHolidaysWithAstroSeasons(date); 0110 for (const KHolidays::Holiday& h : hols) 0111 if (h.dayType() == KHolidays::Holiday::NonWorkday) 0112 return NonWorking; 0113 return hols.isEmpty() ? None : Working; 0114 } 0115 0116 /****************************************************************************** 0117 * Return the name of a holiday. 0118 */ 0119 QStringList Holidays::holidayNames(const QDate& date) const 0120 { 0121 if (date < QDate::currentDate().addDays(-1)) 0122 return {}; 0123 if (date < mNoCacheDate) 0124 return mNames[mCacheStartDate.daysTo(date)]; 0125 // The date is past the end of the cache. Fill the cache. 0126 extendCache(QDate(date.year(), 12, 31)); 0127 if (date < mNoCacheDate) 0128 return mNames[mCacheStartDate.daysTo(date)]; 0129 0130 // The date is past the maximum cache limit. 0131 const KHolidays::Holiday::List hols = mRegion->rawHolidaysWithAstroSeasons(date); 0132 QStringList names; 0133 for (const KHolidays::Holiday& h : hols) 0134 names.append(h.name()); 0135 return names; 0136 } 0137 0138 /****************************************************************************** 0139 * Set the maximum cache size. 0140 */ 0141 void Holidays::setCacheYears(int years) 0142 { 0143 mCacheYears = years; 0144 } 0145 0146 /****************************************************************************** 0147 * Cache holiday data up to an end date. 0148 * This will not be done past mCacheYears from now. 0149 */ 0150 void Holidays::extendCache(const QDate& end) const 0151 { 0152 const QDate limit = QDate(QDate::currentDate().year() + mCacheYears, 12, 31); 0153 const QDate endDate = (end > limit) ? limit : end; 0154 if (endDate < mNoCacheDate) 0155 return; // already cached 0156 0157 const int count = mCacheStartDate.daysTo(endDate) + 1; 0158 const KHolidays::Holiday::List hols = mRegion->rawHolidaysWithAstroSeasons(mNoCacheDate, endDate); 0159 mTypes.resize(count * 2); // this sets all new bits to 0 0160 mNames.resize(count); 0161 // Note that more than one holiday can fall on a given day. 0162 for (const KHolidays::Holiday& h : hols) 0163 { 0164 const QString name = h.name(); 0165 const int workday = (h.dayType() == KHolidays::Holiday::NonWorkday) ? 0 : 1; 0166 const int offset2 = mCacheStartDate.daysTo(h.observedEndDate()); 0167 for (int offset = mCacheStartDate.daysTo(h.observedStartDate()); offset <= offset2; ++offset) 0168 { 0169 mTypes[offset*2 + workday] = 1; 0170 mNames[offset].append(name); 0171 } 0172 } 0173 mNoCacheDate = endDate.addDays(1); 0174 } 0175 0176 } // namespace KAlarmCal 0177 0178 // vim: et sw=4: