日期处理,可以判断是不是闰年,也可以判断是不是输入的日期是不是今年金年今日
那如果这么玩呢?你又如何面对?上才艺!
如果你有更好的见解,欢迎在评论区留言,
题目一:基础日期处理
功能要求:
- 获取当前北京时间的标准年月日(格式:
xxxx,xx,xx
) - 输入一个日期(格式必须为
xxxx,xx,xx
),实现以下判断:- 判断是否为当前年份
- 判断该年份是否为闰年
- 若早于当前年份,计算已过去的年数
- 若晚于当前年份,计算还需多少年
- 日期差计算:
- 判断是否为今天
- 若早于今天,计算已过去的天数
- 若晚于今天,计算还需多少天
实现要求:
- 所有日期数据必须使用
char
类型字符串表示 - 禁止使用
int
类型存储日期数据 - 日期合法性检查:
- 格式必须严格符合
xxxx,xx,xx
- 月份必须在01-12范围内
- 日期必须在该月有效范围内(考虑闰年二月)
- 格式必须严格符合
题目二:两种实现方法
要求:
- 实现两个版本的程序:
- 版本1:使用简单方法实现(非指针)
- 版本2:使用指针操作字符串实现
- 每个版本单独一个源文件
- 文件内需包含精准注释:
- 文件头注释说明实现方法
- 关键函数功能注释
- 重要代码行注释
题目三:朝代判断扩展
功能扩展:
- 在前两题基础上增加朝代判断功能
- 交互流程:
- 程序首先询问"是否显示朝代信息?(1:是 0:否)"
- 若选择1:
- 提示输入年份(公元前用负号,如-1000)
- 输出该年份对应的朝代信息(如"公元前1000年,是西周")
- 继续执行日期处理功能
- 若选择0:直接执行日期处理功能
数据要求:
- 朝代数据需参考提供的朝代表
- 使用结构体数组存储朝代信息(名称、起止年份)
- 起止年份使用字符串格式存储
那这两个代码要如何写出来呢?
/**
* 功能:
* 1. 获取当前北京标准年月日
* 2. 验证输入日期格式和合法性
* 3. 判断年份关系和闰年
* 4. 计算日期差值
* 5. 朝代判断功能
*/
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#define DATE_LEN 10 // xxxx,xx,xx
// 日期结构体(全字符串)
typedef struct {
char year[5]; // 4位年份+null
char month[3]; // 2位月份
char day[3]; // 2位日期
} StringDate;
// 朝代表结构体(根据搜索结果整理)
typedef struct {
const char* name; // 朝代名称
const char* start; // 开始年份(字符串)
const char* end; // 结束年份(字符串)
} Dynasty;
// 简化版朝代表(完整版应根据搜索结果补充)
Dynasty dynasties[] = {
{"夏朝", "-2146", "-1675"},
{"商朝", "-1675", "-1029"},
{"西周", "-1029", "-771"},
{"东周", "-770", "-256"},
{"秦朝", "-221", "-207"},
{"西汉", "-206", "8"},
{"东汉", "25", "220"},
{"三国", "220", "280"},
{"西晋", "265", "316"},
{"东晋", "317", "420"},
{"隋朝", "581", "618"},
{"唐朝", "618", "907"},
{"北宋", "960", "1127"},
{"南宋", "1127", "1279"},
{"元朝", "1206", "1368"},
{"明朝", "1368", "1644"},
{"清朝", "1616", "1911"},
{"中华人民共和国", "1949", "9999"}
};
/**
* @brief 检查字符串是否全为数字
* @param str 字符串指针
* @param len 检查长度
*/
bool is_digits(const char* str, int len) {
for (int i = 0; i < len; i++) {
if (!isdigit(str[i])) return false;
}
return true;
}
/**
* @brief 验证日期格式xxxx,xx,xx
* @param date 日期字符串
*/
bool validate_format(const char* date) {
if (strlen(date) != DATE_LEN) return false;
if (date[4] != ',' || date[7] != ',') return false;
return is_digits(date,4) && is_digits(date+5,2) && is_digits(date+8,2);
}
/**
* @brief 验证日期合法性
* @param date 日期结构体指针
*/
bool validate_date(const StringDate* date) {
const char* months[] = {"01","02","03","04","05","06","07","08","09","10","11","12"};
const char* days[] = {"31","28","31","30","31","30","31","31","30","31","30","31"};
// 验证月份
bool valid_month = false;
for (int i = 0; i < 12; i++) {
if (strcmp(date->month, months[i]) == 0) {
valid_month = true;
break;
}
}
if (!valid_month) return false;
// 验证日期
int month_idx = atoi(date->month) - 1;
int max_day = atoi(days[month_idx]);
// 处理闰年二月
int year = atoi(date->year);
if (month_idx == 1 && ((year%4==0 && year%100!=0) || year%400==0)) {
max_day = 29;
}
int day = atoi(date->day);
return day >= 1 && day <= max_day;
}
/**
* @brief 获取当前北京时间
* @param date 输出日期结构体
*/
void get_current_date(StringDate* date) {
time_t now = time(NULL);
struct tm* tm = localtime(&now);
snprintf(date->year, 5, "%04d", tm->tm_year + 1900);
snprintf(date->month, 3, "%02d", tm->tm_mon + 1);
snprintf(date->day, 3, "%02d", tm->tm_mday);
}
/**
* @brief 计算两个日期的天数差
* @param d1 日期1
* @param d2 日期2
* @return 天数差 (d2-d1)
*/
int days_between(const StringDate* d1, const StringDate* d2) {
struct tm tm1 = {0}, tm2 = {0};
tm1.tm_year = atoi(d1->year) - 1900;
tm1.tm_mon = atoi(d1->month) - 1;
tm1.tm_mday = atoi(d1->day);
tm2.tm_year = atoi(d2->year) - 1900;
tm2.tm_mon = atoi(d2->month) - 1;
tm2.tm_mday = atoi(d2->day);
time_t t1 = mktime(&tm1);
time_t t2 = mktime(&tm2);
return (int)difftime(t2, t1) / (60*60*24);
}
/**
* @brief 判断是否为闰年
* @param year 年份字符串
*/
bool is_leap_year(const char* year) {
int y = atoi(year);
return (y%4==0 && y%100!=0) || y%400==0;
}
/**
* @brief 判断年份所属朝代(基于搜索结果)
* @param year 年份字符串(支持公元前负数)
* @return 朝代名称
*/
const char* get_dynasty(const char* year) {
int y = atoi(year);
for (int i = 0; i < sizeof(dynasties)/sizeof(Dynasty); i++) {
int start = atoi(dynasties[i].start);
int end = atoi(dynasties[i].end);
if (y >= start && y <= end) {
return dynasties[i].name;
}
}
return "未知朝代";
}
int main() {
StringDate current, input;
get_current_date(¤t);
printf("当前日期: %s,%s,%s\n", current.year, current.month, current.day);
// 朝代判断选择
printf("是否要显示朝代信息?(1:是 0:否): ");
int choice;
scanf("%d", &choice);
if (choice == 1) {
char year_str[10];
printf("请输入年份(公元前用负数,如-1000): ");
scanf("%s", year_str);
const char* dynasty = get_dynasty(year_str);
if (atoi(year_str) < 0) {
printf("公元前%d年,是%s\n", -atoi(year_str), dynasty);
} else {
printf("公元%d年,是%s\n", atoi(year_str), dynasty);
}
}
// 日期处理部分
char input_str[DATE_LEN+1];
printf("请输入日期(xxxx,xx,xx): ");
scanf("%10s", input_str);
if (!validate_format(input_str)) {
printf("错误: 日期格式不正确\n");
return 1;
}
strncpy(input.year, input_str, 4);
input.year[4] = '\0';
strncpy(input.month, input_str+5, 2);
input.month[2] = '\0';
strncpy(input.day, input_str+8, 2);
input.day[2] = '\0';
if (!validate_date(&input)) {
printf("错误: 日期不合法\n");
return 1;
}
// 年份比较
int year_cmp = strcmp(input.year, current.year);
if (year_cmp == 0) {
printf("输入的日期是今年\n");
printf("%s年%s闰年\n", input.year, is_leap_year(input.year)?"是":"不是");
} else if (year_cmp < 0) {
printf("输入的日期比今年早%d年\n", atoi(current.year)-atoi(input.year));
} else {
printf("输入的日期比今年晚%d年\n", atoi(input.year)-atoi(current.year));
}
// 天数比较
int days = days_between(¤t, &input);
if (days == 0) {
printf("输入的日期就是今天\n");
} else if (days < 0) {
printf("输入的日期已经过去了%d天\n", -days);
} else {
printf("距离输入的日期还有%d天\n", days);
}
return 0;
}
再来个指针的
/**
* 1. 获取当前北京标准年月日
* 2. 验证输入日期格式和合法性
* 3. 判断年份关系和闰年
* 4. 计算日期差值
* 5. 朝代判断功能
*
*/
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdlib.h>
#define DATE_LEN 10 // 日期格式长度(xxxx,xx,xx)
// 日期结构体(全字符串)
typedef struct {
char year[5]; // 4位年份+null终止符
char month[3]; // 2位月份
char day[3]; // 2位日期
} StringDate;
// 朝代表结构体
typedef struct {
const char* name; // 朝代名称
const char* start; // 开始年份(字符串)
const char* end; // 结束年份(字符串)
} Dynasty;
// 简化版朝代表(根据历史资料整理)
Dynasty dynasties[] = {
{"夏朝", "-2146", "-1675"}, // 约公元前2146-前1675年
{"商朝", "-1675", "-1029"}, // 约公元前1675-前1029年
{"西周", "-1029", "-771"}, // 约公元前1029-前771年
{"东周", "-770", "-256"}, // 约公元前770-前256年
{"秦朝", "-221", "-207"}, // 公元前221-前207年
{"西汉", "-206", "8"}, // 公元前206年-公元8年
{"东汉", "25", "220"}, // 公元25-220年
{"三国", "220", "280"}, // 公元220-280年
{"西晋", "265", "316"}, // 公元265-316年
{"东晋", "317", "420"}, // 公元317-420年
{"隋朝", "581", "618"}, // 公元581-618年
{"唐朝", "618", "907"}, // 公元618-907年
{"北宋", "960", "1127"}, // 公元960-1127年
{"南宋", "1127", "1279"}, // 公元1127-1279年
{"元朝", "1206", "1368"}, // 公元1206-1368年
{"明朝", "1368", "1644"}, // 公元1368-1644年
{"清朝", "1616", "1911"}, // 公元1616-1911年
{"中华人民共和国", "1949", "9999"} // 1949年至今
};
/**
* @brief 使用指针检查字符串是否全为数字
* @param str 待检查字符串指针
* @param len 需要检查的长度
* @return true-全是数字, false-包含非数字字符
*/
bool is_digits_ptr(const char* str, int len) {
const char* p = str;
while (len-- > 0 && *p) { // 添加*p检查防止越界
if (!isdigit(*p++))
return false;
}
return len == -1; // 确保检查了指定长度
}
/**
* @brief 使用指针验证日期格式xxxx,xx,xx
* @param date 日期字符串指针
* @return true-格式正确, false-格式错误
*/
bool validate_format_ptr(const char* date) {
// 检查长度是否为10(xxxx,xx,xx)
if (strlen(date) != DATE_LEN)
return false;
// 使用指针算术检查分隔符位置
if (*(date + 4) != ',' || *(date + 7) != ',')
return false;
// 使用指针分段验证各部分数字
return is_digits_ptr(date, 4) && // 前4位(年)
is_digits_ptr(date + 5, 2) && // 中间2位(月)
is_digits_ptr(date + 8, 2); // 最后2位(日)
}
/**
* @brief 判断是否为闰年
* @param year 年份字符串
* @return true-闰年, false-平年
*/
bool is_leap_year(const char* year) {
int y = atoi(year);
// 闰年规则: 能被4整除但不能被100整除,或能被400整除
return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
}
/**
* @brief 使用指针验证日期合法性
* @param date 日期结构体指针
* @return true-日期合法, false-日期非法
*/
bool validate_date_ptr(const StringDate* date) {
// 月份验证 - 更高效的指针版本
int month_num = (date->month[0]-'0')*10 + (date->month[1]-'0');
if (month_num < 1 || month_num > 12) {
return false;
}
// 日期验证 - 使用指针直接访问字符
int max_day = 31;
const char* month = date->month; // 指向月份字符串
// 处理二月特殊情况
if (month[0] == '0' && month[1] == '2') { // 二月
max_day = is_leap_year(date->year) ? 29 : 28;
}
// 处理30天的月份
else {
switch (month[1]) { // 检查月份的第二位字符
case '4': case '6': case '9': // 4月、6月、9月
max_day = 30;
break;
case '1':
if (month[0] != '1') { // 11月除外
max_day = 30;
}
break;
}
}
// 使用指针直接计算日期值(避免atoi)
int day = (date->day[0]-'0')*10 + (date->day[1]-'0');
return day >= 1 && day <= max_day;
}
/**
* @brief 获取当前北京时间并填充到结构体
* @param date 输出参数,存储当前日期
*/
void get_current_date(StringDate* date) {
time_t now = time(NULL); // 获取当前时间戳
struct tm* tm = localtime(&now); // 转换为本地时间结构
// 格式化为字符串存储
snprintf(date->year, 5, "%04d", tm->tm_year + 1900); // 年(1900-based)
snprintf(date->month, 3, "%02d", tm->tm_mon + 1); // 月(0-based)
snprintf(date->day, 3, "%02d", tm->tm_mday); // 日
}
/**
* @brief 计算两个日期的天数差
* @param d1 起始日期
* @param d2 结束日期
* @return 天数差(d2-d1), 正数表示d2在d1之后
*/
int days_between(const StringDate* d1, const StringDate* d2) {
struct tm tm1 = {0}, tm2 = {0}; // 初始化时间结构体
// 填充tm1结构(起始日期)
tm1.tm_year = atoi(d1->year) - 1900; // tm_year是1900-based
tm1.tm_mon = atoi(d1->month) - 1; // tm_mon是0-based
tm1.tm_mday = atoi(d1->day);
// 填充tm2结构(结束日期)
tm2.tm_year = atoi(d2->year) - 1900;
tm2.tm_mon = atoi(d2->month) - 1;
tm2.tm_mday = atoi(d2->day);
// 转换为time_t值并计算差值(秒数)
time_t t1 = mktime(&tm1);
time_t t2 = mktime(&tm2);
return (int)difftime(t2, t1) / (60*60*24); // 秒数转天数
}
/**
* @brief 判断年份所属朝代
* @param year 年份字符串(支持公元前负数)
* @return 朝代名称字符串
*/
const char* get_dynasty(const char* year) {
int y = atoi(year); // 转换为整数
// 遍历朝代表查找匹配的朝代
for (int i = 0; i < sizeof(dynasties)/sizeof(Dynasty); i++) {
int start = atoi(dynasties[i].start);
int end = atoi(dynasties[i].end);
if (y >= start && y <= end) {
return dynasties[i].name; // 返回匹配的朝代名称
}
}
return "未知朝代"; // 未找到匹配朝代
}
/**
* @brief 主函数
* @return 程序退出状态码
*/
int main() {
StringDate current, input; // 定义当前日期和输入日期结构体
// 获取并显示当前日期
get_current_date(¤t);
printf("当前日期: %s,%s,%s\n", current.year, current.month, current.day);
// 朝代判断选择
printf("是否要显示朝代信息?(1:是 0:否): ");
int choice;
scanf("%d", &choice);
if (choice == 1) {
char year_str[10];
printf("请输入年份(公元前用负数,如-1000): ");
scanf("%s", year_str);
// 获取并显示朝代信息
const char* dynasty = get_dynasty(year_str);
if (atoi(year_str) < 0) {
printf("公元前%d年,是%s\n", -atoi(year_str), dynasty);
} else {
printf("公元%d年,是%s\n", atoi(year_str), dynasty);
}
}
// 日期处理部分 - 使用指针实现
char input_str[DATE_LEN+1]; // 输入缓冲区(+1给null终止符)
printf("请输入日期(xxxx,xx,xx): ");
scanf("%10s", input_str); // 限制输入长度防止溢出
// 使用指针验证日期格式
if (!validate_format_ptr(input_str)) {
printf("错误: 日期格式不正确\n");
return 1;
}
// 使用指针解析输入字符串
char* p = input_str; // 指向输入字符串起始位置
strncpy(input.year, p, 4); // 拷贝前4位(年)
input.year[4] = '\0'; // 确保字符串终止
p += 5; // 跳过逗号
strncpy(input.month, p, 2); // 拷贝月份
input.month[2] = '\0';
p += 3; // 跳过逗号
strncpy(input.day, p, 2); // 拷贝日期
input.day[2] = '\0';
// 使用指针验证日期合法性
if (!validate_date_ptr(&input)) {
printf("错误: 日期不合法\n");
return 1;
}
// 年份比较
int year_cmp = strcmp(input.year, current.year);
if (year_cmp == 0) {
printf("输入的日期是今年\n");
printf("%s年%s闰年\n", input.year,
is_leap_year(input.year)?"是":"不是");
} else if (year_cmp < 0) {
printf("输入的日期比今年早%d年\n",
atoi(current.year)-atoi(input.year));
} else {
printf("输入的日期比今年晚%d年\n",
atoi(input.year)-atoi(current.year));
}
// 计算并显示天数差
int days = days_between(¤t, &input);
if (days == 0) {
printf("输入的日期就是今天\n");
} else if (days < 0) {
printf("输入的日期已经过去了%d天\n", -days);
} else {
printf("距离输入的日期还有%d天\n", days);
}
return 0; // 正常退出
}