Linux时间函数2-时间格式转换:①当地时间 localtime、localtime_r ②UTC 时间‌ gmtime、gmtime_r ③设置时间转换秒数 mktime,并自动修正非法值

 目录 

1.时间格式转换

1.1 localtime() 

1.1.1 非线程安全版本(localtime)

1.1.2 线程安全版本(localtime_r)

1.2 gmtime()

1.2.1非线程安全版本(gmtime)

1.2.2线程安全版本(gmtime_r)

1.2.3 UTC与本地时间偏差

1.2.4 localtime与gmtime对比

1.3 mktime()

1.3.1 将 设置时间 转换为时间戳秒数

1.3.2 自动修正非法时间值

1.3.3 计算两个日期的天数差

1.3.4获取某天是星期几


程序源码:https://pan.baidu.com/s/1j5_EM_ah-E__wGXKmJbasg?pwd=kmrf

1.时间格式转换

1.1 localtime() 

函数原型:

#include <time.h>

struct tm *localtime(const time_t *timer);  // 非线程安全

 // 线程安全版本
struct tm *localtime_r(const time_t *timer, struct tm *result);

‌功能‌:将 time_t 类型的时间戳(自 1970-1-1 的秒数)转换为本地时间的 struct tm 结构体。

‌输入参数‌:
timer:指向 time_t 变量的指针。
result(仅 localtime_r):用户提供的 struct tm 存储地址。

‌返回值‌:
成功返回指向 struct tm 的指针,失败返回 NULL

struct tm 结构体:
struct tm 
{
    int tm_sec;   // 秒 [0-60](允许闰秒)
    int tm_min;   // 分 [0-59]
    int tm_hour;  // 时 [0-23]
    int tm_mday;  // 日 [1-31]
    int tm_mon;   // 月 [0-11](0 代表 1 月)
    int tm_year;  // 年(自 1900 年的偏移,如 2024 年为 124)
    int tm_wday;  // 星期 [0-6](0 代表周日)
    int tm_yday;  // 年中的第几天 [0-365]
    int tm_isdst; // 夏令时标志(>0 启用,=0 禁用,<0 未知)
};

1.1.1 非线程安全版本(localtime)

程序:

#include <stdio.h>
#include <time.h>

#if 0 
//  struct tm *localtime(const time_t *timep);
 struct tm {
    int tm_sec;   // 秒 [0-60]
    int tm_min;   // 分 [0-59]
    int tm_hour;  // 时 [0-23]
    int tm_mday;  // 日 [1-31]
    int tm_mon;   // 月 [0-11]
    int tm_year;  // 年(自 1900)
    int tm_wday;  // 星期 [0-6]
    int tm_yday;  // 年中的第几天 [0-365]
    int tm_isdst; // 夏令时标志
};
#endif

int main() 
{
    time_t now = time(NULL);  // 获取当前时间戳

    struct tm *tm_info = localtime(&now);  // 转换为本地时间
    if (tm_info == NULL) 
    {
        perror("localtime failed");
        return -1;
    }

    printf("当前时间:%04d-%02d-%02d %02d:%02d:%02d\n",
           tm_info->tm_year + 1900, tm_info->tm_mon + 1, tm_info->tm_mday,
           tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec);
    // 输出如 2025-02-06 14:30:29
    
    return 0;
}

运行结果:

1.1.2 线程安全版本(localtime_r)

程序:

#include <stdio.h>
#include <time.h>

#if 0 
//  struct tm *localtime(const time_t *timep);
 struct tm {
    int tm_sec;   // 秒 [0-60]
    int tm_min;   // 分 [0-59]
    int tm_hour;  // 时 [0-23]
    int tm_mday;  // 日 [1-31]
    int tm_mon;   // 月 [0-11]
    int tm_year;  // 年(自 1900)
    int tm_wday;  // 星期 [0-6]
    int tm_yday;  // 年中的第几天 [0-365]
    int tm_isdst; // 夏令时标志
};
#endif

int main() 
{
    time_t now = time(NULL);  // 获取当前时间戳

    struct tm tm_info;  // 用户分配的存储空间

	// 显式传递存储地址
    if (localtime_r(&now, &tm_info) == NULL) 
    {  
        perror("localtime_r failed");
        return -1;
    }

    printf("当前时间:%04d-%02d-%02d %02d:%02d:%02d\n",
           tm_info.tm_year + 1900, tm_info.tm_mon + 1, tm_info.tm_mday,
           tm_info.tm_hour, tm_info.tm_min, tm_info.tm_sec);
    // 输出如 2025-02-06 14:30:29
    
    return 0;
}

