给定标准的ISO 8601时间戳,有没有一种简单的方法可以从原始时间戳之前20分钟获取时间戳,在原始时间戳之后获取另一个时间戳?
例如给定
2010-01-25 18:02:00
我希望返回一个或两个函数, 2010-01-25 17:48:00
和2010-01-25 18:22:00
放弃的解决方案相当麻烦,我用s.substr(14,2)
来获取分钟,s.substr(12,2)
来获取小时,将小时和分钟字符串转换为 int 并减去或添加带有条件的分钟值如果它高于 60 或低于 0。有没有更好/更简单的方法可以做到这一点?
你可以:
- 使用
std::get_time
将字符串转换为struct tm
。 - 修改
struct tm
(无需考虑范围)。 - 使用
mktime
规范化struct tm
。 - 使用
std::put_time
打印struct tm
#include <ctime>
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
std::string increase_minutes(const std::string& input, int delta) {
struct tm tm;
constexpr auto format = "%Y-%m-%d %T";
std::istringstream iss (input);
iss >> std::get_time(&tm, format);
tm.tm_min += delta;
mktime(&tm);
std::ostringstream oss;
oss << std::put_time(&tm, format);
return oss.str();
}
int main() {
auto s = "2012-12-31 23:59:00";
std::cout << increase_minutes(s, 20) << std::endl;
std::cout << increase_minutes(s, -20) << std::endl;
}
请注意,std::get_time
和 std::put_time
在 g++/libstdc++ 中不存在。您可能需要使用 C 函数sscanf
或 strptime
解析字符串,并使用 strftime
打印字符串。另请参阅日期和时间C++。
编辑:如果我们想通过通用std::chrono::duration
进行更改,最好我们直接在std::chrono::time_point
上进行操作。我们可以通过两步转换从struct tm
创建一个time_point:time_point ↔ time_t ↔结构 tm,如下图所示:
#include <ctime>
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <chrono>
template <typename R, typename P>
std::string increase_iso_time(const std::string& input,
const std::chrono::duration<R, P>& duration) {
struct tm tm;
constexpr auto format = "%Y-%m-%d %T";
std::istringstream iss (input);
iss >> std::get_time(&tm, format);
auto time = mktime(&tm);
auto tp = std::chrono::system_clock::from_time_t(time);
tp += duration;
time = std::chrono::system_clock::to_time_t(tp);
tm = *localtime(&time);
std::ostringstream oss;
oss << std::put_time(&tm, format);
return oss.str();
}
int main() {
auto s = "2012-12-31 23:59:00";
std::cout << increase_iso_time(s, std::chrono::minutes(20)) << std::endl;
std::cout << increase_iso_time(s, - std::chrono::hours(4)
- std::chrono::minutes(20)) << std::endl;
}
从 C 或 C++ 标准中查找mktime()
。 您需要类似strptime()
才能将ISO 8601时间转换为struct tm
(或者您可以使用sscanf()
或... 然后制作结构的两个副本,将tm_min
一个调整为 +20,另一个调整 -20,调用 mktime()
,然后strftime()
。
这将适用于 C 和 C++98、C++2003 以及 C++2011。 如果您只想让它与 C++2011 一起使用,那么您需要转到 std::chrono
.
示例代码
由于标头,此代码用于C++,但可以通过更改为 <time.h>
和 <stdio.h>
转换为 C。 是的,它可能不算"好"C++;它肯定会给您留下一些界面决策。 但它确实完成了工作。 (对于纯C++,您可以删除对struct
的引用。
#include <ctime>
#include <cstdio>
static void delta_t(const char *otime, int delta)
{
struct tm tm1;
int n;
if ((n = sscanf(otime, "%4d-%2d-%2d %2d:%2d:%2d", &tm1.tm_year, &tm1.tm_mon, &tm1.tm_mday,
&tm1.tm_hour, &tm1.tm_min, &tm1.tm_sec)) != 6)
{
printf("%s: failed %dn", otime, n);
return;
}
printf("%.4d-%.2d-%.2d %.2d:%.2d:%.2dn", tm1.tm_year, tm1.tm_mon, tm1.tm_mday,
tm1.tm_hour, tm1.tm_min, tm1.tm_sec);
tm1.tm_isdst = -1;
tm1.tm_year -= 1900;
tm1.tm_mon--;
struct tm tm2 = tm1;
tm2.tm_min += delta;
struct tm tm3 = tm1;
tm3.tm_min -= delta;
mktime(&tm2);
mktime(&tm3);
char dt1[20];
char dt2[20];
char dt3[20];
strftime(dt1, sizeof(dt1), "%Y-%m-%d %H:%M:%S", &tm1);
strftime(dt2, sizeof(dt2), "%Y-%m-%d %H:%M:%S", &tm2);
strftime(dt3, sizeof(dt3), "%Y-%m-%d %H:%M:%S", &tm3);
printf("Input: %sn", otime);
printf("Date1: %sn", dt1);
printf("Date2: %sn", dt2);
printf("Date3: %sn", dt3);
}
int main(void)
{
delta_t("2010-01-25 18:02:00", 20);
delta_t("2012-12-31 23:59:00", 20);
return(0);
}
示例输出:
2010-01-25 18:02:00
Input: 2010-01-25 18:02:00
Date1: 2010-01-25 18:02:00
Date2: 2010-01-25 18:22:00
Date3: 2010-01-25 17:42:00
2012-12-31 23:59:00
Input: 2012-12-31 23:59:00
Date1: 2012-12-31 23:59:00
Date2: 2013-01-01 00:19:00
Date3: 2012-12-31 23:39:00