forked from ITwrxOrg/Forget-Me-Not
114 lines
5.1 KiB
Nim
114 lines
5.1 KiB
Nim
#[Copyright 2025 ITwrx.
|
|
This file is part of Forget-Me-Not.
|
|
Forget-Me-Not is released under the GNU Affero General Public License 3.0.
|
|
See COPYING or <https://www.gnu.org/licenses/> for details.]#
|
|
|
|
import std/[times, strutils]
|
|
|
|
proc weekdayFromString(dayStr: string): Weekday =
|
|
## Convert a string representation of a weekday to Weekday enum
|
|
case dayStr
|
|
of "Monday": return dMon
|
|
of "Tuesday": return dTue
|
|
of "Wednesday": return dWed
|
|
of "Thursday": return dThu
|
|
of "Friday": return dFri
|
|
of "Saturday": return dSat
|
|
of "Sunday": return dSun
|
|
|
|
proc monthFromString(monthStr: string): Month =
|
|
## Convert a string representation of a weekday to Weekday enum
|
|
case monthStr
|
|
of "January": return mJan
|
|
of "Febuary": return mFeb
|
|
of "March": return mMar
|
|
of "April": return mApr
|
|
of "May": return mMay
|
|
of "June": return mJun
|
|
of "July": return mJul
|
|
of "August": return mAug
|
|
of "September": return mSep
|
|
of "October": return mOct
|
|
of "November": return mNov
|
|
of "December": return mDec
|
|
|
|
proc nextWeekday*(targetWeekdayString: string): DateTime =
|
|
## Calculates the next occurrence of a specific weekday
|
|
var nextDate = now()
|
|
# We're not including current day, so we move to the next day
|
|
nextDate = nextDate + 1.days
|
|
#convert passed weekday string to nim Weekday.
|
|
let targetWeekday = weekdayFromString(targetWeekdayString)
|
|
# Find the next occurrence of the target weekday
|
|
while nextDate.weekday != targetWeekday:
|
|
nextDate = nextDate + 1.days
|
|
return nextDate
|
|
|
|
proc nthWeekdayInMonth*(year: int, month: Month, weekdayString: string, nth: range[1..3]): DateTime =
|
|
# Start from the first day of the month
|
|
var currentDate = dateTime(year, month, 1)
|
|
let weekday = weekdayFromString(weekdayString)
|
|
# Find the first occurrence of the specified weekday
|
|
while currentDate.weekday != weekday:
|
|
currentDate = currentDate + 1.days
|
|
# Move to the nth occurrence
|
|
currentDate = currentDate + days((nth - 1) * 7)
|
|
return currentDate
|
|
|
|
proc lastWeekdayInMonth(year: int, month: Month, weekdayString: string): DateTime =
|
|
# Create a DateTime for the last day of the given month
|
|
var lastDay = dateTime(year, month, getDaysInMonth(month, year))
|
|
let weekday = weekdayFromString(weekdayString)
|
|
# Work backwards until we find the last occurrence of the specified weekday
|
|
while lastDay.weekday != weekday:
|
|
lastDay = lastDay - 1.days
|
|
return lastDay
|
|
|
|
proc nextMonthlyOnWeekdayOfWeek*(weekdayString: string, ocurrence: string): DateTime =
|
|
var nextSendDate: DateTime
|
|
let nextMonthsDate = now() + 1.months
|
|
let weekNumStrings = @["1", "2", "3"]
|
|
if ocurrence in weekNumStrings:
|
|
#nextSendDate = nthWeekdayInMonth(year(nextMonthsDate), month(now()), weekdayString, parseInt(ocurrence))
|
|
nextSendDate = nthWeekdayInMonth(year(now()), month(now()), weekdayString, parseInt(ocurrence))
|
|
if format(nextSendDate, "yyyy-MM-dd") <= format(now(), "yyyy-MM-dd"):
|
|
nextSendDate = nthWeekdayInMonth(year(nextMonthsDate), month(nextMonthsDate), weekdayString, parseInt(ocurrence))
|
|
else:
|
|
#nextSendDate = lastWeekdayInMonth(year(nextMonthsDate), month(now()), weekdayString)
|
|
nextSendDate = lastWeekdayInMonth(year(now()), month(now()), weekdayString)
|
|
if format(nextSendDate, "yyyy-MM-dd") <= format(now(), "yyyy-MM-dd"):
|
|
nextSendDate = lastWeekdayInMonth(year(nextMonthsDate), month(nextMonthsDate), weekdayString)
|
|
return nextSendDate
|
|
|
|
proc nextYearlyOnWeekdayOfWeekOfMonth*(weekdayString, ocurrence, monthString: string): DateTime =
|
|
var nextSendDate, startingDate, nextYearsDate: DateTime
|
|
nextYearsDate = now() + 1.years
|
|
nextYearsDate = dateTime(year(nextYearsDate), monthFromString(monthString), 01)
|
|
let weekNumStrings = @["1", "2", "3"]
|
|
if ocurrence in weekNumStrings:
|
|
nextSendDate = nthWeekdayInMonth(year(now()), month(now()), weekdayString, parseInt(ocurrence))
|
|
if format(nextSendDate, "yyyy-MM-dd") <= format(now(), "yyyy-MM-dd"):
|
|
nextSendDate = nthWeekdayInMonth(year(nextYearsDate), month(nextYearsDate), weekdayString, parseInt(ocurrence))
|
|
else:
|
|
nextSendDate = lastWeekdayInMonth(year(now()), month(now()), weekdayString)
|
|
if format(nextSendDate, "yyyy-MM-dd") <= format(now(), "yyyy-MM-dd"):
|
|
nextSendDate = lastWeekdayInMonth(year(nextYearsDate), month(nextYearsDate), weekdayString)
|
|
return nextSendDate
|
|
|
|
#[ Returns the next occurrence of the specified month and day, which could be:
|
|
- Later this year if the target date hasn't occurred yet
|
|
- Next year if the target date has already passed this year]#
|
|
proc nextYearlyDate*(monthString: string, targetDay: int): DateTime =
|
|
let baseDate = now()
|
|
let targetMonth = monthFromString(monthString)
|
|
# Get the current year
|
|
let currentYear = baseDate.year
|
|
# Create a DateTime for the target date in the current year
|
|
var nextSendDate = dateTime(currentYear, targetMonth, targetDay, 00, 00, 00, 00)
|
|
# If the target date has already passed this year, move to next year
|
|
if nextSendDate <= baseDate:
|
|
nextSendDate = dateTime(currentYear + 1, targetMonth, targetDay, 00, 00, 00, 00)
|
|
let nextSendDateString = format(nextSendDate, "yyyy-MM-dd")
|
|
nextSendDate = parse(nextSendDateString, "yyyy-MM-dd")
|
|
return nextSendDate
|