【问题标题】:get a set time before and after an iso 8601 timestamp c++在iso 8601时间戳c ++之前和之后获取设定时间
【发布时间】:2012-12-09 18:23:43
【问题描述】:

给定一个标准的 ISO 8601 时间戳,是否有一种简单的方法可以获取原始时间戳之前 20 分钟的时间戳和原始时间戳之后 20 分钟的另一个时间戳?

举个例子

 2010-01-25 18:02:00

我希望返回一两个函数, 2010-01-25 17:48:002010-01-25 18:22:00

我放弃的解决方案相当繁琐,我使用s.substr(14,2) 获取分钟,s.substr(12,2) 获取小时,将小时和分钟字符串转换为 int 并减去或添加带有条件的分钟值 if它高于 60 或低于 0。有没有更好/更简单的方法来做到这一点?

【问题讨论】:

  • 2012-12-31 23:59:00 后 20 分钟是几点?我想没有简单的方法。
  • @BoPersson 是的,我什至没有想到这种情况

标签: c++ c++11


【解决方案1】:

你可以:

  1. 将字符串转换为struct tmusing std::get_time
  2. 修改struct tm(无需考虑范围)。
  3. 规范化struct tmusing mktime
  4. 打印struct tm using std::put_time

#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_timestd::put_time 在 g++/libstdc++ 中不存在。您可能需要使用 C 函数 sscanfstrptime 解析字符串,并使用 strftime 打印字符串。另见C++ date and time


编辑:如果我们想通过通用std::chrono::duration 进行更改,最好直接在std::chrono::time_point 上进行操作。我们可以通过两步转换从struct tm 创建一个 time_point:time_point ↔ time_t ↔ struct 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;
}

【讨论】:

  • +1 那些 C++11 时间 I/O 操纵器肯定很方便!一种可能的改进:您可以通过将delta 的类型更改为std::chrono::minutes 来提高increase_minutes 的类型安全性。它确实使用户代码更加冗长,但也使20 的实际含义变得明确。另一方面,您的函数名称也努力消除20 的歧义。所以这没什么大不了的,只是另一个设计决定。
  • @HowardHinnant:如果我们想接受std::duration,最好将tm 转换为time_point。更新了答案以表明这一点。
  • 是的,我就是这么想的。但是您最初使用mktime 来规范化tm 也很优雅。我敢肯定,对于家庭作业来说,两者都是矫枉过正的。 :-) 如果你真的想把这匹马打死,你可以在RepPeriod 上做模板,制作参数std::chrono::duration&lt;Rep, Period&gt;。这使得increase_iso_timeduration 参数中不会“过于通用”。
【解决方案2】:

从 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++,但可以通过更改为 &lt;time.h&gt;&lt;stdio.h&gt; 转换为 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 %d\n", otime, n);
        return;
    }
    printf("%.4d-%.2d-%.2d %.2d:%.2d:%.2d\n", 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: %s\n", otime);
    printf("Date1: %s\n", dt1);
    printf("Date2: %s\n", dt2);
    printf("Date3: %s\n", 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

【讨论】:

    猜你喜欢
    • 2013-03-11
    • 2023-04-11
    • 1970-01-01
    • 2013-12-06
    • 1970-01-01
    • 2021-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多