Say out loud the promise you make while downloading a file: "I'll read this
later." I have been making that promise for years without any idea whether I
keep it. This evening, scrolling down through my Downloads folder, it struck me
that this is a measurable claim: for every file it indexes, macOS keeps a field
saying when that file was last used. Read the field and you read the report
card for the promise.
I read it. The grade is bad, but the grade wasn't the surprise — the instrument
that wrote it was.
What I counted, and with what
Spotlight keeps a pile of attributes for every item it indexes. Three of them
were useful to me: when the file arrived in this folder (kMDItemDateAdded),
when it was last used (kMDItemLastUsedDate) and how many times it was used
(kMDItemUseCount). You can collect all three from an entire folder with one
command:
mdfind -onlyin ~/Downloads \
-attr kMDItemFSSize \
-attr kMDItemDateAdded \
-attr kMDItemLastUsedDate \
-attr kMDItemUseCount \
'kMDItemContentType == "*"'
Coverage came first, because what the index sees and what sits on disk are
not the same thing — I learned that the hard way
while counting the 1.19 million files in my home directory.
The snapshot, taken 18 October 2026 at 21:16:
| Measurement | Count |
|---|---|
Files on disk (find, hidden files excluded) |
481 |
| Visible in the Spotlight index | 400 |
| Never visible in the index | 81 |
When I first built this table it said 397 instead of 400, and that
three-file gap taught me the first lesson about the measurement itself. The
missing ones were three work files with ü and ş in their names. Here is
why: find hands me the name as the filesystem gives it, with composed
letters (NFC), while mdfind returns the same name decomposed (NFD) — that
ü arrives as u plus a separate combining diaeresis. Identical to the eye,
different as bytes. Because I was comparing the two lists as text, one file
counted as two; once I pushed both sides through
unicodedata.normalize("NFC", path), the intersection rose to 400. Three
files look like a rounding error, but had I not noticed, the number in this
article's title would have been wrong too.
Of the 81 files left out, 69 live in subfolders and most of them are .dylib
and .plist pieces inside an unpacked bundle — not "something I downloaded
and set aside" but the internal organs of something else. So I continued with
the 400 files the index can see. I know nothing about the ones outside the
index, and I won't forget that I don't.
The report card
Of the 400 files, 313 have an empty kMDItemLastUsedDate. That's 78.2
percent. The use counter is empty on exactly the same 313 files; the two
fields live together and die together.
| Group | Files | Size |
|---|---|---|
| No open stamp | 313 | 225.3 MiB |
| Has an open stamp | 87 | 61.8 MiB |
| Total | 400 | 287.1 MiB |
The oldest arrival in the folder is 12 March 2025, the newest 17 October 2026.
The median age of the unstamped files is 23 days; 267 are older than a week,
101 older than a month, 10 older than three months. The oldest has been
sitting there for 584 days and has never once been opened.
Up to here it was exactly what I expected. Three quarters of the things I said
I'd read later, I never read. The uncomfortable things a person learns about
himself don't usually fit in a table this tidy; this one did.
Then I paused. Does that 313 really mean "I never opened them"?
Testing the first instrument
I didn't want to trust the number before reading Apple's own definition of
the field:
Date and time that the file was last used. This value is updated
automatically by LaunchServices every time a file is opened by double
clicking, or by asking LaunchServices to open a file.
The field doesn't say "the file was read", it says "LaunchServices opened this
file". Double-clicking, Finder, an application's open dialog — all of those go
through LaunchServices. Reading with cat in the terminal does not. So that
this wouldn't stay a guess, a small experiment went into Downloads: three text
files, one read with cat, one opened with TextEdit, the third left alone.
All three were checked right after creation, then touched one at a time.
| File | Action | kMDItemLastUsedDate |
kMDItemUseCount |
|---|---|---|---|
| A | read with cat
|
(null) | (null) |
| B | opened with TextEdit | 17:54:29 | 4 |
| C | never touched | (null) | (null) |
| C | then opened once | 18:03:25 | 4 |
| C | opened once more | 18:03:42 | 7 |
Two lessons landed at once. First: cat leaves no trace at all. So my 313 is
not the "never opened" count, it is the "never opened through the graphical
interface" count — an upper bound on genuine indifference. Any file a script
read, a grep scanned or an editor opened looks innocent on this list.
The next suspicion was that the stamp might decay over time — reindexing,
copying, a restore from backup. If that happened, the unstamped share would
climb with age. It does the opposite: of the 51 files younger than a week,
90.2% are unstamped; 76.9% of the 8-30 day group, 77.1% of the 31-90 day
group, and 66.7% of the 15 files older than 90 days. The share falls with age,
so there is no sign of stamp decay in this folder.
The second is subtler: opening file C once took the counter to 4, and a
second open took it to 7. So that one open wrote three or four events — but it
can't be stated as a general rule, because in my own folder 55 of the 87
stamped files sit at exactly 1. If every open wrote three or four, no file
could show 1. The increment isn't a constant: it depends on the application,
probably on preview, and on how the file was opened. Curious, I looked at the
SDK header: kMDItemLastUsedDate and kMDItemDateAdded are both declared in
MDItem.h with explanatory comments, while kMDItemUseCount is not there at
all. It is absent from Apple's current developer documentation too: the other
three keys each have a page (and none of the three is deprecated), while that
key has no page at all. mdls returns it, but there is no public contract
behind it. Here is the whole distribution: 55 files at 1, 14 at 2, 12 at 3, and
six files between 4 and 8. Looking at that table and saying "I opened this file
eight times" is something the experiment rules out; in this article the counter
is read only as full or empty.
The second instrument: the filesystem's own memory
Fine, LaunchServices was blind. Could the filesystem have seen it? In Unix
every file has an access time (atime) and reading updates it — in theory. On a
freshly created file read three times with cat, the first read updated
atime and the next two did not.
Rather than guess from there, a boundary test settled it — this is exactly the
kind of place where I get things wrong. Pushing atime into the past by hand and
reading the file covers both directions:
| Setup | atime after cat
|
|---|---|
| atime older than mtime | updated (2 of 2 runs) |
| atime newer than mtime, a few minutes old | unchanged |
| atime newer than mtime, two years stale | unchanged (3 of 3 runs) |
The rule is clear: what decides it is not how old atime is, but whether it
has passed mtime. Reading a file untouched for two years leaves no trace at
all, as long as its atime already sits ahead of mtime.
That is half of Linux's relatime behaviour. The kernel documentation
describes that option as generally limiting atime updates to once per day on
files that aren't being changed — so there, staleness is also a reason to
update. On APFS that second half is missing in these measurements: staleness
alone triggered nothing. Which is why the claim here is not "macOS uses
relatime"; what was measured is that the mtime gate holds.
The conclusion is the same either way: of the two instruments, one sees only
interface opens, and the other declines to record a second look at a file.
The real finding: 30 seconds
Let's go back to the 87 stamped files, because that is the part of this that
made me think the most. For each one, the gap between "arrival in the folder"
and the stamp.
One subtlety must not be skipped: the field holds the last use, not the
first. On 32 of the 87 files the counter is greater than 1, so for those the
date is my last touch. That doesn't weaken the table below, it strengthens it:
if a file's last use came 60 seconds after it arrived, its first use came no
later than that.
| Stamp, how long after arrival (cumulative) | Files (out of 87) |
|---|---|
| Within 1 minute | 50 |
| Within 5 minutes | 60 |
| Within 1 hour | 72 |
| Within 1 day | 78 |
| After more than 1 day | 9 |
The first four rows are cumulative and the last is the remainder: 78 + 9 = 87.
The median is 30 seconds. The longest delay is 33.8 days, and that is a single
file.
Seeing this table changed the story I tell about my relationship with files.
The story used to be: "I download things, then I never find time to read
them." What the data says is: I either open what I download right then, or
I never open it. Of the 87 stamped files, 50 were opened within the first
minute after arriving, 78 within the first day. The number of files I came back
to after more than a day is nine.
So my Downloads folder is not a reading list, it's a pile of receipts. Paper
that did its job within the minute it was downloaded and then stayed there.
"I'll read it later" is not a plan; it's the permission slip I write myself so
I don't have to delete the file.
Which field I read the arrival from
I owe you an explanation of where that "arrival in the folder" date came from,
because my first choice was a different field. macOS has a key for exactly
this job: kMDItemDownloadedDate. It isn't imaginary — MDItem.h describes it
as "the date that the file was last downloaded / received", and it is
documented as an addition in the OS X 10.7 API diffs.
It is set on zero of the 400 files.
How full of holes the provenance data on this machine is was already clear;
sixteen days ago the count showed that
none of the 1,945 rows in my quarantine ledger carry an address.
Still, the download-date field being completely empty is a separate lesson:
for comparison, the com.apple.quarantine seal sits on 285 files and
kMDItemWhereFroms on 101 — so the system knows these files came from
outside, it just doesn't record when they arrived. (Don't line those up
against the 217 and 86 in that earlier article: the denominators there were
306 and 277, here 400, and the folder has grown from 306 files to 481 since.)
That is why I computed arrival from kMDItemDateAdded — but its definition
isn't "the date it was downloaded" either. In Apple's header comment it is
"the date that the file was moved into the current location". If I moved a
file here from another folder, the clock starts over. The 30-second median
above has to be read with that limit in mind: the figure is not the time between
download and opening, but the time between arrival in the folder and
opening.
If I had written an automation that says "delete downloaded files after 30
days", I would have written it against the most natural-looking field
(kMDItemDownloadedDate), and since the rule would match no file at all I
would have believed for months that it was quietly working. A field existing
does not mean it is populated; I should write that sentence down and pin it
somewhere.
The same measurement in other folders
To avoid generalising from a single folder, I ran the same count in two more
places:
| Folder | Files | Unstamped | Share |
|---|---|---|---|
| Downloads | 400 | 313 | 78.2% |
| Desktop | 252 | 211 | 83.7% |
| Documents | 152,855 | 152,827 | 100.0% |
The first two confirm each other: in places where a human leaves things by
hand, the share lands between 78% and 84%. The third shows
where the instrument stops meaning anything. My Documents folder holds more
than 152,000 files, and almost all of them are source code, dependencies and
build output inside project trees. None of them get double-clicked, nor are
they supposed to be. That 100% says nothing about my habits; it only tells me
what kind of files live in that folder. This is what happens when you carry a
metric to the wrong place: the number still computes, the meaning evaporates.
Counting in your own folder
So that you can recompute the tables above, here is the plain version of the
count behind them. All it does is look at every item the index treats as a
file and check whether the stamp is empty:
import os, re, subprocess, sys, collections
folder = os.path.expanduser(sys.argv[1] if len(sys.argv) > 1 else "~/Downloads")
output = subprocess.run(
["mdfind", "-onlyin", folder, "-attr", "kMDItemLastUsedDate",
'kMDItemContentType == "*"'],
capture_output=True, text=True).stdout
counter = collections.Counter()
for line in output.splitlines():
parts = re.split(r"\s{2,}", line.strip())
path = parts[0]
if not path.startswith("/") or not os.path.isfile(path):
continue
value = next((p.split("=", 1)[1].strip()
for p in parts[1:] if p.startswith("kMDItemLastUsedDate")), None)
if value is None:
continue
counter["unstamped" if value == "(null)" else "stamped"] += 1
total = sum(counter.values())
print(f"{folder}: {counter['unstamped']} of {total} files carry no open "
f"stamp ({counter['unstamped'] / total * 100:.1f}%)")
It changes nothing and deletes nothing; it only counts. It is deliberately
written to survive any -attr ordering: it splits the line on whitespace and
finds the field by name. The first version expected the field right after the
path, and against the output of this article's own four-attribute command it
returned a silent zero — precisely the failure this article warns about.
That much is enough to see your own number; the refinements above (NFC
normalisation, intersecting with the disk, the age distribution) move the
figure by a percent or two without changing the story.
What I did, and what I didn't
Let me start with what I didn't do: bulk deletion. Because the real number
doesn't deserve it. All 313 unstamped files come to 225.3 MiB. This disk is tight — only 25
GiB free out of 460 GiB — and even so the pile amounts to about one percent of
that free space. Ending this article with
"run this command and reclaim this much space" would have been cheap, and
wrong.
The cost is elsewhere. When I look for something, I walk through 481 files.
Every time I download something I defer the "should this stay?" decision, and
those deferred decisions pile up in the folder. There's also this: 64 of the
70 .zip files carry no open stamp, and they are the group taking the most
space (158.4 MiB). Downloading an archive and extracting it is work that can be done without ever
"opening" the archive itself, so a missing stamp there may mean a different
method rather than indifference. By contrast, all 24 of the .md files are unstamped — opening a
note file by double-clicking is not expected behaviour in my setup, those get
read in an editor or in the terminal. Which puts them squarely in the
instrument's blind spot.
Four questions I'd offer anyone looking at their own setup:
- Which folder is genuinely an "entrance"? Downloads was the entrance for me, but I was treating it as a warehouse. An entrance staying full is not normal.
- What does the field you measured say, and what does it not say? The "last used" field counts interface opens; it doesn't see what you read with a script. You're reading an upper bound, not the truth.
- Verify the field is populated before writing your rule. On my machine the download date was empty on all 400 files; an automation resting on that field looks like it's working while it never runs.
- If the number is small, relax. 225 MiB isn't worth an evening's plan; deferred decisions are.
The next step belongs here too, since this article doesn't take it: there is a
way to narrow the 313. By the rule measured above, atime only updates while it
hasn't passed mtime, so among the unstamped files the ones whose atime sits
ahead of mtime form a "may have been read" set. That isn't proof on its own —
copying or downloading a file can also push atime past mtime, so this filter
gives another upper bound rather than certainty. Still, two blind instruments
laid over each other beat one. It hasn't been run yet.
The measurement itself changes something too, and I want to note it: the
moment I move a file into the project folder it belongs to, its
kMDItemDateAdded clock resets. The more order I create, the more I damage my
own measurement axis. There are 10 files older than three months with no trace
at all; I'm leaving that many to be looked at one by one rather than to a bulk
command. Files being in the right place matters more than my measurement
staying clean.
The most durable thing I took from this isn't a cleanup habit. It's this: when
I produce a number about myself, I should remember that the number describes
what my instrument can see, not my behaviour. There is no trace on 313 files;
I still don't know how many of them I never opened. That's the honest answer —
and a good enough reason not to round off a number as uncomfortable as three
quarters.
Top comments (11)
Longest post award goes to mustafa ERBAY Sir
Haha, guilty as charged! 😂 I started with a simple question about my Downloads folder and somehow ended up investigating Spotlight, LaunchServices, APFS, and Unicode normalization.
Apparently, measuring one small thing properly takes more words than expected. 😄
Thanks for making it to the end!
bro I'm dropping best post today
Haha, now you’ve got me curious! 😂🔥
That’s a bold promise, bro. Looking forward to reading it. Just make sure the content lives up to the hype! 😄
yea yea... spoil alert: you are part of that post
Wait, I’m part of it too?! 😂 Now you’ve really got my attention, bro!
Should I be excited or worried? 😆 Looking forward to the surprise! 🔥
you can be both ☠️🔥😂
Haha, that sounds suspiciously like a threat disguised as a compliment! 😂☠️ Now I’m definitely curious. Alright bro, bring it on! 🔥🍿
I should post it now?
Absolutely, bro! 😂🔥 You’ve built enough suspense already. Drop it! Let’s see what you’ve been cooking. 🍿😎
dropped 😳🫣