“通过 CalDAV 将日程导入 iCloud 日历“的失败记录

踩坑速览(重要的说在前头)

本以为“只要接个接口、跑个脚本、连个日历”,没想到问题重重…

主要遇到了两个问题

  1. Apple ID 必须是邮箱注册的
    要用 CalDAV 连接 iCloud,必须拥有一个 iCloud 邮箱地址(@icloud.com)。
    👉 解决办法:重新注册一个带 iCloud 邮箱的 Apple ID。

  2. CalDAV 无法通过验证
    按照常规步骤,进入 设置 → 日历 → 账户 添加 CalDAV,但输入正确信息后,始终无法通过验证。尝试多次后只好作罢。

    注意:需要在iCloud官网中添加一个App专用密码,路径在:右上角的图标-管理Apple账户。


代码

# 测试连接情况
from caldav import DAVClient

client = DAVClient(
    url="https://caldav.icloud.com/",
    username="xxxx@icloud.com",
    password="APP专用密码",
    ssl_verify_cert=False  
)

principal = client.principal()
print("✅ 连接成功!")
# main.py
from datetime import datetime, timedelta
import requests
from schedule_builder import build_schedule
from calendar_helper import write_schedule_to_icloud

APPLE_ID = "替换为你的 Apple ID"
APP_SPECIFIC_PASSWORD = "替换为你的 App 专用密码"
CALENDAR_NAME = "日历名称" # 要在日历App-日历(导航栏中间)中新建一个对应名字的

tomorrow = datetime.now() + timedelta(days=1)
tomorrow_str = tomorrow.strftime('%Y-%m-%d')
weekday = tomorrow.weekday()

url = f"https://timor.tech/api/holiday/info/{tomorrow_str}"
response = requests.get(url)
is_holiday = False
if response.ok:
    data = response.json()
    is_holiday = data.get("holiday", {}).get("holiday", False) or data.get("type", {}).get("type") == 1

schedule = build_schedule(date=tomorrow, weekday=weekday, is_holiday=is_holiday)

write_schedule_to_icloud(schedule, APPLE_ID, APP_SPECIFIC_PASSWORD, CALENDAR_NAME)
print(f"✅ 明天({tomorrow_str})的日程已写入日历:{CALENDAR_NAME}")
# calendar_helper.py
from caldav import DAVClient
from caldav.elements import dav, cdav
from datetime import datetime
from caldav.lib.error import AuthorizationError
import os

def write_schedule_to_icloud(events, apple_id, app_password, calendar_name):
    url = 'https://caldav.icloud.com.cn/'
    client = DAVClient(url, username=apple_id, password=app_password)
    principal = client.principal()
    calendars = principal.calendars()

    calendar = None
    for cal in calendars:
        if calendar_name in cal.name:
            calendar = cal
            break

    if calendar is None:
        raise ValueError(f"未找到日历:{calendar_name}")

    for event in events:
        dtstamp = datetime.now().strftime('%Y%m%dT%H%M%S')
        uid = f"elite-plan-{event['dtstart']}-{event['summary'].replace(' ', '')}"

        ical = f"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//ElitePlan//EN
BEGIN:VEVENT
UID:{uid}
DTSTAMP:{dtstamp}Z
DTSTART;TZID=Asia/Shanghai:{event['dtstart']}
DTEND;TZID=Asia/Shanghai:{event['dtend']}
SUMMARY:{event['summary']}
END:VEVENT
END:VCALENDAR
"""
        try:
            calendar.add_event(ical)
        except AuthorizationError as e:
            print(f"⚠️ 无法写入 iCloud,已降级为本地导出 .ics:{uid}.ics")
            with open(f"{uid}.ics", "w", encoding="utf-8") as f:
                f.write(ical)

# schedule_builder.py
from datetime import datetime, timedelta

def build_schedule(date: datetime, weekday: int, is_holiday: bool):
    events = []
    date_str = date.strftime('%Y%m%d')

    def add_event(summary, start_time, end_time):
        dt_start = f"{date_str}T{start_time}00"
        dt_end = f"{date_str}T{end_time}00"
        events.append({
            "summary": summary,
            "dtstart": dt_start,
            "dtend": dt_end
        })

    is_weekend = weekday >= 5

    if not is_holiday and not is_weekend:
        if weekday in [1, 3, 5]:
            add_event("英语阅读", "060000", "071000")
        elif weekday in [2, 4, 6]:
            add_event("跑步锻炼", "060000", "071000")
        add_event("规划时间(晚上)", "200000", "213000")
        add_event("阅读时间", "213000", "221500")
        add_event("准备入睡", "221500", "223000")
    else:
        if weekday in [1, 3, 5, 6]:
            add_event("英语阅读", "060000", "071000")
        elif weekday in [2, 4]:
            add_event("跑步锻炼", "060000", "071000")

        add_event("洗澡准备", "071000", "080000")
        add_event("规划时间(上午1)", "080000", "093000")
        add_event("休息", "093000", "094000")
        add_event("规划时间(上午2)", "094000", "113000")
        add_event("午间休息", "113000", "133000")
        add_event("苏醒时间", "133000", "140000")
        add_event("规划时间(下午1)", "140000", "153000")
        add_event("下午茶时间", "153000", "160000")
        add_event("规划时间(下午2)", "160000", "173000")
        add_event("晚间休息", "173000", "200000")
        add_event("规划时间(晚上)", "200000", "213000")
        add_event("阅读时间", "213000", "221500")
        add_event("准备入睡", "221500", "223000")

    return events
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值