You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
v4.2.0 — dates keep their zone, series edited as a whole, parsed search
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fixed
Updates to a recurring event or todo reach the series, not one
occurrence (#96). A server may store the change to a single occurrence
before the series itself. update_event and update_todo then wrote the
new fields into that occurrence, while the event list showed the series, so
the update looked lost; update_todo's cleanup (a new due date replacing a
duration) and its date checks also ran on the occurrence. The update tools,
the todo list and todo_query's due-date filter now all use the series
(tsdav-utils 0.4.0).
Recurrence rules are written as rules.update_event with fields: { RRULE: 'FREQ=DAILY;COUNT=5' } stored a garbled line
(RRULE:0=F;1=R;2=E;...) that servers refused with a 500. Rules are now
checked and written properly, and a rule end can be set together with a
move to all-day in the same call (RRULE: 'FREQ=DAILY;UNTIL=2026-10-20'
with start_date: '2026-10-01'), which used to be refused.
freebusy_query no longer fails with "cannot relate exception to
exceptions" on a calendar holding several occurrences of a series without
the series itself (as servers store invitations to single occurrences);
each occurrence now counts as busy. update_event/update_todo refuse
such an object with an error that names the route that works: calendar_multi_get/todo_multi_get, then update_event_raw/ update_todo_raw.
Dates written through update_todo keep their time and zone (#91). fields.DUE rejected the iCal form its own description advertised
(20261026T180000Z), and a value with an offset such as 2026-10-26T14:00:00-04:00 was stored without its zone — hours off for
anyone reading it elsewhere. A TZID or all-day marker left on the old value
produced lines RFC 5545 forbids. The same applied to every date field of update_event (EXDATE, RECURRENCE-ID) and to REV in update_contact.
All date values are now encoded in one place (tsdav-utils 0.3.0): offsets are
converted to UTC, a bare date (2026-10-26) makes an all-day value, and a
time without a zone keeps the timezone the property already has. The other
dates of an event or todo (end, due date, excluded dates) follow its start:
its timezone, and its kind (all-day or timed). Otherwise a time without a zone
is read in the server timezone, as create_event always did.
todo_query finds todos with an all-day due date or one in a named
timezone; its date filter only matched DUE: followed by a UTC time.
Field names in the fields map are case-insensitive, so due and DUE
pass the same checks.
update_todo keeps a todo's dates coherent: setting DUE replaces a DURATION
and the other way round, and a DUE that is not later than DTSTART, or not of
the same kind (date vs. date-time), is rejected before anything is written.
todo_query, calendar_query and addressbook_query filter on parsed
values (#94). A summary, location, name or organization with a parameter
(SUMMARY;LANGUAGE=de:), folded across lines or containing an escaped
comma now matches; every EMAIL of a contact is searched, not just the
first; and name_filter no longer matches text from other lines (vcard
matched every contact). The filters read exactly what the list shows, so
an event is always listed with the text it was found by. With a time range, calendar_query finds a recurring event by any occurrence inside the range
— one renamed or moved included — and lists the first occurrence that
matches, with its own title, place and date; summary and location must
match the same occurrence. Without a range only the series itself is
searched. A recurring todo is found and listed by its series, not by a
completed single occurrence. status_filter compares
case-insensitively, and the list shows STATUS:completed as COMPLETED.
Contacts exported with unnamed parameters (vCard 2.1 / Outlook / Android: EMAIL;PREF;INTERNET:, TEL;CELL:) are shown with their name and fields
and found by addressbook_query; they appeared as "Unnamed Contact". A
one-part name (N:Cher) shows as "Cher", not "r h e C", and an
organization with an empty part reads "Acme, Sales", not "Acme, , Sales".
When a query result is capped, the earliest events are kept even if they
carry a timezone; the zone definition's 1970 start date was sorted on
instead, so the kept events were arbitrary. With a time range, a recurring
event is sorted by the occurrence it is listed as, not by when the series
began. A capped contact list says it shows the first contacts by name, not
"the earliest".
Range queries over long-running daily or weekly series no longer walk
every occurrence since the series began: 500 daily series since 2020 are
listed about five times faster than before.
Changed
create_todo accepts a bare date for due_date, giving a todo due that day;
before, it became midnight UTC. create_event, create_todo and the update
tools now share one date encoder instead of three, and check input against
the same rules: every write tool accepts 20261026T180000Z, 20261026 and
times without seconds (2026-10-26T18:00).
update_event: a start_date/end_date without a zone on an event that has
a timezone stays in that timezone (18:00 on a Berlin event is 18:00 Berlin);
before, it was read in the server timezone and stored as UTC. A start_date/end_date pair where one names a zone and the other does not is
refused, because its order cannot be checked: the zoneless one is read in the
event's own timezone.