【日历】生成ics日历信息

发布时间 2024-01-13 09:44:38作者: 我有我奥妙

参考

https://zhuanlan.zhihu.com/p/547193192

https://blog.csdn.net/Snakewood/article/details/130204963

解析步骤

目前有2种思路

解析百度接口

通过调用 https://sp1.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php 接口,拉取日历信息后再生成ics日历信息

def baiduContent(year):
    festival_lst = []
    # 因该接口传入的时间,查询了前一个月,当前月和后一个月的数据,所以只需要2、5、8、11即可全部获取到。比如查询5月份,则会查询4,5,6月分的数据
    months = ["2", "5", "8", "11"]

    for month in months:
        ts = int(time.time() * 1000)
        domain = "https://sp1.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?tn=wisetpl&format=json&resource_id=39043&query="
        url = domain + str(year) + "" + month + "月&t=" + str(ts)

        response = requests.get(url)
        content = response.text

        root = json.loads(content)
        almanac = root["data"][0]["almanac"]
        for item in almanac:
            if ('status' in item and item["status"] == '1'):
                current_date = convert_to_date(item["year"] + "" + item["month"] + "" + item["day"] + "", year)
                festival = ''
                if ('term' in item):
                    festival = item["term"]
                fest = FestivalModel(current_date, festival, '', 1)
                festival_lst.append(fest)
            elif ('status' in item and item["status"] == '2'):
                current_date = convert_to_date(item["year"] + "" + item["month"] + "" + item["day"] + "", year)
                festival = ''
                if ('term' in item):
                    festival = item["term"]
                fest = FestivalModel(current_date, festival, '', 2)
                festival_lst.append(fest)

解析法定节假日通知

通过访问 https://www.gov.cn/zhengce/content/202310/content_6911527.htm 页面,解析通知内容后再生成ics日历信息

def getfestival(year, content):
    festival_lst = []
    for item in content.split('\n'):
        if not item:
            item = ''
        item = item.strip()
        if item == "":
            continue

        if "放假," in item:
            idx1 = item.find('')
            idx2 = item.find('')
            idx3 = item.find('放假,')

            festival = item[idx1 + 1: idx2]
            date = item[idx2 + 1: idx3]

            if "" in festival:
                festival_many = festival.split('')
                festival = festival_many[1]

            appointed_date = convert_to_date(date, year)

            fest = FestivalModel(appointed_date, festival, '', 1)
            festival_lst.append(fest)

            # 处理与周末连休
            if "与周末连休" in item:
                weekday = appointed_date.weekday()
                if weekday == 0:
                    festival_sun = FestivalModel(appointed_date - timedelta(days=1), festival, '', 1)
                    festival_lst.append(festival_sun)
                    festival_sat = FestivalModel(appointed_date - timedelta(days=2), festival, '', 1)
                    festival_lst.append(festival_sat)
                elif weekday == 4:
                    festival_sat = FestivalModel(appointed_date + timedelta(days=1), festival, '', 1)
                    festival_lst.append(festival_sat)
                    festival_sun = FestivalModel(appointed_date + timedelta(days=2), festival, '', 1)
                    festival_lst.append(festival_sun)

        elif "放假调休," in item:
            idx1 = item.find('')
            idx2 = item.find('')
            idx3 = item.find('放假调休,')

            festival = item[idx1 + 1: idx2]
            date_range = item[idx2 + 1: idx3]

            if "" in festival:
                festival_many = festival.split('')
                festival = festival_many[1]

            # 处理10月1日至7日这样的日期
            date_continuous = date_range.split('')
            start = date_continuous[0]
            end = date_continuous[1]
            if "" not in end:
                end = start[0:start.find('') + 1] + end
            start_date = convert_to_date(start, year)
            end_date = convert_to_date(end, year)
            current_date = start_date
            while current_date <= end_date:
                fest = FestivalModel(current_date, festival, '', 1)
                festival_lst.append(fest)
                current_date += timedelta(days=1)

            # 处理补班
            many_sentence = item.split('')
            for single_sentence in many_sentence:
                if "上班" in single_sentence:
                    many_work = single_sentence.split('')
                    for single_work in many_work:
                        left_bracket = single_work.find('')
                        date_work = single_work[0:left_bracket]

                        fest = FestivalModel(convert_to_date(date_work, year), festival, '', 2)
                        festival_lst.append(fest)

生成步骤

通过上面的解析,得到节假日信息的数组,再遍历输出ics的内容

def getics(festival_lst, year):
    print("BEGIN:VCALENDAR")
    print("VERSION:2.0")
    print("X-WR-CALNAME:" + str(year) + "订阅法定节假日")
    print("X-APPLE-CALENDAR-COLOR:#FBD36A")
    print("X-WR-TIMEZONE:Asia/Shanghai")

    festival_lst = sorted(festival_lst, key=lambda x: x.dt)

    idx = 1
    for item in festival_lst:
        formatted_date = item.dt.strftime("%Y%m%d")
        print("BEGIN:VEVENT")
        print("UID:" + str(year) + "-" + f"{idx:04d}")
        print("DTSTART;VALUE=DATE:" + formatted_date)
        print("DTEND;VALUE=DATE:" + formatted_date)
        print("SUMMARY:" + item.festivalTips)
        print("SEQUENCE:0")
        print("BEGIN:VALARM")
        print("TRIGGER;VALUE=DATE-TIME:19760401T005545Z")
        print("ACTION:NONE")
        print("END:VALARM")
        print("END:VEVENT")

        idx += 1

    print("END:VCALENDAR")

效果预览

将生成的内容保存到ics上传服务器,即可供客户端使用。比如ios手机订阅日历

BEGIN:VCALENDAR
VERSION:2.0
X-WR-CALNAME:2024订阅法定节假日
X-APPLE-CALENDAR-COLOR:#FBD36A
X-WR-TIMEZONE:Asia/Shanghai
BEGIN:VEVENT
UID:2024-0001
DTSTART;VALUE=DATE:20240101
DTEND;VALUE=DATE:20240101
SUMMARY:元旦(休息)
SEQUENCE:0
BEGIN:VALARM
TRIGGER;VALUE=DATE-TIME:19760401T005545Z
ACTION:NONE
END:VALARM
END:VEVENT
END:VCALENDAR