iCalendar日历文件裁剪

由于了解到之前部署的Radicale似乎并未严格遵守RFC 5545标准,而Radicale在苹果设备上访问比较麻烦,所以前段时间尝试将自己的日历服务重新部署到Baikal(但事后发现部署变得更麻烦了TAT),在备份日历文件的时候发现自己的日历文件体积太大了,便顺手抽时间写了个python脚本来切割日历文件。

友情提示:使用脚本前请备份你的日历文件

本脚本依赖icalendar模块。其作用主要是读入ics文件中的全部Component(例如VEVENTVTODO等),并提取其中最近的日期(如果你的日历中有持续或者重复时间为永远的请谨慎使用),将其与watershed_datetime比较。若is_before_watershed_datetime = True,则保存比watershed_datetime更早的Component,否则保存更新的Component。

ics_rotate.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
from icalendar import Calendar
from datetime import date, time, datetime
import pytz

uniform_tz = pytz.timezone("Asia/Shanghai")
watershed_datetime = datetime(2022, 1, 1, 0, 0, 0, tzinfo=uniform_tz)
is_before_watershed_datetime = True # 取事件最近日期,保存分水岭前/后的事件

read_file_path = "my-calendar.ics"
save_file_path = "my-calendar-20220101.ics"


def get_datetime_from_event(event, param):
result = event.get(param).dt
if type(result) == date:
result = datetime.combine(
result,
time(tzinfo=uniform_tz),
)
return result


with open(read_file_path, "r") as f:
cal = Calendar.from_ical(f.read())

new_cal = Calendar()

param_list = ["dtstart", "dtend", "due", "completed", "dtstamp"]
watershed_datetime = watershed_datetime.replace(tzinfo=pytz.UTC)
for event in cal.walk():
if event.name not in [
"VEVENT",
"VTODO",
"VJOURNAL",
"VFREEBUSY",
"VTIMEZONE",
"VALARM",
]:
continue
dates = list()
for param in param_list:
try:
dates.append(get_datetime_from_event(event, param))
except AttributeError:
pass

if len(dates) > 0:
event_datetime = max(dates).replace(tzinfo=pytz.UTC)
if (
event_datetime >= watershed_datetime
) ^ is_before_watershed_datetime:
new_cal.add_component(event)
else:
new_cal.add_component(event)

with open(save_file_path, "w") as f:
f.write(new_cal.to_ical().decode("utf-8").replace("\r\n", "\n").strip())

参考资料: