<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: mkt</title>
    <description>The latest articles on DEV Community by mkt (@mkt).</description>
    <link>https://dev.to/mkt</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3533376%2F53a2bbf3-6313-480b-bd79-92c15c8c0546.jpg</url>
      <title>DEV Community: mkt</title>
      <link>https://dev.to/mkt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mkt"/>
    <language>en</language>
    <item>
      <title>Moving Away from sudo su (Ubuntu 26.04, sudo-rs)</title>
      <dc:creator>mkt</dc:creator>
      <pubDate>Tue, 22 Sep 2026 07:07:54 +0000</pubDate>
      <link>https://dev.to/mkt/moving-away-from-sudo-su-ubuntu-2604-sudo-rs-480d</link>
      <guid>https://dev.to/mkt/moving-away-from-sudo-su-ubuntu-2604-sudo-rs-480d</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;sudo -i&lt;/code&gt; (or &lt;code&gt;sudo -s&lt;/code&gt;) instead of &lt;code&gt;sudo su&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In Ubuntu 26.04, the traditional &lt;code&gt;sudo&lt;/code&gt; implementation has been replaced by &lt;code&gt;sudo-rs&lt;/code&gt;, and signal handling seems to have changed slightly. As a result, if your SSH connection drops while you are running &lt;code&gt;sudo su&lt;/code&gt;, the &lt;code&gt;sudo su&lt;/code&gt; processes can stay alive indefinitely...&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Noticed
&lt;/h2&gt;

&lt;p&gt;While setting up an Ubuntu Server 26.04 machine over SSH, I happened to look at the process tree in &lt;code&gt;htop&lt;/code&gt; and noticed several &lt;code&gt;sudo su&lt;/code&gt; processes running.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc6uadglpcawn8nqo87xj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc6uadglpcawn8nqo87xj.png" alt="Process tree showing sudo su processes left running directly under PID 1" width="799" height="153"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;None of them were running under &lt;code&gt;tmux&lt;/code&gt;; they were all children of PID 1.&lt;/p&gt;

&lt;p&gt;What was going on...?&lt;/p&gt;

&lt;p&gt;I decided to investigate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Investigating the Cause
&lt;/h2&gt;

&lt;p&gt;Here's the environment I used for testing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ubuntu Server 26.04&lt;/li&gt;
&lt;li&gt;sudo-rs (0.2.13-0ubuntu1.2)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reproducing the Issue
&lt;/h3&gt;

&lt;p&gt;After running a range of tests on an Ubuntu Server 26.04 virtual machine, I confirmed that the &lt;code&gt;sudo su&lt;/code&gt; processes stayed alive under the following conditions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect to the server over SSH.&lt;/li&gt;
&lt;li&gt;Start a root shell with &lt;code&gt;sudo su&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Force the SSH connection to close by closing the local terminal.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With a reproducible case, I could start narrowing down the cause.&lt;/p&gt;

&lt;h3&gt;
  
  
  "sudo su" vs. "sudo -i"
&lt;/h3&gt;

&lt;p&gt;While looking into &lt;code&gt;sudo su&lt;/code&gt;, I learned that these days, the recommendation is to use &lt;code&gt;sudo -i&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;I repeated the same test with &lt;code&gt;sudo -i&lt;/code&gt;, and no &lt;code&gt;sudo&lt;/code&gt; processes remained after the SSH connection closed. That suggested the &lt;code&gt;su&lt;/code&gt; part of &lt;code&gt;sudo su&lt;/code&gt; was involved.&lt;/p&gt;

&lt;p&gt;With a likely cause in mind, I gave ChatGPT access to the virtual machine and asked it to investigate what was happening.&lt;/p&gt;

&lt;p&gt;Here's a rough summary of what it found. This is a simplified explanation, not a technically precise one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When an SSH connection closes, processes such as the shell launched by SSH are notified of the disconnect through SIGHUP. Whether a parent process forwards SIGHUP to its children depends on the implementation, but programs such as &lt;code&gt;sudo&lt;/code&gt; and &lt;code&gt;bash&lt;/code&gt; do forward it.&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;sudo su&lt;/code&gt;, &lt;code&gt;su&lt;/code&gt; blocks SIGHUP. As a result, the &lt;code&gt;sudo su&lt;/code&gt; processes do not exit unless their child process exits on its own (i.e., the &lt;code&gt;bash&lt;/code&gt; process running under &lt;code&gt;sudo su&lt;/code&gt; stays alive).&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;sudo -i&lt;/code&gt;, the shell launched by &lt;code&gt;sudo&lt;/code&gt; sends SIGHUP to its child process. Once that process exits, &lt;code&gt;sudo -i&lt;/code&gt; exits naturally as well.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, it seems that SIGHUP from the SSH disconnect did not terminate &lt;code&gt;sudo su&lt;/code&gt; or the processes beneath it. When its parent process exited, &lt;code&gt;sudo su&lt;/code&gt; was reparented to PID 1.&lt;/p&gt;

&lt;h3&gt;
  
  
  "sudo" vs. "sudo-rs"
