Skip to content

v4.2.0 — dates keep their zone, series edited as a whole, parsed search

Choose a tag to compare

@PhilflowIO PhilflowIO released this 07 Oct 16:38
4e17070

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.