运行结果:

1.2 gmtime()

将 time_t 类型的时间戳(自 Epoch 的秒数)转换为 ‌UTC 时间‌(世界标准时间)。

函数原型:

#include <time.h>

struct tm *gmtime(const time_t *timer);  // 非线程安全

 // 线程安全版本
struct tm *gmtime_r(const time_t *timer, struct tm *result); 

‌功能‌:将 time_t 类型的时间戳(自 Epoch 的秒数)转换为 ‌UTC 时间‌(协调世界时)。

‌输入参数‌:
timer:指向 time_t 变量的指针。
result(仅 gmtime_r):用户提供的 struct tm 存储地址。

‌返回值‌:
成功返回指向 struct tm 的指针,失败返回 NULL。

struct tm结构体:
struct tm
 {
    int tm_sec;   // 秒 [0-60]
    int tm_min;   // 分 [0-59]
    int tm_hour;  // 时 [0-23]
    int tm_mday;  // 日 [1-31]
    int tm_mon;   // 月 [0-11](0 代表 1 月)
    int tm_year;  // 年(自 1900 年的偏移,如 2024 年为 124)
    int tm_wday;  // 星期 [0-6](0 代表周日)
    int tm_yday;  // 年中的第几天 [0-365]
    int tm_isdst; // 夏令时标志(UTC 时间中通常为 0)
};

1.2.1非线程安全版本(gmtime)

程序:

#include <stdio.h>
#include <time.h>

/*
struct tm {
    int tm_sec;   // 秒 [0-60]
    int tm_min;   // 分 [0-59]
    int tm_hour;  // 时 [0-23]
    int tm_mday;  // 日 [1-31]
    int tm_mon;   // 月 [0-11](0 代表 1 月)
    int tm_year;  // 年(自 1900 年的偏移,如 2024 年为 124)
    int tm_wday;  // 星期 [0-6](0 代表周日)
    int tm_yday;  // 年中的第几天 [0-365]
    int tm_isdst; // 夏令时标志(UTC 时间中通常为 0)
};
*/

int main()
{
    time_t now = time(NULL);  // 获取当前时间戳

    struct tm *tm_utc = gmtime(&now);  // 转换为 UTC 时间
    if (tm_utc == NULL) 
    {
        perror("gmtime failed");
        return -1;
    }

    printf("UTC 时间:%04d-%02d-%02d %02d:%02d:%02d\n",
           tm_utc->tm_year + 1900, tm_utc->tm_mon + 1, tm_utc->tm_mday,
           tm_utc->tm_hour, tm_utc->tm_min, tm_utc->tm_sec);
    // 输出如 UTC 时间:2024-06-06 06:30:00(假设本地时区为 UTC+8)
    return 0;
}

运行结果:

1.2.2线程安全版本(gmtime_r)

程序:

#include <stdio.h>
#include <time.h>

/*
struct tm {
    int tm_sec;   // 秒 [0-60]
    int tm_min;   // 分 [0-59]
    int tm_hour;  // 时 [0-23]
    int tm_mday;  // 日 [1-31]
    int tm_mon;   // 月 [0-11](0 代表 1 月)
    int tm_year;  // 年(自 1900 年的偏移,如 2024 年为 124)
    int tm_wday;  // 星期 [0-6](0 代表周日)
    int tm_yday;  // 年中的第几天 [0-365]
    int tm_isdst; // 夏令时标志(UTC 时间中通常为 0)
};
*/

int main()
{
    time_t now = time(NULL);  // 获取当前时间戳

    struct tm tm_utc;  // 用户分配的存储空间

    if (gmtime_r(&now, &tm_utc) == NULL) 
    {
        perror("gmtime_r failed");
        return -1;
    }

    printf("UTC 时间:%04d-%02d-%02d %02d:%02d:%02d\n",
           tm_utc.tm_year + 1900, tm_utc.tm_mon + 1, tm_utc.tm_mday,
           tm_utc.tm_hour, tm_utc.tm_min, tm_utc.tm_sec);
    // 输出如 UTC 时间:2024-06-06 06:30:00(假设本地时区为 UTC+8)
    return 0;
}

运行结果:

1.2.3 UTC与本地时间偏差

程序:

#include <stdio.h>
#include <time.h>

