文章目录
- ⏰介绍
- ⏰常量
- ⏱️`CLOCKS_PER_SEC`
- ⏰类型
- ⏱️`tm`
- ⏱️`time_t`
- ⏱️`clock_t`
- ⏱️`timespec` (C11)
- ⏰函数-时间操作
- ⏲️`time`
- 🏷️返回纪元开始经过的当前系统日历时间
- ⏲️`clock`
- 🏷️返回未加工的程序启动时开始经过的处理器时间
- ⏲️`difftime`
- 🏷️计算时间差
- ⏰函数-格式转换-类型转换
- ⏲️`gmtime`
- 🏷️将从纪元开始的时间转换成以协调世界时(UTC)表示的日历时间
- 🏷️time_t -> tm
- ⏲️`localtime`
- 🏷️将从纪元开始的时间转换成以本地时间表示的日历时间
- 🏷️time_t -> tm
- ⏲️`mktime`
- 🏷️将日历时间转换成纪元开始经过的时间
- 🏷️tm -> time_t
- ⏰函数-格式转换-文本表示
- ⏲️`asctime`
- 🏷️将 `struct tm` 对象转换成文本表示
- 🏷️tm -> str
- ⏲️`ctime`
- 🏷️将 `struct time_t` 对象转换成文本表示
- 🏷️time_t -> str
- ⏲️`strftime`
- 🏷️将 `struct tm` 对象转换成自定义文本表示
- 🏷️time_t -> copyToStr
- ⏰格式
- 🧮`Www Mmm dd hh:mm:ss yyyy\n`
- ⏰应用
- ✍️力扣[1185. 一周中的第几天](https://leetcode.cn/problems/day-of-the-week/)
- ✍️力扣[1154. 一年中的第几天](https://leetcode.cn/problems/day-of-the-year/)
- END
⏰介绍
日期和时间工具 - cppreference.com
<time.h>
是在C语言中的日期与时间工具。其中主要有三大模块,常量,类型和函数。
在C++中推荐写成<ctime>
,基本都是继承.h中的东西。
函数主要分为两类,时间操作
函数和格式转换
函数。
本文主要为C语言中的标准操作,其中在C11和C23又添加和废弃了许多内容,但这块不会本文着重讲解。
UTC 协调世界时
纪元(地球纪元)
夏令时
⏰常量
⏱️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
-
tm - cppreference.com
-
(结构体)
-
日历时间类型
struct tm {int tm_sec; // [秒 [0, 61] (C89) [0, 60] (C99)] seconds after the minuteint tm_min; // [分 [0, 59]] minutes after the hourint tm_hour; // [时 [0, 23]] hours since midnightint tm_mday; // [日 [1, 31]] day of the monthint tm_mon; // [月 [0, 11]] months since Januaryint tm_year; // [年 [1900:0]] years since 1900int tm_wday; // [周 [0, 6]] days since Sundayint tm_yday; // [第几天 [0, 365]] days since January 1int 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 1900printf("%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_UTCtimespec_get(&ts, TIME_UTC);
#endifchar 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 - cppreference.com
🏷️返回纪元开始经过的当前系统日历时间
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 - cppreference.com
🏷️返回未加工的程序启动时开始经过的处理器时间
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
difftime - cppreference.com
🏷️计算时间差
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
gmtime, gmtime_r, gmtime_s - cppreference.com
🏷️将从纪元开始的时间转换成以协调世界时(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
localtime, localtime_r, localtime_s - cppreference.com
🏷️将从纪元开始的时间转换成以本地时间表示的日历时间
🏷️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
mktime - cppreference.com
🏷️将日历时间转换成纪元开始经过的时间
🏷️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
asctime, asctime_s - cppreference.com
🏷️将 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
ctime, ctime_s - cppreference.com
🏷️将 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
strftime - cppreference.com
🏷️将 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:24if (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 timestampstd::time_t ctime_t = std::mktime(&ctm);// return a static retctm = *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;}
};