&lt;/h3&gt;

&lt;p&gt;But I hadn't seen this happen on Ubuntu 24.04 or earlier...&lt;/p&gt;

&lt;p&gt;Then I remembered that Ubuntu 26.04 uses &lt;code&gt;sudo-rs&lt;/code&gt; as its &lt;code&gt;sudo&lt;/code&gt; implementation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User management — sudo-rs (Ubuntu Server documentation): &lt;a href="https://ubuntu.com/server/docs/how-to/security/user-management/#sudo-rs" rel="noopener noreferrer"&gt;https://ubuntu.com/server/docs/how-to/security/user-management/#sudo-rs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I switched from &lt;code&gt;sudo-rs&lt;/code&gt; back to the traditional &lt;code&gt;sudo&lt;/code&gt; implementation and repeated the test. This time, the &lt;code&gt;sudo su&lt;/code&gt; processes exited properly when the SSH connection closed.&lt;/p&gt;

&lt;p&gt;So it seemed that &lt;code&gt;sudo-rs&lt;/code&gt; handled SIGHUP differently from the traditional &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;At this point, I asked ChatGPT to look into the implementations of both the traditional &lt;code&gt;sudo&lt;/code&gt; (the sudo-project version) and &lt;code&gt;sudo-rs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;From that investigation, it appeared that the traditional &lt;code&gt;sudo&lt;/code&gt; has its own logic for cleaning up child processes when the TTY disconnects, while the newer &lt;code&gt;sudo-rs&lt;/code&gt; does not currently seem to handle that situation well. I haven't modified either implementation to test this, so I can't be certain.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub sudo-project/sudo exec_pty.c: &lt;a href="https://github.com/sudo-project/sudo/blob/1815241c464259564541cc6306e12f2763691d92/src/exec_pty.c#L335-L360" rel="noopener noreferrer"&gt;https://github.com/sudo-project/sudo/blob/1815241c464259564541cc6306e12f2763691d92/src/exec_pty.c#L335-L360&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub trifectatechfoundation/sudo-rs, issue "Better handling of closed user tty": &lt;a href="https://github.com/trifectatechfoundation/sudo-rs/issues/1379" rel="noopener noreferrer"&gt;https://github.com/trifectatechfoundation/sudo-rs/issues/1379&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;sudo-rs&lt;/code&gt; implementation used in Ubuntu 26.04 handles signals differently from the traditional &lt;code&gt;sudo&lt;/code&gt;. This seems like a good opportunity to move away from &lt;code&gt;sudo su&lt;/code&gt; and use &lt;code&gt;sudo -i&lt;/code&gt; (or &lt;code&gt;sudo -s&lt;/code&gt;) instead.&lt;/p&gt;

&lt;p&gt;You could perhaps call this a bug in &lt;code&gt;sudo-rs&lt;/code&gt;. Still, considering that the traditional &lt;code&gt;sudo&lt;/code&gt; has extra logic to work around the issue with &lt;code&gt;sudo su&lt;/code&gt;, avoiding &lt;code&gt;sudo su&lt;/code&gt; may be the safer choice.&lt;/p&gt;

&lt;p&gt;That said, seeing &lt;code&gt;sudo su&lt;/code&gt; processes linger under PID 1 is still pretty unsettling...&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;On Ubuntu 26.04, you can switch between &lt;code&gt;sudo&lt;/code&gt; implementations with the following command:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;update-alternatives &lt;span class="nt"&gt;--config&lt;/span&gt; &lt;span class="nb"&gt;sudo

&lt;/span&gt;There are 2 choices &lt;span class="k"&gt;for &lt;/span&gt;the alternative &lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;providing /usr/bin/sudo&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

  Selection    Path                     Priority   Status
&lt;span class="nt"&gt;------------------------------------------------------------&lt;/span&gt;
&lt;span class="k"&gt;*&lt;/span&gt; 0            /usr/lib/cargo/bin/sudo   50        auto mode
  1            /usr/bin/sudo.ws          40        manual mode
  2            /usr/lib/cargo/bin/sudo   50        manual mode

