简介这是一份覆盖1970年1月1日至2100年12月31日的完整万年历MySQL数据库资源面向需要日期维度数据的开发者、数据分析人员及后端工程师可用于日历查询、节假日统计、报表按日聚合等场景省去自行推算农历与公历对应关系的繁琐工作。压缩包共3个文件以1个sql脚本为主内含完整建表语句与逐日插入语句另附2张png截图用于展示数据表结构与运行效果整体约872KB导入前注意将数据库编码设为utf8创建后直接执行脚本即可使用。目前已有1433人学习下载说明该数据在日期处理类项目中具备一定实用价值。数据时间跨度长达131年字段信息齐全可直接作为基础维表接入业务系统减少手工造数与校验成本适合对数据完整性要求较高的中高级开发者参考使用。1. 从 1970 到 2100一份能直接拉进 MySQL 的万年历数据库做排班系统、考勤统计、节假日判断或者金融计息模块时绕不开一个基础问题某一天到底是星期几、是不是节假日、属于哪个周、农历对应哪一天。很多团队一开始想用代码算写完发现闰年、大小月、跨年周序这些边界能把人逼疯最后还是要落一张日历表。这份资源就是干这个的——一份覆盖 1970-01-01 到 2100-12-31 的 MySQL 万年历数据库包含建表语句和插入语句编码 utf8建完库直接导入就能用。它适合后端、数据开发、报表工程师也适合做考勤、排班、账期类业务的人。下面我按实际拆包和导入的流程把这份 SQL 怎么用、参数怎么设、哪里容易翻车讲清楚。2. 拆开这份 SQL表结构、字段含义与日期跨度设计2.1 为什么日历要落库而不是现算日历计算看着简单实际是个玄学重灾区。公历闰年规则是「四年一闰、百年不闰、四百年再闰」农历更复杂涉及朔望月和二十四节气纯代码实现要么引第三方库要么自己维护一张对照表。业务上真正高频的查询是「给定日期返回星期、周序、是否周末、是否节假日」这类查询如果每次都走函数计算在批量统计场景下会拖慢执行计划也没法建索引。落库的核心价值有三个第一查询变成一次主键或索引命中毫秒级返回第二节假日、调休这类人为定义的字段可以随时改不用改代码重新发版第三跨年周序ISO 周这种容易算错的东西提前算好存进去业务侧直接读。1970 到 2100 这个跨度覆盖了绝大多数系统的生命周期往前够到 Unix 时间戳起点往后留了七十多年余量对一般业务足够。2.2 表结构长什么样这份 SQL 的建表语句是典型的单表日历结构主键落在日期字段上。常见做法是日期列用date类型而不是varchar这样能直接用 MySQL 的日期函数和范围查询。下面是我按这类资源常见结构还原的建表语句字段命名和类型以实际 SQL 文件为准导入前建议先打开看一眼CREATE TABLE calendar ( id int(11) NOT NULL AUTO_INCREMENT COMMENT 自增主键, c_date date NOT NULL COMMENT 公历日期格式 yyyy-MM-dd, c_year smallint(6) NOT NULL COMMENT 公历年份, c_month tinyint(4) NOT NULL COMMENT 公历月份 1-12, c_day tinyint(4) NOT NULL COMMENT 公历日 1-31, c_week tinyint(4) NOT NULL COMMENT 星期0周日 1周一 ... 6周六, c_week_name varchar(8) NOT NULL COMMENT 星期中文名如 星期一, c_week_of_year tinyint(4) DEFAULT NULL COMMENT 当年第几周ISO 周序, c_quarter tinyint(4) DEFAULT NULL COMMENT 季度 1-4, c_is_weekend tinyint(1) DEFAULT 0 COMMENT 是否周末 1是 0否, c_is_holiday tinyint(1) DEFAULT 0 COMMENT 是否法定节假日 1是 0否, c_holiday_name varchar(32) DEFAULT NULL COMMENT 节假日名称如 春节, c_lunar_date varchar(32) DEFAULT NULL COMMENT 农历日期描述, PRIMARY KEY (id), UNIQUE KEY uk_c_date (c_date), KEY idx_year_month (c_year,c_month) ) ENGINEInnoDB DEFAULT CHARSETutf8 COMMENT万年历表 1970-2100;字段设计上有几个点值得注意。c_date上建唯一索引保证同一天不会重复插入导入时如果 SQL 里用了INSERT IGNORE或REPLACE重复执行也不会炸。c_week用 0 表示周日是 MySQLDAYOFWEEK()的默认约定但很多业务习惯周一为 1导入后要确认一下别直接拿去和WEEKDAY()的结果比对两者差一天。c_week_of_year如果是 ISO 周序跨年那几天会出现「12 月 31 日属于下一年第 1 周」的情况做周维度报表时要注意。2.3 日期跨度与数据量估算1970 到 2100 一共 131 年按每年 365 或 366 天算总行数在 47800 行左右。这个量级对 MySQL 来说非常小单表全量导入几秒钟的事不需要分表。导入后表大小通常在几 MB 以内随便一台开发机都能扛。跨度设计上1970 这个起点不是随便选的它对齐 Unix 时间戳方便和FROM_UNIXTIME()互相转换。2100 这个终点要注意2100 不是闰年能被 100 整除但不能被 400 整除所以 2100 年 2 月只有 28 天如果你的业务算到 2100 年之后这份数据就不够了得自己补。常见做法是导入后跑一句SELECT MAX(c_date) FROM calendar;确认终点确实是 2100-12-31别拿到一份被截断的 SQL。3. 导入实操建库、编码设置与批量插入验证3.1 建库时把编码定死摘要里特别提了一句「编码格式是 utf8创建的时候注意一下编码格式」这不是客套话。如果建库时用了默认的 latin1导入含中文的节假日名称或农历描述时会变乱码而且乱码是写进表里的事后改库编码救不回来只能重导。所以第一步就把字符集定死-- 建库时显式指定字符集和排序规则 CREATE DATABASE calendar_db DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; -- 切换到这个库 USE calendar_db; -- 确认当前库的编码输出应该是 utf8 SELECT DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME calendar_db;这里用utf8而不是utf8mb4是因为这份 SQL 本身是 utf8 编码的节假日名称和农历描述都是常用汉字utf8 三字节足够存。如果你的 MySQL 版本是 8.0 且默认字符集已经是 utf8mb4建库时写 utf8 也能兼容但导入前最好用file命令或编辑器确认 SQL 文件本身的编码别出现「文件是 GBK、库是 utf8」这种错配。3.2 两种导入方式与执行顺序导入有两种常见做法看 SQL 文件里建表和插入是不是分开的。如果文件里已经包含CREATE TABLE和INSERT直接整文件导入# 方式一命令行整文件导入-u 用户名 -p 回车后输密码 mysql -u root -p calendar_db 万年历mysql数据库.sql # 导入完成后进库验证行数和日期范围 mysql -u root -p calendar_db -e SELECT COUNT(*) AS total_rows, MIN(c_date) AS min_date, MAX(c_date) AS max_date FROM calendar;如果文件里只有插入语句、建表要自己来那就先执行 2.2 节的建表语句再导入数据。命令行导入比用图形工具拖拽更稳因为图形工具在处理大文件时偶尔会截断而mysql 是流式读取几万行不会出问题。导入时如果报ERROR 1366 (HY000): Incorrect string value基本就是编码没对上回到 3.1 检查库编码和文件编码。3.3 导入后的三条验证 SQL导入不是看到「Query OK」就完事得验证数据真的对。我一般跑三条-- 验证一抽查几个已知日期2024-01-01 是周一2024-02-29 存在闰年 SELECT c_date, c_week, c_week_name, c_is_weekend FROM calendar WHERE c_date IN (2024-01-01, 2024-02-29, 2100-02-28, 2100-03-01); -- 验证二确认没有重复日期结果应为 0 SELECT COUNT(*) AS dup_count FROM ( SELECT c_date FROM calendar GROUP BY c_date HAVING COUNT(*) 1 ) t; -- 验证三确认总行数在合理区间47800 左右 SELECT COUNT(*) FROM calendar;第一条验证里2024-02-29 能查出来说明闰年数据没漏2100-02-28 和 2100-03-01 能查出来说明 2100 年非闰年处理正确。第二条查重复如果结果不是 0说明导入时唯一索引没生效或者 SQL 里有重复插入得清表重来。第三条看总量如果只有几千行多半是 SQL 文件被截断或者导入中途报错没注意。提示导入前先在测试库跑一遍确认行数和日期范围无误再上生产库避免脏数据污染业务表。4. 避坑排查导入万年历 SQL 最容易翻车的五个地方4.1 现象导入报 1366 编码错误中文变问号原因SQL 文件本身是 GBK 或 UTF-8 带 BOM而目标库是 latin1 或 utf8两边对不上。带 BOM 的文件尤其坑MySQL 会把 BOM 头当成 SQL 语句的一部分报语法错误或插入乱码。解决先用编辑器把文件另存为「UTF-8 无 BOM」再确认库编码是 utf8。命令行下可以用file -i 万年历mysql数据库.sql看文件编码输出charsetutf-8才正常。如果已经导入了乱码数据别试图 UPDATE 修复直接TRUNCATE TABLE calendar;清空重导。4.2 现象日期范围不对最大日期只到 2038 年原因有些日历数据是用 32 位时间戳生成的2038-01-19 是 32 位有符号整数的上限超过就溢出。如果这份 SQL 是从某个老系统导出的可能被截断在 2038 年。解决导入后立刻跑SELECT MAX(c_date) FROM calendar;如果结果不是 2100-12-31说明数据不完整。这份资源标题明确写了到 2100 年正常应该完整但拿到任何 SQL 都先验证终点这是血泪经验。4.3 现象星期对不上业务算出来差一天原因c_week字段的约定和业务代码不一致。MySQLDAYOFWEEK()返回 1周日WEEKDAY()返回 0周一而这份表可能用 0周日。三种约定混用差一天是必然的。解决导入后先查一个已知日期比如 2024-01-01 是周一看c_week返回的是 1 还是 2确认约定后再写业务代码。别凭感觉假设我见过太多因为星期差一天导致排班全错的案例。4.4 现象节假日字段全是 0判断不出调休原因法定节假日和调休每年由相关部门发布这份 SQL 生成时的节假日数据可能只覆盖到某一年之后的年份c_is_holiday默认是 0。解决把节假日字段当成「基础数据 年度维护」来用。导入后查一下SELECT c_year, COUNT(*) FROM calendar WHERE c_is_holiday 1 GROUP BY c_year;看覆盖到哪一年。之后的年份需要自己按年度更新常见做法是每年年底批量 UPDATE 下一年的节假日标记。4.5 现象批量插入慢几万行跑了十几分钟原因SQL 文件里如果是逐条INSERT INTO ... VALUES (...);几万条就是几万次事务提交InnoDB 每次提交都要刷盘慢是正常的。解决导入前临时关闭自动提交或者把多条 INSERT 合并成批量插入。命令行导入时可以加参数# 导入时关闭自动提交并加大包大小加快批量插入 mysql -u root -p --init-commandSET autocommit0; calendar_db 万年历mysql数据库.sql如果 SQL 文件本身是逐条插入且不方便改导入慢就慢点几万行十几分钟能接受别为了快把innodb_flush_log_at_trx_commit改成 0生产库上这么干有丢数据风险。5. 进阶用法把日历表接进业务查询与年度维护导入只是第一步真正省事的是把它接进日常查询。最常见的三个场景算工作日天数、按周聚合、判断账期。下面这段 SQL 是算某个月的工作日天数直接 join 日历表比用函数循环快得多-- 算 2024 年 2 月的工作日天数排除周末和法定节假日 SELECT COUNT(*) AS work_days FROM calendar WHERE c_year 2024 AND c_month 2 AND c_is_weekend 0 AND c_is_holiday 0;参数说明c_is_weekend 0排除周六周日c_is_holiday 0排除法定节假日。如果你的业务把调休上班的周末也算工作日那条件要改成(c_is_weekend 0 OR c_is_holiday -1)具体看表里调休是怎么标记的导入后先SELECT DISTINCT c_is_holiday FROM calendar;看有哪些取值。按周聚合做报表时用c_week_of_year分组但要注意跨年周。ISO 周序下每年第 1 周可能包含上一年的 12 月 29-31 日所以分组时最好带上c_year一起或者直接用YEARWEEK(c_date, 3)现算和表里的周序字段交叉验证。年度维护是个长期活。我的习惯是每年 11 月把下一年的节假日安排更新进表用一条批量 UPDATE 搞定-- 示例把 2025 年春节假期标记为节假日日期仅为示例以实际安排为准 UPDATE calendar SET c_is_holiday 1, c_holiday_name 春节 WHERE c_date BETWEEN 2025-01-28 AND 2025-02-03; -- 更新完确认影响行数别 UPDATE 错范围 SELECT ROW_COUNT() AS affected_rows;执行 UPDATE 前一定先SELECT一遍确认日期范围我吃过亏BETWEEN的边界写错一天把整个月都标成节假日报表直接崩了。从那以后我每次改节假日数据都强制走一遍「先 SELECT 确认、再 UPDATE、最后 ROW_COUNT 核对」的流程多花两分钟省得事后回滚。这份万年历数据库把 1970 到 2100 的基础数据一次性铺好剩下的就是按业务节奏维护年度字段希望帮到你。本文还有配套的精品资源点击获取