mirror of
https://github.com/borgbackup/borg.git
synced 2026-05-28 04:03:21 -04:00
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:
parent
2177b78945
commit
b844dd7645
2 changed files with 50 additions and 2 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Reference in a new issue