Press &amp;lt;enter&amp;gt; to keep the current choice[&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;, or &lt;span class="nb"&gt;type &lt;/span&gt;selection number:
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can also run either &lt;code&gt;sudo&lt;/code&gt; implementation using its absolute path shown above, without changing the system-wide selection.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;As a related aside, I learned that &lt;code&gt;nohup&lt;/code&gt; deliberately ignores SIGHUP (&lt;code&gt;SIG_IGN&lt;/code&gt;), rather than blocking it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;User management — sudo-rs (Ubuntu Server documentation): &lt;a href="https://ubuntu.com/server/docs/how-to/security/user-management/#sudo-rs" rel="noopener noreferrer"&gt;https://ubuntu.com/server/docs/how-to/security/user-management/#sudo-rs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;sudo-project/sudo (GitHub): &lt;a href="https://github.com/sudo-project/sudo" rel="noopener noreferrer"&gt;https://github.com/sudo-project/sudo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;trifectatechfoundation/sudo-rs (GitHub): &lt;a href="https://github.com/trifectatechfoundation/sudo-rs" rel="noopener noreferrer"&gt;https://github.com/trifectatechfoundation/sudo-rs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Change History
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;2026/09/22: First version.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Personal Blog: &lt;a href="https://mkt-sidenotes.dev/ja/tech/2026-09-20-do-not-use-sudo-su-ubuntu-26/" rel="noopener noreferrer"&gt;https://mkt-sidenotes.dev/ja/tech/2026-09-20-do-not-use-sudo-su-ubuntu-26/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>command</category>
      <category>sudo</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>Visualizing Year/Month/Day Progress in Grafana</title>
      <dc:creator>mkt</dc:creator>
      <pubDate>Sun, 30 Nov 2025 09:21:51 +0000</pubDate>
      <link>https://dev.to/mkt/visualizing-yearmonthday-progress-in-grafana-1mf4</link>
      <guid>https://dev.to/mkt/visualizing-yearmonthday-progress-in-grafana-1mf4</guid>
      <description>&lt;p&gt;As of writing this post (2025/11/30), apparently around 90% of this year has already passed.&lt;/p&gt;

&lt;p&gt;

&lt;iframe class="tweet-embed" id="tweet-1993184119292149949-95" src="https://platform.twitter.com/embed/Tweet.html?id=1993184119292149949"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1993184119292149949-95');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1993184119292149949&amp;amp;theme=dark"
  }





&lt;/p&gt;

&lt;p&gt;I use Grafana and Prometheus for system monitoring, and I thought it would be cool to see "How much of this year has passed?" directly on my Grafana dashboard.&lt;/p&gt;

&lt;p&gt;So I built it!&lt;/p&gt;

&lt;p&gt;While I was at it, I decided to show not only the progress of this year but also the progress of this month and today.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Here's what the panel looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfarvz0hff5d6qx4c31b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfarvz0hff5d6qx4c31b.png" alt="Time Progress Panel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After some trial and error, I managed to create this using only Grafana and Prometheus (PromQL), which I already use every day.&lt;/p&gt;

