This issue is observed in bash with various distributions (SLES12, SLES15, Debian12, etc). When HISTFILESIZE is set to be less than or equal to HISTSIZE, the timestamp of the oldest command will be truncated.
To reproduce the issue: sles12sp5:~ # export HISTSIZE=3 sles12sp5:~ # export HISTFILESIZE=3 sles12sp5:~ # export HISTFILE=/home/history.hlog sles12sp5:~ # export HISTTIMEFORMAT=${HISTTIMEFORMAT:-"%F %H:%M:%S "} sles12sp5:~ # sles12sp5:~ # sleep 1 sles12sp5:~ # sleep 2 sles12sp5:~ # exit logout <login> sles12sp5:~ # cat /home/history.hlog sleep 1 # missing timestamp #1750923608 sleep 2 #1750923612 exit If HISTFILESIZE controls the total number of lines in the history file, the file should only contain 3 lines. Otherwise, if HISTFILESIZE controls the total number of history entries (command + timestamp), then the timestamp of the oldest entry is missing. Either way, we don't get the expected result. This proposed fix assumes the latter, i.e., HISTFILESIZE controls the total number of history entries. --- histfile.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/histfile.c b/histfile.c index 3bfec55..40c5565 100644 --- a/histfile.c +++ b/histfile.c @@ -594,7 +594,8 @@ history_truncate_file (const char *fname, int lines) both a newline and the history comment character, it should be OK. */ for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--) { - if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0) + /* skips the first iteration */ + if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0 && bp1 != bp) lines--; bp1 = bp; } @@ -606,7 +607,7 @@ history_truncate_file (const char *fname, int lines) this line until the end of the buffer. */ for ( ; bp > buffer; bp--) { - if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0) + if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 1) { bp++; break; --