🛰️ find · locate · xargs, reimagined

BFIND — BrightDate Findutils

GNU findutils 4.10.0 re-dressed for the BrightDate time system. bfind, blocate, bupdatedb, and bxargs — with -after/-before predicates, a %Wt printf format, and a -daystart that floors to the BrightDate boundary. One sortable, timezone-free scalar — everywhere.

# files modified after BD 9600 (≈ Sep 2025) — no date parsing, no TZ
$bfind . -after 9600 -name '*.log' -printf '%Wt %p\n'
9628.195697 ./app.log
9615.320041 ./audit.log
# how old is the newest source file? — plain float subtraction
$age=$(bfind . -name '*.c' -printf '%Wt\n' | sort -rn | head -1)
$echo "newest: BD $age — $(echo "($age - 9628) * 86400 / 3600" | bc) h old"
newest: BD 9628.197104 — 4.7 h old
# database-backed search; DB timestamp shown as BD
$blocate kernel | head -3
Database: /var/db/locate.database (BD 9628.12) 6 423 144 entries
$ brew install → View on GitHub BSH — the BrightShell

Why BrightDate? Why new findutils?

find's time predicates — -mtime, -newer, -newermt — are a perennial source of confusion: -mtime -1 means "within the last 24 hours, rounded down to integer days," -newermt needs an ISO 8601 string with the right timezone, and the results differ on Linux vs macOS because stat's timestamp resolution and epoch handling differ subtly between the two. Every script that filters files by recency carries this invisible complexity.

BSH (BrightShell) showed that the fix is not a better date-parsing library — it's a better time representation. BrightDate is a single Float64: decimal days since the astronomical epoch J2000.0, on a TAI substrate. No timezone. No leap-second jumps. b − a = elapsed days, always.

This fork carries that same fix into the findutils layer. If your shell prints BrightDate (BSH, or any shell using $BRIGHTEPOCH), and your file-search tool speaks BrightDate, there is no translation step anywhere in the pipeline. The number in your prompt is the number you pass to -after, which is the number printed by -printf '%Wt'.

In one sentence: BrightDate is a timezone-free SI-day count since J2000.0 (2000-01-01T11:58:55.816 UTC). BD 0.0 = the standard astronomical epoch. BD 9628 ≈ May 2026. b − a = elapsed days, no date library required.

🔎 Old find pain

Problem What goes wrong
-mtime -1 Rounds to integer days from "now", not a clean boundary
-newermt "2026-01-01" Needs TZ; differs on macOS vs Linux
-printf "%T+" Locale-dependent, not sortable as-is
Duration math Requires date -d, gdate, or Python
Daystart Midnight in local timezone — silently wrong in UTC+N

✨ bfind fix

Feature What it does
-after 9600 Files whose mtime > BD 9600 — universal, exact
-before 9628 Files whose mtime < BD 9628 — same scalar
%Wt / %Wa / %Wc / %WB Print mtime/atime/ctime/btime as BrightDate decimal
-daystart Floors to BD integer — same on every machine
-newerXY 9600 All -newer variants accept BD literals

BrightDate across the whole pipeline.

Every time-sensitive surface in findutils now speaks the same float. The changes are surgical: all four binaries are renamed (b prefix) so they coexist with system find/locate/xargs.

-after / -before

New predicates that accept a BrightDate scalar directly — no string parsing, no timezone argument. Both compare against mtime by default.

# files touched after BD 9600
bfind . -after 9600 -name '*.py'

# files older than BD 9000
bfind . -before 9000 -name '*.log' -delete
📋

%Wt / %Wa / %Wc / %WB

A new %W printf family prints file timestamps as BrightDate decimals. t = mtime, a = atime, c = ctime, B = birth time. Output is plain float — sort with sort -n, diff with awk.

bfind . -printf '%Wt %p\n' | sort -rn | head -5
# 9628.197104 ./src/pred.c
# 9628.195697 ./src/parser.c
# …
🌅

-daystart redefined

