使用O365库获取微软日历全天事件时的查询异常问题
O365库查询土耳其时区全天日历事件时返回前一天事件的问题解决
问题场景
使用O365库查询伊斯坦布尔时区(Turkey Standard Time)下指定日期(2022-09-18)的日历事件时,结果意外包含了前一天(2022-09-17)的全天事件dummy 1,而预期只获取当天的dummy 2、event 2和event 4。
实现代码如下:
... start_date = pytz.timezone("Europe/Istanbul").localize(datetime(2022, 9, 18)) end_date = pytz.timezone("Europe/Istanbul").localize(datetime(2022, 9, 19)) q = calendar.new_query('start').greater_equal(start_date) q.chain('and').on_attribute('end').less(end_date) events = calendar.get_events(query=q, include_recurring=True) pprint( [ ( g.to_api_data()["subject"], g.to_api_data()["start"], g.to_api_data()["end"] ) for g in events])
实际输出:
[('dummy 1', {'dateTime': '2022-09-17T03:00:00', 'timeZone': 'Turkey Standard Time'}, {'dateTime': '2022-09-18T03:00:00', 'timeZone': 'Turkey Standard Time'}), ('event 2', {'dateTime': '2022-09-18T00:00:00', 'timeZone': 'Turkey Standard Time'}, {'dateTime': '2022-09-18T00:30:00', 'timeZone': 'Turkey Standard Time'}), ('dummy 2', {'dateTime': '2022-09-18T03:00:00', 'timeZone': 'Turkey Standard Time'}, {'dateTime': '2022-09-19T03:00:00', 'timeZone': 'Turkey Standard Time'}), ('event 4', {'dateTime': '2022-09-18T23:30:00', 'timeZone': 'Turkey Standard Time'}, {'dateTime': '2022-09-19T00:00:00', 'timeZone': 'Turkey Standard Time'}) ]
原因分析
微软Graph/Exchange API中,全天事件的时间戳是基于UTC转换为当地时区的:
- 土耳其时区为UTC+3,当天的全天事件会被存储为UTC时间的
YYYY-MM-DDT00:00:00,转换为当地时间就是YYYY-MM-DDT03:00:00 - 前一天的全天事件(如
dummy 1)的结束时间是UTC2022-09-18T00:00:00,转换为土耳其时间就是2022-09-18T03:00:00,这个时间落在查询的end_date(2022-09-19T00:00:00)之前,所以被误纳入结果。
而普通事件的时间是直接按当地时区存储的,不会出现这种偏移。
解决方案
针对全天事件和非全天事件分别构建查询条件,再通过OR逻辑合并,避免时区偏移带来的查询错误:
- 非全天事件:保留原有的时间范围条件(
start >= 2022-09-18T00:00且end < 2022-09-19T00:00) - 全天事件:直接匹配事件的
start.date等于目标日期(2022-09-18),API会自动按日历时区解析日期
修改后的代码示例:
import pytz from datetime import datetime from pprint import pprint ... target_date = datetime(2022, 9, 18).date() tz = pytz.timezone("Europe/Istanbul") start_datetime = tz.localize(datetime(2022, 9, 18)) end_datetime = tz.localize(datetime(2022, 9, 19)) # 构建非全天事件查询 non_all_day_q = calendar.new_query('isAllDay').equals(False) non_all_day_q.chain('and').on_attribute('start').greater_equal(start_datetime) non_all_day_q.chain('and').on_attribute('end').less(end_datetime) # 构建全天事件查询 all_day_q = calendar.new_query('isAllDay').equals(True) all_day_q.chain('and').on_attribute('start').equals(target_date) # 合并两个查询(OR逻辑) combined_q = calendar.new_query().or_query(non_all_day_q, all_day_q) # 获取事件 events = calendar.get_events(query=combined_q, include_recurring=True) # 输出结果 pprint( [ ( g.to_api_data()["subject"], g.to_api_data()["start"], g.to_api_data()["end"] ) for g in events])
内容的提问来源于stack exchange,提问作者Benyamin Jafari
相关产品推荐
相关产品推荐

