Python arrow
last modified October 30, 2026 Python 3.15
In this article we show how to work with date and time in Python with the arrow module.
Python arrow
Arrow is a Python module for working with date and time. Compared to the built-in date and time tools, it makes it much easier to create, manipulate, format and convert dates, times, and timestamps. Arrow objects are always time zone aware.
The arrow module is installed with the following command:
$ pip install arrow
UTC time
There is a pragmatic need for one global time. One global time helps to avoid confusion about time zones and daylight saving time. UTC (Coordinated Universal Time) is the primary time standard. UTC is used in aviation, weather forecasts, flight plans, air traffic control clearances, and maps. Unlike local time, UTC does not change with a change of seasons.
import arrow
utc = arrow.utcnow()
print(utc)
print(utc.to('local'))
print(utc.to('Asia/Tokyo'))
The UTC time is created with the utcnow function.
print(utc.to('local'))
print(utc.to('Asia/Tokyo'))
With the to method, we convert the UTC time to the local time
of the computer and to the time in Tokyo. The time zones are given by their
IANA names.
$ python utc_time.py 2026-10-30T17:37:11.023395+00:00 2026-10-30T18:37:11.023395+01:00 2026-10-31T02:37:11.023395+09:00
Local time
Local time is a time in a particular region or time zone.
import arrow
now = arrow.now()
print(now)
print(now.tzinfo)
print(now.to('UTC'))
tokyo = arrow.now('Asia/Tokyo')
print(tokyo)
The local time is created with the now function. The
to method is used to convert the local time into the UTC time.
The tzinfo attribute holds the time zone.
tokyo = arrow.now('Asia/Tokyo')
The now function also accepts a time zone; we get the current
time in Tokyo.
$ python local_time.py 2026-10-30T18:37:11.073172+01:00 CET 2026-10-30T17:37:11.073172+00:00 2026-10-31T02:37:11.073286+09:00
Parsing time
The get function is used to create arrow objects from strings,
timestamps, and datetime objects.
from datetime import datetime
import arrow
d1 = arrow.get('2012-06-05 16:20:03', 'YYYY-MM-DD HH:mm:ss')
print(d1)
d2 = arrow.get(1504384602)
print(d2)
d3 = arrow.get('2026-10-30T14:25:07+01:00')
print(d3)
d4 = arrow.get('05/06/2012 16:20', 'DD/MM/YYYY HH:mm', tzinfo='Europe/Bratislava')
print(d4)
d5 = arrow.get('Born on 13 December 1948', 'D MMMM YYYY')
print(d5)
d6 = arrow.get(datetime(2026, 1, 15, 8, 30))
print(d6)
The example parses time from various sources. Unless the input contains an
offset or we pass the tzinfo argument, the time is in UTC.
d1 = arrow.get('2012-06-05 16:20:03', 'YYYY-MM-DD HH:mm:ss')
The second argument is the format of the string. The tokens are described in the formatting section below.
d3 = arrow.get('2026-10-30T14:25:07+01:00')
ISO 8601 strings are parsed without a format, and the offset is kept.
d5 = arrow.get('Born on 13 December 1948', 'D MMMM YYYY')
When a format is given, arrow searches for the date in the string and ignores the surrounding text.
d6 = arrow.get(datetime(2026, 1, 15, 8, 30))
A naive datetime is interpreted as UTC.
$ python parse_time.py 2012-06-05T16:20:03+00:00 2017-09-02T20:36:42+00:00 2026-10-30T14:25:07+01:00 2012-06-05T16:20:00+02:00 1948-12-13T00:00:00+00:00 2026-01-15T08:30:00+00:00
Unix time
The Unix time is the number of seconds since the Unix epoch, 0 hours, 0 minutes, 0 seconds, January 1, 1970, Coordinated Universal Time.
import arrow
dt = arrow.get('2026-10-30T14:25:07+01:00')
print(dt.timestamp())
print(dt.int_timestamp)
print(dt.format('X'))
print(dt.format('x'))
ts = 1793366707
print(arrow.get(ts))
print(arrow.Arrow.fromtimestamp(ts, tzinfo='Europe/Bratislava'))
The example converts a date to the Unix time and back.
print(dt.timestamp()) print(dt.int_timestamp)
The timestamp method returns the Unix time as a float; the
int_timestamp property returns whole seconds. In arrow 1.0 and
later, timestamp is a method, not a property.
print(dt.format('X'))
print(dt.format('x'))
The X format token gives the timestamp in seconds, the
x token in microseconds.
print(arrow.Arrow.fromtimestamp(ts, tzinfo='Europe/Bratislava'))
With the fromtimestamp method, we convert the Unix time back to
an arrow object in the given time zone. The get function returns
it in UTC.
$ python unix_time.py 1793366707.0 1793366707 1793366707.0 1793366707000000 2026-10-30T13:25:07+00:00 2026-10-30T14:25:07+01:00
Formatting date and time
Date and time can be formatted with the format method. We create
a fixed date with the Arrow constructor, so that the output is
reproducible.
import arrow
dt = arrow.Arrow(2026, 10, 30, 14, 25, 7, tzinfo='Europe/Bratislava')
print(dt.format('YYYY'))
print(dt.format('YYYY-MM-DD'))
print(dt.format('YYYY-MM-DD HH:mm:ss'))
print(dt.format('YYYY-MM-DD HH:mm:ss ZZ'))
print(dt.format('dddd, MMMM Do YYYY [at] h:mm A'))
print(dt.format('ddd D MMM YYYY', locale='sk'))
print(dt.isoformat())
print(dt.format(arrow.FORMAT_RFC2822))
The example shows a date and time in various formats.
print(dt.format('dddd, MMMM Do YYYY [at] h:mm A'))
The dddd token is the full weekday name, MMMM the
full month name, and Do the day of month with an ordinal suffix.
The h token is a 12-hour clock hour and A is
AM/PM. Text in square brackets is printed literally.
print(dt.format('ddd D MMM YYYY', locale='sk'))
The locale argument translates the names; here we use Slovak.
print(dt.format(arrow.FORMAT_RFC2822))
Arrow has constants for common formats, such as the RFC 2822 format used in email headers.
$ python formatting.py 2026 2026-10-30 2026-10-30 14:25:07 2026-10-30 14:25:07 +01:00 Friday, October 30th 2026 at 2:25 PM pi 30 okt 2026 2026-10-30T14:25:07+01:00 Fri, 30 Oct 2026 14:25:07 +0100
Converting to regional time
With the to method, we can convert the date and time to a
regional time.
import arrow
utc = arrow.get('2026-10-30T12:00:00+00:00')
for tz in ['America/Los_Angeles', 'Europe/Bratislava', 'Europe/Moscow',
'Asia/Tokyo']:
local = utc.to(tz)
print(f'{tz:20} {local.format("HH:mm ZZ")}')
The example converts a UTC time to four regional times. We use the
canonical America/Los_Angeles name; US/Pacific is
a legacy alias kept in the time zone database for backward compatibility.
$ python converting.py America/Los_Angeles 05:00 -07:00 Europe/Bratislava 13:00 +01:00 Europe/Moscow 15:00 +03:00 Asia/Tokyo 21:00 +09:00
The replace and to methods
The to method converts the time to another time zone and keeps
the instant. The replace method changes the fields and keeps the
rest.
import arrow
dt = arrow.get('2026-10-30T12:00:00+00:00')
print(dt.to('Asia/Tokyo'))
print(dt.replace(tzinfo='Asia/Tokyo'))
print(dt.replace(hour=8, minute=15))
Converting noon UTC to Tokyo gives 21:00 in Tokyo; it is the same moment.
print(dt.replace(tzinfo='Asia/Tokyo'))
Replacing the time zone keeps 12:00 and attaches the Tokyo time zone, which is a different moment, nine hours earlier.
print(dt.replace(hour=8, minute=15))
We can also replace the individual fields of the date and time.
$ python replace_vs_to.py 2026-10-30T21:00:00+09:00 2026-10-30T12:00:00+09:00 2026-10-30T08:15:00+00:00
Getting weekday
The weekday of a date can be found with the weekday,
isoweekday, or the format method.
import arrow
d1 = arrow.get('1948-12-13')
print(d1.weekday())
print(d1.isoweekday())
print(d1.format('dddd'))
print(d1.format('dddd', locale='de'))
The code example gets the weekday of 1948-12-13. The weekday
method counts from Monday as 0, isoweekday from Monday as 1.
$ python weekday.py 0 1 Monday Montag
Shifting time
The shift method is used to shift time. It returns a new arrow
object; arrow objects are immutable.
import arrow
dt = arrow.get('2026-10-30T14:25:07+01:00')
print(dt.shift(hours=5))
print(dt.shift(days=5).date())
print(dt.shift(years=-8).date())
print(dt.shift(weeks=2, days=-1).date())
end_of_jan = arrow.get('2026-01-31')
print(end_of_jan.shift(months=1).date())
The example shifts a date and time several times.
print(dt.shift(hours=5))
We shift the time forward by five hours.
print(dt.shift(years=-8).date())
Negative values shift backward; here, by eight years.
print(dt.shift(weeks=2, days=-1).date())
Several units can be combined in one call.
end_of_jan = arrow.get('2026-01-31')
print(end_of_jan.shift(months=1).date())
Shifting by months keeps the day of month if possible. There is no February 31, so arrow uses the last day of February.
$ python shifting.py 2026-10-30T19:25:07+01:00 2026-11-04 2018-10-30 2026-11-12 2026-02-28
Daylight saving time
Daylight saving time (DST) is the practice of advancing clocks during summer months so that evening daylight lasts longer. The time is adjusted forward one hour in the beginning of spring and adjusted backward in the autumn to standard time.
import arrow
summer = arrow.get('2026-07-01 12:00', tzinfo='Europe/Bratislava')
winter = arrow.get('2026-12-01 12:00', tzinfo='Europe/Bratislava')
print(summer.format('YYYY-MM-DD HH:mm ZZ'), summer.dst())
print(winter.format('YYYY-MM-DD HH:mm ZZ'), winter.dst())
before = arrow.get('2026-03-29 01:30', tzinfo='Europe/Bratislava')
after = before.shift(hours=1)
print(before)
print(after)
print(after - before)
print(after.to('UTC') - before.to('UTC'))
The example shows daylight saving time with dst for a summer
and a winter date.
before = arrow.get('2026-03-29 01:30', tzinfo='Europe/Bratislava')
after = before.shift(hours=1)
On March 29, 2026, the clocks in Central Europe jumped from 02:00 to 03:00. Shifting 01:30 by one hour correctly gives 03:30 summer time.
print(after - before)
print(after.to('UTC') - before.to('UTC'))
Subtracting two times in the same time zone computes the difference of the wall clock times, which is two hours. To get the elapsed time, we convert both times to UTC first.
$ python daylight_saving.py 2026-07-01 12:00 +02:00 1:00:00 2026-12-01 12:00 +01:00 0:00:00 2026-03-29T01:30:00+01:00 2026-03-29T03:30:00+02:00 2:00:00 1:00:00
Spans, floor and ceil
The span method returns the start and the end of a time frame,
such as an hour, a day, a week, or a month. The floor and
ceil methods return just the start or the end.
import arrow
dt = arrow.get('2026-10-30T14:25:07+01:00')
print(dt.floor('hour'))
print(dt.ceil('day'))
start, end = dt.span('week')
print(start)
print(end)
start, end = dt.span('month')
print(start.date(), end.date())
We get the start of the hour, the end of the day, and the boundaries of the week and the month. Weeks start on Monday.
$ python span_floor.py 2026-10-30T14:00:00+01:00 2026-10-30T23:59:59.999999+01:00 2026-10-26T00:00:00+01:00 2026-11-01T23:59:59.999999+01:00 2026-10-01 2026-10-31
Time ranges
The Arrow.range method generates arrow objects between two
times, and Arrow.span_range generates spans.
import arrow
start = arrow.get('2026-10-26')
end = arrow.get('2026-11-01')
for day in arrow.Arrow.range('day', start, end):
print(day.format('ddd YYYY-MM-DD'))
print()
for first, last in arrow.Arrow.span_range('hour', start.replace(hour=9),
start.replace(hour=11)):
print(first.format('HH:mm:ss'), '-', last.format('HH:mm:ss'))
We print all days of a week; both ends are included.
for first, last in arrow.Arrow.span_range('hour', start.replace(hour=9),
start.replace(hour=11)):
The span_range method yields the start and end of each hour
from 9:00 to 11:00.
$ python time_range.py Mon 2026-10-26 Tue 2026-10-27 Wed 2026-10-28 Thu 2026-10-29 Fri 2026-10-30 Sat 2026-10-31 Sun 2026-11-01 09:00:00 - 09:59:59 10:00:00 - 10:59:59 11:00:00 - 11:59:59
Comparing times
Arrow objects can be subtracted and compared, even when they are in different time zones.
import arrow
start = arrow.get('2026-10-30T09:00:00+01:00')
end = arrow.get('2026-10-30T17:30:00+01:00')
lunch = arrow.get('2026-10-30T11:00:00Z')
print(end - start)
print((end - start).total_seconds() / 3600)
print(start < lunch < end)
print(lunch.is_between(start, end))
print(lunch.to('Europe/Bratislava'))
Subtracting two arrow objects gives a timedelta. Comparisons are
based on the instant, so 11:00 UTC lies between 9:00 and 17:30 in UTC+1.
print(lunch.is_between(start, end))
The is_between method checks if a time lies between two others.
By default, both ends are excluded.
$ python compare.py 8:30:00 8.5 True True 2026-10-30T12:00:00+01:00
Humanizing date and time
On social web sites we can often see terms such as 'an hour ago' or '5 min
ago', which provide quick information for humans about when the post was
created or modified. Arrow contains a humanize method to create
such terms.
import arrow
now = arrow.now()
print(now.shift(minutes=-15).humanize())
print(now.shift(hours=5, minutes=1).humanize())
base = arrow.get('2026-10-30T12:00:00')
dt = base.shift(days=-3, hours=-4)
print(dt.humanize(base))
print(dt.humanize(base, granularity=['day', 'hour']))
print(dt.humanize(base, locale='sk'))
print(base.dehumanize('in 2 weeks'))
The example humanizes dates relative to the current time and relative to a fixed date.
print(now.shift(hours=5, minutes=1).humanize())
Humanizing compares with the current time at the moment of the call, which
is a bit later than now. Exactly five hours would already be
less than five hours and would print 'in 4 hours'; we add a minute.
print(dt.humanize(base, granularity=['day', 'hour'])) print(dt.humanize(base, locale='sk'))
The granularity argument selects the units to show. The
locale argument translates the result.
print(base.dehumanize('in 2 weeks'))
The dehumanize method works in the opposite direction: it shifts
the date by the humanized expression.
$ python humanize.py 15 minutes ago in 5 hours 3 days ago 3 days and 4 hours ago Pred 3 dňami 2026-11-13T12:00:00+00:00
Source
In this article we have worked with date and time in Python with the arrow module. For time zones with the standard library only, see Python zoneinfo.
Author
List all Python tutorials.