"""Tests for datetime formula functions (R1).""" from __future__ import annotations from agentkit.bitable.formula.functions.datetime import ( DATETIME_FUNCTIONS, _date, _dateadd, _datedif, _day, _eomonth, _hour, _minute, _month, _networkdays, _now, _second, _today, _weekday, _year, ) def test_registry_has_15_functions() -> None: assert len(DATETIME_FUNCTIONS) == 15 assert "DATE" in DATETIME_FUNCTIONS assert "NETWORKDAYS" in DATETIME_FUNCTIONS def test_date_constructor() -> None: result = _date(2026, 7, 6) assert result == "2026-07-06T00:00:00" def test_year_month_day() -> None: d = _date(2026, 7, 6) assert _year(d) == 2026 assert _month(d) == 7 assert _day(d) == 6 def test_hour_minute_second() -> None: dt = "2026-07-06T14:30:45" assert _hour(dt) == 14 assert _minute(dt) == 30 assert _second(dt) == 45 def test_weekday() -> None: # 2026-07-06 is a Monday → ISO weekday 1 assert _weekday("2026-07-06") == 1 # 2026-07-12 is a Sunday → ISO weekday 7 assert _weekday("2026-07-12") == 7 def test_datedif_days() -> None: assert _datedif("2026-07-01", "2026-07-06", "days") == 5 def test_datedif_months() -> None: assert _datedif("2026-01-15", "2026-07-15", "months") == 6 def test_datedif_years() -> None: assert _datedif("2020-01-01", "2026-01-01", "years") == 6 def test_dateadd_days() -> None: assert _dateadd("2026-07-06", 5, "days") == "2026-07-11T00:00:00" def test_dateadd_months() -> None: assert _dateadd("2026-01-15", 1, "months") == "2026-02-15T00:00:00" def test_dateadd_months_clamps_day() -> None: # Jan 31 + 1 month → Feb 28 (2026 is not a leap year) assert _dateadd("2026-01-31", 1, "months") == "2026-02-28T00:00:00" def test_networkdays() -> None: # 2026-07-06 (Mon) to 2026-07-10 (Fri) = 5 working days assert _networkdays("2026-07-06", "2026-07-10") == 5 def test_networkdays_includes_weekend() -> None: # 2026-07-06 (Mon) to 2026-07-12 (Sun) = 5 working days (weekend excluded) assert _networkdays("2026-07-06", "2026-07-12") == 5 def test_networkdays_reversed_args() -> None: # Should swap if start > end assert _networkdays("2026-07-10", "2026-07-06") == 5 def test_eomonth() -> None: # End of July 2026 assert _eomonth("2026-07-06", 0) == "2026-07-31T00:00:00" def test_eomonth_next_month() -> None: # End of August 2026 assert _eomonth("2026-07-06", 1) == "2026-08-31T00:00:00" def test_today_returns_iso_string() -> None: result = _today() assert isinstance(result, str) assert "T00:00:00" in result def test_now_returns_iso_string() -> None: result = _now() assert isinstance(result, str) assert "T" in result def test_none_input_returns_none_for_accessors() -> None: assert _year(None) is None assert _month(None) is None assert _day(None) is None def test_empty_string_returns_none_for_accessors() -> None: assert _year("") is None assert _datedif("", "2026-07-06") is None