/*
struct tm {
    int tm_sec;   // 秒 [0-60]
    int tm_min;   // 分 [0-59]
    int tm_hour;  // 时 [0-23]
    int tm_mday;  // 日 [1-31]
    int tm_mon;   // 月 [0-11](0 代表 1 月)
    int tm_year;  // 年(自 1900 年的偏移,如 2024 年为 124)
    int tm_wday;  // 星期 [0-6](0 代表周日)
    int tm_yday;  // 年中的第几天 [0-365]
    int tm_isdst; // 夏令时标志(UTC 时间中通常为 0)
};
*/

int main() 
{
    time_t now = time(NULL);
    struct tm tm_local, tm_utc;

    localtime_r(&now, &tm_local);  // 本地时间
    gmtime_r(&now, &tm_utc);       // UTC 时间

    // 计算时区偏移(单位:秒)
    int time_offset = (tm_local.tm_hour - tm_utc.tm_hour) * 3600 +
                          (tm_local.tm_min - tm_utc.tm_min) * 60;
                          
    printf("UTC 时间 与 本地时区偏移:%d 秒\n", time_offset);  
    return 0;
}

运行结果:

1.2.4 localtimegmtime对比

函数时区线程安全输入类型输出存储
localtime()本地时间time_t *静态内存
gmtime()UTCtime_t *静态内存
localtime_r()本地时间time_t *用户提供的内存
gmtime_r()UTCtime_t *用户提供的内存

1.3 mktime()

将本地时间的 struct tm 结构体转换为 time_t 类型的时间戳(自 1970-1-1 以来的秒数),并自动修正字段的非法值

(1)函数原型:

#include <time.h>

time_t mktime(struct tm *tm);

功能‌:将本地时间(struct tm)转换为 time_t 类型的时间戳(自1970-1-1的秒数)。
‌输入参数‌:指向 struct tm 的指针(时间值可能被修改)。

‌返回值‌:
成功返回对应的时间戳。
失败返回 (time_t)-1(如时间超出 time_t 表示范围)


struct tm 结构体(输入要求):
struct tm 
{
    int tm_sec;   // 秒 [0, 60](允许闰秒)
    int tm_min;   // 分 [0, 59]
    int tm_hour;  // 时 [0, 23]
    int tm_mday;  // 日 [1, 31]
    int tm_mon;   // 月 [0, 11](0 表示 1 月)
    int tm_year;  // 年(实际年份 = tm_year + 1900)
    int tm_isdst; // 夏令时标志(>0: 生效,0: 不生效,<0: 自动判断)
};

(2)核心特性 ‌

①自动修正非法时间值‌ 若输入的 tm 结构体字段(如 tm_mday=35)不合法,mktime() 会自动调整字段至有效值。 ‌示例‌:

示例一:
struct tm tm = {0};
tm.tm_year = 124;  // 2024 年
tm.tm_mon  = 1;    // 2 月
tm.tm_mday = 35;   // 非法日期(2 月最多 29 天)
mktime(&tm);       // 修正为 2024-03-06

示例二:
struct tm tm = {0};
tm.tm_year = 124;  // 2024 年
tm.tm_mon = 11;    // 12 月(合法)
tm.tm_mday = 32;   // 非法日期(12 月 32 日)
tm.tm_isdst = -1;

