18 KiB
title, library_name, pypi_package, category, python_compatibility, last_updated, official_docs, official_repository, maintenance_status
| title | library_name | pypi_package | category | python_compatibility | last_updated | official_docs | official_repository | maintenance_status |
|---|---|---|---|---|---|---|---|---|
| Arrow - Better Dates & Times for Python | arrow | arrow | datetime | 3.8+ | 2025-11-02 | https://arrow.readthedocs.io | https://github.com/arrow-py/arrow | active |
Arrow - Better Dates & Times for Python
Core Purpose
Arrow provides a sensible, human-friendly approach to creating, manipulating, formatting, and converting dates, times, and timestamps. It addresses critical usability problems in Python's standard datetime ecosystem:
Problems Arrow Solves:
- Module fragmentation: Eliminates the need to import datetime, time, calendar, dateutil, pytz separately
- Type complexity: Provides a single Arrow type instead of managing date, time, datetime, tzinfo, timedelta, relativedelta
- Timezone verbosity: Simplifies timezone-aware operations that are cumbersome with standard library
- Missing functionality: Built-in ISO 8601 parsing, humanization, and time span operations
- Timezone naivety: UTC-aware by default, preventing common timezone bugs
Arrow is a drop-in replacement for datetime that consolidates scattered tools into a unified, elegant interface.
When to Use Arrow
Use Arrow When
- Building user-facing applications that display relative times ("2 hours ago", "in 3 days")
- Working extensively with timezones - converting between zones, handling DST transitions
- Parsing diverse datetime formats - ISO 8601, timestamps, custom formats
- Need cleaner, more readable code - Arrow's chainable API reduces boilerplate
- Generating time ranges or spans - iterate over hours, days, weeks, months
- Internationalization is required - 75+ locale support for humanized output
- API development where timezone-aware timestamps are standard
- Data processing pipelines that handle datetime transformations frequently
Use Standard datetime When
- Performance is absolutely critical - Arrow is ~50% slower than datetime.utcnow() @benchmark
- Minimal datetime operations - simple date storage with no manipulation
- Library compatibility requirements mandate standard datetime objects
- Memory-constrained environments - datetime objects have smaller footprint
- Working within pandas/numpy which have optimized datetime64 types
- No timezone logic needed and you're comfortable with datetime's API
Real-World Usage Patterns
Pattern 1: Timezone-Aware Timestamp Creation
@source: https://arrow.readthedocs.io/en/latest/
import arrow
# Get current time in UTC (default)
utc = arrow.utcnow()
# <Arrow [2013-05-11T21:23:58.970460+00:00]>
# Get current time in specific timezone
local = arrow.now('US/Pacific')
# <Arrow [2013-05-11T13:23:58.970460-07:00]>
# Convert between timezones effortlessly
utc_time = arrow.utcnow()
tokyo_time = utc_time.to('Asia/Tokyo')
ny_time = tokyo_time.to('America/New_York')
Why this matters: Standard datetime requires verbose pytz.timezone() calls and manual localization. Arrow handles this in one method.
Pattern 2: Parsing Diverse Formats
@source: Context7 documentation snippets
import arrow
# Parse ISO 8601 automatically
arrow.get('2013-05-11T21:23:58.970460+07:00')
# Parse with format string
arrow.get('2013-05-05 12:30:45', 'YYYY-MM-DD HH:mm:ss')
# Parse Unix timestamps (int or float)
arrow.get(1368303838)
arrow.get(1565358758.123413)
# Parse with timezone
arrow.get('2013-05-11T21:23:58', tzinfo='Europe/Paris')
# Handle inconsistent spacing
arrow.get('Jun 1 2005 1:33PM', 'MMM D YYYY H:mmA', normalize_whitespace=True)
# Parse ISO week dates
arrow.get('2013-W29-6', 'W') # Year-Week-Day format
Why this matters: datetime.strptime() requires exact format matching. Arrow intelligently handles variations and timezone strings directly.
Pattern 3: Humanization for User Interfaces
@source: https://arrow.readthedocs.io/en/latest/
import arrow
now = arrow.utcnow()
past = now.shift(hours=-1)
future = now.shift(days=3, hours=2)
# English humanization
past.humanize() # 'an hour ago'
future.humanize() # 'in 3 days'
# Localized humanization (75+ locales)
past.humanize(locale='ko-kr') # '한시간 전'
past.humanize(locale='es') # 'hace una hora'
# Multiple granularities
later = arrow.utcnow().shift(hours=2, minutes=19)
later.humanize(granularity=['hour', 'minute'])
# 'in 2 hours and 19 minutes'
# Quarter granularity (business applications)
four_months = now.shift(months=4)
four_months.humanize(granularity='quarter') # 'in a quarter'
Why this matters: Building this with datetime requires third-party libraries or manual logic. Arrow includes it with extensive locale support.
Pattern 4: Time Shifting and Manipulation
@source: Context7 documentation snippets
import arrow
now = arrow.utcnow()
# Relative shifts (chainable)
future = now.shift(years=1, months=-2, days=5, hours=3)
past = now.shift(weeks=-2)
# Dehumanize - parse human phrases
base = arrow.get('2020-05-27 10:30:35')
base.dehumanize('8 hours ago')
base.dehumanize('in 4 days')
base.dehumanize('hace 2 años', locale='es') # Spanish: "2 years ago"
# Replace specific components
now.replace(hour=0, minute=0, second=0) # Start of day
now.replace(year=2025)
Why this matters: timedelta only supports days/seconds. dateutil.relativedelta is verbose. Arrow combines both with intuitive API.
Pattern 5: Time Ranges and Spans
@source: Context7 documentation snippets
import arrow
from datetime import datetime
# Generate time ranges
start = arrow.get(2020, 5, 5, 12, 30)
end = arrow.get(2020, 5, 5, 17, 15)
# Iterate by hour
for hour in arrow.Arrow.range('hour', start, end):
print(hour)
# Get floor and ceiling (span)
now = arrow.utcnow()
now.span('hour') # Returns (floor, ceiling) tuple
now.floor('hour') # Start of current hour
now.ceil('day') # End of current day
# Span ranges - generate (start, end) tuples
for span in arrow.Arrow.span_range('hour', start, end):
floor, ceiling = span
print(f"Hour from {floor} to {ceiling}")
# Handle DST transitions correctly
before_dst = arrow.get('2018-03-10 23:00:00', tzinfo='US/Pacific')
after_dst = arrow.get('2018-03-11 04:00:00', tzinfo='US/Pacific')
for t in arrow.Arrow.range('hour', before_dst, after_dst):
print(f"{t} (UTC: {t.to('UTC')})")
Why this matters: Standard datetime has no built-in iteration. Arrow handles DST transitions automatically in ranges.
Pattern 6: Formatting with Built-in Constants
@source: Context7 documentation snippets
import arrow
arw = arrow.utcnow()
# Use predefined format constants
arw.format(arrow.FORMAT_ATOM) # '2020-05-27 10:30:35+00:00'
arw.format(arrow.FORMAT_COOKIE) # 'Wednesday, 27-May-2020 10:30:35 UTC'
arw.format(arrow.FORMAT_RFC3339) # '2020-05-27 10:30:35+00:00'
arw.format(arrow.FORMAT_W3C) # '2020-05-27 10:30:35+00:00'
# Custom formats with tokens
arw.format('YYYY-MM-DD HH:mm:ss ZZ') # '2020-05-27 10:30:35 +00:00'
# Escape literal text in formats
arw.format('YYYY-MM-DD h [h] m') # '2020-05-27 10 h 30'
# Timestamp formats
arw.format('X') # '1590577835' (seconds)
arw.format('x') # '1590577835123456' (microseconds)
Why this matters: datetime.strftime() uses different token syntax (%Y vs YYYY). Arrow uses consistent, JavaScript-inspired tokens.
Integration Patterns
Works seamlessly with
python-dateutil (required dependency >=2.7.0)
- Arrow uses dateutil.parser internally for flexible parsing
- Timezone objects from dateutil are directly compatible
pytz (optional, for Python <3.9)
- Arrow accepts pytz timezone objects in
to()andtzinfoparameters - Handles pytz's DST quirks automatically
zoneinfo (Python 3.9+, via backports.zoneinfo on 3.8)
- Arrow supports ZoneInfo timezone objects natively
- Uses tzdata package on Python 3.9+ for timezone database
datetime (standard library)
arrow_obj.datetimereturns standard datetime objectarrow.get(datetime_obj)creates Arrow from datetime- Arrow subclasses datetime, so it works anywhere datetime does
pandas (data analysis)
import arrow
import pandas as pd
# Convert Arrow to pandas Timestamp
arrow_time = arrow.utcnow()
pd.Timestamp(arrow_time.datetime)
# Or use Arrow for timezone-aware operations before pandas
df['timestamp'] = df['utc_string'].apply(lambda x: arrow.get(x).to('US/Pacific').datetime)
Django/Flask (web frameworks)
# Django models - store as DateTimeField
from django.db import models
import arrow
class Event(models.Model):
created_at = models.DateTimeField()
def save(self, *args, **kwargs):
self.created_at = arrow.utcnow().datetime # Convert to datetime
super().save(*args, **kwargs)
@property
def created_humanized(self):
return arrow.get(self.created_at).humanize()
Python Version Compatibility
@source: https://github.com/arrow-py/arrow/blob/master/pyproject.toml
Minimum: Python 3.8 Tested versions: 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, 3.14 Status: Production/Stable across all supported versions
Version-specific notes:
- Python 3.8: Requires
backports.zoneinfo==0.2.1for timezone support - Python 3.9+: Uses built-in
zoneinfoandtzdatapackage - Python 3.6-3.7: No longer supported as of Arrow 1.3.0 (EOL Python versions)
Dependencies:
python-dateutil>=2.7.0
backports.zoneinfo==0.2.1 # Python <3.9 only
tzdata # Python >=3.9 only
Installation
# Basic installation
pip install -U arrow
# With uv (recommended)
uv pip install arrow
# In pyproject.toml
[project]
dependencies = [
"arrow>=1.3.0",
]
When NOT to Use Arrow
Scenario 1: High-Performance Timestamp Generation
@source: https://www.dataroc.ca/blog/most-performant-timestamp-functions-python
Performance benchmarks show:
time.time(): Baseline (fastest)datetime.utcnow(): ~50% slower than time.time()- Arrow operations: Additional overhead for object wrapping
Use datetime when: You're generating millions of timestamps in tight loops (e.g., high-frequency trading, real-time analytics pipelines).
# High-performance scenario - use standard library
import time
timestamp = time.time() # Fastest for epoch timestamps
import datetime
dt = datetime.datetime.utcnow() # Faster for datetime objects
Scenario 2: Working with Pandas/NumPy DateTime
@source: Performance analysis and library comparisons
Pandas has highly optimized datetime64 vectorized operations. Arrow's object-oriented approach doesn't vectorize well.
Use pandas when: Processing large datasets with datetime columns.
import pandas as pd
# Pandas is optimized for this
df['date'] = pd.to_datetime(df['date_string'])
df['hour'] = df['date'].dt.hour # Vectorized operation
# Arrow would require row-by-row operations (slow)
# df['hour'] = df['date'].apply(lambda x: arrow.get(x).hour)
Scenario 3: Simple Date Storage
Use datetime when: You only need to store dates with no manipulation:
from datetime import datetime
# Simple storage - datetime is sufficient
user.created_at = datetime.utcnow()
Scenario 4: Library Compatibility Constraints
Some libraries explicitly require standard datetime objects and don't accept subclasses. Always test compatibility.
Scenario 5: Memory-Constrained Environments
Arrow objects carry additional overhead. For millions of cached datetime objects, standard datetime is lighter.
Decision Matrix
| Requirement | Arrow | datetime | Notes |
|---|---|---|---|
| Timezone conversion | ✓✓✓ | ✓ | Arrow: one-line. datetime: verbose with pytz |
| ISO 8601 parsing | ✓✓✓ | ✓✓ | Arrow: automatic. datetime: fromisoformat() limited |
| Humanization | ✓✓✓ | ✗ | Arrow: built-in with 75+ locales |
| Time ranges/iteration | ✓✓✓ | ✗ | Arrow: native. datetime: manual loops |
| Performance (creation) | ✓✓ | ✓✓✓ | datetime ~50% faster |
| Performance (parsing) | ✓✓ | ✓✓✓ | datetime.strptime() faster |
| Memory footprint | ✓✓ | ✓✓✓ | datetime objects lighter |
| Learning curve | ✓✓✓ | ✓✓ | Arrow: more intuitive |
| Pandas integration | ✓ | ✓✓✓ | Use pandas.Timestamp for large data |
| Standard library | ✗ | ✓✓✓ | Arrow: requires installation |
| Type hints | ✓✓✓ | ✓✓✓ | Both have full PEP 484 support |
| DST handling | ✓✓✓ | ✓✓ | Arrow: automatic. datetime: manual |
Legend: ✓✓✓ Excellent | ✓✓ Good | ✓ Adequate | ✗ Not supported
Quick Decision Guide
START: Do you need datetime functionality?
|
├─ Is performance critical? (>100k ops/sec)
| └─ YES → Use datetime or time.time()
|
├─ Working with pandas/numpy large datasets?
| └─ YES → Use pandas.Timestamp
|
├─ Need any of: humanization, easy timezone conversion, time ranges, multi-locale?
| └─ YES → Use Arrow
|
├─ Simple date storage only?
| └─ YES → Use datetime
|
└─ Building user-facing application with datetime logic?
└─ YES → Use Arrow (cleaner code, better UX)
Common Gotchas and Solutions
Gotcha 1: Arrow is timezone-aware by default
@source: Arrow documentation
# This gives you UTC time, not local time
arrow.now() # <Arrow [2020-05-27T10:30:35.123456+00:00]>
# For local timezone, be explicit
arrow.now('local') # or arrow.now('America/New_York')
Gotcha 2: Converting to datetime loses Arrow methods
arrow_time = arrow.utcnow()
dt = arrow_time.datetime # Now a standard datetime object
# This works
arrow_time.humanize() # ✓
# This fails
dt.humanize() # ✗ AttributeError
Gotcha 3: Timestamp parsing requires format token in 0.15.0+
@source: Context7 CHANGELOG snippets
# Deprecated (pre-0.15.0)
arrow.get("1565358758") # ✗ No longer works
# Correct (0.15.0+)
arrow.get("1565358758", "X") # ✓ Explicit format token
arrow.get(1565358758) # ✓ Or pass as int/float directly
Gotcha 4: Ambiguous datetimes during DST transitions
@source: Context7 documentation
# During DST "fall back", 2 AM occurs twice
# Use fold parameter (PEP 495)
ambiguous = arrow.Arrow(2017, 10, 29, 2, 0, tzinfo='Europe/Stockholm')
ambiguous.fold # 0 (first occurrence)
# Specify which occurrence
second_occurrence = arrow.Arrow(2017, 10, 29, 2, 0, tzinfo='Europe/Stockholm', fold=1)
Alternatives Comparison
@source: https://python.libhunt.com/arrow-alternatives, https://aboutsimon.com/blog/2016/08/04/datetime-vs-Arrow-vs-Pendulum-vs-Delorean-vs-udatetime.html
Pendulum (arrow alternative)
- Similar goals: human-friendly datetime
- Better timezone handling in some edge cases
- Slower than Arrow in benchmarks
- Less widely adopted (fewer GitHub stars)
Maya (Datetimes for Humans)
- Simpler API, fewer features
- Less actively maintained
- Good for very basic use cases
udatetime (performance-focused)
- Written in C for speed (faster than datetime)
- Limited feature set (encode/decode only)
- Use when you need Arrow-like simplicity with datetime-like speed
Standard datetime (built-in)
- Always available, no dependencies
- Verbose but performant
- Use when Arrow features aren't needed
dateutil (datetime extension)
- Powerful parser, relativedelta for arithmetic
- Often used with datetime for enhanced functionality
- Arrow uses dateutil internally
Real-World Example Projects
@source: GitHub search results
arrow-py/arrow (8,944 stars)
- Official repository with comprehensive examples
- https://github.com/arrow-py/arrow
Common usage in web applications:
# API endpoint returning human-readable timestamps
from flask import jsonify
import arrow
@app.route('/events')
def get_events():
events = Event.query.all()
return jsonify([{
'id': e.id,
'name': e.name,
'created': arrow.get(e.created_at).humanize(),
'start_time': arrow.get(e.start_time).format('YYYY-MM-DD HH:mm ZZ')
} for e in events])
Data processing pipelines:
import arrow
def process_log_file(log_path):
with open(log_path) as f:
for line in f:
# Parse diverse timestamp formats
timestamp_str = extract_timestamp(line)
timestamp = arrow.get(timestamp_str, normalize_whitespace=True)
# Convert to consistent timezone
utc_time = timestamp.to('UTC')
# Filter by time range
if utc_time >= arrow.get('2025-01-01'):
yield utc_time, line
References and Sources
@official_docs: https://arrow.readthedocs.io/en/latest/ @repository: https://github.com/arrow-py/arrow @pypi: https://pypi.org/project/arrow/ @context7: /arrow-py/arrow @changelog: https://github.com/arrow-py/arrow/blob/master/CHANGELOG.rst
Performance analysis: @benchmark: https://www.dataroc.ca/blog/most-performant-timestamp-functions-python @comparison: https://aboutsimon.com/blog/2016/08/04/datetime-vs-Arrow-vs-Pendulum-vs-Delorean-vs-udatetime.html
Community resources: @alternatives: https://python.libhunt.com/arrow-alternatives @tutorial: https://code.tutsplus.com/arrow-for-better-date-and-time-in-python--cms-29624t @guide: https://stackabuse.com/working-with-datetime-in-python-with-arrow/
Summary
Arrow eliminates datetime friction by consolidating Python's fragmented date/time ecosystem into a single, intuitive API. Use it when developer experience and feature richness matter more than raw performance. For high-frequency operations or pandas-scale data processing, stick with the standard library or specialized tools. Arrow shines in web applications, APIs, CLI tools, and any code where humans read the timestamps.
The reinvented wheel: Without Arrow, you'd manually implement timezone conversion helpers, humanization logic, flexible parsing, and time range iteration using datetime + dateutil + pytz + custom code. Arrow packages these common patterns into a production-ready library.