C语言如何校验rrrrmmdd格式日期 修复日期前导零识别异常问题
8位YYYYMMDD格式日期校验修复方案
核心故障原因
- 你用
log10(abs(数值)) + 1计算月/日的长度逻辑错误:带前导零的日期值(比如05)转成整数后是5,计算出来的长度为1,不满足你设定的长度等于2的判断条件,所以会被误判为无效 - 额外还存在多处逻辑错误:月份拆分时多余的
-30操作、用浮点数运算拆分年份存在精度风险、未处理fgets读取的换行符、未校验不同月份对应的合法天数等
修复后的代码
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> // 校验是否为闰年 int is_leap(int year) { return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); } int main() { char load[50]; long year, month, day; FILE *file; // 每月对应的最大天数,索引0占位,1-12对应1-12月 int max_days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; file = fopen("input.txt", "r"); if (file == NULL) { printf("文件打开失败"); return 1; } while (fgets(load, sizeof load, file) != NULL) { // 去掉fgets读取到的换行符 int len = strlen(load); if (load[len-1] == '\n') { load[len-1] = '\0'; len--; } // 先校验长度必须是8位,且全为数字 if (len != 8) { printf("Invalid input.\n"); continue; } int is_all_num = 1; for (int i=0; i<8; i++) { if (!isdigit(load[i])) { is_all_num = 0; break; } } if (!is_all_num) { printf("Invalid input.\n"); continue; } // 按位置拆分年、月、日,天然兼容前导零 char year_str[5] = {0}, month_str[3] = {0}, day_str[3] = {0}; strncpy(year_str, load, 4); strncpy(month_str, load+4, 2); strncpy(day_str, load+6, 2); year = atoi(year_str); month = atoi(month_str); day = atoi(day_str); // 校验范围 int valid = 1; if (month < 1 || month > 12) { valid = 0; } else { // 处理闰年2月的天数 int max_day = max_days[month]; if (month == 2 && is_leap(year)) { max_day = 29; } if (day <1 || day > max_day) { valid = 0; } } if (valid) { printf("Datum: %s\n", load); } else { printf("Invalid input.\n"); } } fclose(file); return 0; }
主要修改点
- 先处理读取到的换行符,避免长度判断错误
- 新增纯数字校验,避免非数字内容的非法输入
- 直接按字符串位置拆分年、月、日,不需要复杂的数值运算,天然支持前导零的场景,完全取消了用
log10计算长度的错误逻辑 - 补充闰年校验、不同月份的天数校验逻辑,避免出现
20230230、20230431这类非法日期 - 修复了原代码中月份拆分错误的问题
- 如果你只需要校验第一行日期,可以在while循环内加对应的判断逻辑即可
内容的提问来源于stack exchange,提问作者user17277981
相关产品推荐
相关产品推荐

