Elegant epoch timestamp handling with timezone-aware operations, fluent API, and smart defaults for Python developers who hate datetime complexity.
Project description
Bear Epoch Time
A lightweight Python library for working with epoch timestamps. Bear Epoch Time provides timezone-aware conversion utilities and a fluent API for manipulating times without wrestling with datetime quirks.
Key Features:
EpochTimestampinherits fromint- use it anywhere you'd use an integer- Milliseconds by default (configurable to seconds)
- UTC-first with explicit timezone conversions
- Fluent, chainable API
- Full comparison support with
datetime,date,time,int, andfloat
Requirements: Python 3.11+
Installation
Install from PyPI:
pip install bear-epoch-time
# or with uv
uv pip install bear-epoch-time
Quick Start
from bear_epoch_time import EpochTimestamp
# Current UTC timestamp in milliseconds
now = EpochTimestamp.now()
print(now) # 1734567890123
print(now.to_seconds) # 1734567890
print(now.date_str()) # "12-18-2025"
Creating Timestamps
From Various Sources
from datetime import datetime, date
from bear_epoch_time import EpochTimestamp
# Current time
now = EpochTimestamp.now()
now_in_seconds = EpochTimestamp.now(milliseconds=False)
# From datetime
dt = datetime(2025, 12, 25, 10, 30, 0)
ts = EpochTimestamp.from_datetime(dt)
# From date (creates timestamp at midnight)
d = date(2025, 12, 25)
ts = EpochTimestamp.from_date(d)
# From seconds
ts = EpochTimestamp.from_seconds(1734567890)
# From ISO string
ts = EpochTimestamp.from_iso_string("2025-12-25T10:30:00+00:00")
# From custom format string
ts = EpochTimestamp.from_dt_string("12-25-2025 10:30 AM", fmt="%m-%d-%Y %I:%M %p")
Time Arithmetic
Adding and Subtracting Time
from datetime import timedelta
from bear_epoch_time import EpochTimestamp
now = EpochTimestamp.now()
# Add time components
future = now.add(days=7, hours=3, minutes=30)
# Subtract time
past = now.subtract(days=1, hours=12)
# Use timedelta
delta = timedelta(weeks=2)
two_weeks_later = now.add(delta=delta)
# Use negative values for subtraction via add()
yesterday = now.add(days=-1)
Calculating Differences
ts1 = EpochTimestamp.now()
ts2 = ts1.add(days=5, hours=3)
# Get difference as int (milliseconds by default)
diff_ms = ts1.diff(ts2)
# Get difference in seconds
diff_s = ts1.diff(ts2, milliseconds=False)
# Get difference as timedelta
delta = ts1.diff(ts2, as_timedelta=True)
# Get difference in specific units
days = ts1.time_since(ts2, unit="d") # days
hours = ts1.time_since(ts2, unit="h") # hours
minutes = ts1.time_since(ts2, unit="m") # minutes
Day Boundaries
import pytz
from bear_epoch_time import EpochTimestamp
now = EpochTimestamp.now()
# Get start/end of day (UTC by default)
start = now.start_of_day()
end = now.end_of_day()
# With specific timezone
pacific = pytz.timezone("America/Los_Angeles")
start_pacific = now.start_of_day(tz=pacific)
end_pacific = now.end_of_day(tz=pacific)
String Formatting
Output Formats
from bear_epoch_time import EpochTimestamp
ts = EpochTimestamp.now()
# Default formatted strings
ts.to_string() # "12-18-2025 03:30 PM PST"
ts.date_str() # "12-18-2025"
ts.time_str() # "03:30 PM"
# Custom format
ts.to_string(fmt="%A, %B %d, %Y") # "Thursday, December 18, 2025"
# Ordinal day format (special %Do code)
ts.to_string(fmt="%B %Do, %Y") # "December 18th, 2025"
# ISO format
ts.to_iso # "2025-12-18T23:30:00+00:00"
ts.get_iso_string(sep=" ") # "2025-12-18 23:30:00+00:00"
# Template formatting with $variables
ts.format("$month_name $day, $year") # "December 18, 2025"
ts.format("$day_name at $time") # "Thursday at 03:30 PM"
Available Template Variables
$epoch, $seconds, $milliseconds, $iso, $date, $time, $datetime, $year, $month, $day, $hour, $minute, $week, $isoweekday, $day_of_week, $day_of_year, $month_name, $day_name
Accessing Components
from bear_epoch_time import EpochTimestamp
ts = EpochTimestamp.now()
# Date components
ts.year # 2025
ts.month # 12
ts.day # 18
ts.week # ISO week number (1-53)
# Time components
ts.hour # 15 (0-23)
ts.minute # 30 (0-59)
ts.second # 45 (0-59)
ts.microsecond # 123456 (0-999999)
# Day information
ts.day_of_week # 0-6 (Monday=0, Sunday=6)
ts.iso_weekday # 1-7 (Monday=1, Sunday=7)
ts.day_of_year # 1-366
ts.day_name # "Thursday"
ts.month_name # "December"
# Conversions
ts.to_datetime # datetime object (UTC)
ts.to_seconds # int (epoch seconds)
ts.to_milliseconds # int (epoch milliseconds)
ts.date # date object
ts.time # time object
ts.to_iso # ISO 8601 string
ts.to_duration # "675M 28d 2h 12m 28s" (human-readable)
Replacing Components
Create a new timestamp with specific components changed:
from bear_epoch_time import EpochTimestamp
ts = EpochTimestamp.now()
# Change specific components
new_year = ts.replace(year=2026)
noon = ts.replace(hour=12, minute=0, second=0)
first_of_month = ts.replace(day=1)
Finding Future Times
from bear_epoch_time import EpochTimestamp
now = EpochTimestamp.now()
# Get next occurrence of a weekday
next_monday = now.next_weekday("Monday")
next_friday = now.next_weekday("friday") # case-insensitive
# Get next occurrence of a specific time
next_9am = now.next_time_of_day(hour=9)
next_meeting = now.next_time_of_day(hour=14, minute=30)
Comparisons
EpochTimestamp supports comparison with multiple types:
from datetime import datetime, date, time
from bear_epoch_time import EpochTimestamp
ts = EpochTimestamp.now()
# Compare with other EpochTimestamp
ts1 < ts2
ts1 == ts2
# Compare with datetime
ts < datetime.now()
# Compare with date (compares date portion only)
ts == date.today()
# Compare with int/float (raw epoch value)
ts > 1734567890000
# Boolean evaluation (False if zero/placeholder)
if ts:
print("Valid timestamp")
Class Configuration
Configure defaults for all instances:
import pytz
from bear_epoch_time import EpochTimestamp
# Set default timezone
EpochTimestamp.set_timezone(pytz.timezone("America/New_York"))
# Set default formats
EpochTimestamp.set_date_format("%Y-%m-%d")
EpochTimestamp.set_time_format("%H:%M:%S")
EpochTimestamp.set_full_format("%Y-%m-%d %H:%M:%S %Z")
# Set repr style: "int", "object", or "datetime"
EpochTimestamp.set_repr_style("datetime")
Placeholder Values
Use zero as a placeholder for "no timestamp set":
from bear_epoch_time import EpochTimestamp
placeholder = EpochTimestamp(0)
if placeholder.is_default:
print("No timestamp set")
# Boolean evaluation also works
if not placeholder:
print("No timestamp set")
TimeTools Helper
For common timezone-aware operations:
from bear_epoch_time import TimeTools, EpochTimestamp
tools = TimeTools() # Uses local timezone
# Get start and end of today
start, end = tools.get_day_range()
# Check if timestamps are on the same day
tools.is_same_day(ts1, ts2)
# Check if a date range spans multiple days
tools.is_multi_day("12-18-2025 11:00 PM", "12-19-2025 01:00 AM")
# Quick conversions
tools.dt_to_ts(datetime_obj)
tools.str_to_ts("12-18-2025 03:30 PM")
tools.ts_to_str(timestamp)
TimeConverter Utilities
Parse and format time strings:
from bear_epoch_time import TimeConverter
# Parse duration strings to seconds
TimeConverter.parse_to_seconds("2d 3h 15m") # 183300.0
TimeConverter.parse_to_seconds("1M 5d") # ~35 days in seconds
# Format seconds as human-readable
TimeConverter.format_seconds(183300) # "2d 3h 15m"
TimeConverter.format_seconds(90061.5, show_subseconds=True) # "1d 1h 1m 1s 500ms"
Timer Utilities
Context managers and decorators for timing:
from bear_epoch_time import timer, create_timer, TimerData
# Context manager
with timer(name="my_operation", console=print) as t:
# do work
pass
print(f"Took {t.seconds:.2f}s")
# Decorator factory
@create_timer(console=print)
def my_function():
pass
# Async support
from bear_epoch_time import async_timer, create_async_timer
async with async_timer(name="async_op") as t:
await some_async_work()
Limitations
The EpochTimestamp class is designed for UTC timestamps in the recent past and future. It is not intended for:
- Historical dates before the Unix epoch (1970-01-01)
- High-precision timing (use
time.perf_counter()instead) - Dates far in the future where leap second handling becomes significant
This is a utility library for working with epoch timestamps in a more human-friendly way.
License
MIT License - see LICENSE file for details.
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 Distributions
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 bear_epoch_time-1.2.11-py3-none-any.whl.
File metadata
- Download URL: bear_epoch_time-1.2.11-py3-none-any.whl
- Upload date:
- Size: 30.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc10a3db430a3f1e78301751b9a4d1abaed50d4b461afee5ad5e3e7fdaa8ce90
|
|
| MD5 |
c51ecf818cf46577f243f1cf8db7f180
|
|
| BLAKE2b-256 |
20a8fd0f79010d441ffe67897b1d35108390c4a29f3fd18bf3bfc381d550f74a
|