ZetCode

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.

utc_time.py
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.

local_time.py
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.

parse_time.py
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.

unix_time.py
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.

formatting.py
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.

converting.py
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.

replace_vs_to.py
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.

weekday.py
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.

shifting.py
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.

daylight_saving.py
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.

span_floor.py
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.

time_range.py
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.

compare.py
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.

humanize.py
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

Python arrow documentation

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

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Python tutorials.