shellsystemdsystemctlsystemd-timer

Systemd timers - how to get Epoch timestamps?


I am creating a shell script that needs to calculate e.g. durations between different timestamps.

When shown with list-timers:

systemctl list-timers my

NEXT                        LEFT          LAST                        PASSED UNIT                 ACTIVATES             
Sat 2025-05-31 15:32:22 UTC 1min 45s left Sat 2025-05-31 15:29:22 UTC 1min 14s ago my.timer my.service

And in the show output:

systemctl show my.timer | grep Timestamp

StateChangeTimestamp=Sat 2025-05-31 15:29:22 UTC
StateChangeTimestampMonotonic=7574600882
InactiveExitTimestamp=Sat 2025-05-31 13:23:11 UTC
InactiveExitTimestampMonotonic=3241811
ActiveEnterTimestamp=Sat 2025-05-31 13:23:11 UTC
ActiveEnterTimestampMonotonic=3241811
ActiveExitTimestampMonotonic=0
InactiveEnterTimestampMonotonic=0
ConditionTimestamp=Sat 2025-05-31 13:23:11 UTC
ConditionTimestampMonotonic=3241785
AssertTimestamp=Sat 2025-05-31 13:23:11 UTC
AssertTimestampMonotonic=3241786

None of these are regular UNIX Epoch timestamps. It appears to be a chore to convert the formatted timestamps. The monotonic ones do not seem to be based accurately off anything in particular.

  1. Is there a way to get all the values as Epoch timestamps instead?
  2. Alternatively, what is the formula expressing relationship of *Timestamp and *TimestampMonotonic values?

In other words, how to obtain or calculate (what exact base value to add to the "monotonic" values and how to obtain it in order to get) Epoch timestamps?


Systemd uses CLOCK_REALTIME and CLOCK_MONOTONIC (of clock_gettime(2)) on its own, but there's no nice way to get them when implementing a shell script. What is possible is to infer the difference from systemctl show -p KernelTimestamp -p KernelTimestampMonotonic --time unix (and the monotonic is typically 0 there).

I will not edit this question further, not because I do not need further answers anymore, but because this is how someone will be searching for it - they will need to get timestamps from systemd and they will need them as Epoch timestamps. And some are only available as monotonic, so they will need to convert them. And some do not respect the --timestamp unix, so they will need DBus or systemd-analyze timestamp. Also, in a shell script, they will be looking at what they could grab off systemctl show output.

Hope this helps someone.


Solution

  • Is there a way to get all the values as Epoch timestamps instead?

    Use --timestamp unix.

    $ systemctl show --value --timestamp=unix --property=ActiveEnterTimestamp foo.timer
    ActiveEnterTimestamp=@1744548379
    

    If you're running systemd older than v247, bypass systemctl and query the properties directly via D-Bus (the properties themselves were available in all systemd versions):

    #!/bin/python3
    import dbus
    
    bus = dbus.SystemBus()
    
    manager = bus.get_object("org.freedesktop.systemd1",
                             "/org/freedesktop/systemd1")
    # manager = dbus.Interface(manager, "org.freedesktop.systemd1.Manager")
    unit_path = manager.GetUnit("sshd.service",
                                dbus_interface="org.freedesktop.systemd1.Manager")
    
    unit = bus.get_object("org.freedesktop.systemd1",
                          unit_path)
    timestamp_us = unit.Get("org.freedesktop.systemd1.Unit",
                            "ActiveEnterTimestamp",
                            dbus_interface="org.freedesktop.DBus.Properties")
    
    timestamp = timestamp_us / 1e6
    

    (pydbus might be more convenient but the legacy dbus-python is more widely available.)

    If you want "pure Bash":

    res=$(busctl call org.freedesktop.systemd1 \
                      /org/freedesktop/systemd1 \
                      org.freedesktop.systemd1.Manager GetUnit \
                      s "$unit")
    if [[ $res =~ ^o\ \"(.+)\"$ ]]; then
        obj=${BASH_REMATCH[1]}
        res=$(busctl get-property org.freedesktop.systemd1 \
                                  "$obj" \
                                  org.freedesktop.systemd1.Unit \
                                  ActiveEnterTimestamp)
        if [[ $res =~ ^t\ (.+)$ ]]; then
            timestamp_us=${BASH_REMATCH[1]}
            timestamp=$(( timestamp_us / 1000000 ))
        fi
    fi
    

    (It's not really "pure Bash" but I'm not about to implement the D-Bus binary protocol in Bash.)

    what is the formula expressing relationship of *Timestamp and *TimestampMonotonic values?

    They're independent timestamps, both obtained via clock_gettime() from two clocks kept by the kernel. The "epoch" of the monotonic clock is the time the system has booted; however, there is no formula for relationship between them, as the monotonic timestamp does not advance while the system is suspended whereas the wall clock does.

    The monotonic clock also does not react to manual adjustments of the wall clock – even if wall time jumps back/forward or is delayed/sped up by NTP sync, the monotonic clock continues advancing monotonically (hence the name).

    So if the difference between two monotonic timestamps is 10, that always means 10 seconds of "system running" time, which cannot be said about the difference between two wall-clock Unix epoch timestamps.

    Use lsclocks or Python time.clock_gettime() to compare the values.