我所在地区的时间相关信息是否有上限?

Is There an Upper Bound in my locale for Time Related Information?

在标准命名空间的某处是否有设置前向的定义:

  1. 一年中的几个月
  2. 一周有几天
  3. 一天中的几个小时
  4. 一小时中的几分钟
  5. 一分钟秒

struct tm 包含必须在这些范围内的成员变量,但我无法在任何地方找到定义的限制。

我什至不确定是否定义了与常规设置 (12/7/24/60/60) 不匹配的语言环境。

即使没有其他范围限制的潜在用户,我也肯定会使用标准命名空间中的定义,而不是任意定义我自己的。

编辑:

看来我不是第一个提出这种要求的人了:http://david.tribble.com/text/c0xcalendar.html 我注意到在这个提案中提到了 struct calendarinfo 这正是我正在寻找的。

最近一次更改似乎是在 2009 年。我想从那以后什么都没发生?我想这也意味着这些东西对我来说不是现成的?

更多信息,boost::locale::calendar::maximum 似乎完全符合我的要求。我不能使用 Boost,但我确信 Boost 中的代码是 关于如何提出这些限制的事实上的标准。不幸的是,我似乎无法实现 maximum。也许这里的其他人知道怎么做?

C 和 C++ 标准对除公历以外的任何日历都只字未提,而且对公历的了解也不多。

1.一年中的几个月

您唯一能找到的是 C 标准中 tmtm_mon 成员旁边的注释:

int tm_mon;  // months since January -- [0, 11]

嗯,几乎只有。您还会在 strftime 中找到 %b%B 说明符,它们对应于当前语言环境的缩写和完整月份名称,对应于 tm_mon.

2. 一周中的天数

你有:

int tm_wday;  // days since Sunday -- [0, 6]

%a%Astrftime

3. 一天中的几个小时

你有:

int tm_hour;  // hours since midnight -- [0, 23]

还有 strftime 说明符,其中一些对当前语言环境敏感。

4. 分钟等于一小时

int tm_min;  // minutes after the hour -- [0, 59]

在这种情况下,您还从新的 C++11 <chrono> 库中获得了一些帮助:

std::cout << std::chrono::hours{1}/std::chrono::minutes{1} << '\n';

这将可移植地(并且始终如一地)输出 60。如果你的编译器支持constexpr,又担心效率,这个量可以是一个编译时整型常量:

constexpr auto minutes_per_hour = std::chrono::hours{1}/std::chrono::minutes{1};

minutes_per_hour类型保证为有符号整数且至少29位

5.一分钟秒

C 规范在这方面有点有趣:

int tm_sec;  // seconds after the minutes -- [0, 60]

范围未记录为 [0, 59],以便添加正闰秒。话虽如此,据我所知,没有 OS 实际上实现了对闰秒的准确计算。每个人似乎都关注 Unix Time which tracks UTC except ignoring leap seconds. When a leap second occurs, all OS's I'm aware of simply treat it as an ordinary clock correction. Google famously treats it as a smear of corrections over some window of time

此外,您可以一致且可移植地编写:

std::cout << std::chrono::minutes{1}/std::chrono::seconds{1} << '\n';

得到60.


虽然未由 C 或 C++ 标准定义,但每个 OS 似乎都在测量自 1970 年新年以来的时间 (neglecting leap seconds)。在 C++11 中,此数量可通过以下方式获得:

auto tp = std::chrono::system_clock::now();

其中 tp 的类型为 std::chrono::system_clock::time_point。此 time_point 具有未指定的精度(两周、秒、飞秒等)。精度可在编译时以编程方式发现。


如果有帮助,this link 包含可以将 tp 转换为 year/month/day hour:minute:second 甚至几分之一秒(反之亦然)的代码。哦,星期几,如果你也想要它(以及其他几个日历技巧)。此 public 域代码依赖于 非标准 但实际上可移植的 1970 年新年纪元。如果需要,它可以很容易地应用于其他纪元。

我相信我可以肯定地说 没有 namespace std 中任何这些数字的定义。

我的声明基于这样一个事实,即 Boost 的 gregorian.cpp 将所有这些值硬编码在 get_value

如果您有 Boost,您可以利用 get_value 通过以下操作找到 "Months in a year"、"Days in a week" 和 "Hours in a day":

locale::global(boost::locale::generator()(""));
cout.imbue(locale());

boost::locale::date_time now;

cout << "Months in a year: " << now.maximum(boost::locale::period::period_type(boost::locale::period::marks::month)) << endl;
cout << "Days in a week: " << now.maximum(boost::locale::period::period_type(boost::locale::period::marks::day_of_week)) << endl;
cout << "Hours in a day: " << now.maximum(boost::locale::period::period_type(boost::locale::period::marks::hour)) << endl;

输出:

Months in a year: 11
Days in a week: 7
Hours in a day: 23

注意从 0 开始的月份和时间以及从 1 开始的天数。这与 put_time%u 标志一致。

如果您没有 Boost,则需要自己定义这些。

Howard Hinnant 查找 "Minutes in an hour" 和 "Seconds in a minute" 的解决方案 实际上基于 namespace std 的定义:

cout << "Minutes in an hour: " << chrono::hours{1} / chrono::minutes{1} << endl;
cout << "Seconds in a minute: " << chrono::minutes{1} / chrono::seconds{1} << endl;

输出:

Minutes in an hour: 60
Seconds in a minute: 60