mrkeyoor.com_
Sun 20 Sept 11:42 UTC
PyPIUtilsupdated 20 Sept 2026

arrow review

Arrow 1.4.0 is a pure-Python layer over datetime for creating aware timestamps, parsing ISO 8601 input, changing time zones, shifting calendar values, building spans and ranges, and writing relative phrases such as '2 hours ago.' This release replaces pytz with ZoneInfo for named zones, lets floor() and ceil() choose the first weekday, and adds a strict RFC 3339 format constant. Our Python 3.12 import took 0.17 seconds, and the distribution carries a py.typed marker. Arrow makes sense when the same service repeatedly crosses the boundary between stored instants and dates shown to people.

Verdict

Arrow 1.4.0 installed in 0.4 seconds and used 4 MB in our sandbox, with a 0.17-second import and no pip-audit findings. Install it when zone conversion, calendar boundaries, and localized relative time recur in one codebase; keep datetime and zoneinfo when you only store UTC and add timedeltas.

We installed it

Lab card: what happened when we installed arrowScreenshot of arrow documentation
Install✓ · 0.4s4 packages on disk · 4 MB
Importimport arrow in 0.17s · pure Python · py.typed · requires Python >=3.8
Known vulns0(pip-audit)

Answers from our run

Does arrow install cleanly?

Yes. In a fresh container with an empty cache, pip install arrow finished in 0.4s, leaving 4 packages and 4 MB on disk. pip-audit reported no known vulnerabilities.

What does arrow need to run?

Python >=3.8, and nothing compiled: it is pure Python. In our run import arrow succeeded in 0.17s, and the package ships py.typed for type checkers.

arrow or python-dateutil: which should you use?

python-dateutil: Choose it for parsing and relativedelta while keeping datetime as the value passed through the application. Arrow 1.4.0 installed in 0.4 seconds and used 4 MB in our sandbox, with a 0.17-second import and no pip-audit findings.

When should you not use arrow?

The job only records UTC instants and adds fixed timedeltas. datetime and zoneinfo already do that, while Arrow installs 4 packages and occupies 4 MB in our sandbox.

API stability4/5Arrow 1.4.0 keeps the established get(), utcnow(), now(), to(), shift(), span(), range(), floor(), ceil(), format(), and humanize() shapes, and its new week_start argument is optional. The release does replace pytz with ZoneInfo underneath named time zones. That implementation change can reach application results at DST transitions even though most call sites require no edit, so zone-sensitive upgrades deserve fixtures for repeated and nonexistent local times.
Docs4/5The official documentation returned HTTP 200 and gives working examples for construction, parsing, conversion, shifting, formatting, spans, ranges, humanization, locales, factories, and subclasses. Its token table and API reference answer exact syntax questions. The material is thinner on policy decisions around naive input and DST ambiguity, so a team still needs to document those choices beside its integrations instead of expecting the quick start to settle them.
Maintenance4/5PyPI lists 1.4.0 as current, and GitHub shows an unarchived repository pushed on June 22, 2026 with 189 open issues and pull requests in the combined counter. The 1.4.0 notes identify focused work on ZoneInfo, configurable week boundaries, RFC 3339 output, locale additions, humanize month limits, shift behavior, and typing. That is concrete maintenance on a mature 1.x API, though the combined queue is large enough that a niche edge case may wait.
Ecosystem4/5The current library record reports 18,248,882 weekly downloads, while GitHub reports 9,047 stars. Arrow accepts datetime, date, timestamps, tzinfo objects, and formatted strings, then exposes a datetime-compatible object with packaged type information. That makes it easy to place at an application's display boundary. It does not absorb business calendars, dataframe time series, or natural-language parsing, and separate packages remain the better fit for those jobs.

Use it if

  • Request handlers repeatedly parse offset-bearing timestamps, convert them to a user's named zone, and format the result for display.
  • Reporting code needs calendar floors, ceilings, spans, or ranges and those rules have started to spread across home-grown datetime helpers.
  • The product displays relative time in several supported locales and can treat that text as presentation rather than stored data.
  • Your type checker should recognize the date wrapper without installing a separate stub package.
Skip it if

Setup reality

We installed Arrow 1.4.0 in a fresh Python 3.12 Bookworm sandbox. Installation finished in 0.4 seconds, leaving 4 packages and 4 MB on disk. pip-audit reported 0 known vulnerabilities. The pure-Python distribution declares 15 direct dependencies, requires Python 3.8 or later, includes py.typed, and imported in 0.17 seconds. Its package metadata identifies the license as Apache Software License.

Arrow asks for no credentials and creates no config file. Decide how each integration treats a datetime without an offset. Use arrow.utcnow() or arrow.now('Europe/Paris') when your code creates the value, and pass an exact token format when a vendor sends a non-ISO string. A shared parser that silently assigns one zone to every feed is hard to audit.

