每日一记:日期处理

日期处理,可以判断是不是闰年,也可以判断是不是输入的日期是不是今年金年今日

那如果这么玩呢?你又如何面对?上才艺!

如果你有更好的见解,欢迎在评论区留言,

题目一:基础日期处理

功能要求:

  1. 获取当前北京时间的标准年月日(格式:xxxx,xx,xx
  2. 输入一个日期(格式必须为xxxx,xx,xx),实现以下判断:
    • 判断是否为当前年份
    • 判断该年份是否为闰年
    • 若早于当前年份,计算已过去的年数
    • 若晚于当前年份,计算还需多少年
  3. 日期差计算:
    • 判断是否为今天
    • 若早于今天,计算已过去的天数
    • 若晚于今天,计算还需多少天

实现要求:

  • 所有日期数据必须使用char类型字符串表示
  • 禁止使用int类型存储日期数据
  • 日期合法性检查:
    • 格式必须严格符合xxxx,xx,xx
    • 月份必须在01-12范围内
    • 日期必须在该月有效范围内(考虑闰年二月)
题目二:两种实现方法

要求:

  1. 实现两个版本的程序:
    • 版本1:使用简单方法实现(非指针)
    • 版本2:使用指针操作字符串实现
  2. 每个版本单独一个源文件
  3. 文件内需包含精准注释:
    • 文件头注释说明实现方法
    • 关键函数功能注释
    • 重要代码行注释
题目三:朝代判断扩展

功能扩展:

  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(&current);
    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(&current, &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(&current);
    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(&current, &input);
    if (days == 0) {
        printf("输入的日期就是今天\n");
    } else if (days < 0) {
        printf("输入的日期已经过去了%d天\n", -days);
    } else {
        printf("距离输入的日期还有%d天\n", days);
    }
    
    return 0;  // 正常退出
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

司铭鸿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值