Working with dates and times

Dates and times come up constantly in Home Assistant templates. “How long ago did the door open?” “Is it past sunset?” “How many days until my next bin collection?” This page gathers the tools and patterns you need, in one place.

If you only need the current moment, start with now(). If you’re converting or formatting, jump to the formatting section. If you’re working with a timestamp from a sensor, head to the conversion section.

Getting the current time

now() and utcnow()

now() returns the current date and time in your configured time zone. utcnow() returns it in UTC.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
Local: {{ now() }}
UTC:   {{ utcnow() }}
Result
Local: 2026-04-04 14:30:00.123456+02:00
UTC:   2026-04-04 12:30:00.123456+00:00

Important

Templates that use now() or utcnow() re-run once per minute. This is how clock-based templates stay current. If you need something to refresh more often, base it on a state change instead.

today_at

today_at gives you a specific time on the current day, handy for “is it past bedtime?” checks.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{ today_at('22:00') }}
Result
2026-04-04 22:00:00+02:00

Accessing parts of a datetime

Once you have a datetime, you can pull out individual parts with dots.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
Year:    {{ now().year }}
Month:   {{ now().month }}
Day:     {{ now().day }}
Hour:    {{ now().hour }}
Minute:  {{ now().minute }}
Weekday: {{ now().weekday() }}
Result
Year:    2026
Month:   4
Day:     4
Hour:    14
Minute:  30
Weekday: 5

weekday() is 0 for Monday through 6 for Sunday. If you prefer the other convention, isoweekday() gives you 1 for Monday through 7 for Sunday.

Formatting with strftime

strftime turns a datetime into text, shaped the way you want. This is the single most useful method for displaying dates and times.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
24-hour:      {{ now().strftime('%H:%M') }}
12-hour:      {{ now().strftime('%I:%M %p') }}
Weekday:      {{ now().strftime('%A') }}
Short date:   {{ now().strftime('%Y-%m-%d') }}
Long date:    {{ now().strftime('%A, %B %-d, %Y') }}
Sentence:     {{ now().strftime('It is %A at %H:%M') }}
Result
24-hour:      14:30
12-hour:      02:30 PM
Weekday:      Saturday
Short date:   2026-04-04
Long date:    Saturday, April 4, 2026
Sentence:     It is Saturday at 14:30

Common format codes

Here are the ones you will use most often:

  • %Y: four-digit year (for example, 2026)
  • %m: zero-padded month (for example, 04)
  • %d: zero-padded day (for example, 04)
  • %-d: day without leading zero (for example, 4)
  • %H: hour in 24-hour format (for example, 14)
  • %M: minute (for example, 30)
  • %S: second (for example, 00)
  • %I: hour in 12-hour format (for example, 02)
  • %p: AM or PM
  • %A: full weekday name (for example, Saturday)
  • %a: short weekday name (for example, Sat)
  • %B: full month name (for example, April)
  • %b: short month name (for example, Apr)

The Python documentation has the full list of format codes if you need something unusual.

Parsing text into a datetime with strptime

strptime is the reverse of strftime. It takes a piece of text and a format string, and gives you back a datetime.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set event = strptime('2026-12-25 10:30', '%Y-%m-%d %H:%M') %}
{{ event }}
Result
2026-12-25 10:30:00

See the strptime reference for the full signature.

Converting between types

Sensors, APIs, and MQTT messages deliver timestamps in many different shapes. These functions convert between them.

UNIX timestamp to datetime

A UNIX timestamp is the number of seconds since January 1, 1970. Many APIs use them.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set ts = 1710510600 %}
Local: {{ ts | timestamp_local }}
UTC:   {{ ts | timestamp_utc }}
Custom: {{ ts | timestamp_custom('%H:%M on %B %d') }}
Result
Local: 2024-03-15 14:30:00+01:00
UTC:   2024-03-15 13:30:00+00:00
Custom: 14:30 on March 15

See timestamp_local, timestamp_utc, and timestamp_custom.

Datetime to UNIX timestamp

Use as_timestamp:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{ as_timestamp(now()) | int }}
Result
1743768600

Text to datetime

as_datetime is a forgiving version of strptime that tries to figure out common formats on its own.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{ as_datetime('2026-04-04 14:30:00') }}
Result
2026-04-04 14:30:00+02:00

Time differences

When you subtract two datetimes, you get a timedelta that represents the duration between them. Timedeltas support their own calculations and methods.

How long ago did something happen?

Every state has a last_changed timestamp. Subtract it from now() to get a timedelta.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set since = now() - states.binary_sensor.front_door.last_changed %}
Total seconds: {{ since.total_seconds() | int }}
Total minutes: {{ (since.total_seconds() / 60) | int }}
Result
Total seconds: 900
Total minutes: 15

For a human-readable version, reach for relative_time or time_since instead:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{ relative_time(states.binary_sensor.front_door.last_changed) }} ago
Result
15 minutes ago

Is it more than X minutes?

A common pattern: trigger an alert when something has been in a state too long.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{
  (now() - states.binary_sensor.front_door.last_changed)
  .total_seconds() > 600
}}
Result
True (when the door has been in its state for more than 10 minutes)

Counting down to a future date

time_until turns a future datetime into a human-readable duration.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set birthday = strptime('2026-12-25', '%Y-%m-%d') %}
Christmas: {{ time_until(birthday) }}
Result
Christmas: 8 months

Time zones

Home Assistant stores state timestamps (last_changed, last_updated) in your configured time zone. now() also returns your local time zone. utcnow() returns UTC.

If you need to compare datetimes, both sides need to be in the same time zone. as_datetime and strptime return datetimes without a time zone by default. Apply the matching conversion before comparing, or stick to timestamp_local and timestamp_utc which handle this for you.

Common gotchas

  • Text comparison vs time comparison. Comparing date-looking text with < or > compares alphabetically, not chronologically. Convert both sides to datetimes first.
  • timestamp_custom is not the only option. For datetime values (like now()), use .strftime(...) directly. timestamp_custom is specifically for UNIX timestamps.
  • Templates using now() re-run every minute. Don’t use it for things that should update more often.
  • Subtraction gives you a timedelta, not seconds. Call .total_seconds() on the result when you need a number.

Next steps