Named zones in version 1.4.0 go through ZoneInfo. The package declares tzdata for Python 3.9 and later, so those names do not have to depend only on the operating system's zone files. Still test the two awkward clock changes: a local time that occurs twice and one that does not occur at all. shift(hours=1), shift(months=1), and replace(hour=...) express different rules. Billing and appointment code should choose deliberately.

Methods such as to(), shift(), floor(), and replace() return a new Arrow value. A range includes the endpoint when it falls exactly on the requested frame, which can add one more item than a half-open database interval. humanize() depends on both locale and reference time, so store an ISO timestamp and generate the phrase at display time. Pass a fixed reference in tests; otherwise assertions will age as the clock moves.

Patterns

Parse and normalize an ISO timestamp parse-offset-timestamp

import arrow

received = arrow.get('2026-08-26T09:15:00+05:30')
stored = received.to('UTC').isoformat()

The +05:30 offset fixes the instant. Keep the offset in vendor input or supply the missing zone as an explicit application rule.

Parse a vendor-specific date format parse-known-format

import arrow

issued = arrow.get('26/08/2026 09:15', 'DD/MM/YYYY HH:mm', tzinfo='Asia/Kolkata')

The format token order is explicit, so 03/04 cannot silently switch between March 4 and April 3.

Create a wall time in a named zone create-zoned-time

import arrow

appointment = arrow.get(2026, 10, 27, 9, 0, tzinfo='Europe/Berlin')
print(appointment.to('Asia/Kolkata'))

Arrow 1.4.0 resolves named zones with ZoneInfo. Add tests when a local time touches a daylight-saving transition.

Move a due date by one month shift-calendar-month

import arrow

due = arrow.get('2026-01-31T10:00:00Z')
next_due = due.shift(months=1)

Calendar-month shifts can land on a different day when the target month is shorter. Write the expected month-end rule into billing tests.

Get Monday-based week boundaries round-custom-week

import arrow

value = arrow.get('2026-08-26T09:15:00Z')
week_start = value.floor('week', week_start=1)
week_end = value.ceil('week', week_start=1)

The week_start option arrived in 1.4.0 and uses ISO weekday numbers, where Monday is 1.

Build a half-open day interval build-half-open-day

import arrow

day = arrow.get('2026-08-26', 'YYYY-MM-DD', tzinfo='UTC')
start = day.floor('day')
stop = start.shift(days=1)

Use start <= timestamp < stop for database filters. span('day') returns an inclusive final microsecond instead.

Walk an hourly reporting range iterate-hourly-range

import arrow

start = arrow.get('2026-08-26T00:00:00Z')
end = arrow.get('2026-08-26T06:00:00Z')
for hour in arrow.Arrow.range('hour', start, end):
    aggregate(hour)

Arrow includes end when it sits on the frame, so this example yields 7 hourly values. Validate user-controlled bounds before materializing a range.

Render deterministic relative text render-relative-time

import arrow

event = arrow.get('2026-08-26T07:00:00Z')
reference = arrow.get('2026-08-26T09:00:00Z')
label = event.humanize(reference, locale='en-us')

Supplying the reference makes the result stable in tests. The phrase belongs in the UI, not in a stored record or cache key.

Emit strict RFC 3339 text format-strict-rfc3339

import arrow
from arrow import FORMAT_RFC3339_STRICT

value = arrow.get('2026-08-26T09:15:00Z')
wire_value = value.format(FORMAT_RFC3339_STRICT)

FORMAT_RFC3339_STRICT was added in 1.4.0 and places T between the date and time.

Show one instant in two zones preserve-source-value

import arrow

instant = arrow.get('2026-08-26T03:45:00Z')
india = instant.to('Asia/Kolkata')
california = instant.to('America/Los_Angeles')

to() returns a new Arrow object. The original value stays in UTC for another presentation or comparison.

Wrap a standard-library datetime wrap-aware-datetime

from datetime import datetime, timezone
import arrow

native = datetime(2026, 8, 26, 9, 0, tzinfo=timezone.utc)
wrapped = arrow.get(native)
restored = wrapped.datetime

An aware datetime carries its instant into Arrow. Reject or normalize naive values before this boundary if their zone is unknown.

Set clock fields without elapsed arithmetic replace-clock-fields

import arrow

value = arrow.get('2026-08-26T09:15:42+05:30')
midnight = value.replace(hour=0, minute=0, second=0, microsecond=0)

replace() changes named wall-clock fields and retains the zone. shift(hours=...) answers an elapsed-time question instead.

Alternatives

PackageRegistryPick it when
python-dateutilPyPIChoose it for parsing and relativedelta while keeping datetime as the value passed through the application.
pendulumPyPIChoose it when an explicit duration type and its formatting API are part of the application model.
wheneverPyPIChoose it when separate types for UTC instants, offset datetimes, and local calendar values should prevent accidental mixing.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.