Daylight Savings Time (DST) - Template and Automation

The thing is, timezone information is part of glibc, which pretty well every distro uses, although HAOS uses a buildroot, and I do not know which C library that uses. Nevertheless timezone data should be available on any system. Time zone data includes DST info - it has to in order to switch your device’s timezone when DST comes and goes.

So the info is available on the system.

EDIT: the zone information is compiled, and in most systems is in (for my zone) /usr/share/zoneinfo/Pacific/Aukland

After much googling there is an obscure program on linux systems (found in coreutils) that dumps some zoneinfo information in a semi digestible format, It can show your DST transitions. For example

nick@hass:~$ zdump -V -c 2021,2023 Pacific/Auckland
Pacific/Auckland  Sat Apr  3 13:59:59 2021 UT = Sun Apr  4 02:59:59 2021 NZDT isdst=1 gmtoff=46800
Pacific/Auckland  Sat Apr  3 14:00:00 2021 UT = Sun Apr  4 02:00:00 2021 NZST isdst=0 gmtoff=43200
Pacific/Auckland  Sat Sep 25 13:59:59 2021 UT = Sun Sep 26 01:59:59 2021 NZST isdst=0 gmtoff=43200
Pacific/Auckland  Sat Sep 25 14:00:00 2021 UT = Sun Sep 26 03:00:00 2021 NZDT isdst=1 gmtoff=46800
Pacific/Auckland  Sat Apr  2 13:59:59 2022 UT = Sun Apr  3 02:59:59 2022 NZDT isdst=1 gmtoff=46800
Pacific/Auckland  Sat Apr  2 14:00:00 2022 UT = Sun Apr  3 02:00:00 2022 NZST isdst=0 gmtoff=43200
Pacific/Auckland  Sat Sep 24 13:59:59 2022 UT = Sun Sep 25 01:59:59 2022 NZST isdst=0 gmtoff=43200
Pacific/Auckland  Sat Sep 24 14:00:00 2022 UT = Sun Sep 25 03:00:00 2022 NZDT isdst=1 gmtoff=46800

This shows transitions on April 3, 2021, Sept 25, 2021, April 2 , 2022 and Sept 24 2022. A bit of parsing required though, and there is no json output that I can see.

1 Like

This output may be simpler to parse

nick@hass:~$ zdump -i -c 2021,2023 Pacific/Auckland

TZ="Pacific/Auckland"
-       -       +13     NZDT    1
2021-04-04      02      +12     NZST
2021-09-26      03      +13     NZDT    1
2022-04-03      02      +12     NZST
2022-09-25      03      +13     NZDT    1
walaj@JonLabNUC:/home/homeassistant/.homeassistant/automations$ zdump -i -c 2021,2023 Australia/Sydney
zdump: invalid option -- 'i'
zdump: usage: zdump [--version] [--help] [-{vV}] [-{ct} [lo,]hi] zonename ...

Report bugs to <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
walaj@JonLabNUC:/home/homeassistant/.homeassistant/automations$ zdump --version
zdump (Ubuntu GLIBC 2.23-0ubuntu11.3) 2.23

Interesting, maybe the versions are different between debian and ubuntu. What does man zdump and/or zdump --help tell you?

nick@hass:~$ zdump --version
zdump (Debian GLIBC 2.31-13+deb11u2) 2.31

I’m on ubuntu 16.04 - its pretty old.

walaj@JonLabNUC:/home/homeassistant/.homeassistant/automations$ zdump --help
zdump: usage: zdump [--version] [--help] [-{vV}] [-{ct} [lo,]hi] zonename ...

Report bugs to <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.

lol.

Yes, this is ultimately the problem with all languages too. This is why you have to loop until you find the datetime because the APIs do not offer it. They only tell you when it’s applied or not. I can get all of that information directly from the datetime library, and you have access to them in templates.

This is why I was saying the code I provided can be optimized. It’s currently using the time zone because originally dst() wasn’t exposed to templates. It always returned null. After switching to pytz, it now is populated in the template engine.

I updated it, it’s now 3 separate sensors. Try it out and let me know if it works. The automation changed too. It should properly tell you the gain/lose

@mobile.andrew.jones

I also optimized it. It now does a maximum of 449 calcs opposed to the previous one which was upwards of 7565 calcs

OK the first 2 work in template editor, but the last one won’t render for me:

ValueError: not enough values to unpack (expected 3, got 1)

I set

{% set daylight_savings_next = "2022-03-27T02:00:00+00:00" %}

Which was returned from the first template, and then replace states('sensor.daylight_savings_next') with just daylight_savings_next which for the second template correctly renders and returns 146 days.

ok, try it now

TypeError: bad operand type for abs(): 'str'

You pulled the rest one, not the offline one

Nope, refreshed the post too just to be sure I have the latest edit.

{% set daylight_savings_next = "2022-03-27T02:00:00+00:00" %}
      {%- macro hms(t) %}
      {%- set h, m, s = (t.dst() | string).split(':') | map('int') %}
      {{- h * 60 * 60 + m * 60 + s }}
      {%- endmacro %}

      {%- macro phrase(seconds, name, divisor, mod=None) %}
        {%- set value = ((seconds | abs // divisor) % (mod if mod else divisor)) | int %}
        {%- set end = 's' if value > 1 else '' %}
        {{- '{} {}{}'.format(value, name, end) if value > 0 else '' }}
      {%- endmacro %}

      {%- macro total(seconds) %}
      {%- set values = [ 
        phrase(seconds, 'hour', 60*60, 60*60*24),
        phrase(seconds, 'minute', 60, 60),
        ] | select('!=','') | list %}
      {{- values[:-1] | join(', ') ~ ' and ' ~ values[-1] if values | length > 1 else values | first }}
      {%- endmacro %}

      {%- set next = daylight_savings_next | as_datetime | as_local %}
      {%- if next is not none %}
        {%- set ns = hms(next) %}
        {%- set ps = hms(next - timedelta(days=1)) %}
        {% if ns %}
          lose {{ total(ns) }}
        {% else %}
          gain {{ total(ps) }}
        {% endif %}
      {%- endif %}

Returns that error.

ah missing the ints

Yup adding | int after seconds has done the job.
lose 1 hour

That’s correct.

EDIT:
Thank you for your efforts, it’s very much appreciated. I have now copied the code in to daylight_savings.yaml in my template directory and will shortly have shiny new sensors!

1 Like

you might want to lose the unit there :wink:

yep, done. Thanks

Just got caught out by this as I was adding to someone else’s server… haha

Yes, according to man zdump, it iterates over dates/times to identify transitions.

btw:

2021-11-01 21:32:10 ERROR (MainThread) [homeassistant.helpers.event] Error while processing template: Template("{%- macro hms(t) %} {%- set h, m, s = (t.dst() | string).split(':') | map('int') %} {{- h * 60 * 60 + m * 60 + s }} {%- endmacro %}

and

2021-11-01 21:32:15 WARNING (MainThread) [homeassistant.helpers.template] Template warning: 'int' got invalid input ' None' when rendering template '{%- macro hms(t) %} {%- set h, m, s = (t.dst() | string).split(':') | map('int') %} {{- h * 60 * 60 + m * 60 + s }} {%- endmacro %}

show at startup.