&lt;p&gt;The PromQL queries to calculate each value (for UTC) are as follows:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This Year (UTC)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(
  ((day_of_year() - 1) * (3600 * 24)) + (time() % (3600 * 24))
)
/
(
  (365 + (day_of_year() != bool day_of_year(vector(time() + 3600 * 24 * 365)))) * 3600 * 24
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;This Month (UTC)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(
  ((day_of_month() - 1) * (3600 * 24)) + (time() % (3600 * 24))
)
/
(
  days_in_month() * (3600 * 24)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Today (UTC)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(time() % (3600 * 24)) / (3600 * 24)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you want to display progress in a timezone other than UTC, simply add the appropriate offset (in seconds) to your queries.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UTC+9 (Japan Standard Time; JST): add &lt;code&gt;3600 * 9&lt;/code&gt; (= 32400) seconds&lt;/li&gt;
&lt;li&gt;UTC+2: add &lt;code&gt;3600 * 2&lt;/code&gt; (= 7200) seconds&lt;/li&gt;
&lt;li&gt;UTC-5: add &lt;code&gt;3600 * -5&lt;/code&gt; (= -18000) seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Replace the offsets in the queries to match your local timezone.&lt;/p&gt;

&lt;p&gt;Below are JST examples:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This Year (JST)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# JST
(
  (day_of_year(vector(time() + 3600 * 9) - 1) * 3600 * 24) + ((time() + 3600 * 9) % (3600 * 24) )
)
/
(
  (365 + (day_of_year(vector(time() + 3600 * 9)) != bool day_of_year(vector(time() + 3600 * 9 + 3600 * 24 * 365)))) * 3600 * 24
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;This Month (JST)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# JST
(
  ((day_of_month(vector(time() + 3600 * 9)) - 1) * (3600 * 24)) + ((time() + 3600 * 9) % (3600 * 24))
)
/
(
  days_in_month(vector(time() + 3600 * 9)) * (3600 * 24)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Today (JST)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# JST
((time() + 3600 * 9) % (3600 * 24)) / (3600 * 24)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you know a better way to do this, let me know 🙇‍♂️&lt;/p&gt;
&lt;h2&gt;
  
  
  Test Environment
&lt;/h2&gt;

&lt;p&gt;Here's the environment I used for testing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ubuntu Server 24.04

&lt;ul&gt;
&lt;li&gt;Grafana: 12.3.0&lt;/li&gt;
&lt;li&gt;Prometheus: 2.45.3 (the version available via apt on Ubuntu 24.04)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: I used Prometheus 2.x for testing. Things might be simpler with 3.x, but I haven't tried yet.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Calculation Formulas
&lt;/h2&gt;

&lt;p&gt;To visualize how much of today, this month, and this year has passed (which I'll call the "progress"), you need to calculate these values.&lt;/p&gt;

&lt;p&gt;The formulas themselves are pretty straightforward: subtract the unixtime at the start of day/month/year from the current unixtime, then divide by the total seconds in day/month/year.&lt;/p&gt;

&lt;p&gt;So, if you can express PromQL queries that match the following formulas, you're good to go:&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Today’s&amp;nbsp;Progress&amp;nbsp;(%)&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mopen nulldelimiter"&gt;&lt;/span&gt;&lt;span class="mfrac"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;3600&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;24&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="frac-line"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Current&amp;nbsp;Unixtime&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Unixtime&amp;nbsp;at&amp;nbsp;Today’s&amp;nbsp;00:00&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose nulldelimiter"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;




&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;This&amp;nbsp;Month’s&amp;nbsp;Progress&amp;nbsp;(%)&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mopen nulldelimiter"&gt;&lt;/span&gt;&lt;span class="mfrac"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;3600&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;24&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Days&amp;nbsp;in&amp;nbsp;Month&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="frac-line"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Current&amp;nbsp;Unixtime&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Unixtime&amp;nbsp;at&amp;nbsp;00:00&amp;nbsp;of&amp;nbsp;the&amp;nbsp;1st&amp;nbsp;Day&amp;nbsp;of&amp;nbsp;Month&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose nulldelimiter"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;



&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;This&amp;nbsp;Year’s&amp;nbsp;Progress&amp;nbsp;(%)&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mopen nulldelimiter"&gt;&lt;/span&gt;&lt;span class="mfrac"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;3600&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;24&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Days&amp;nbsp;in&amp;nbsp;Year&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="frac-line"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Current&amp;nbsp;Unixtime&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Unixtime&amp;nbsp;at&amp;nbsp;00:00&amp;nbsp;of&amp;nbsp;Jan&amp;nbsp;1st&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose nulldelimiter"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;100&lt;/span&gt;&lt;span class="mspace"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;


&lt;p&gt;&lt;em&gt;Note: I didn't account for daylight saving time (DST) here.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PromQL Queries
&lt;/h2&gt;

&lt;p&gt;Let's implement the formulas above using Prometheus Query Language (PromQL), which provides a number of helpful built-in functions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prometheus docs: &lt;a href="https://prometheus.io/docs/prometheus/latest/querying/functions/" rel="noopener noreferrer"&gt;https://prometheus.io/docs/prometheus/latest/querying/functions/&lt;/a&gt;
(&lt;em&gt;Note: Prometheus 2.x and 3.x differ in some literals and syntax. Be careful!&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One thing to keep in mind: PromQL's time functions operate in UTC. If you want values in your local timezone, you must add an offset manually.&lt;/p&gt;

&lt;p&gt;The following explanations are a bit log, so if you just want the final queries, feel free to scroll back to the TL;DR section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Today's Progress
&lt;/h3&gt;

&lt;p&gt;First, let's calculate today's progress.&lt;/p&gt;


&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Today’s&amp;nbsp;Progress&amp;nbsp;(%)&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mopen nulldelimiter"&gt;&lt;/span&gt;&lt;span class="mfrac"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;3600&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;24&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="frac-line"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Current&amp;nbsp;Unixtime&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Unixtime&amp;nbsp;at&amp;nbsp;Today’s&amp;nbsp;00:00&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose nulldelimiter"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;


&lt;p&gt;In PromQL, you can get the current unixtime by the &lt;code&gt;time()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;You can also calculate today's 00:00 unixtime using the &lt;code&gt;day_of_year()&lt;/code&gt; function, but you don't need to. The number of seconds since 00:00 can be calculated by taking the remainder of the unixtime divided by 86400 (&lt;code&gt;= 3600 * 24&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;So we can use modulo directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# UTC
(time() % (3600 * 24)) / (3600 * 24)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;GitHub Gist: &lt;a href="https://gist.github.com/md-irohas/e8289be61c554d0b59fdd36fa085f5fe#file-1_today-progress-utc-promql" rel="noopener noreferrer"&gt;https://gist.github.com/md-irohas/e8289be61c554d0b59fdd36fa085f5fe#file-1_today-progress-utc-promql&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to display the value in your local timezone, add the appropriate offset in seconds. For example, for JST (UTC+9), add &lt;code&gt;3600 * 9&lt;/code&gt; (= 32400) seconds.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# JST
((time() + 3600 * 9) % (3600 * 24)) / (3600 * 24)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;GitHub Gist: &lt;a href="https://gist.github.com/md-irohas/e8289be61c554d0b59fdd36fa085f5fe#file-2_today-progress-jst-promql" rel="noopener noreferrer"&gt;https://gist.github.com/md-irohas/e8289be61c554d0b59fdd36fa085f5fe#file-2_today-progress-jst-promql&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Grafana can multiply by 100 for percentage formatting, so you can leave the raw ratio as-is.&lt;/p&gt;
&lt;h3&gt;
  
  
  This Month's Progress
&lt;/h3&gt;

&lt;p&gt;Next, this month's progress.&lt;/p&gt;


&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;This&amp;nbsp;Month’s&amp;nbsp;Progress&amp;nbsp;(%)&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mopen nulldelimiter"&gt;&lt;/span&gt;&lt;span class="mfrac"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;3600&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;24&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Days&amp;nbsp;in&amp;nbsp;Month&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="frac-line"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Current&amp;nbsp;Unixtime&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Unixtime&amp;nbsp;at&amp;nbsp;00:00&amp;nbsp;of&amp;nbsp;the&amp;nbsp;1st&amp;nbsp;Day&amp;nbsp;of&amp;nbsp;Month&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose nulldelimiter"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;



&lt;p&gt;Getting the current unixtime is the same as before, but the tricky part is "Unixtime at 00:00 of the 1st Day of Month" and "Days in Month".&lt;/p&gt;

&lt;p&gt;Obviously, the number of days in a month varies, so you can't use modulo like I did for today's progress.&lt;/p&gt;

&lt;p&gt;Fortunately, PromQL provides the &lt;code&gt;days_in_month()&lt;/code&gt; function for the latter.&lt;/p&gt;

&lt;p&gt;Then, how do you get the unixtime for the 1st day of the month?&lt;/p&gt;

&lt;p&gt;You don't need to calculate it directly. PromQL has a &lt;code&gt;day_of_month()&lt;/code&gt; function that returns the current day of the month, so you can write the numerator as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(day_of_month() - 1) * (3600 * 24)  # Seconds for previous days
+ (time() % (3600 * 24))            # Seconds for today
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So, the query for this month's progress looks like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# UTC
(
  ((day_of_month() - 1) * (3600 * 24)) + (time() % (3600 * 24))
)
/
(
  days_in_month() * (3600 * 24)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;GitHub Gist: &lt;a href="https://gist.github.com/md-irohas/e8289be61c554d0b59fdd36fa085f5fe#file-3_this-month-progress-utc-promql" rel="noopener noreferrer"&gt;https://gist.github.com/md-irohas/e8289be61c554d0b59fdd36fa085f5fe#file-3_this-month-progress-utc-promql&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For other timezones, you need to make sure &lt;code&gt;day_of_month()&lt;/code&gt; and &lt;code&gt;days_in_month()&lt;/code&gt; are calculated in your local timezone, not UTC. These functions accept a unixtime (as a vector) as an argument, so you can use your offset-adjusted time.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# JST
(
  ((day_of_month(vector(time() + 3600 * 9)) - 1) * (3600 * 24)) + ((time() + 3600 * 9) % (3600 * 24))
)
/
(
  days_in_month(vector(time() + 3600 * 9)) * (3600 * 24)
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;GitHub Gist: &lt;a href="https://gist.github.com/md-irohas/e8289be61c554d0b59fdd36fa085f5fe#file-4_this-month-progress-jst-promql" rel="noopener noreferrer"&gt;https://gist.github.com/md-irohas/e8289be61c554d0b59fdd36fa085f5fe#file-4_this-month-progress-jst-promql&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's a bit tricky, but it works!&lt;/p&gt;
&lt;h3&gt;
  
  
  This Year's Progress
&lt;/h3&gt;

&lt;p&gt;Finally, this year's progress.&lt;/p&gt;


&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;This&amp;nbsp;Year’s&amp;nbsp;Progress&amp;nbsp;(%)&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mopen nulldelimiter"&gt;&lt;/span&gt;&lt;span class="mfrac"&gt;&lt;span class="vlist-t vlist-t2"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;3600&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;24&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Days&amp;nbsp;in&amp;nbsp;Year&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="frac-line"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Current&amp;nbsp;Unixtime&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;−&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord text"&gt;&lt;span class="mord"&gt;Unixtime&amp;nbsp;at&amp;nbsp;00:00&amp;nbsp;of&amp;nbsp;Jan&amp;nbsp;1st&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-s"&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose nulldelimiter"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;



&lt;p&gt;Just like with the month, you can use the &lt;code&gt;day_of_year()&lt;/code&gt; function to get the number of seconds since the start of the year:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(day_of_year() - 1) * (3600 * 24) # Seconds for previous days
+ (time() % (3600 * 24))          # Seconds for today
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only missing piece is "Days in Year".&lt;/p&gt;

&lt;p&gt;Years normally have 365 days, but leap years have 366. If you've ever taken a programming class, you've probably written an if-else statement to check for leap years. But PromQL doesn't have if-else clause, and there's no handy &lt;code&gt;days_in_year()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;So, I asked ChatGPT for help, and it suggested the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# PromQL to calculate the number of days in the year
365
+ clamp_max(
  (
    (
      ((floor(vector(time()) / 31557600) + 1970) % 400) == bool 0
    )
    +
    (
      (((floor(vector(time()) / 31557600) + 1970) % 4) == bool 0)
      *
      (((floor(vector(time()) / 31557600) + 1970) % 100) != bool 0)
    )
  ),
  1
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;31557600 represents 365.25 days * 86400 seconds, an approximation for a year. By dividing the unixtime by this value, you can get the year difference since 1970.&lt;/p&gt;

&lt;p&gt;Also, you can use the &lt;code&gt;bool&lt;/code&gt; modifier to simulate conditional logic. Comparisons return true/false as 1/0, so you can mimic simple if-else behavior.&lt;/p&gt;

&lt;p&gt;Interesting... but since it's an approximation, there might be some error (I haven't checked how much it is).&lt;/p&gt;

&lt;p&gt;After thinking a bit, I realized we can use PromQL's &lt;code&gt;day_of_year()&lt;/code&gt; function to check for leap years. Specifically, if it is a leap year, the length of the year is 366 days, so if you calculate &lt;code&gt;day_of_year()&lt;/code&gt; at the same time 365 days (
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;3600&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;24&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;×&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;365&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 seconds) later, the value must be different from the current value.&lt;/p&gt;

&lt;p&gt;So, you can calculate the number of days in the year like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# PromQL to calculate if this year has 365 or 366 days
365
+
(
  day_of_year() != bool day_of_year(vector(time() + (3600 * 24 * 365)))   # Returns 1 or 0
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final query for this year's progress is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# UTC
(
  ((day_of_year() - 1) * (3600 * 24)) + (time() % (3600 * 24))
)
/
(
  (365 + (day_of_year() != bool day_of_year(vector(time() + 3600 * 24 * 365)))) * 3600 * 24
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;GitHub Gist: &lt;a href="https://gist.github.com/md-irohas/e8289be61c554d0b59fdd36fa085f5fe#file-5_this-year-progress-utc-promql" rel="noopener noreferrer"&gt;https://gist.github.com/md-irohas/e8289be61c554d0b59fdd36fa085f5fe#file-5_this-year-progress-utc-promql&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's a bit hard to read, but the same logic applies for any timezone. Just adjust the offset in the query to match your local timezone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# JST
(
  (day_of_year(vector(time() + 3600 * 9) - 1) * 3600 * 24) + ((time() + 3600 * 9) % (3600 * 24) )
)
/
(
  (365 + (day_of_year(vector(time() + 3600 * 9)) != bool day_of_year(vector(time() + 3600 * 9 + 3600 * 24 * 365)))) * 3600 * 24
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;GitHub Gist: &lt;a href="https://gist.github.com/md-irohas/e8289be61c554d0b59fdd36fa085f5fe#file-6_this-year-progress-jst-promql" rel="noopener noreferrer"&gt;https://gist.github.com/md-irohas/e8289be61c554d0b59fdd36fa085f5fe#file-6_this-year-progress-jst-promql&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this, you have all the PromQL queries you need for visualization.&lt;/p&gt;

&lt;p&gt;I haven't thoroughly tested all edge cases, so if you spot a bug, please let me know!&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualizing in Grafana
&lt;/h2&gt;

&lt;p&gt;Once the queries are ready, all that's left is to create your favorite panel in Grafana.&lt;/p&gt;

&lt;p&gt;To make a panel like the screenshot above, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a new panel to your dashboard.&lt;/li&gt;
&lt;li&gt;Select "Bar gauge" as the visualization type.&lt;/li&gt;
&lt;li&gt;Choose Prometheus as the data source (assuming you've already added it).&lt;/li&gt;
&lt;li&gt;Paste the queries for year, month, and day progress. Set the legend to "This Year", "This Month", and "Today" respectively.&lt;/li&gt;
&lt;li&gt;In the right sidebar, configure:

&lt;ul&gt;
&lt;li&gt;Bar gauge:

&lt;ul&gt;
&lt;li&gt;Orientation: Horizontal&lt;/li&gt;
&lt;li&gt;Display mode: Retro LCD&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Standard options:

&lt;ul&gt;
&lt;li&gt;Unit: Misc / Percent (0.0-1.0)&lt;/li&gt;
&lt;li&gt;Min: 0&lt;/li&gt;
&lt;li&gt;Max: 1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This should give you a panel that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfarvz0hff5d6qx4c31b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpfarvz0hff5d6qx4c31b.png" alt="Time Progress Panel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What About Other Datasources?
&lt;/h2&gt;

&lt;p&gt;You can probably do something similar with other datasources, but there are too many to test.&lt;/p&gt;

&lt;p&gt;If you use NodeExporter or Pushgateway, you could create your own custom metrics. PostgreSQL can handle pretty complex SQL, so you could probably calculate it there too (though setting up PostgreSQL just for this might be overkill).&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This article walks through how to visualize the progress of year, month, and day using Grafana + Prometheus.&lt;/p&gt;

&lt;p&gt;Writing these queries in a DSL like PromQL was a fun little puzzle.&lt;/p&gt;

&lt;p&gt;If you try this setup or come up with a cleaner approach, I'd love to hear about it!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Prometheus: &lt;a href="https://prometheus.io/docs/prometheus/latest/querying/functions/" rel="noopener noreferrer"&gt;https://prometheus.io/docs/prometheus/latest/querying/functions/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Changelog
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;2025/11/30: First version.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>grafana</category>
      <category>prometheus</category>
    </item>
    <item>
      <title>Understanding Timestamp Difference between shutdown and systemctl poweroff</title>
      <dc:creator>mkt</dc:creator>
      <pubDate>Wed, 22 Oct 2025 09:48:21 +0000</pubDate>
      <link>https://dev.to/mkt/understanding-timestamp-difference-between-shutdown-and-systemctl-poweroff-4a5l</link>
      <guid>https://dev.to/mkt/understanding-timestamp-difference-between-shutdown-and-systemctl-poweroff-4a5l</guid>
      <description>&lt;p&gt;&lt;em&gt;(This is the English translation of my original Japanese post at &lt;a href="https://zenn.dev/md_irohas/articles/343351fac096e3" rel="noopener noreferrer"&gt;Zenn&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I ran into trouble because I didn't properly understand the difference in time formats between the Linux &lt;code&gt;shutdown&lt;/code&gt; command and the &lt;code&gt;systemctl poweroff&lt;/code&gt; family (same applies to &lt;code&gt;systemctl halt&lt;/code&gt; and &lt;code&gt;systemctl reboot&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;As a reminder to myself, here's a concise summary of each time format and how they differ.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;shutdown -P 06:00&lt;/code&gt;
-&amp;gt; (On Ubuntu,) this means the next 6:00. If it's before 6:00 now, that's today at 6:00; if it's already past 6:00, it's tomorrow at 6:00.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;systemctl poweroff --when=06:00&lt;/code&gt;
-&amp;gt; Today at 6:00; if it's already past that time, it executes immediately.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More examples are in the latter half.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test environment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ubuntu Server 24.04 (systemd 255)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My mistake
&lt;/h2&gt;

&lt;p&gt;When managing servers, you'll sometimes want to schedule a shutdown for planned power outages, etc.&lt;/p&gt;

&lt;p&gt;The other day, when I tried to run the &lt;code&gt;shutdown&lt;/code&gt; command on Ubuntu 24.04, I saw this warning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;shutdown &lt;span class="nt"&gt;--help&lt;/span&gt;
... omitted ...

This is a compatibility interface, please use the more powerful &lt;span class="s1"&gt;'systemctl reboot'&lt;/span&gt;,
&lt;span class="s1"&gt;'systemctl poweroff'&lt;/span&gt;, &lt;span class="s1"&gt;'systemctl reboot'&lt;/span&gt; commands instead.

&lt;span class="c"&gt;# 'systemctl reboot' appears twice... 🤔&lt;/span&gt;
&lt;span class="c"&gt;# It's fixed in the latest systemd source.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ah, so even &lt;code&gt;shutdown&lt;/code&gt; is unified by systemd.&lt;/p&gt;

&lt;p&gt;So I checked systemctl's man page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;poweroff
    ... omitted ...
    This command honors --force and --when= in a similar way as halt.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I can use the &lt;code&gt;--when&lt;/code&gt; option for scheduling.&lt;/p&gt;

&lt;p&gt;Looking at the &lt;code&gt;--when&lt;/code&gt; option description:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--when=
    When used with halt, poweroff, reboot, or kexec, schedule the action
    to be performed at the given timestamp, which should adhere to the
    syntax documented in systemd.time(7) section "PARSING TIMESTAMPS".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I didn't feel like reading all of that, so I quickly asked Copilot.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;(The original chat is in Japanese)&lt;/p&gt;

&lt;p&gt;Me:&lt;br&gt;
Tell me how to write --when option of systemctl poweroff&lt;/p&gt;

&lt;p&gt;Copilot:&lt;br&gt;
The --when option in the systemctl poweroff command is used to specify when to power off the system.&lt;/p&gt;

&lt;p&gt;Basic syntax&lt;br&gt;
sudo systemctl poweroff --when=&lt;time&gt;&lt;/time&gt;&lt;/p&gt;

&lt;p&gt;Common options&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;now: Power off immediately&lt;/li&gt;
&lt;li&gt;reboot: Power off on the next reboot&lt;/li&gt;
&lt;li&gt;shutdown: Power off on the next system shutdown&lt;/li&gt;
&lt;li&gt;Specific time (e.g. 12:30): Power off at the specified time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples&lt;br&gt;
sudo systemctl poweroff --when=now&lt;br&gt;
→ Power off immediately&lt;br&gt;
sudo systemctl poweroff --when=20:00&lt;br&gt;
→ Power off at 20:00 today&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I thought, okay, same as the &lt;code&gt;shutdown&lt;/code&gt; command (THIS WAS THE MISTAKE. Btw, what is reboot or shutdown at a specified time?).&lt;br&gt;
Indeed, the actual &lt;code&gt;shutdown&lt;/code&gt; command is a symbolic link to &lt;code&gt;systemctl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So I assumed that -- just like &lt;code&gt;shutdown&lt;/code&gt; -- if I specify the time as &lt;code&gt;06:00&lt;/code&gt;, it would schedule it for 06:00 the next day, and I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;systemctl poweroff &lt;span class="nt"&gt;--when&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"06:00"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hit Enter, then...&lt;/p&gt;

&lt;p&gt;It powered off immediately. 😇&lt;/p&gt;

&lt;p&gt;It was just a personal desktop I use casually, so no real harm was done.&lt;/p&gt;

&lt;h2&gt;
  
  
  What went wrong?
&lt;/h2&gt;

&lt;p&gt;Let's read the &lt;code&gt;systemd.time&lt;/code&gt; man page section "PARSING TIMESTAMPS."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;... omitted ...

Examples &lt;span class="k"&gt;for &lt;/span&gt;valid timestamps and their normalized form &lt;span class="o"&gt;(&lt;/span&gt;assuming the current &lt;span class="nb"&gt;time &lt;/span&gt;was 2012-11-23 18:15:22 and the timezone was UTC+8, &lt;span class="k"&gt;for &lt;/span&gt;example &lt;span class="s2"&gt;"TZ=:Asia/Shanghai"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;:

      Fri 2012-11-23 11:12:13 -&amp;gt; Fri 2012-11-23 11:12:13
      2012-11-23 11:12:13 -&amp;gt; Fri 2012-11-23 11:12:13
      2012-11-23 11:12:13 UTC -&amp;gt; Fri 2012-11-23 19:12:13
      2012-11-23T11:12:13Z -&amp;gt; Fri 2012-11-23 19:12:13
      2012-11-23T11:12+02:00 -&amp;gt; Fri 2012-11-23 17:12:00
      2012-11-23 -&amp;gt; Fri 2012-11-23 00:00:00
      12-11-23 -&amp;gt; Fri 2012-11-23 00:00:00
      11:12:13 -&amp;gt; Fri 2012-11-23 11:12:13
      11:12 -&amp;gt; Fri 2012-11-23 11:12:00    &amp;lt;- here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you specify only a time, the date is filled in as "today."&lt;br&gt;
If that time has already passed, the action happens immediately.&lt;/p&gt;

&lt;p&gt;A bit unfriendly.&lt;/p&gt;
&lt;h2&gt;
  
  
  How shutdown and systemctl poweroff handle times
&lt;/h2&gt;
&lt;h3&gt;
  
  
  shutdown
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;shutdown &lt;span class="o"&gt;[&lt;/span&gt;OPTIONS...] &lt;span class="o"&gt;[&lt;/span&gt;TIME] &lt;span class="o"&gt;[&lt;/span&gt;WALL...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;TIME can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;now&lt;/code&gt;: immediately
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;+n&lt;/code&gt;: n minutes from now
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hh:mm&lt;/code&gt;: the next occurrence of hh:mm (24-hour format). For example, 06:30 means the next 06:30 (this works on Ubuntu; other distros may differ).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also note that the &lt;code&gt;shutdown&lt;/code&gt; command can't specify a date.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# If you specify nothing, it's 1 minute later&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;shutdown &lt;span class="nt"&gt;-P&lt;/span&gt;

&lt;span class="c"&gt;# Immediate&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;shutdown &lt;span class="nt"&gt;-P&lt;/span&gt; now

&lt;span class="c"&gt;# The next 06:30 (uses the server's time zone)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;shutdown &lt;span class="nt"&gt;-P&lt;/span&gt; 06:30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  systemctl poweroff
&lt;/h3&gt;

&lt;p&gt;Use the &lt;code&gt;--when&lt;/code&gt; option to specify the time.&lt;/p&gt;

&lt;p&gt;The time format can include not only time (&lt;code&gt;hh:mm&lt;/code&gt;) but also a full datetime and timezone.&lt;/p&gt;

&lt;p&gt;If you specify only a time, the date is completed as "today."&lt;br&gt;
If that time has already passed, it executes immediately.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# If you specify nothing, it's immediate (differs from shutdown)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;systemctl poweroff

&lt;span class="c"&gt;# Run at 06:30 today; if already past, run immediately&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;systemctl poweroff &lt;span class="nt"&gt;--when&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"06:30"&lt;/span&gt;

&lt;span class="c"&gt;# Run at 06:30 on 2025-10-05&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;systemctl poweroff &lt;span class="nt"&gt;--when&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"2025-10-05T06:30:00"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To be safe, avoid time-only strings; specify a full date and time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;Read the official documentation properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ubuntu 22.04 doesn't have the &lt;code&gt;--when&lt;/code&gt; option yet.
&lt;/li&gt;
&lt;li&gt;You can check how timestamps are parsed with &lt;code&gt;systemd-analyze timestamp "06:30"&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;On Ubuntu (and possibly elsewhere), &lt;code&gt;shutdown&lt;/code&gt; is a symlink to &lt;code&gt;systemctl&lt;/code&gt;, but their time formats are not compatible; &lt;code&gt;shutdown&lt;/code&gt; is implemented as a compatibility command inside &lt;code&gt;systemctl&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Change history
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;2025-10-21: Translated from my original Japanese post.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>command</category>
      <category>mistake</category>
    </item>
  </channel>
</rss>
