Split UK holiday code into own file

This commit is contained in:
Edward Betts 2023-11-06 09:30:40 +00:00
parent 74e135e9c3
commit 84ea916747
2 changed files with 85 additions and 75 deletions

View file

@ -1,22 +1,18 @@
import asyncio import asyncio
import configparser import configparser
import json
import operator import operator
import os import os
import typing import typing
import warnings import warnings
from datetime import date, datetime, time, timedelta from datetime import date, datetime, time, timedelta
from time import time as unixtime
import dateutil import dateutil
import dateutil.parser import dateutil.parser
import dateutil.tz import dateutil.tz
import holidays import holidays
import httpx
import lxml import lxml
import pytz import pytz
import yaml import yaml
from dateutil.easter import easter
from dateutil.relativedelta import FR, relativedelta from dateutil.relativedelta import FR, relativedelta
from . import ( from . import (
@ -32,6 +28,7 @@ from . import (
sun, sun,
thespacedevs, thespacedevs,
travel, travel,
uk_holiday,
waste_schedule, waste_schedule,
) )
from .types import Event from .types import Event
@ -62,51 +59,6 @@ config.read(config_filename)
data_dir = config.get("data", "dir") 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( def timezone_transition(
start_dt: datetime, end_dt: datetime, key: str, tz_name: str start_dt: datetime, end_dt: datetime, key: str, tz_name: str
) -> list[Event]: ) -> 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: def uk_financial_year_end(input_date: date) -> date:
"""Next date of the end of the UK financial year, April 5th.""" """Next date of the end of the UK financial year, April 5th."""
# Determine the year of the input date # 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( ) = await asyncio.gather(
fx.get_gbpusd(config), fx.get_gbpusd(config),
gwr.advance_ticket_date(data_dir), 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), thespacedevs.get_launches(rocket_dir, limit=40),
waste_collection_events(), waste_collection_events(),
bristol_waste_collection_events(today), 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( "us_clock_change": timezone_transition(
minus_365, plus_365, "us_clock_change", "America/New_York" minus_365, plus_365, "us_clock_change", "America/New_York"
), ),
"mothers_day": next_uk_mothers_day(today), "mothers_day": uk_holiday.get_mothers_day(today),
"fathers_day": next_uk_fathers_day(today), "fathers_day": uk_holiday.get_fathers_day(today),
"uk_financial_year_end": uk_financial_year_end(today), "uk_financial_year_end": uk_financial_year_end(today),
"xmas_last_posting_dates": xmas_last_posting_dates, "xmas_last_posting_dates": xmas_last_posting_dates,
"gwr_advance_tickets": gwr_advance_tickets, "gwr_advance_tickets": gwr_advance_tickets,

81
agenda/uk_holiday.py Normal file
View file

@ -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