Last active
January 3, 2023 16:46
-
-
Save sgibson91/9aed6386ad164be4b7d9d87d84f16012 to your computer and use it in GitHub Desktop.
Short Python script to calculate the number of working hours in a month, account for public holidays *in England*. (Could be edited for other locales though(
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
repos: | |
- repo: https://github.com/asottile/pyupgrade | |
rev: v2.34.0 | |
hooks: | |
- id: pyupgrade | |
args: | |
- "--py36-plus" | |
- repo: https://github.com/psf/black | |
rev: 22.3.0 | |
hooks: | |
- id: black | |
- repo: https://github.com/pycqa/flake8 | |
rev: 4.0.1 | |
hooks: | |
- id: flake8 | |
args: | |
- "--max-line-length=88" | |
- "--extend-ignore=E501,E203" | |
- repo: https://github.com/pycqa/isort | |
rev: 5.10.1 | |
hooks: | |
- id: isort | |
args: | |
- "--profile=black" | |
- "--trailing-comma" | |
- "--line-length=88" | |
- "--multi-line=3" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import calendar | |
import sys | |
from datetime import datetime | |
import holidays | |
import pandas as pd | |
from rich import print | |
from rich.pretty import pprint | |
from rich.prompt import IntPrompt | |
cal = calendar.Calendar() | |
today = datetime.today() | |
# Year to calculate for | |
year = IntPrompt.ask( | |
":calendar: [blue] Enter the numerical year to calculate total working hours for[/blue] [magenta](YYYY)", | |
default=today.year, | |
) | |
# Month to calculate for | |
month = IntPrompt.ask( | |
":calendar: [blue]Enter the numerical month to calculate total working hours for[/blue] [magenta](1 - 12)", | |
default=today.month, | |
) | |
if (month < 1) or (month > 12): | |
print(":cross_mark: [prompt.invalid]Month must be between 1 and 12 (Jan - Dec)") | |
sys.exit(1) | |
# Number of working hours per day | |
working_hours_per_day = IntPrompt.ask( | |
":clock9: [blue]Enter the number of hours you work per day", | |
default=8, | |
) | |
if working_hours_per_day < 0: | |
print(":cross_mark: [prompt.invalid]A positive integer must be provided") | |
sys.exit(1) | |
# Number of non-PTO days taken | |
non_pto_days = IntPrompt.ask( | |
":beach_with_umbrella: [blue] How many [bold]NON[/bold] PTO days did you take this month?", | |
default=0, | |
) | |
if non_pto_days < 0: | |
print(":cross_mark: [prompt.invalid]A positive integer must be provided") | |
sys.exit(1) | |
# Get holidays in England for the current year | |
en_hols = holidays.country_holidays("GB", subdiv="England", years=[year]).items() | |
en_hols = pd.DataFrame(en_hols, columns=["date", "holiday"]) | |
en_hols["date"] = pd.to_datetime(en_hols["date"]) | |
en_hols.sort_values("date", inplace=True) | |
# Only count holidays that fall within the specified month | |
dates_to_drop = [] | |
for i, row in en_hols.iterrows(): | |
if row.date.month != month: | |
# Exlude holidays that don't fall in this month | |
dates_to_drop.append(i) | |
elif row.date.weekday() > 4: | |
# Exclude holidays that don't fall on a workday | |
dates_to_drop.append(i) | |
en_hols.drop(index=dates_to_drop, inplace=True) | |
# Calculate how many working days are in the specified month | |
working_days_in_month = [ | |
day | |
for day in cal.itermonthdays2(year, month) | |
if day[0] != 0 # Ensure day is within the month | |
and day[1] < 5 # Count Mon-Fri days | |
] | |
# Find total number of working days by subtracting the holidays in that month | |
total_working_days = len(working_days_in_month) - len(en_hols) - non_pto_days | |
# Print the results to the console | |
print( | |
f""" | |
For the month of: [bold green]{calendar.month_name[month]}, {year}[/bold green] | |
:calendar: There are [blue]{total_working_days}[/blue] working days | |
:clock9: There are [blue]{total_working_days * working_hours_per_day}[/blue] working hours ([blue]{working_hours_per_day}[/blue] hr/day) | |
:beach_with_umbrella: You took [blue]{non_pto_days}[/blue] extra days off this month (not paid) | |
:tada: There are [blue]{len(en_hols)}[/blue] holidays in this month""" | |
) | |
if len(en_hols) > 0: | |
pprint(en_hols) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
holidays | |
pandas | |
pre-commit | |
rich |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment