CRT中的时间(time_t和tm)

本文介绍了C语言中常用的时间处理函数,包括time、localtime_s、gmtime_s和mktime等函数的功能及使用方法,并通过示例代码展示了如何进行本地时间和UTC时间的转换。

    时间处理时实际项目中经常碰到的问题,这里介绍最常用的时间处理函数。

    首先介绍基本的时间概念。时间一般分为两种,一种是本地时间(Local Time),一种是协调世界时间(Coordinated Universal Time ,UTC),也就是传说中的格林威治时间。本地时间与UTC时间之间的差即为时差,比如,北京时间(东八区)比UTC时间晚8个小时。

    C运行库中处理时间的函数主要是这四个:

    

    time_t类型为32位或64位整型,具体类型由编译系统决定。此函数用来获得从1970年1月1日子夜(这个时刻在不同的CRT实现中可能会不一样)到当前时刻以来所流逝的时间,以秒为单位。这个时间差叫做日历时间(Calendar Time )。

    这是当然让我困惑的地方:这个特殊的时刻——1970年1月1日零时零分零秒——是指本地时间呢,还是UTC时间呢?我认为是本地时间,也就是各个时区自己的1970年1月1日零时零分零秒。可以设想这样一种情况,如果全球24时区各有一台电脑,都依次在自己所在时区的本地时间1970年1月1日零时1分零秒调用time函数,那么返回值都是60。注意,这里是依次调用(事实上是每隔1小时),而不是想象中的同时调用,这是因为相邻时区的同一本地时间,总是相差1小时。

    当然,time_t型的时间方便计算机处理,但普通用户无法理解这种数字。所以我们通常需要将time_t型时间转换成我们平常所见的年月日形式。CRT中为此定义了tm结构。

   

    注释中已详细解释了各个字段的用法。显然这个结构中的字段对用户更有意义。我们通常用localtime_s函数将time_t时间转换为tm时间。

   

    其中第二个参数为传入的time_t时间,第一个参数为返回的tm时间。由函数名可看出,返回的tm时间表示的是本地时间。当然,我们有时候也需要获得对应的UTC时间,这时我们需要gmtime函数。

   

    后面我们会看到两者的区别。

    我们知道了如何将time_t时间转换为tm时间。同样,我们会需要将tm表示的时间转换为time_t时间。这时我们需要mktime函数。

   

    此函数返回从"特殊时刻"到参数表示的时刻之间流逝的日历时间。另外还有个很好用的特性,就是它能修正传进来的tm结构中各字段的取值范围。比如,如果你将tm.tm_mon设为1,tm.tm_day设为33,然后以其为参数调用mktime函数,此函数会将tm.tm_mon修正为2,tm.tm_day修正为2。具体用法参照MSDN。

    我们来分析下面示例代码:

   

    输出结果如下:

    输出结果

    上面代码中,11行time函数获得从"特殊时刻"到当前时刻的日历时间,如输出结果中的第一行显示的1267192581秒。

    14行localtime_s函数将日历时间转换为本地tm时间,如输出结果第二行。

    18行gmtime_s函数将将日历时间转换为对应的UTC的tm时间,如输出结果第三行显示。很容易看出,第二,三行输出的时间相差8小时,因为我在东八区。如果你修改自己电脑的时区(在控制面板的Date and Time中修改),再运行此程序,比较两次的运行结果,你就可以更好的理解了。

    22行mktime函数将tm时间转换为日历时间,输出结果中第四行显示的结果与第一行一样,这是必须的。。。

