⏰介绍
<time.h>
是在C语言中的日期与时间工具。其中主要有三大模块,常量,类型和函数。
在C++中推荐写成<ctime>
,基本都是继承.h中的东西。
函数主要分为两类,时间操作
函数和格式转换
函数。
本文主要为C语言中的标准操作,其中在C11和C23又添加和废弃了许多内容,但这块不会本文着重讲解。
⏰常量
⏱️CLOCKS_PER_SEC
- CLOCKS_PER_SEC - cppreference.com
- (宏常量)
- 处理器每秒的时间计数
- 一般来说都是数值1000
#include <stdio.h>
#include <time.h>
int main(void) {
clock_t beg = clock();
clock_t end = clock();
printf("Use time:%lf\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
⏰类型
⏱️tm
-
(结构体)
-
日历时间类型
struct tm {
int tm_sec; // [秒 [0, 61] (C89) [0, 60] (C99)] seconds after the minute
int tm_min; // [分 [0, 59]] minutes after the hour
int tm_hour; // [时 [0, 23]] hours since midnight
int tm_mday; // [日 [1, 31]] day of the month
int tm_mon; // [月 [0, 11]] months since January
int tm_year; // [年 [1900:0]] years since 1900
int tm_wday; // [周 [0, 6]] days since Sunday
int tm_yday; // [第几天 [0, 365]] days since January 1
int tm_isdst; // [夏时令标签] daylight savings time flag
};
#include <stdio.h>
#include <time.h>
int main(void) {
struct tm start = {.tm_mday = 1};
mktime(&start);
// Sun Jan 01 00:00:00 1900
printf("%s\n", asctime(&start));
}
⏱️time_t
- time_t - cppreference.com
- (typedef)
- 从纪元开始的日历时间类型
⏱️clock_t
- clock_t - cppreference.com
- (typedef)
- 从时点开始的处理器时间类型
⏱️timespec
(C11)
- timespec - cppreference.com
- (结构体)
- 单位为秒和纳秒的时间
// 保有时间间隔的结构体,将其拆分成秒数和纳秒数。
struct timespec {
time_t tv_sec; // [秒 >= 0] Seconds
long tv_nsec; // [纳秒 [0, 999999999]] Nanoseconds
};
timespec_get()
C11 返回基于给定时间基底的日历时间
#include <stdint.h>
#include <stdio.h>
#include <time.h>
int main(void) {
struct timespec ts;
// C11 函数
// 修改 ts 所指向的 struct timespec 对象
// 以保有以时间基底 base 表示的当前日历时间。
#ifdef TIME_UTC
timespec_get(&ts, TIME_UTC);
#endif
char buff[100];
strftime(buff, sizeof buff, "%D %T", gmtime(&ts.tv_sec));
printf("Current time: %s.%09ld UTC\n", buff, ts.tv_nsec);
printf("Raw timespec.time_t: %jd\n", (intmax_t)ts.tv_sec);
printf("Raw timespec.tv_nsec: %09ld\n", ts.tv_nsec);
}
⏰函数-时间操作
⏲️time
🏷️返回纪元开始经过的当前系统日历时间
time_t time( time_t *arg );
- 运行失败
- return -1
- 运行成功
- 入参,返回值数值一致
#include <stdio.h>
#include <time.h>
int main(void) {
time_t in;
time_t out = time(&in);
// >success: out == in
// >error: -1
// 1709276388 = time(1709276388)
printf("%ld = time(%ld)\n", out, in);
return 0;
}
⏲️clock
🏷️返回未加工的程序启动时开始经过的处理器时间
clock_t clock(void);
最经典的应用就是计时器了。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ARR_LEN (100000)
// return (arg1 > arg2) - (arg1 < arg2); // 可行的简写
// return arg1 - arg2; // 错误的简写(若给出 INT_MIN 则会失败)
int cmp(const void* a, const void* b) {
int arg1 = *(const int*)a;
int arg2 = *(const int*)b;
if (arg1 < arg2) {
return -1;
}
if (arg1 > arg2) {
return 1;
}
return 0;
}
int main(void) {
int arr[ARR_LEN];
clock_t beg = clock();
qsort(arr, sizeof(arr) / sizeof(*arr), sizeof(int), cmp);
clock_t end = clock();
printf("Use time:%lf\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
⏲️difftime
🏷️计算时间差
double difftime( time_t time_end, time_t time_beg );
简单测了下和直接相减效果一样。可能是为了统一接口和适配器模式。
#include <stdio.h>
#include <time.h>
int main(void) {
time_t now = time(NULL);
time_t beg = {0};
// 计算时间差
double during = difftime(now, beg);
printf("Now:\t %lf\n", 1.0 * now);
printf("During:\t %lf\n", during);
}
⏰函数-格式转换-类型转换
⏲️gmtime
🏷️将从纪元开始的时间转换成以协调世界时(UTC)表示的日历时间
🏷️time_t -> tm
注意,这里存储的是一个全局的静态对象。
函数 gmtime
可能不是线程安全的。
struct tm *gmtime ( const time_t *timer );
#include <stdio.h>
#include <time.h>
int main(void) {
time_t t = time(NULL);
struct tm *tm_p1 = gmtime(&t);
struct tm *tm_p2 = gmtime(&t);
// 指向同一个静态对象
printf("First struct tm* = %p\n", tm_p1);
printf("Second struct tm* = %p\n", tm_p2);
printf("UTC: %s", asctime(gmtime(&t)));
printf("local: %s", asctime(localtime(&t)));
}
⏲️localtime
🏷️将从纪元开始的时间转换成以本地时间表示的日历时间
🏷️time_t -> tm
注意,这里存储的是一个全局的静态对象。
函数 localtime
可以不是线程安全的。
struct tm *localtime ( const time_t *timer );
#include <stdio.h>
#include <time.h>
int main(void) {
time_t t = time(NULL);
struct tm *tm_p1 = localtime(&t);
struct tm *tm_p2 = localtime(&t);
// 指向同一个静态对象
printf("First struct tm* = %p\n", tm_p1);
printf("Second struct tm* = %p\n", tm_p2);
printf("UTC: %s", asctime(gmtime(&t)));
printf("local: %s", asctime(localtime(&t)));
}
⏲️mktime
🏷️将日历时间转换成纪元开始经过的时间
🏷️tm -> time_t
time_t mktime( struct tm *time );
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
time_t now = time(NULL);
// 获取当前时间,并加一天
struct tm tmm = *localtime(&now);
tmm.tm_mday += 1;
time_t nexDay = mktime(&tmm);
printf("Now:\t%ld\n", now);
printf("NexDay:\t%ld\n", nexDay);
printf("OneDayTime:\t%lf\n", difftime(nexDay, now));
printf("24*60*60=\t%d\n", 24 * 60 * 60);
}
⏰函数-格式转换-文本表示
⏲️asctime
🏷️将 struct tm
对象转换成文本表示
🏷️tm -> str
asctime
返回指向静态数据的指针从而不是线程安全的。
char* asctime( const struct tm* time_ptr );
#include <stdio.h>
#include <time.h>
int main(void) {
struct tm tm = *localtime(&(time_t){time(NULL)});
printf("%s\n", asctime(&tm));
printf("%p\n", asctime(&tm));
printf("%p\n", asctime(&tm));
}
⏲️ctime
🏷️将 struct time_t
对象转换成文本表示
🏷️time_t -> str
char* ctime( const time_t* timer );
#include <stdio.h>
#include <time.h>
int main(void) {
time_t result = time(NULL);
printf("%s\n", ctime(&result));
printf("%p\n", ctime(&result));
printf("%p\n", ctime(&result));
}
⏲️strftime
🏷️将 struct tm
对象转换成自定义文本表示
🏷️time_t -> copyToStr
size_t strftime(char* str,
size_t count,
const char* format,
const struct tm* time);
#include <stdio.h>
#include <time.h>
int main(void) {
struct tm now_tm = *localtime(&(time_t){time(NULL)});
char buff[1024];
// >strftime():Friday 03/01/24 19:41:24
if (strftime(buff, sizeof buff, ">strftime():%A %c", &now_tm)) {
puts(buff);
} else {
puts("strftime failed");
}
}
⏰格式
🧮Www Mmm dd hh:mm:ss yyyy\n
// `asctime() & ctime()`以下固定的 25 字符表示形式: `Www Mmm dd hh:mm:ss yyyy\n`
errno_t asctime_s( char* buf, rsize_t bufsz, const struct tm* time_ptr );
errno_t ctime_s( char *buf, rsize_t bufsz, const time_t* timer );
Www
——来自time_ptr->tm_wday
的星期之日
的三字母英文缩写,Mon
、Tue
、Wed
、Thu
、Fri
、Sat
、Sun
之一。Mmm
——来自time_ptr->tm_mon
的月
名的三字母英文缩写,Jan
、Feb
、Mar
、Apr
、May
、Jun
、Jul
、Aug
、Sep
、Oct
、Nov
、Dec
之一。dd
——来自timeptr->tm_mday
的 2 位月之日
,如同由 sprintf 以%2d
打印hh
——来自timeptr->tm_hour
的 2 位时
,如同由 sprintf 以%.2d
打印mm
——来自timeptr->tm_min
的 2 位分
,如同由 sprintf 以%.2d
打印ss
——来自timeptr->tm_sec
的 2 位秒
,如同由 sprintf 以%.2d
打印yyyy
——来自timeptr->tm_year + 1900
的 4 位年
,如同由 sprintf 以%4d
打印
若是非法入参则行为未定义,如:
-
若
*time_ptr
的任何成员在其正常范围外则行为未定义 -
若
time_ptr->tm_year
所指示的历年拥有多于 4 位数或小于 1000 年则行为未定义。
自定义格式函数:
strftime()
的格式:strftime - cppreference.com
⏰应用
下面两份是使用C++代码表示。
其中主要用到的是<ctime>
的类型,还有一些别的库中对时间操作的函数。
✍️力扣1185. 一周中的第几天
给你一个日期,请你设计一个算法来判断它是对应一周中的哪一天。
输入为三个整数:
day
、month
和year
,分别表示日、月、年。您返回的结果必须是这几个值中的一个
{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
。
static const std::string weekDays[] = {
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
};
class Solution {
public:
std::string dayOfTheWeek(int day, int month, int year) {
std::tm ctm{};
ctm.tm_year = year - 1900;
ctm.tm_mon = month - 1;
ctm.tm_mday = day;
// a timestamp
std::time_t ctime_t = std::mktime(&ctm);
// return a static ret
ctm = *std::localtime(&ctime_t);
return weekDays[ctm.tm_wday];
}
};
✍️力扣1154. 一年中的第几天
给你一个字符串
date
,按YYYY-MM-DD
格式表示一个 现行公元纪年法 日期。返回该日期是当年的第几天。
class Solution {
public:
int dayOfYear(string date) {
std::tm dt;
std::istringstream(date) >> std::get_time(&dt, "%Y-%m-%d");
return dt.tm_yday + 1;
}
};