3

给定一个标准的 ISO 8601 时间戳,是否有一种简单的方法可以从原始时间戳之前 20 分钟和另一个时间戳之后 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。是有更好/更简单的方法吗?

4

2 回答 2

9

你可以:

  1. 将字符串转换为struct tm usingstd::get_time
  2. 修改struct tm(无需考虑范围)。
  3. 规范化struct tm 使用mktime.
  4. 打印struct tm 使用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 函数sscanf或解析字符串strptime,并使用 打印字符串strftime。另请参见C++ 日期和时间


编辑:如果我们想通过泛型进行更改std::chrono::duration,最好std::chrono::time_point直接在 a 上进行操作。我们可以通过两步转换从 a 创建 time_point struct tm: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;
}
于 2012-12-09T19:09:17.120 回答
3

mktime()从 C 或 C++ 标准查找。您需要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>and转换为<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 %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
于 2012-12-09T19:35:43.490 回答