diff --git a/agenda/__init__.py b/agenda/__init__.py index 8b890ea..e23263c 100644 --- a/agenda/__init__.py +++ b/agenda/__init__.py @@ -1,22 +1,18 @@ import asyncio import configparser -import json import operator import os import typing import warnings from datetime import date, datetime, time, timedelta -from time import time as unixtime import dateutil import dateutil.parser import dateutil.tz import holidays -import httpx import lxml import pytz import yaml -from dateutil.easter import easter from dateutil.relativedelta import FR, relativedelta from . import ( @@ -32,6 +28,7 @@ from . import ( sun, thespacedevs, travel, + uk_holiday, waste_schedule, ) from .types import Event @@ -62,51 +59,6 @@ config.read(config_filename) data_dir = config.get("data", "dir") -def next_uk_mothers_day(input_date: date) -> date: - """Calculate the date of the next UK Mother's Day from the current date.""" - current_year = input_date.year - - easter_date = easter(current_year) - - # Calculate the date of Mother's Day, which is the fourth Sunday of Lent - mothers_day = easter_date + timedelta(weeks=3) - - # Check if Mother's Day has already passed this year - if input_date > mothers_day: - # If it has passed, calculate for the next year - easter_date = easter(current_year + 1) - mothers_day = easter_date + timedelta(weeks=3) - - return mothers_day - - -def next_uk_fathers_day(input_date: date) -> date: - """Calculate the date of the next UK Father's Day from the current date.""" - # Get the current date - # Calculate the day of the week for the current date (0 = Monday, 6 = Sunday) - current_day_of_week = input_date.weekday() - - # Calculate the number of days until the next Sunday - days_until_sunday = (6 - current_day_of_week) % 7 - - # Calculate the date of the next Sunday - next_sunday = input_date + timedelta(days=days_until_sunday) - - # Calculate the date of Father's Day, which is the third Sunday of June - fathers_day = date(next_sunday.year, 6, 1) + timedelta( - weeks=2, days=next_sunday.weekday() - ) - - # Check if Father's Day has already passed this year - if input_date > fathers_day: - # If it has passed, calculate for the next year - fathers_day = date(fathers_day.year + 1, 6, 1) + timedelta( - weeks=2, days=next_sunday.weekday() - ) - - return fathers_day - - def timezone_transition( start_dt: datetime, end_dt: datetime, key: str, tz_name: str ) -> list[Event]: @@ -119,29 +71,6 @@ def timezone_transition( ] -async def get_next_bank_holiday(start_date: date, end_date: date) -> list[Event]: - """Date and name of the next UK bank holiday.""" - url = "https://www.gov.uk/bank-holidays.json" - filename = os.path.join(data_dir, "bank-holidays.json") - mtime = os.path.getmtime(filename) - if (unixtime() - mtime) > 60 * 60 * 6: # six hours - async with httpx.AsyncClient() as client: - r = await client.get(url) - open(filename, "w").write(r.text) - - events = json.load(open(filename))["england-and-wales"]["events"] - hols: list[Event] = [] - for event in events: - event_date = datetime.strptime(event["date"], "%Y-%m-%d").date() - if event_date < start_date: - continue - if event_date > end_date: - break - hols.append(Event(name="bank_holiday", date=event_date, title=event["title"])) - - return hols - - def uk_financial_year_end(input_date: date) -> date: """Next date of the end of the UK financial year, April 5th.""" # Determine the year of the input date @@ -276,7 +205,7 @@ async def get_data(now: datetime) -> typing.Mapping[str, str | object]: ) = await asyncio.gather( fx.get_gbpusd(config), gwr.advance_ticket_date(data_dir), - get_next_bank_holiday(last_year, next_year), + uk_holiday.bank_holiday_list(last_year, next_year, data_dir), thespacedevs.get_launches(rocket_dir, limit=40), waste_collection_events(), bristol_waste_collection_events(today), @@ -296,8 +225,8 @@ async def get_data(now: datetime) -> typing.Mapping[str, str | object]: "us_clock_change": timezone_transition( minus_365, plus_365, "us_clock_change", "America/New_York" ), - "mothers_day": next_uk_mothers_day(today), - "fathers_day": next_uk_fathers_day(today), + "mothers_day": uk_holiday.get_mothers_day(today), + "fathers_day": uk_holiday.get_fathers_day(today), "uk_financial_year_end": uk_financial_year_end(today), "xmas_last_posting_dates": xmas_last_posting_dates, "gwr_advance_tickets": gwr_advance_tickets, diff --git a/agenda/uk_holiday.py b/agenda/uk_holiday.py new file mode 100644 index 0000000..070d02d --- /dev/null +++ b/agenda/uk_holiday.py @@ -0,0 +1,81 @@ +"""UK holidays.""" + +import json +import os +from datetime import date, datetime, timedelta +from time import time + +import httpx +from dateutil.easter import easter + +from .types import Event + + +async def bank_holiday_list( + start_date: date, end_date: date, data_dir: str +) -> list[Event]: + """Date and name of the next UK bank holiday.""" + url = "https://www.gov.uk/bank-holidays.json" + filename = os.path.join(data_dir, "bank-holidays.json") + mtime = os.path.getmtime(filename) + if (time() - mtime) > 60 * 60 * 6: # six hours + async with httpx.AsyncClient() as client: + r = await client.get(url) + open(filename, "w").write(r.text) + + events = json.load(open(filename))["england-and-wales"]["events"] + hols: list[Event] = [] + for event in events: + event_date = datetime.strptime(event["date"], "%Y-%m-%d").date() + if event_date < start_date: + continue + if event_date > end_date: + break + hols.append(Event(name="bank_holiday", date=event_date, title=event["title"])) + + return hols + + +def get_mothers_day(input_date: date) -> date: + """Calculate the date of the next UK Mother's Day from the current date.""" + current_year = input_date.year + + easter_date = easter(current_year) + + # Calculate the date of Mother's Day, which is the fourth Sunday of Lent + mothers_day = easter_date + timedelta(weeks=3) + + # Check if Mother's Day has already passed this year + if input_date > mothers_day: + # If it has passed, calculate for the next year + easter_date = easter(current_year + 1) + mothers_day = easter_date + timedelta(weeks=3) + + return mothers_day + + +def get_fathers_day(input_date: date) -> date: + """Calculate the date of the next UK Father's Day from the current date.""" + # Get the current date + # Calculate the day of the week for the current date (0 = Monday, 6 = Sunday) + current_day_of_week = input_date.weekday() + + # Calculate the number of days until the next Sunday + days_until_sunday = (6 - current_day_of_week) % 7 + + # Calculate the date of the next Sunday + next_sunday = input_date + timedelta(days=days_until_sunday) + + # Calculate the date of Father's Day, which is the third Sunday of June + fathers_day = date(next_sunday.year, 6, 1) + timedelta( + weeks=2, days=next_sunday.weekday() + ) + + # Check if Father's Day has already passed this year + if input_date > fathers_day: + # If it has passed, calculate for the next year + fathers_day = date(fathers_day.year + 1, 6, 1) + timedelta( + weeks=2, days=next_sunday.weekday() + ) + + return fathers_day