c++boostc++-chronoctimeboost-locale

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


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?


Solution

  • 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.