Log time exactly 0 (nano)seconds after epoch is not properly recognised as such
lnav version lnav 0.14.0-a2e2380-dirty (pulled and compiled as of 2025-11-15)
Describe the bug When processing some log files, where the timestamp is expressed as nanoseconds from UNIX epoch, timestamps being exactly 0 are not correctly interpreted as "the origin of times" (midnight UTC 1970-01-01), instead taking the time stamp for some later log entry
To Reproduce Let's say I have an input file (TAB delimited) like this:
name mtime fileid size
/data/item/subdir/f001 0 4485 52
/data/item/subdir/f002 0 4486 380
/data/item/subdir/f003 0 4590 380
/data/item/subdir/f004 1542205104057741601 30180 436
/data/item/subdir/f005 1642205104057741601 30180 436
"mtime" column being "nanoseconds from epoch", which is a timestamp supported since author kindly introduced it a few months ago. I have a custom format for this, and hence the timestamp for the first files should be shown as "1970-01-01 00:00:00.000000000", however, "lnav" output is as shown:
/data/item/subdir/f001 2018-11-14 15:18:24.057741000 4485 52
/data/item/subdir/f002 2018-11-14 15:18:24.057741000 4486 380
/data/item/subdir/f003 2018-11-14 15:18:24.057741000 4590 380
/data/item/subdir/f004 2018-11-14 15:18:24.057741601 30180 436
/data/item/subdir/f005 2022-01-15 01:05:04.057741601 30180 436
However if I manually set the timestamp in the input file to "1" (one nanosecond from UNIX epoch) for the third file, and load the input file from "lnav" again, I see the expected output:
/data/item/subdir/f001 1970-01-01 00:00:00.000000000 4485 52
/data/item/subdir/f002 1970-01-01 00:00:00.000000000 4486 380
/data/item/subdir/f003 1970-01-01 00:00:00.000000001 4590 380
/data/item/subdir/f004 2018-11-14 15:18:24.057741601 30180 436
/data/item/subdir/f005 2022-01-15 01:05:04.057741601 30180 436
This can be one of the most stupid bug reports ever, still, I thought it was worth mentioning. Use case is the same as when I requested adding nanosenconds from epoch as a valid timestamp : processing files which are lists of file metadata (including time of creation) using "lnav" very powerful filtering and seamless indexing of data in SQLite.
Huh, that's an odd one. I think there is some sanity check somewhere that checks for zero timestamp. Will have to dig around a bit.
Continued to chase my own reported bugs using AI tools, and for this one, it reported as follows:
2. Fundamental Code Problem
-
Root Cause: In
src/ptimec.hh, the epoch timestamp parsing functions (ptime_s,ptime_i,ptime_6,ptime_9) used a return conditionreturn (epoch_value > 0);to indicate successful parsing. This rejected valid epoch 0 timestamps because 0 is not greater than 0, causing the parser to fail and fall back to incorrect timestamps from other entries. -
Why It Matters: UNIX epoch 0 is a legitimate timestamp representing the start of 1970 UTC. The condition
> 0was overly restrictive, assuming 0 is invalid, but in timestamp contexts, 0 is meaningful and should be accepted if digits were consumed during parsing. - Broader Implication: This bug affected all epoch-based parsers (seconds, milliseconds, microseconds, nanoseconds), preventing accurate handling of logs starting from the epoch origin.
For the parsing of nanoseconds from epoch function, the tool returned the following patch:
--- a/src/ptimec.hh
+++ b/src/ptimec.hh
@@ -612,6 +612,7 @@ inline bool
ptime_9(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
{
+ off_t off_start = off_inout;
uint64_t epoch_ns = 0;
lnav::time64_t epoch;
@@ -631,5 +632,5 @@ ptime_9(struct exttm* dst, const char* str, off_t& off_inout, ssize_t len)
dst->et_flags = ETF_DAY_SET | ETF_MONTH_SET | ETF_YEAR_SET | ETF_HOUR_SET
| ETF_MINUTE_SET | ETF_SECOND_SET | ETF_NANOS_SET | ETF_MACHINE_ORIENTED
| ETF_EPOCH_TIME | ETF_ZONE_SET | ETF_SUB_NOT_IN_FORMAT | ETF_Z_FOR_UTC;
- return (epoch_ns > 0);
+ return (off_inout > off_start);
}
What the tool told to be the thinking process to arrive to the solution above was:
-
Addition:
off_t off_start = off_inout;captures the starting offset before parsing. -
Change: Return condition now checks if parsing consumed any input (
off_inout > off_start), allowing epoch 0 (valid timestamp) while rejecting no-input cases. - Rationale: This fixes the bug by accepting 0 as a parsed value if digits were present, aligning with UNIX epoch standards. If you prefer a different approach (e.g., explicit 0 allowance or additional validation), this can be adjusted. The change is isolated to the return logic for low risk.
I let the tool create a branch in my local copy and compile the latest version and tested with some of my input data, and now a timestamp exactly 0 nanoseconds from epoch is correctly presented in the log view as expected.
Of course, it is up to you to see if the findings are correct and if the solution proposed here is adequate, I only hope I saved you spending too much quality time on a minor issue like this.
Hope it helps.