Skip to content

Instantly share code, notes, and snippets.

@sgibson91
Last active January 3, 2023 16:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sgibson91/9aed6386ad164be4b7d9d87d84f16012 to your computer and use it in GitHub Desktop.
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(
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"
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)
holidays
pandas
pre-commit
rich
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment