I have been using Yazi as my terminal file manager for a while now, and the more I use it, the more I want small workflow shortcuts that live right next to the files I am looking at. So I finally sat down and wrote my first Yazi plugin: date-diff.yazi.
It does one thing: select exactly two files, press a key, and Yazi shows a notification with each file’s modification time and the duration between them.
That is it. But building it taught me a lot about how Yazi’s plugin system actually works.
Why this plugin?
I often end up with two versions of the same file sitting next to each other: an old backup, a freshly generated artifact, or two downloaded copies with similar names. Sorting by mtime in Yazi already tells me which one is newer, but it does not immediately tell me how much newer. I wanted a quick comparison without leaving the file manager or reaching for stat and date.
Installing it
The plugin is published on Yazi’s package registry, so installing it is a one-liner:
ya pkg add rio-gesulgon/date-diff
Then bind it to a key in yazi.toml:
[[mgr.prepend_keymap]]
on = "<C-S-d>"
run = "plugin date-diff"
desc = "Show modification-time difference between two selected files"
I picked Ctrl+Shift+D because it is easy to hit and I do not already use it for anything else.
What the code looks like
The whole plugin is a single main.lua file. Here are the interesting parts.
Reading the selection
The plugin entry point runs in a worker thread, so you cannot access cx.active.selected directly. Yazi gives you ya.sync for that:
local get_selected_urls = ya.sync(function(_)
local urls = {}
for _, url in pairs(cx.active.selected) do
urls[#urls + 1] = url
end
return urls
end)
I missed this detail on my first attempt and spent a few minutes staring at an empty selection before I realized the sync wrapper was required.
Fetching file metadata
With the URLs in hand, fs.cha reads each file’s attributes:
local cha, err = fs.cha(url)
if not cha then
notify("DateDiff", string.format("Failed to read metadata for %s: %s", tostring(url), err or "unknown error"), "error", 5)
return
end
local mtime = cha.mtime
cha.mtime is an epoch timestamp in seconds, which is exactly what you need for math and os.date formatting.
Formatting the result
The diff itself is just subtraction, then a little helper breaks the duration into years, months, days, hours, minutes, and seconds:
local function format_duration(seconds)
seconds = math.floor(math.abs(seconds))
if seconds == 0 then
return "0 seconds"
end
local years = math.floor(seconds / 31536000)
seconds = seconds % 31536000
local months = math.floor(seconds / 2592000)
seconds = seconds % 2592000
-- ... days, hours, minutes, seconds
local parts = {}
if years > 0 then table.insert(parts, pluralize(years, "year")) end
-- ... etc
return table.concat(parts, ", ")
end
I sort the two items so the older file is always shown first, which makes the difference read naturally.
Showing the notification
Yazi’s ya.notify is simple but effective:
ya.notify({
title = "DateDiff",
content = message,
timeout = 6,
level = "info",
})
The final message looks something like this:
2026-07-10 14:22:01 — backup.tar.gz
2026-07-19 09:15:33 — latest.tar.gz
Difference: 8 days, 18 hours, 53 minutes, 32 seconds
Lessons from my first plugin
- Start tiny. A plugin that does one narrowly defined thing is easier to reason about, and you can always expand it later.
- Read the API version. This plugin targets Yazi
>= 25.5.28because it uses APIs introduced around that release. Declaring the@sincecomment at the top of the file keeps that clear. - Use
ya.errfor debugging. When the notification did not show up early on, addingya.err("[date-diff] entry start")let me trace the flow in Yazi’s log. - Handle the boring cases. Exactly two files must be selected, metadata must exist, and
mtimemight be missing. Bailing out early with a clear warning is much better than a silent failure.
What is next
For now the plugin only compares modification times. Possible small extensions include:
- Comparing creation times or access times when the filesystem provides them.
- Supporting directories by using their own
mtimevalues. - A config option to control the output format or notification timeout.
But I am resisting feature creep until I have used the current version for a while.
Try it
If you use Yazi and run into the same “which copy is newer, and by how much?” question, give it a shot:
ya pkg add rio-gesulgon/date-diff
Source and issue tracker are on GitHub: rio-gesulgon/date-diff.yazi.
It is a small thing, but it is my first published Yazi plugin, and it feels good to have a file-manager shortcut that I actually built.