"""司龄 — one definition of "how long have you been here", shared by every surface that shows it. The footprint page and the year-in-review used to compute this differently: footprint compared ``(month, day)`` (真·完整年) while wrapped compared bare years (``year - hire_date.year``). Someone hired 2025-12-20 saw "0 年" on footprint and "1 年" on the 2026 recap — and the two pages link to each other, so the disagreement was one click wide. They also conflated two different numbers under one name. "满 3 年" (cardinal, completed) and "第 4 年" (ordinal, the year you are currently living) differ by one, and the old ``years_as_of_eoy`` was rendered as *both*: the tenure slide said 「第 3 年」 while the poster said 「3 年 · 一路同行」 from the same value. Only one of those could be right. Both are exposed here, separately named. """ from __future__ import annotations from datetime import date def observed_anniversary(anchor: date, year: int) -> date: """The date ``anchor``'s anniversary is actually observed in ``year``. Only Feb-29 anchors differ from the naive ``(year, month, day)``: in a common year that date does not exist, and the anniversary is observed on Feb 28. Every other anchor returns itself shifted to ``year``. This exists because "does today match the anniversary" and "how many years is it" were answered by two different rules. The celebration scanner observed a 2/29 anchor on 2/28 in common years; the year counter compared ``(2, 28) < (2, 29)`` and subtracted one. The two disagreed by exactly the year they were describing, and the ``years >= 1`` gate downstream turned that disagreement into silence: someone hired on a Feb 29 got **no first work anniversary at all**, and every later one was announced a year short. Every caller derives from this one function so they cannot drift again — and "every" is load-bearing: a post-merge review found a THIRD private copy in ``domains/me_universe/cohort.py``, carrying the same bug, which an earlier version of this docstring had already declared impossible. When adding a tenure surface, import from here; ``grep -rn "years -= 1"`` is the cheap check that nobody has re-implemented it. >>> observed_anniversary(date(2024, 2, 29), 2025) datetime.date(2025, 2, 28) >>> observed_anniversary(date(2024, 2, 29), 2028) datetime.date(2028, 2, 29) """ try: return date(year, anchor.month, anchor.day) except ValueError: # Feb 29 in a common year. ``date`` rejects nothing else: every other # (month, day) pair that is valid once is valid every year. return date(year, 2, 28) def is_anniversary(anchor: date, as_of: date) -> bool: """True iff ``as_of`` is the day ``anchor``'s anniversary is observed. In a leap year a Feb-29 anchor is observed on the 29th only, so the celebration does not fire twice. """ return as_of == observed_anniversary(anchor, as_of.year) def completed_years(anchor: date, as_of: date) -> int: """Full years elapsed between ``anchor`` and ``as_of`` — 「满 N 年」. Month/day aware, so an anniversary that has not yet come round this year does not count. Never negative (a future hire date reads as 0). Feb-29 anchors complete their year on the observed date (see ``observed_anniversary``), not on March 1. >>> completed_years(date(2022, 6, 1), date(2025, 5, 31)) 2 >>> completed_years(date(2022, 6, 1), date(2025, 6, 1)) 3 >>> completed_years(date(2024, 2, 29), date(2025, 2, 28)) 1 """ years = as_of.year - anchor.year if as_of < observed_anniversary(anchor, as_of.year): years -= 1 return max(0, years) def ordinal_year(anchor: date, as_of: date) -> int: """Which year of the relationship ``as_of`` falls in — 「第 N 年」. Always ``completed_years + 1``: the day you join you are in your first year, and you enter your fourth year the moment you complete three. >>> ordinal_year(date(2022, 6, 1), date(2025, 5, 31)) 3 >>> ordinal_year(date(2022, 6, 1), date(2025, 6, 1)) 4 """ return completed_years(anchor, as_of) + 1 def tenure_reference_date(year: int, today: date) -> date: """The date a recap for ``year`` should measure tenure against. A finished year is measured at its own 12-31; the year still in progress is measured **today**, because telling someone in January that they have completed the years they will only complete in December is a lie the poster would then print. """ if year < today.year: return date(year, 12, 31) if year > today.year: return date(year, 1, 1) return today __all__ = [ "completed_years", "is_anniversary", "observed_anniversary", "ordinal_year", "tenure_reference_date", ]