【问题标题】:C++ Standard library that supports time arithmetic支持时间算术的 C++ 标准库
【发布时间】:2017-07-29 17:33:27
【问题描述】:

我有很多格式为“HH:MM”的字符串,我必须经常对它们进行算术运算(例如加 5 分钟、加 24 小时等)。

我想知道标准库中是否有任何内置类可以处理此类算术,而不必手动更改字符串和处理极端情况?

【问题讨论】:

  • 在我看来,在输入时将这些字符串转换为整数会更容易,做任何你想要的算术,然后将其转换回这种格式进行输出。
  • @Mattenii 这就是我现在正在做的事情。但是,有时我需要加上“168”分钟。然后我需要找到多少小时,多少分钟,检查分钟是否超过 59,迭代小时,添加小时数,看看它是否超过 23,如果它确实采用了 mod 24。看起来仅做一项基本任务(我猜这不仅仅是我的问题),这就是为什么我要问是否有任何本地支持。
  • 也就是说,时代在不断地改变,而不仅仅是改变一次。所以我想要一个自动处理时间转换/时间差异的类。
  • 但是如果你只存储一个数字,比如分钟,那么你可以添加分钟没问题,小时只需要乘以60。
  • 听起来您想转换为std::time_t 并对其执行任何操作,然后将其转换回您喜欢的任何格式的字符串。看看<ctime> 标准库。

标签: c++ datetime time


【解决方案1】:

如果您没有strptime 可用,并且如果您有<chrono> 并且不想在C API 中胡闹,您可以使用Howard Hinnant's free, open-source, portable datetime library 编写帮助程序来与@987654324 相互转换@。

所以从字符串转换为分钟,做任何你需要的计算,然后再转换回字符串:

#include "date.h"
#include <iostream>
#include <string>
#include <sstream>

std::chrono::minutes
to_minutes(const std::string& s)
{
    std::istringstream in{s};
    in.exceptions(std::ios::failbit);
    std::chrono::minutes m;
    in >> date::parse("%H:%M", m);
    return m;
}

std::string
to_string(std::chrono::minutes m)
{
    return date::format("%H:%M", m);
}

int
main()
{
    using namespace std::chrono_literals;
    std::cout << to_string(to_minutes("5:47") + 2h + 168min) << '\n';
}

输出:

10:35

此库已移植到最新版本的 VS、gcc 和 clang。

您还可以使用此库无缝地处理不同的精度,例如秒,甚至毫秒,甚至可以将您需要的所有精度混合在一起:

std::chrono::milliseconds
to_milliseconds(const std::string& s)
{
    std::istringstream in{s};
    in.exceptions(std::ios::failbit);
    std::chrono::milliseconds ms;
    in >> date::parse("%T", ms);
    return ms;
}

std::string
to_string(std::chrono::milliseconds ms)
{
    return date::format("%T", ms);
}

// ...

    std::cout << to_string(to_minutes("5:47") + 2h + 168min +
                           122s + 465ms + to_milliseconds("1:23:02.123")) << '\n';

输出:

12:00:04.588

【讨论】:

  • 本应该想到 Howard Hinnant 会在推荐 Howard Hinnant 的图书馆方面打败我……
【解决方案2】:

使用&lt;ctime&gt;,您可以将 HH:MM 字符串转换为struct tm,如下所示:

struct tm time_components;
memset(&time_components, 0, sizeof(struct tm));
time_components.tm_year = 2017;
strptime("01:45", "%H:%M", &time_components);

这假设您有 strptime 可用。如果没有,请使用sscanf 或类似的东西来提取你的小时和分钟组件——我相信你已经这样做了。我将tm_year 设置在那里,否则它为零,这不是稍后转换为time_t 的有效年份。

我们可以使用strftime 轻松地将tm 结构体转换回HH:MM 字符串。

char buf[6];
strftime(buf, 6, "%H:%M", &time_components);

printf("time_components before manipulation: %s\n", buf);

但是如何操纵它呢?我的第一个想法是'只需转换为time_t 并添加/减去你想要的秒数'。但是time_t 不能保证在几秒钟内,所以不要那样做。相反,将您喜欢的分钟数添加到tm 结构的tm_min 组件,然后用它调用mktime,这将正确处理超出小时/分钟/秒的正常范围的任何值。那时你有一个time_t,我们不想弄乱它,所以只需使用localtimeback 转换为tmlocaltime 将反映mktime 中发生的转换,因此您不必担心时区等问题。现在您已经基本规范化了tm 结构,并且溢出的分钟已转换为小时,溢出的小时已转换为天。

time_components.tm_min += 65; // Add 65 minutes. Negative values work as expected too!
time_t temp_time = mktime(&time_components);
struct tm* adjusted_time = localtime(&temp_time);
strftime(buf, 6, "%H:%M", adjusted_time);
printf("adjusted_time: %s\n", buf);

adjusted_time 指针似乎指向内部tm 结构,该结构将在任何后续调用mktimegmtime 时发生变化,仅供参考。

毫无疑问,这是一种相当糟糕的方法。如果您需要做的只是处理分钟/小时溢出和简单的算术运算,我会很想自己动手或寻找其他地方。

【讨论】:

    【解决方案3】:

    http://en.cppreference.com/w/cpp/chrono/duration 支持你想要的算术和类型,但我不认为你可以从字符串构造。

    但是您可以使用Boost Chrono。在大多数情况下,我倾向于使用它,因为如果我要处理小时和分钟的问题,我将来可能最终也会处理日期。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多