打造智能农历纪念日管家:用Python和Flask实现自动提醒系统
每逢家人农历生日临近,总有人手忙脚乱翻看日历换算日期?传统节日当天才临时准备礼物?现在,用30行核心代码就能打造专属的智能提醒系统。本文将带你从零构建一个能自动转换农历日期、提前推送提醒的Web服务,从此不再错过任何重要时刻。
1. 系统架构设计
这个农历提醒系统的核心在于三个模块的协同工作:
- 日期转换引擎:sxtwl库负责农历与公历的精准转换
- 业务逻辑层:Flask处理用户请求和提醒规则
- 任务调度器:APScheduler管理定时提醒任务
# 系统核心架构示意 from flask import Flask import sxtwl from apscheduler.schedulers.background import BackgroundScheduler app = Flask(__name__) lunar = sxtwl.Lunar() # 农历转换引擎 scheduler = BackgroundScheduler() # 任务调度器与传统日历应用相比,我们的解决方案有三大优势:
- 精准转换:支持1900-2100年的农历公历互转
- 灵活规则:可设置提前N天提醒、重复周期等
- 多端通知:邮件、微信、短信等多种提醒方式
2. 环境配置与基础搭建
2.1 安装必要的Python库
推荐使用Python 3.8+环境,通过pip安装以下依赖:
pip install sxtwl==2.0.6 flask==2.0.1 pip install apscheduler==3.8.1 python-dotenv==0.19.02.2 项目目录结构
采用模块化设计,便于后期功能扩展:
/lunar_reminder ├── app.py # 主程序入口 ├── config.py # 配置文件 ├── templates/ # 网页模板 │ └── index.html ├── static/ # 静态资源 └── requirements.txt3. 核心功能实现
3.1 农历日期转换引擎
sxtwl库提供了丰富的日期转换接口,以下是几个典型使用场景:
# 公历转农历示例 day = lunar.getDayBySolar(2023, 5, 14) print(f"农历日期:{day.getLunarYear()}年{day.getLunarMonth()}月{day.getLunarDay()}日") # 农历转公历示例 day = lunar.getDayByLunar(2023, 4, 15) # 2023年农历4月15日 print(f"公历日期:{day.getSolarYear()}-{day.getSolarMonth()}-{day.getSolarDay()}")日期转换常见问题处理:
| 问题类型 | 解决方案 | 代码示例 |
|---|---|---|
| 闰月处理 | 使用isLunarLeap()判断 | day.isLunarLeap() |
| 节气计算 | hasJieQi()检测节气日 | day.hasJieQi() |
| 日期跨度 | after()/before()方法 | day.after(30) |
3.2 提醒规则管理系统
在Flask中实现RESTful API来管理提醒规则:
from flask import request, jsonify reminders = {} # 存储提醒规则的字典 @app.route('/api/reminder', methods=['POST']) def add_reminder(): data = request.json lunar_date = (data['year'], data['month'], data['day']) solar_date = lunar.getDayByLunar(*lunar_date) reminders[data['name']] = { 'lunar': lunar_date, 'solar': (solar_date.getSolarYear(), solar_date.getSolarMonth(), solar_date.getSolarDay()), 'advance_days': data.get('advance', 3), 'repeat': data.get('repeat', True) } return jsonify({"status": "success"})4. 定时任务与通知系统
4.1 使用APScheduler实现定时检查
每天凌晨检查未来7天内需要提醒的事件:
def check_reminders(): today = datetime.now() for name, reminder in reminders.items(): target_date = datetime(*reminder['solar']) delta = (target_date - today).days if 0 <= delta <= reminder['advance_days']: send_notification(name, delta) scheduler.add_job( check_reminders, 'cron', hour=0, minute=1 ) scheduler.start()4.2 多通道通知实现
根据不同场景选择通知方式:
邮件通知(适合正式场合)
import smtplib from email.message import EmailMessage def send_email(subject, content): msg = EmailMessage() msg['Subject'] = subject msg['From'] = 'your_email@example.com' msg['To'] = 'recipient@example.com' msg.set_content(content) with smtplib.SMTP('smtp.server.com', 587) as smtp: smtp.starttls() smtp.login('user', 'password') smtp.send_message(msg)微信推送(适合即时提醒)
import requests def send_wechat(content): url = "https://qyapi.weixin.com/cgi-bin/webhook/send" params = { "key": "YOUR_WEBHOOK_KEY" } data = { "msgtype": "text", "text": {"content": content} } requests.post(url, params=params, json=data)
5. 系统优化与扩展
5.1 性能优化技巧
当处理大量提醒事件时,可以采用以下策略:
批量日期转换:减少重复计算
def batch_convert(lunar_dates): return [lunar.getDayByLunar(*date) for date in lunar_dates]缓存机制:存储常用日期转换结果
from functools import lru_cache @lru_cache(maxsize=365) def cached_conversion(year, month, day): return lunar.getDayByLunar(year, month, day)
5.2 功能扩展方向
节日数据库:预置传统节日数据
traditional_festivals = { '春节': (None, 1, 1), # 农历正月初一 '端午节': (None, 5, 5), '中秋节': (None, 8, 15) }重复规则增强:
- 支持"每年农历同一天"提醒
- 支持"每月初一"等周期规则
用户界面优化:
- 添加可视化日历组件
- 支持拖拽调整提醒日期
# 复杂重复规则实现示例 def should_remind(event, current_date): if event['repeat'] == 'yearly': return (current_date.month, current_date.day) == event['solar'][1:] elif event['repeat'] == 'monthly': return current_date.day == event['solar'][2] return False6. 部署与维护方案
6.1 生产环境部署
推荐使用Docker容器化部署:
FROM python:3.8-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . CMD ["gunicorn", "-b :5000", "app:app"]启动命令:
docker build -t lunar-reminder . docker run -d -p 5000:5000 --restart always lunar-reminder6.2 系统监控策略
确保提醒服务稳定运行的关键指标:
| 监控项 | 正常范围 | 检查频率 |
|---|---|---|
| 任务队列积压 | < 10 | 每分钟 |
| 通知发送成功率 | > 99% | 每小时 |
| 日期转换延迟 | < 100ms | 每次请求 |
实现简单的健康检查端点:
@app.route('/health') def health_check(): return jsonify({ 'status': 'healthy', 'reminders_count': len(reminders), 'last_check': scheduler.get_jobs()[0].next_run_time })在实际项目中,我发现将农历转换结果缓存24小时可以显著降低CPU使用率,特别是在处理大量重复日期查询时。另一个实用技巧是为每个提醒事件添加UUID标识符,便于后续的日志追踪和管理。