Standard -daystart floors to local midnight — a timezone-dependent boundary. In bfind, -daystart floors to the BrightDate integer boundary (the same on every machine). Pair with -mtime for "since BD boundary" queries.

# files changed since the start of BD 9628
bfind . -daystart -mtime -1
🔗

-newer* accepts BD

All -newerXY variants now try to parse the reference value as a BrightDate literal first. If it looks like a BD float (DDDDD.ddddd), it's used directly. Otherwise the original ISO/file-path logic applies, so old scripts continue to work unchanged.

bfind . -newermt 9628.0 -name '*.c'
bfind . -newerat 9600 -newer 9610
🗄️

blocate — BD database stats

blocate shows the database modification time as a BrightDate value in the statistics header, so you can instantly compare "how stale is my locate database" against $BRIGHTEPOCH with plain subtraction.

$ blocate --statistics
Database: /var/db/locate.database
  Created: BD 9628.12 (5.32 h ago)
  Entries: 6 423 144
🦀

Rust-quality C core

The BrightDate conversion lives in a single find/brightdate.c / brightdate.h with a 28-entry leap-second table. The same TAI/J2000 math as the Rust crate and the npm package — one formula, every platform.

# print the 10 most-recently modified files as BD + path
$bfind . -maxdepth 3 -type f -printf '%Wt\t%p\n' | sort -rn | head -10
9628.197104 ./find/pred.c
9628.195697 ./find/parser.c
9628.194201 ./find/brightdate.c
# find C files modified since BD 9625 and run clang-format on them
$bfind src -after 9625 -name '*.c' -print0 | bxargs -0 clang-format -i
# age of every log — float subtraction in awk, no date library
$bfind /var/log -name '*.log' -printf '%Wt %p\n' \
| awk '{printf "%.4f days old %s\n", 9628.2 - $1, $2}'
0.0042 days old /var/log/system.log
3.1804 days old /var/log/install.log

Install in seconds.

1

Add the tap (once)

brew tap digital-defiance/tap
2

Install the tools

brew install digital-defiance/tap/findutils-brightdate

This installs bfind, blocate, bupdatedb, and bxargs into $(brew --prefix)/bin. They coexist with system find/locate/xargs without shadowing them.

3

Try it

bfind ~ -maxdepth 2 -type f -printf '%Wt %p\n' | sort -rn | head -5

Build from source

A

Prerequisites

A C compiler (clang or gcc), autoconf, automake ≥ 1.16, and gettext. macOS, Linux, and *BSD all work.

B

Clone & build

git clone https://github.com/Digital-Defiance/findutils-brightdate.git
cd findutils-brightdate
autoreconf -fi
./configure --prefix=/usr/local --disable-nls
make -C gl && make -C lib
make -C find bfind
make -C locate blocate bupdatedb
make -C xargs bxargs
C

Install

sudo cp find/bfind locate/blocate locate/bupdatedb xargs/bxargs /usr/local/bin/

Want BrightDate throughout your whole shell? Install BSH (BrightShell) — a zsh-compatible shell where date, ls -l, stat, history -d, and $BRIGHTEPOCH all speak the same float. bfind fits right in.

The BrightDate ecosystem.

🐚

BSH — the BrightShell

A zsh-compatible shell with BrightDate woven into every time-related surface: date, ls -l, stat, history -d, sched, and $BRIGHTEPOCH. The natural home for bfind pipelines.

bsh.brightchain.org · GitHub

🦀

crates.io — brightdate

The Rust crate powering BSH internally. Also ships standalone CLI tools (bdate, btime, buptime, bcal, bwatch) via the Homebrew tap.

crates.io · GitHub

📦

npm — @brightchain/brightdate

TypeScript/JavaScript library. Same J2000.0 / TAI semantics, same epoch. Works in Node.js, Deno, and the browser.

npm · GitHub

🍺

Homebrew tap

All Digital Defiance BrightDate tools in one tap. Install bfind, the Rust CLI tools, and BSH itself from a single tap.

brew tap digital-defiance/tap
brew install findutils-brightdate
brew install bdate btime buptime bcal bwatch bsh