Skip to content

borg2 prune: Make time spans calendar-aware #9929

Description

@PhrozenByte

Thanks to @Goddesen's amazing work with #8775 (❤️), borg2 prune now supports interval-based retention policies like --keep-daily 1m to keep daily archives within a one-month time span.

As discussed earlier in #8775 (comment), borg2 prune uses a rather unusual definition of what a month and a year is. A month is treated as a fixed 31-day interval regardless of the actual calendar month, and a year as a fixed 365-day interval regardless of leap years. This yields rather surprising results: Assume today is 2026-07-22. A timespan of 12m results in a 372-day period (i.e. 2025-07-15), instead of the expected 2025-07-22. A timespan of 3y results in a 3 × 365 = 1,095-day period, which introduces a one-day offset because 2024 is a leap year. So instead of the expected 2023-07-22, Borg assumes 2023-07-23.

We initially assumed that this 1m == 31d definition wasn't new (#8775 (comment)), but after digging into Borg's code, it turns out that it actually is. Although helpers.parseformat.interval() already existed before, it appears that it was dead code and wasn't used anywhere before. Other Borg code that utilises relative time spans, such as borg2 repo-list --oldest/--newest/--older/--newer, doesn't use helpers.parseformat.interval(), but helpers.time.calculate_relative_offset() instead (via manifest.filter_archives_by_date(), initial implementation in #7272), which interprets months and years as calendar-aware units. Since we have added a note regarding this 1m == 31d semantic to the docs, it now matches borg2 prune, but is now incorrect for the rest of Borg using relative time spans.

I'd like to suggest using helpers.time.calculate_relative_offset() for borg2 prune as well. For borg2 prune, from_ts would naturally be the value of --from.

Since changing this later would be a breaking change, it should ideally be addressed during the Borg 2 beta phase.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions