Convert seconds to days, hours, minutes

This thread being named “Convert seconds to days, hours, minutes”, I hadn’t noticed your template is based on sensor.hass_uptime_minutes which has minute resolution.

My bad.

1 Like

He, really great, thanks @SupahNoob!

But where do you get the units from? And are they exchangable to jus ‘d’ instead of days for expample?
I tried googling after time formatting for jinja or pyhton but didn’t find a thing on what methods you are relying here.

I don’t necessarily think this has anything specifically to do what you are asking but here is something I wrote up a while back that has some info on time formatting:

Now there is an understatement.

1 Like

My apologies, I realized this is a 3-year-old thread. However, it’s still very relevant; and, easily searchable on Google.com.

I just wanted to post ChatGPT’s solution; which I think IMHO is the nicest solution out of all the examples above. The resulting output and the code itself are both easier to read. It also supports years and months, and does NOT unnecessarily display 0 years or 0 months or 0 weeks or 0 hours for those cases.

Output Example:
8d 11h 45m

sensor.rt_ac5300_uptime value is in seconds

template:
  - sensor:
      - name: "Asus Router Uptime"
        state: >
          {% set uptime = states.sensor.rt_ac5300_uptime.state | int %}
          {% set years = uptime // 31536000 %}
          {% set months = (uptime % 31536000) // 2592000 %}
          {% set days = (uptime % 2592000) // 86400 %}
          {% set hours = (uptime % 86400) // 3600 %}
          {% set minutes = (uptime % 3600) // 60 %}
          {{ '%dy ' % years if years else '' }}{{ '%dm ' % months if months else '' }}{{ '%dd ' % days if days else '' }}{{ '%dh ' % hours if hours else '' }}{{ '%dm' % minutes if minutes else '' }}
6 Likes

My UPS gives the time in seconds. I have added that to your ChatGPT example and it displays nicely.

      - type: custom:mushroom-template-card
        entity: sensor.ups_battery_runtime
        primary: Runtime
        secondary: |
          {% set uptime = states.sensor.ups_battery_runtime.state | int %} 
	  {% set years = uptime // 31536000 %} 
	  {% set months = (uptime % 31536000) // 2592000 %}
	  {% set days = (uptime % 2592000) // 86400 %}
	  {% set hours = (uptime % 86400) // 3600 %}
	  {% set minutes = (uptime % 3600) // 60 %}
	  {% set seconds = (uptime % 60) %} 
          {{ '%dy ' % years if years else '' }}
	  {{ '%dm ' % months if months else '' }}
	  {{ '%dd ' % days if days else '' }}
	  {{ '%dh ' % hours if hours else '' }}
	  {{ '%dm ' % minutes if minutes else '' }}
          {{ '%ds' % seconds if seconds else '' }}

Is there a way to get the minutes and seconds to always display 2 digits with a leading zero if necessary?

Thank you.

Screenshot 2023-06-23 at 21.54.10

`

1 Like

Nice! I purposefully didn’t add the seconds for mine since it was completely unnecessary in my case. But, nice that you were able to add seconds too.

Works well! Thank you very much!

So, I am trying the above timeticks conversion and am getting nowhere… I have my sensor configs in a sensors directory with files per device under that. This works and has worked for ages. But, when I put the below code in my mikrotik sensors file and run a configuration check it just sits and spins until I cut the code out and check it again… What have I done wrong? I have included the snmp sensor that sources the data and works fine.

  - platform: snmp
    name: "MT610 uptime"
    unique_id: mt610uptime
    host: 192.168.1.9
    community: homeread
    baseoid: .1.3.6.1.2.1.1.3.0
    accept_errors: true

  - platform: template
    sensors:
      mt610_real_uptime:
      friendly_name: Mt610 Real Uptime
      value_template: >-
        {% set time = states.sensor.mt610_uptime.state | int %}
        {% set minutes = ((time % 360000) / 6000) | int%}
        {% set hours = ((time % 8640000) / 360000) | int %}
        {% set days = (time / 8640000) | int %}

        {%- if time < 6000 -%}
          Less than a minute
        {%- else -%}
          {%- if days > 0 -%}
            {%- if days == 1 -%}
              1 day
            {%- else -%}
              {{ days }} days
            {%- endif -%}
          {%- endif -%}
          {%- if hours > 0 -%}
            {%- if days > 0 -%}
              {{ ', ' }}
            {%- endif -%}
            {%- if hours == 1 -%}
              1 hour
            {%- else -%}
              {{ hours }} hours
            {%- endif -%}
          {%- endif -%}
          {%- if minutes > 0 -%}
            {%- if days > 0 or hours > 0 -%}
              {{ ', ' }}
            {%- endif -%}
            {%- if minutes == 1 -%}
              1 minute
            {%- else -%}
              {{ minutes }} minutes
            {%- endif -%}
          {%- endif -%}
        {%- endif -%}

So, when I put the above template sensor it the template tool, it works. It is off a couple of minutes, but it works.

When I save it to the yaml file that has the associated snmp sensor, save it and run a configuration check the configuration check just spins and never resolves.

Running the following on an i5 USSF.
Home Assistant 2023.8.4
Supervisor 2023.08.1
Operating System 10.5
Frontend 20230802.1 - latest

Results of the template test:

- platform: template
    sensors:
      mt610_real_uptime:
      friendly_name: Mt610 Real Uptime
      value_template: >-
        
        
        
        8 days, 17 hours, 30 minutes

I think this is associated from the logs during check…

Logger: aiohttp.server
Source: helpers/config_validation.py:872
First occurred: 12:25:34 PM (3 occurrences)
Last logged: 12:29:04 PM

Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/aiohttp/web_protocol.py", line 433, in _handle_request
    resp = await request_handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/aiohttp/web_app.py", line 504, in _handle
    resp = await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/aiohttp/web_middlewares.py", line 117, in impl
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/http/security_filter.py", line 85, in security_filter_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/http/forwarded.py", line 100, in forwarded_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/http/request_context.py", line 28, in request_context_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/http/auth.py", line 236, in auth_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/http/view.py", line 148, in handle
    result = await handler(request, **request.match_info)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/config/core.py", line 33, in post
    errors = await async_check_ha_config_file(request.app["hass"])
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/config.py", line 978, in async_check_ha_config_file
    res = await check_config.async_check_ha_config_file(hass)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/check_config.py", line 235, in async_check_ha_config_file
    p_validated = platform_schema(p_validated)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/validators.py", line 232, in __call__
    return self._exec((Schema(val) for val in self.validators), v)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/validators.py", line 351, in _exec
    v = func(v)
        ^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 272, in __call__
    return self._compiled([], data)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 818, in validate_callable
    return schema(data)
           ^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 272, in __call__
    return self._compiled([], data)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 595, in validate_dict
    return base_validate(path, iteritems(data), out)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 387, in validate_mapping
    cval = cvalue(key_path, value)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 818, in validate_callable
    return schema(data)
           ^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/config_validation.py", line 568, in verify
    return cast(dict, schema(value))
                      ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 272, in __call__
    return self._compiled([], data)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 595, in validate_dict
    return base_validate(path, iteritems(data), out)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 387, in validate_mapping
    cval = cvalue(key_path, value)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/validators.py", line 229, in _run
    return self._exec(self._compiled, value, path)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/validators.py", line 353, in _exec
    v = func(path, v)
        ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 818, in validate_callable
    return schema(data)
           ^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/config_validation.py", line 872, in validator
    if key in config:
       ^^^^^^^^^^^^^
TypeError: argument of type 'NoneType' is not iterable
1 Like

im using this with a shunt in an off grid battery back up system. I have it working, but one thing id like to do is have it display the words “AC Power” when the unit is being charged. currently this code displays as per the attached photo when AC power is connected. Is there a way to do this.

Were you able to figure out how to resolve your problem?

Nope, would love to though.

I think the issue lies in the fact that states.sensor.mt610_uptime.state is unknown at the time of configuration check:

TypeError: argument of type 'NoneType' is not iterable

'| int’, '| float', etc. need default values so try changing:

        {% set time = states.sensor.mt610_uptime.state | int %}
        {% set minutes = ((time % 360000) / 6000) | int%}
        {% set hours = ((time % 8640000) / 360000) | int %}
        {% set days = (time / 8640000) | int %}

to:

        {% set time = states('sensor.mt610_uptime') | int(0) %}
        {% set minutes = ((time % 360000) // 6000) %}
        {% set hours = ((time % 8640000) // 360000) %}
        {% set days = (time // 8640000) %}

and see if configuration check can complete.

My personal use of the coding in this topic looks like this:

{% set uptime = as_timestamp(now(),0) - as_timestamp(states('sensor.system_started'),0) -%}
{%- set years = uptime // 31536000 -%}
{%- set months = uptime % 31536000 // 2592000 -%}
{%- set days = uptime % 2592000 // 86400 -%}
{%- set hours = uptime % 86400 // 3600 -%}
{%- set minutes = uptime % 3600 // 60 -%}
{{ '%dy ' % years if years else '' }}{{ '%dm ' % months if months else '' }}{{ '%dd ' % days if days else '' }}{{ '%dh ' % hours if hours else '' }}{{ '%dm' % minutes if minutes else '' }}

Note the use of ‘//’.

Floor division is an operation in Python that allows us to divide two numbers and rounds the resultant value down to the nearest integer. The floor division occurs through the double-backslash (//) operator .

So, gave it a shot… still will not verify config.

Also tried it with just the template in yaml file. It is definitely a problem in the main conversion logic.

It still works this way in template test, but still about 9 minutes off.

Same logs… included below and triggered by configuration check.

    sensors:
      mt610_real_uptime:
      friendly_name: Mt610 Real Uptime
      value_template: >-
        {% set time = states('sensor.mt610_uptime') | int(0) %}
        {% set minutes = ((time % 360000) // 6000) %}
        {% set hours = ((time % 8640000) // 360000) %}
        {% set days = (time // 8640000) %}

        {%- if time < 6000 -%}
          Less than a minute
        {%- else -%}
          {%- if days > 0 -%}
            {%- if days == 1 -%}
              1 day
            {%- else -%}
              {{ days }} days
            {%- endif -%}
          {%- endif -%}
          {%- if hours > 0 -%}
            {%- if days > 0 -%}
              {{ ', ' }}
            {%- endif -%}
            {%- if hours == 1 -%}
              1 hour
            {%- else -%}
              {{ hours }} hours
            {%- endif -%}
          {%- endif -%}
          {%- if minutes > 0 -%}
            {%- if days > 0 or hours > 0 -%}
              {{ ', ' }}
            {%- endif -%}
            {%- if minutes == 1 -%}
              1 minute
            {%- else -%}
              {{ minutes }} minutes
            {%- endif -%}
          {%- endif -%}
        {%- endif -%}
2024-01-01 22:43:54.095 ERROR (MainThread) [aiohttp.server] Error handling request
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/aiohttp/web_protocol.py", line 452, in _handle_request
    resp = await request_handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/aiohttp/web_app.py", line 543, in _handle
    resp = await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/aiohttp/web_middlewares.py", line 114, in impl
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/http/security_filter.py", line 85, in security_filter_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/http/forwarded.py", line 100, in forwarded_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/http/request_context.py", line 28, in request_context_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/http/auth.py", line 233, in auth_middleware
    return await handler(request)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/http/headers.py", line 31, in headers_middleware
    response = await handler(request)
               ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/http/view.py", line 149, in handle
    result = await handler(request, **request.match_info)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/http/decorators.py", line 63, in with_admin
    return await func(self, request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/config/core.py", line 34, in post
    res = await check_config.async_check_ha_config_file(request.app["hass"])
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/check_config.py", line 292, in async_check_ha_config_file
    p_validated = platform_schema(p_validated)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/validators.py", line 232, in __call__
    return self._exec((Schema(val) for val in self.validators), v)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/validators.py", line 351, in _exec
    v = func(v)
        ^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 272, in __call__
    return self._compiled([], data)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 818, in validate_callable
    return schema(data)
           ^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 272, in __call__
    return self._compiled([], data)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 595, in validate_dict
    return base_validate(path, iteritems(data), out)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 387, in validate_mapping
    cval = cvalue(key_path, value)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 818, in validate_callable
    return schema(data)
           ^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/config_validation.py", line 563, in verify
    return cast(dict, schema(value))
                      ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 272, in __call__
    return self._compiled([], data)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 595, in validate_dict
    return base_validate(path, iteritems(data), out)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 387, in validate_mapping
    cval = cvalue(key_path, value)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/validators.py", line 229, in _run
    return self._exec(self._compiled, value, path)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/validators.py", line 353, in _exec
    v = func(path, v)
        ^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/voluptuous/schema_builder.py", line 818, in validate_callable
    return schema(data)
           ^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/config_validation.py", line 866, in validator
    if key in config:
       ^^^^^^^^^^^^^
TypeError: argument of type 'NoneType' is not iterable

What does Dev Tools > Template show for {{ states('sensor.mt610_uptime') }}?

Try adding the sensor via HA Helpers > Template a sensor:

Can you try setting up the sensor using HA modern configuration?
I use modern style and my uptime sensor is this:

configuration.yaml:

template: !include_dir_merge_list templates/

templates/sensor.yaml:

- sensor:
  - name: "System Uptime"
    unique_id: system_uptime
    state: >
     {% set uptime = as_timestamp(now(),0) - as_timestamp(states('sensor.system_started'),0) -%}
     {%- set years = uptime // 31536000 -%}
     {%- set months = uptime % 31536000 // 2592000 -%}
     {%- set days = uptime % 2592000 // 86400 -%}
     {%- set hours = uptime % 86400 // 3600 -%}
     {%- set minutes = uptime % 3600 // 60 -%}
     {{ '%dy ' % years if years else '' }}{{ '%dm ' % months if months else '' }}{{ '%dd ' % days if days else '' }}{{ '%dh ' % hours if hours else '' }}{{ '%dm' % minutes if minutes else '' }}

You can use modern format within configuration.yaml without !include_dir_merge_list in which case your template would be:

template:
  - sensor:
    - name: "System Uptime"
      unique_id: system_uptime
      state: >
       {% set uptime = as_timestamp(now(),0) - as_timestamp(states('sensor.system_started'),0) -%}
   . . . 

It shows 432427643

So I currently have a /sensor/mikrotiksnmp.yaml file that pulls other snmp data and applies templates to all the different data. They are working… I have converted some of the included yaml files to the “modern” style, but I really do not understand the process fully. I can get them to work, but you know…

So, looking at the last block you have included it looks like that would provide the uptime already in proper format? There must be more to it? Can I include a template section in the configuration.yaml if I have !include files that also have templates?

I went ahead and added you block with my variable names to my configuration.yaml file in my existing new format template section and I kind of worked! I got a really wrong answer, but I got one. I think the Mikrotik uses linux timeticks as the base uptime.

sensor.mt610_ymd_uptime 54y 14d 14h 19m

Checked the system time in the cli and it is right on the money.

It looks to me like your years conversion factor is way off… The box shows 50 days, 1 hour and change in the management interface.

In the template helper…

50 days at 86,400 seconds/day is 4,320,000 but you have 432,427,643.
It looks like your mt610_uptime in timeticks has a timetick of 100 timeticks per second (100Hz).

Try this version of my formula:
{% set uptime = (as_timestamp(now(),0) - as_timestamp(states(‘sensor.system_started’),0)) // 100 -%}
{%- set years = uptime // 315360 -%}
{%- set months = uptime % 315360 // 25920 -%}
{%- set days = uptime % 2592000 // 86400 -%}
{%- set hours = uptime % 86400 // 3600 -%}
{%- set minutes = uptime % 3600 // 60 -%}

Yes, you can have legacy and modern styles mixed.

sensor:
  - platform: template
    sensors:
template:
  - sensor:

I put your template verbatim into my sensor.yaml file and I got the forever spinning wheel in Dev Tools > YAML > Check Configuration.
Your indenting is wrong. It should be:

  - platform: template
    sensors:
      mt610_real_uptime:
        friendly_name: Mt610 Real Uptime
        value_template: >-

With indentation corrected, config check completes.