Calendar-based time window filtering, age calculations, and business logic for dates and times.
Project description
Frist: Property-Based Date and Time Operations
Frist is a modern Python library for calendar, age, and time window calculations. Its API is property-driven—most operations are performed by accessing properties or calling simple methods, with minimal need for manual math or low-level datetime manipulation.
In German, "Frist" means "deadline" or "time limit." This reflects the package's focus on time windows, periods, and calendar logic.
Key Features
- Property-based API: Access date and time information through properties and high-level methods.
- Calendar windows: Easily check if a date falls within a day, week, month, quarter, fiscal period, or custom working day window.
- Working day and holiday logic: Built-in support for excluding weekends and holidays from all calendar calculations. Simply provide a set of holiday dates and Frist will automatically skip them in working day windows and related queries.
- Customizable business calendars: Define your own holiday sets and fiscal year start months for precise business logic.
- Age calculations: Compute age spans and durations using flexible input types.
- No manual math required: Most operations are declarative and require no arithmetic or direct datetime handling.
Installation
pip install frist
Or clone the repository and install locally:
git clone https://github.com/hucker/frist.git
cd frist
pip install .
Usage
Calendar Operations
from frist import Cal
import datetime as dt
cal = Cal(target_dt=dt.datetime(2024, 5, 8), ref_dt=dt.datetime(2024, 5, 6), holidays={"2024-05-08"})
print(cal.in_workdays(-2, 2)) # True/False
print(cal.in_months(0)) # True/False
print(cal.in_fiscal_quarters(0)) # True/False
Age Calculations
from frist import Age
import datetime as dt
age = Age(dt.datetime(2000, 1, 1), dt.datetime(2024, 1, 1))
print(age.years) # Property: number of years
print(age.days) # Property: number of days
age_now = Age(dt.datetime(2000, 1, 1))
print(age_now.years)
API Highlights
Cal
target_dt,ref_dt: Properties for target and reference datetimesin_days,in_weeks,in_months,in_quarters,in_years,in_workdays,in_fiscal_quarters,in_fiscal_years: Methods to check if the target date falls within various calendar windowsholiday,fiscal_year,fiscal_quarter: Properties for holiday and fiscal calculations
Age
years,months,days,seconds: Properties for age span- Flexible initialization: accepts datetimes, timestamps, or protocols
Configuration
- Holidays: Pass a set of date strings (YYYY-MM-DD) to exclude from working day calculations
- Fiscal year start: Set
fy_start_monthfor fiscal calculations
Testing
- Comprehensive test suite covers edge cases, holidays, weekends, and exception handling
- Run tests with:
pytest
Contributing
Pull requests and issues are welcome! See the repository for guidelines.
License
MIT License
Acknowledgments
Inspired by real-world business calendar needs and designed for clarity and ease of use.
Chrono objects support fiscal year and quarter calculations with customizable fiscal year start months. For example:
# Fiscal year starts in April (fy_start_month=4)
meeting = Chrono(target_time=dt.datetime(2025, 7, 15), fy_start_month=4)
print(meeting.fiscal_year) # 2025 (fiscal year for July 15, 2025)
print(meeting.fiscal_quarter) # 2 (Q2: July–September for April start)
# Check if a date is in a fiscal quarter or year window
if meeting.cal.in_fiscal_quarters(0):
print("Meeting is in the current fiscal quarter.")
if meeting.cal.in_fiscal_years(0):
print("Meeting is in the current fiscal year.")
Holiday Detection Example
Frist can instantly check if a date is a holiday using a set of holiday dates:
holidays = {
'2025-12-25', # Christmas
'2025-01-01', # New Year's Day
'2025-07-04', # Independence Day
}
# Check a specific date
meeting = Chrono(target_time=dt.datetime(2025, 12, 25), holidays=holidays)
if meeting.holiday:
print("Meeting date is a holiday!")
# Check multiple dates
for date_str in holidays:
date = dt.datetime.strptime(date_str, '%Y-%m-%d')
c = Chrono(target_time=date, holidays=holidays)
print(f"{date.date()}: Holiday? {c.holiday}")
# Use with custom reference time
project = Chrono(target_time=dt.datetime(2025, 7, 4), reference_time=dt.datetime(2025, 7, 5), holidays=holidays)
if project.holiday:
print("Project start date is a holiday!")
Short Examples
Age Calculation
person = Chrono(target_time=dt.datetime(1990, 5, 1), reference_time=dt.datetime(2025, 5, 1))
print(f"Age in days: {person.age.days}, Age in years: {person.age.years:.2f}")
Calendar Windows
meeting = Chrono(target_time=dt.datetime(2025, 12, 25))
if meeting.cal.in_days(0):
print("Meeting is today!")
if meeting.cal.in_weeks(-1):
print("Meeting was last week.")
API Reference
Frist
Chrono(target_time: datetime, reference_time: datetime = None, fy_start_month: int = 1, holidays: set[str] = None)
- Properties:
age: Age object with properties for.days,.hours,.minutes,.seconds,.weeks,.months,.quarters,.years,.fiscal_year,.fiscal_quarter.cal: Cal object for calendar window logic.fiscal_year: Fiscal year for the target time.fiscal_quarter: Fiscal quarter for the target time.holiday: True if target time is a holiday (if holidays set provided).
Cal
-
Properties:
dt_val: Target datetime.base_time: Reference datetime.fiscal_year: Fiscal year fordt_val.fiscal_quarter: Fiscal quarter fordt_val.holiday: True ifdt_valis a holiday.
-
Interval Methods:
in_minutes(start: int = 0, end: int | None = None) -> boolin_hours(start: int = 0, end: int | None = None) -> boolin_days(start: int = 0, end: int | None = None) -> boolin_weeks(start: int = 0, end: int | None = None, week_start: str = "monday") -> boolin_months(start: int = 0, end: int | None = None) -> boolin_quarters(start: int = 0, end: int | None = None) -> boolin_years(start: int = 0, end: int | None = None) -> boolin_fiscal_quarters(start: int = 0, end: int | None = None) -> boolin_fiscal_years(start: int = 0, end: int | None = None) -> bool
-
Static Methods:
get_fiscal_year(dt: datetime, fy_start_month: int) -> intget_fiscal_quarter(dt: datetime, fy_start_month: int) -> int
-
Exceptions:
- All interval methods raise
ValueErrorifstart > end. normalize_weekday(day_spec: str) -> intraisesValueErrorfor invalid day specifications, with detailed error messages.
- All interval methods raise
Age
Age(target_time: datetime, reference_time: datetime)
-
Properties:
days,hours,minutes,seconds,weeks,months,quarters,years,fiscal_year,fiscal_quarter
-
Properties:
target_dt: Target datetime.ref_dt: Reference datetime.
Testing and Support
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file frist-0.9.0.tar.gz.
File metadata
- Download URL: frist-0.9.0.tar.gz
- Upload date:
- Size: 27.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.5.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
186d18e1dffd0fc618fc4d4779e3aad8c5c43cddd08c9b19eae9a274e8419b58
|
|
| MD5 |
9fede4516cfe07555357f175af21edb9
|
|
| BLAKE2b-256 |
a94fbf224338ee3d999fa1e4a2f5931638b6e07a8c65e3eaa72b5f45c2e96cbb
|
File details
Details for the file frist-0.9.0-py3-none-any.whl.
File metadata
- Download URL: frist-0.9.0-py3-none-any.whl
- Upload date:
- Size: 13.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.5.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e13022d8b54cce0b995d8d56b29eec7ad5de19ec9912b6f564bd2c894179e37a
|
|
| MD5 |
a60851a854ab1f57db126162981e3283
|
|
| BLAKE2b-256 |
f695ae017d87c647fb4d566aa00cfc35cc4b9dc13a0cdb6e2c87b01aad259ffa
|