#include <stdio.h> #include <st_t_time_members.h> #include <string.h> #include "aip_common.h" int main() { time_t u4_t_time_now =time (NULL); ST tm st_t_time_members; // 改为栈分配的结构体 localtime_s(&st_t_time_members, &u4_t_time_now); // 使用安全版本 // 中文星期数组 const U1* u1p_tp_cnweeks_members[] = { "日", "一", "二", "三", "四", "五", "六" }; // 英文月份数组 const U1* u1p_tp_enmonths_members[] = { "January", "February", "March", "April", "May", "June","July", "August", "September", "October", "November", "December" }; // 英文星期数组 const U1* u1p_tp_enweeks_members[] = { "Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday" }; // 日文星期数组 const U1* u1p_tp_jpweeks_members[] = { "日", "月", "火", "水", "木", "金", "土" }; // 格式1:2017年9月28日 星期四 14点26分13秒 printf("格式1:%d年%d月%d日 星期%s %d点%d分%d秒\n", st_t_time_members.tm_year + 1900, st_t_time_members.tm_mon + 1, st_t_time_members.tm_mday, u1p_tp_cnweeks_members[st_t_time_members.tm_wday], st_t_time_members.tm_hour, st_t_time_members.tm_min, st_t_time_members.tm_sec); // 格式2:2017/9/28 星期四 14:26:13 printf("格式2:%d/%d/%d 星期%s %d:%02d:%02d\n", st_t_time_members.tm_year + 1900, st_t_time_members.tm_mon + 1, st_t_time_members.tm_mday, u1p_tp_cnweeks_members[st_t_time_members.tm_wday], st_t_time_members.tm_hour, st_t_time_members.tm_min, st_t_time_members.tm_sec); // 格式3:2017/9/28 星期四 2:26:13(PM) int hour12 = st_t_time_members.tm_hour % 12; if (hour12 == 0) hour12 = 12; printf("格式3:%d/%d/%d 星期%s %d:%02d:%02d(%s)\n", st_t_time_members.tm_year + 1900, st_t_time_members.tm_mon + 1, st_t_time_members.tm_mday, u1p_tp_cnweeks_members[st_t_time_members.tm_wday], hour12, st_t_time_members.tm_min, st_t_time_members.tm_sec, (st_t_time_members.tm_hour >= 12) ? "PM" : "AM"); // 格式4:Thursday, September 28, 2017 14:26:13 printf("格式4:%s, %s %d, %d %02d:%02d:%02d\n", u1p_tp_enweeks_members[st_t_time_members.tm_wday], u1p_tp_enmonths_members[st_t_time_members.tm_mon], st_t_time_members.tm_mday, st_t_time_members.tm_year + 1900, st_t_time_members.tm_hour, st_t_time_members.tm_min, st_t_time_members.tm_sec); // 格式5:2017年9月28日() 2:26:13(PM) printf("格式5:%d年%d月%d日(%s) %d:%02d:%02d(%s)\n", st_t_time_members.tm_year + 1900, st_t_time_members.tm_mon + 1, st_t_time_members.tm_mday, u1p_tp_jpweeks_members[st_t_time_members.tm_wday], hour12, st_t_time_members.tm_min, st_t_time_members.tm_sec, (st_t_time_members.tm_hour >= 12) ? "PM" : "AM"); return 0; } 该代码有什么会导致无法运行的错误码
08-06
#include <iostream> #include <chrono> #include <ctime> #include <iomanip> #include <thread> #include <windows.h> // 依赖Windows控制台API using namespace std; void clearLastNLines(int n) { // 1. 获取标准输出句柄 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); if (hOut == INVALID_HANDLE_VALUE) { return; } // 2. 获取控制台缓冲区信息(含窗口大小、光标位置等) CONSOLE_SCREEN_BUFFER_INFO csbi; if (!GetConsoleScreenBufferInfo(hOut, &csbi)) { return; } // 3. 计算需要清空的行范围(最后n行) // 控制台窗口的行号从0开始,当前最后一行的行号为 csbi.dwCursorPosition.Y int lastRow = csbi.dwCursorPosition.Y; // 当前光标所在行(即最后一行) int startRow = lastRow - n + 1; // 要清空的起始行 if (startRow < 0) startRow = 0; // 避免越界 // 4. 循环清空每一行:用空格覆盖原有内容 COORD coord; // 光标位置 DWORD written; // 实际写入的字符数 for (int row = startRow; row <= lastRow; ++row) { // 定位光标到当前行的第0列(行首) coord.X = 0; coord.Y = row; SetConsoleCursorPosition(hOut, coord); // 用空格覆盖当前行(长度为窗口宽度) FillConsoleOutputCharacter( hOut, // 输出句柄 ' ', // 填充字符(空格) csbi.dwSize.X, // 填充长度(窗口宽度) coord, // 起始位置 &written // 输出的字符数(忽略) ); // 重置当前行的文本属性(可选,保持默认颜色) FillConsoleOutputAttribute( hOut, csbi.wAttributes, csbi.dwSize.X, coord, &written ); } // 5. 将光标定位到清空后的起始行(方便后续输出) coord.X = 0; coord.Y = startRow; SetConsoleCursorPosition(hOut, coord); } int main() { // 目标时间:2025年10月24日 21:39:27 tm target_tm = {}; target_tm.tm_year = 2025 - 1900; // 年份从1900开始计 target_tm.tm_mon = 10 - 1; // 月份从0开始(10月是第9个月) target_tm.tm_mday = 24; target_tm.tm_hour = 21; target_tm.tm_min = 39; target_tm.tm_sec = 27; // 将 tm 结构转换为 time_t(自UTC 1970-01-01以来的秒数) time_t target_time = mktime(&target_tm); while (true) { cout << "---------------------------------" << endl; cout << " NOP时间 " << endl; cout << "---------------------------------" << endl; // 获取当前时间 auto now = chrono::system_clock::now(); time_t now_time = chrono::system_clock::to_time_t(now); // 计算时间差(秒) double seconds_diff = difftime(now_time, target_time); // 输出信息 cout << "NOP时间: 2025-10-24 21:39:27" << endl; printf("\n"); int t = static_cast<long long>(seconds_diff); //提取时间/秒 //将时间转换为天、时、分、秒 int tk = t; int time_second = tk % 60; tk = tk / 60; int time_minute = tk % 60; tk /= 60; int time_hour = tk % 24; int time_day = tk / 24; printf("一共经历了%d天%d小时%d分钟%d秒\n", time_day, time_hour, time_minute, time_second); printf("\n%2d天:",time_day); for (int i = 0; i < time_day; i++) printf("正"); printf("\n%2d时:", time_hour); for (int i = 0; i < time_hour; i++) printf("正"); printf("\n%2d分:", time_minute); for (int i = 0; i < time_minute/2; i++) printf("正"); printf("\n%2d秒:", time_second); for (int i = 0; i < time_second/2; i++) printf("正"); this_thread::sleep_for(chrono::seconds(1)); system("cls"); //clearLastNLines(3); } return 0; } 以上代码为什么报错? 未知特性 "no_init_all"
10-26
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值