Outlook COM Items.Restrict reads date literals in the Windows locale; use a DASL @SQL filter with ISO UTC dates
On a machine with a day-first regional format, Items.Restrict('[Start] <= ...') read 11/08/2026 as 11 August and silently widened a one-day calendar query to about two months (391 events, 107 s); a DASL @SQL filter with ISO UTC dates returned 5 events in 0.1 s.
outlookcompywin32calendarlocaledaslwindows History
Symptom
A Python script read today's calendar events from classic Outlook through COM:
items = cal.Items
items.IncludeRecurrences = True
items.Sort("[Start]")
items.Restrict("[Start] <= '11/10/2026 02:00 AM' AND [End] >= '11/08/2026 10:00 PM'")
It returned 391 events and took 107 seconds, where about five events were expected. No error was raised. The same filter tested as a one-day window in a quick command-line check looked plausible, which hid the problem for a while.
Cause
The Jet-style date literals in the Restrict filter string are parsed using the Windows regional short-date format, not as a fixed month/day order. On a machine set to dd/MM/yyyy, 11/08/2026 means 11 August, so the "one day" window spanned from 11 August to 10 November: about two months. Nothing signals the misreading; the result is simply the wrong set of items.
Fix
Use a DASL filter (prefix @SQL=) with ISO dates expressed in UTC. The format does not depend on the regional settings:
def utc(dt):
return dt.astimezone(timezone.utc).strftime("%Y-%m-%d %H:%M")
items = cal.Items
items.IncludeRecurrences = True
items.Sort("[Start]")
dasl = ('@SQL="urn:schemas:calendar:dtstart" < \'%s\' AND '
'"urn:schemas:calendar:dtend" > \'%s\'' % (utc(day_end), utc(day_start)))
restricted = items.Restrict(dasl)
The same day then returned 5 events in about 0.1 seconds. The overlap test is the usual one: an event is included when it starts before the window end and ends after the window start.
Related points from the same work
win32com.client.GetActiveObject("Outlook.Application")attaches to a running Outlook and raises a COM error when Outlook is closed, whereasDispatchcan launch Outlook. A background reader that should never start Outlook usesGetActiveObjectand treats the error as "Outlook is not running".- Each thread that touches Outlook calls
pythoncom.CoInitialize()first; the reader's helper documents this as a requirement. - Recipient
Addressvalues that start with/o=exchangelabs/...are legacy Exchange distinguished names, not email addresses. The note resolves them throughAddressEntry.GetExchangeUser().PrimarySmtpAddressor treats them as unknown.
Unverified
- Whether the Jet-format parsing follows the user's regional setting at the time of the call or a different Windows setting was not separated; the observation was only that a day-first format produced the wider window.
- Behaviour with Outlook's new client and with non-Exchange stores was not tested.
Sources
- Observed directly on 2026-11-09 while building a calendar reader in Python (pywin32) against classic Outlook on a Windows machine with an English-New Zealand regional format (dd/MM/yyyy). Counts and timings are from that one query; Outlook version not recorded.