fix: DiffFormatter.format_time() uses microsecond precision for sub-second timestamp diffs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
hiepau1231 2026-04-05 14:13:00 +07:00
parent 2177b78945
commit b844dd7645
2 changed files with 50 additions and 2 deletions

View file

@ -27,7 +27,7 @@ from .errors import Error
from .fs import get_keys_dir, make_path_safe, slashify
from .argparsing import Action, ArgumentError, ArgumentTypeError, register_type
from .msgpack import Timestamp
from .time import OutputTimestamp, format_time, safe_timestamp
from .time import OutputTimestamp, format_time, format_timestamp_pair, safe_timestamp
from .. import __version__ as borg_version
from .. import __version_tuple__ as borg_version_tuple
from ..constants import * # NOQA
@ -1235,7 +1235,12 @@ class DiffFormatter(BaseFormatter):
def format_time(self, key, diff: "ItemDiff"):
change = diff.changes().get(key)
return f"[{key}: {change.diff_data['item1']} -> {change.diff_data['item2']}]" if change else ""
if not change:
return ""
ts1 = change.diff_data["item1"].ts
ts2 = change.diff_data["item2"].ts
s1, s2 = format_timestamp_pair(ts1, ts2)
return f"[{key}: {s1} -> {s2}]"
def format_iso_time(self, key, diff: "ItemDiff"):
change = diff.changes().get(key)

View file

@ -25,8 +25,10 @@ from ...helpers.parseformat import (
swidth_slice,
eval_escapes,
ChunkerParams,
DiffFormatter,
)
from ...helpers.time import format_timedelta, parse_timestamp
from ...item import ItemDiff, Item
from ...platformflags import is_win32
@ -642,3 +644,44 @@ def test_valid_chunkerparams(chunker_params, expected_return):
def test_invalid_chunkerparams(invalid_chunker_params):
with pytest.raises(ArgumentTypeError):
ChunkerParams(invalid_chunker_params)
def _make_item_with_ctime(ctime_ns: int) -> Item:
"""Helper: create a minimal Item with the given ctime nanoseconds.
Item.ctime is a PropDictProperty(int, encode=int_to_timestamp) set via
attribute assignment, not dict subscript.
"""
return Item(path="test/file", mode=0o100644, mtime=0, ctime=ctime_ns)
def test_diff_formatter_format_time_shows_microseconds_when_same_second():
"""DiffFormatter.format_time() must use microsecond precision when
two ctimes differ only at sub-second level (the BSD hardlink issue)."""
# Two nanosecond timestamps that are the same second but different microsecond
# 2025-11-05 17:45:53.000123 UTC → 1746467153000123000 ns
# 2025-11-05 17:45:53.000456 UTC → 1746467153000456000 ns
ctime1_ns = 1746467153_000123_000
ctime2_ns = 1746467153_000456_000
item1 = _make_item_with_ctime(ctime1_ns)
item2 = _make_item_with_ctime(ctime2_ns)
diff = ItemDiff(
path="test/file",
item1=item1,
item2=item2,
chunk_1=iter([]),
chunk_2=iter([]),
can_compare_chunk_ids=True,
)
fmt = DiffFormatter("{ctime} {path}{NL}", content_only=False)
result = fmt.format_item(diff)
# Must contain a dot — microseconds visible
assert "." in result, f"Expected microseconds in output, got: {result!r}"
# Must not look like [ctime: X -> X] (same string both sides)
import re
m = re.search(r"\[ctime: (.+?) -> (.+?)\]", result)
assert m is not None
assert m.group(1) != m.group(2), "Timestamps should differ in output"