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

别等时光非礼了梦想. 提交于 2019-12-11 02:39:32

问题


Is there a definition somewhere in the standard namespace that sets forward:

  1. Months in a year
  2. Days in a week
  3. Hours in a day
  4. Minutes in an hour
  5. Seconds in a minute

The struct tm has contains member variables that must be in these ranges, but I can't find the defined limits anywhere.

I'm not even sure if there are locales defined where these wouldn't match the conventional set (12/7/24/60/60).

Even if there aren't potential users with other range limits, I'd sure like to use a define from the standard namespace rather than arbitrarily defining my own.

EDIT:

It looks like I'm not the first to ask for such a thing: http://david.tribble.com/text/c0xcalendar.html I notice in this proposal there is mention of the struct calendarinfo which does exactly what I'm looking for.

It looks like the last change on this was 2009. I guess nothing's happened since then? I guess that also means this stuff is not readily available to me?

More info, boost::locale::calendar::maximum seems to accomplish exactly what I'm looking for. I can't use Boost, but I'm certain that the code in Boost is the defacto standard on how to come up with these limits. Unfortuantely I can't seem to get at the implementation of maximum. Maybe someone else here knows how?


回答1:


The C and C++ standards say absolutely nothing about any calendar except the Gregorian calendar, and not a lot about that one.

1. Months in a year

The only thing you'll find is a comment in the C standard beside the tm_mon member of tm:

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

Well, almost only. You'll also find %b and %B specifiers in strftime which correspond to the current locale's abbreviated and full month names corresponding to tm_mon.

2. Days in a week

You've got:

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

and %a, %A for strftime.

3. Hours in a day

You've got:

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

There's also strftime specifiers, a few of which are sensitive to the current locale.

4. Minutes in an hour

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

Also in this case you've got some help from the new C++11 <chrono> library:

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

This will portably (and consistently) output 60. If your compiler supports constexpr and you are worried about efficiency, this quantity can be a compile-time integral constant:

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

The type of minutes_per_hour is guaranteed to be signed integral and at least 29 bits.

5. Seconds in a minute

The C spec is a little interesting on this one:

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

The range is not documented as [0, 59] so as to allow for the addition of a positive leap second. That being said, no OS that I'm aware of actually implements an accurate accounting of leap seconds. Everyone appears to follow 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.

Additionally you can consistently and portably write:

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

and get 60.


While not defined by the C or C++ standards, every OS appears to be measuring time since New Years 1970 (neglecting leap seconds). In C++11 this quantity is available via:

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

where tp will have type std::chrono::system_clock::time_point. This time_point has an unspecified precision (fortnights, seconds, femtoseconds, whatever). The precision is programmatically discoverable at compile time.


In case it is helpful, this link contains code which can translate tp into year/month/day hour:minute:second and even fractions of a second (and vice-versa). Oh, day-of-week if you want it too (and several other calendrical tricks). This public domain code depends on the non-standard but de-facto portable epoch of New Years 1970. It could easily be adopted to other epochs if the need ever arises.




回答2:


I believe that I can conclusively say that there is not a define for any of these numbers in namespace std.

I am basing this statement on the fact that Boost's gregorian.cpp hard codes all of these values in get_value

If you do have Boost, you are able to leverage get_value to find "Months in a year", "Days in a week", and "Hours in a day" by doing:

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;

Which outputs:

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

Note the 0-based months and hours and the 1-based days. This is consistant with put_time's %u flag.

If you do not have Boost you'll need to define these yourself.

Howard Hinnant's solution for finding "Minutes in an hour" and "Seconds in a minute" is actually based in defines from 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;

Which outputs:

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



来源:https://stackoverflow.com/questions/28548634/is-there-an-upper-bound-in-my-locale-for-time-related-information

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!