time_t t = mktime(&tm);
// 函数自动修正为 2025 年 1 月 1 日,并更新 tm 结构体字段
printf("修正后日期: %04d-%02d-%02d\n",
       tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
// 输出:2025-01-01

②依赖时区与夏令时‌

  • 使用 ‌本地时区‌(由系统或 TZ 环境变量决定)。
  • 自动处理夏令时(tm_isdst 字段可强制指定或设为 -1 由系统推断)

1.3.1 将 设置时间 转换为时间戳秒数

程序:


#include <stdio.h>
#include <time.h>

int main() 
{
    struct tm tmp = {0};
    tmp.tm_year = 124;  // 2024 年(2024 - 1900)
    tmp.tm_mon  = 5;    // 6 月(0 代表 1 月)
    tmp.tm_mday = 15;   // 15 日
    tmp.tm_hour = 14;   // 14 时
    tmp.tm_min  = 30;   // 30 分
    tmp.tm_sec  = 0;    // 0 秒
    tmp.tm_isdst = -1;  // 由系统推断是否夏令时

	//将 tm 转换为 秒数
    time_t timestamp = mktime(&tmp);
    if (timestamp == -1) 
    {
        perror("mktime failed");
        return -1;
    }
    printf("时间戳秒数:%ld s\n", timestamp);  
    return 0;
}

运行结果:

1.3.2 自动修正非法时间值

程序:

#include <stdio.h>
#include <time.h>

/*
struct tm 
{
    int tm_sec;   // 秒 [0, 60](允许闰秒)
    int tm_min;   // 分 [0, 59]
    int tm_hour;  // 时 [0, 23]
    int tm_mday;  // 日 [1, 31]
    int tm_mon;   // 月 [0, 11](0 表示 1 月)
    int tm_year;  // 年(实际年份 = tm_year + 1900)
    int tm_isdst; // 夏令时标志(>0: 生效,0: 不生效,<0: 自动判断)
};
*/

void test1()
{
	struct tm tmp = {0};
	tmp.tm_year = 124;  // 2024 年
	tmp.tm_mon = 11;    // 12 月(合法)
	tmp.tm_mday = 32;   // 非法日期(12 月 32 日)
	tmp.tm_isdst = -1;

	time_t t = mktime(&tmp);
	// 函数自动修正为 2025 年 1 月 1 日,并更新 tm 结构体字段
	printf("修正后日期: %04d-%02d-%02d\n",
	       tmp.tm_year + 1900, tmp.tm_mon + 1, tmp.tm_mday);
	// 输出:2025-01-01
}


void test2()
{
	struct tm tmp = {0};
	tmp.tm_year = 124;  // 2024 年
	tmp.tm_mon = 11;    // 12 月(合法)
	tmp.tm_mday = 28;   // 28 日(合法)
	tmp.tm_hour = 26;	// 26时 (不合法,时 [0, 23])
	tmp.tm_isdst = -1;

	time_t t = mktime(&tmp);
	// 函数自动修正为 2025 年 1 月 1 日,并更新 tm 结构体字段
	printf("修正后日期: %04d-%02d-%02d %02d时\n",
	       tmp.tm_year + 1900, tmp.tm_mon + 1, tmp.tm_mday, tmp.tm_hour + 1 );
	// 输出: 2024-12-29 03时
}

int main() 
{
    test1();
    printf("==\n");
	test2();
    return 0;
}

运行结果:

1.3.3 计算两个日期的天数差

程序:

#include <stdio.h>
#include <time.h>

/*
struct tm 
{
    int tm_sec;   // 秒 [0, 60](允许闰秒)
    int tm_min;   // 分 [0, 59]
    int tm_hour;  // 时 [0, 23]
    int tm_mday;  // 日 [1, 31]
    int tm_mon;   // 月 [0, 11](0 表示 1 月)
    int tm_year;  // 年(实际年份 = tm_year + 1900)
    int tm_isdst; // 夏令时标志(>0: 生效,0: 不生效,<0: 自动判断)
};
*/


int main() 
{
	 // 2024-06-15 20时
	struct tm date1 = { .tm_year=124, .tm_mon=5, .tm_mday=15, .tm_hour=20, .tm_isdst=-1 }; 
	 // 2024-06-20 16时
    struct tm date2 = { .tm_year=124, .tm_mon=5, .tm_mday=20,  .tm_hour=16, .tm_isdst=-1 }; 
    time_t t1 = mktime(&date1);
    time_t t2 = mktime(&date2);

    //计算两个 time_t 类型时间戳之间的差值(以秒为单位),t2为较晚时间
    double diff_days = difftime(t2, t1) / (24 * 3600);
	/*
	 double minutes = duration / 60;    // 分钟
	double hours = duration / 3600;     // 小时
	double days = duration / 86400;    // 天
	*/

    printf("相差天数:%.2f\n", diff_days);  // 输出 4.83
    return 0;
}

运行结果:

1.3.4获取某天是星期几

程序:

#include <stdio.h>
#include <time.h>

/*
struct tm 
{
    int tm_sec;   // 秒 [0, 60](允许闰秒)
    int tm_min;   // 分 [0, 59]
    int tm_hour;  // 时 [0, 23]
    int tm_mday;  // 日 [1, 31]
    int tm_mon;   // 月 [0, 11](0 表示 1 月)
    int tm_year;  // 年(实际年份 = tm_year + 1900)
    int tm_isdst; // 夏令时标志(>0: 生效,0: 不生效,<0: 自动判断)
};
*/


int main() 
{
	struct tm tmp = {.tm_year=124, .tm_mon=8, .tm_mday=26, .tm_isdst=-1};
	mktime(&tmp); // 自动填充 tm_wday(星期几)
	const char *weekdays[] = {"日", "一", "二", "三", "四", "五", "六"};
	printf(" %04d-%02d-%02d 是星期%s\n",tmp.tm_year + 1900, tmp.tm_mon+1, tmp.tm_mday ,weekdays[tmp.tm_wday]); 
	
    return 0;
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值