Python datetimes made easy with timezone-aware datetime manipulation and human-readable formatting
—
Time span calculations with support for years and months. The Duration class extends Python's timedelta with year and month support, while Interval represents the time span between two specific DateTime objects.
Functions for creating Duration instances with comprehensive time unit support.
def duration(
days: float = 0,
seconds: float = 0,
microseconds: float = 0,
milliseconds: float = 0,
minutes: float = 0,
hours: float = 0,
weeks: float = 0,
years: float = 0,
months: float = 0
) -> Duration:
"""
Create Duration instance.
Parameters:
- days: Number of days
- seconds: Number of seconds
- microseconds: Number of microseconds
- milliseconds: Number of milliseconds
- minutes: Number of minutes
- hours: Number of hours
- weeks: Number of weeks
- years: Number of years (unique to Pendulum)
- months: Number of months (unique to Pendulum)
Returns:
Duration: New Duration instance
"""The Duration class with its constructor and methods.
class Duration:
def __init__(
self,
days: float = 0,
seconds: float = 0,
microseconds: float = 0,
milliseconds: float = 0,
minutes: float = 0,
hours: float = 0,
weeks: float = 0,
years: float = 0,
months: float = 0
):
"""Create Duration with specified time components"""
def total_seconds(self) -> float:
"""
Total duration in seconds.
Returns:
float: Total seconds (excluding years/months)
"""
def total_minutes(self) -> float:
"""
Total duration in minutes.
Returns:
float: Total minutes
"""
def total_hours(self) -> float:
"""
Total duration in hours.
Returns:
float: Total hours
"""
def total_days(self) -> float:
"""
Total duration in days.
Returns:
float: Total days
"""
def total_weeks(self) -> float:
"""
Total duration in weeks.
Returns:
float: Total weeks
"""
def in_weeks(self) -> int:
"""
Duration as integer weeks.
Returns:
int: Number of complete weeks
"""
def in_days(self) -> int:
"""
Duration as integer days.
Returns:
int: Number of complete days
"""
def in_hours(self) -> int:
"""
Duration as integer hours.
Returns:
int: Number of complete hours
"""
def in_minutes(self) -> int:
"""
Duration as integer minutes.
Returns:
int: Number of complete minutes
"""
def in_seconds(self) -> int:
"""
Duration as integer seconds.
Returns:
int: Number of complete seconds
"""
def in_words(self, locale: str | None = None, separator: str = " ") -> str:
"""
Human-readable duration description.
Parameters:
- locale: Locale for formatting
- separator: Separator between components
Returns:
str: Human-readable duration (e.g., "1 year 2 months 3 days")
"""
def as_timedelta(self):
"""
Convert to standard timedelta.
Note: Years and months are converted to approximate days.
Returns:
timedelta: Standard timedelta object
"""Properties available on Duration instances.
class Duration:
@property
def years(self) -> int:
"""Number of years in duration"""
@property
def months(self) -> int:
"""Number of months in duration"""
@property
def weeks(self) -> int:
"""Number of weeks in duration"""
@property
def days(self) -> int:
"""Total days (including converted years/months)"""
@property
def remaining_days(self) -> int:
"""Days not included in weeks calculation"""
@property
def hours(self) -> int:
"""Hours component (0-23)"""
@property
def minutes(self) -> int:
"""Minutes component (0-59)"""
@property
def seconds(self) -> int:
"""Total seconds in duration"""
@property
def remaining_seconds(self) -> int:
"""Seconds component not included in larger units (0-59)"""
@property
def microseconds(self) -> int:
"""Microseconds component"""
@property
def invert(self) -> bool:
"""Whether duration is negative"""Functions for creating Interval instances between DateTime objects.
def interval(start: DateTime, end: DateTime, absolute: bool = False) -> Interval:
"""
Create Interval between two DateTime objects.
Parameters:
- start: Start DateTime
- end: End DateTime
- absolute: Whether to make interval absolute (always positive)
Returns:
Interval: Time interval between the DateTimes
"""The Interval class representing time spans between specific points.
class Interval(Duration):
"""
Interval inherits all Duration methods and properties.
Represents the time span between two DateTime objects.
"""
def __init__(self, start: DateTime, end: DateTime, absolute: bool = False):
"""Create Interval between DateTimes"""
@property
def start(self) -> DateTime:
"""Start DateTime of interval"""
@property
def end(self) -> DateTime:
"""End DateTime of interval"""
@property
def years(self) -> int:
"""Years in interval"""
@property
def months(self) -> int:
"""Months in interval"""
@property
def weeks(self) -> int:
"""Weeks in interval"""
@property
def days(self) -> int:
"""Days in interval"""import pendulum
# Create durations
dur1 = pendulum.duration(hours=2, minutes=30)
dur2 = pendulum.duration(years=1, months=6, days=15)
dur3 = pendulum.duration(weeks=2, days=3, hours=4)
# Access components
print(f"Years: {dur2.years}") # 1
print(f"Months: {dur2.months}") # 6
print(f"Days: {dur2.days}") # 15 + ~365 + ~182 = ~562
print(f"Hours: {dur1.hours}") # 2
print(f"Minutes: {dur1.minutes}") # 30
# Total calculations
print(f"Total hours: {dur1.total_hours()}") # 2.5
print(f"Total seconds: {dur1.total_seconds()}") # 9000.0
# Integer conversions
print(f"In hours: {dur1.in_hours()}") # 2
print(f"In minutes: {dur1.in_minutes()}") # 150
# Human-readable format
print(dur2.in_words()) # "1 year 6 months 15 days"
print(dur1.in_words()) # "2 hours 30 minutes"
# Convert to standard timedelta
td = dur1.as_timedelta()
print(type(td)) # <class 'datetime.timedelta'>import pendulum
dt = pendulum.now()
# Add/subtract durations
future = dt + pendulum.duration(years=1, months=2)
past = dt - pendulum.duration(weeks=3, days=2)
# Duration arithmetic with DateTime methods
future2 = dt.add(years=1, months=2, days=5)
past2 = dt.subtract(hours=6, minutes=30)
# Complex duration
complex_dur = pendulum.duration(
years=2,
months=3,
weeks=1,
days=4,
hours=5,
minutes=30,
seconds=45
)
result = dt + complex_dur
print(f"Added duration: {result}")
print(f"Duration in words: {complex_dur.in_words()}")import pendulum
# Create interval between two dates
start = pendulum.datetime(2024, 1, 1)
end = pendulum.datetime(2025, 6, 15)
interval = pendulum.interval(start, end)
# Access interval properties
print(f"Years: {interval.years}")
print(f"Months: {interval.months}")
print(f"Days: {interval.days}")
# Interval inherits Duration methods
print(f"Total days: {interval.total_days()}")
print(f"In words: {interval.in_words()}")
# Create interval from DateTime.diff()
dt1 = pendulum.now()
dt2 = dt1.add(months=3, days=10)
diff_interval = dt1.diff(dt2) # Returns Interval
print(f"Difference: {diff_interval.in_words()}")
# Absolute intervals
past_dt = pendulum.now().subtract(days=30)
future_dt = pendulum.now().add(days=30)
# Normal interval (negative)
normal = pendulum.interval(future_dt, past_dt)
print(f"Normal: {normal.total_days()}") # -60
# Absolute interval (positive)
absolute = pendulum.interval(future_dt, past_dt, absolute=True)
print(f"Absolute: {absolute.total_days()}") # 60import pendulum
dur1 = pendulum.duration(hours=2)
dur2 = pendulum.duration(minutes=120)
dur3 = pendulum.duration(hours=3)
# Duration comparison
print(dur1 == dur2) # True (both are 2 hours)
print(dur1 < dur3) # True
print(dur1 > dur3) # False
# Duration arithmetic
combined = dur1 + dur3 # 5 hours
difference = dur3 - dur1 # 1 hour
# Multiplication and division
doubled = dur1 * 2 # 4 hours
half = dur1 / 2 # 1 hour
print(f"Combined: {combined.in_words()}")
print(f"Difference: {difference.in_words()}")
print(f"Doubled: {doubled.in_words()}")
print(f"Half: {half.in_words()}")import pendulum
# Create negative duration
neg_dur = pendulum.duration(hours=-2, minutes=-30)
print(f"Negative duration: {neg_dur.invert}") # True
print(f"In words: {neg_dur.in_words()}")
# Use with DateTime
dt = pendulum.now()
past_time = dt + neg_dur # Same as dt.subtract(hours=2, minutes=30)
# Interval creating negative duration
start = pendulum.now()
end = start.subtract(hours=5)
negative_interval = pendulum.interval(start, end)
print(f"Negative interval: {negative_interval.invert}")import pendulum
import datetime
# Pendulum Duration to standard timedelta
pd_dur = pendulum.duration(days=5, hours=3, minutes=30)
std_td = pd_dur.as_timedelta()
# Use standard timedelta with Pendulum DateTimes
dt = pendulum.now()
future = dt + std_td
# Note: Years and months are converted to approximate days
complex_dur = pendulum.duration(years=1, months=2, days=5)
# This conversion is approximate since months/years vary in length
approx_td = complex_dur.as_timedelta()
print(f"Original: {complex_dur.in_words()}")
print(f"As timedelta days: {approx_td.days}")Install with Tessl CLI
npx tessl i tessl/pypi-pendulum