As of writing this post (2025/11/30), apparently around 90% of this year has already passed.
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.
So I built it!
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.
TL;DR
Here’s what the panel looks like:
After some trial and error, I managed to create this using only Grafana and Prometheus (PromQL), which I already use every day.
The PromQL queries to calculate each value (for UTC) are as follows:
This Year (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
)
This Month (UTC)
(
((day_of_month() - 1) * (3600 * 24)) + (time() % (3600 * 24))
)
/
(
days_in_month() * (3600 * 24)
)
Today (UTC)
(time() % (3600 * 24)) / (3600 * 24)
If you want to display progress in a timezone other than UTC, simply add the appropriate offset (in seconds) to your queries.
For example:
- UTC+9 (Japan Standard Time; JST): add
3600 * 9(= 32400) seconds - UTC+2: add
3600 * 2(= 7200) seconds - UTC-5: add
3600 * -5(= -18000) seconds
Replace the offsets in the queries to match your local timezone.
Below are JST examples:
This Year (JST)
# 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
)
This Month (JST)
# 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)
)
Today (JST)
# JST
((time() + 3600 * 9) % (3600 * 24)) / (3600 * 24)
If you know a better way to do this, let me know 🙇♂️
Test Environment
Here’s the environment I used for testing:
- Ubuntu Server 24.04
- Grafana: 12.3.0
- Prometheus: 2.45.3 (the version available via apt on Ubuntu 24.04)
Note: I used Prometheus 2.x for testing. Things might be simpler with 3.x, but I haven’t tried yet.
Calculation Formulas
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.
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.
So, if you can express PromQL queries that match the following formulas, you’re good to go:
Note: I didn’t account for daylight saving time (DST) here.
PromQL Queries
Let’s implement the formulas above using Prometheus Query Language (PromQL), which provides a number of helpful built-in functions.
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.
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.
Today’s Progress
First, let’s calculate today’s progress.
In PromQL, you can get the current unixtime by the time() function.
You can also calculate today’s 00:00 unixtime using the day_of_year() 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 (= 3600 * 24).
So we can use modulo directly.
# UTC
(time() % (3600 * 24)) / (3600 * 24)
If you want to display the value in your local timezone, add the appropriate offset in seconds. For example, for JST (UTC+9), add 3600 * 9 (= 32400) seconds.
# JST
((time() + 3600 * 9) % (3600 * 24)) / (3600 * 24)
Grafana can multiply by 100 for percentage formatting, so you can leave the raw ratio as-is.
This Month’s Progress
Next, this month’s progress.
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”.
Obviously, the number of days in a month varies, so you can’t use modulo like I did for today’s progress.
Fortunately, PromQL provides the days_in_month() function for the latter.
Then, how do you get the unixtime for the 1st day of the month?
You don’t need to calculate it directly. PromQL has a day_of_month() function that returns the current day of the month, so you can write the numerator as:
(day_of_month() - 1) * (3600 * 24) # Seconds for previous days
+ (time() % (3600 * 24)) # Seconds for today
So, the query for this month’s progress looks like this:
# UTC
(
((day_of_month() - 1) * (3600 * 24)) + (time() % (3600 * 24))
)
/
(
days_in_month() * (3600 * 24)
)
For other timezones, you need to make sure day_of_month() and days_in_month() 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.
# 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)
)
It’s a bit tricky, but it works!
This Year’s Progress
Finally, this year’s progress.
Just like with the month, you can use the day_of_year() function to get the number of seconds since the start of the year:
(day_of_year() - 1) * (3600 * 24) # Seconds for previous days
+ (time() % (3600 * 24)) # Seconds for today
The only missing piece is “Days in Year”.
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 days_in_year() function.
So, I asked ChatGPT for help, and it suggested the following code:
# 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
)
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.
Also, you can use the bool modifier to simulate conditional logic. Comparisons return true/false as 1/0, so you can mimic simple if-else behavior.
Interesting… but since it’s an approximation, there might be some error (I haven’t checked how much it is).
After thinking a bit, I realized we can use PromQL’s day_of_year() 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 day_of_year() at the same time 365 days (
seconds) later, the value must be different from the current value.
So, you can calculate the number of days in the year like this:
# 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
)
The final query for this year’s progress is:
# 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
)
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.
# 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
)
With this, you have all the PromQL queries you need for visualization.
I haven’t thoroughly tested all edge cases, so if you spot a bug, please let me know!
Visualizing in Grafana
Once the queries are ready, all that’s left is to create your favorite panel in Grafana.
To make a panel like the screenshot above, follow these steps:
- Add a new panel to your dashboard.
- Select “Bar gauge” as the visualization type.
- Choose Prometheus as the data source (assuming you’ve already added it).
- Paste the queries for year, month, and day progress. Set the legend to “This Year”, “This Month”, and “Today” respectively.
- In the right sidebar, configure:
- Bar gauge:
- Orientation: Horizontal
- Display mode: Retro LCD
- Standard options:
- Unit: Misc / Percent (0.0-1.0)
- Min: 0
- Max: 1
- Bar gauge:
This should give you a panel that looks like this:
What About Other Datasources?
You can probably do something similar with other datasources, but there are too many to test.
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).
Summary
This article walks through how to visualize the progress of year, month, and day using Grafana + Prometheus.
Writing these queries in a DSL like PromQL was a fun little puzzle.
If you try this setup or come up with a cleaner approach, I’d love to hear about it!
References
Changelog
- 2025/11/30: First version.

