Есть ли в моем регионе верхняя граница для информации, связанной со временем?

Есть ли определение где-то в стандартном пространстве имен, которое устанавливает вперед:

  1. Месяцы в году
  2. Дней в неделю
  3. Часов в день
  4. Минуты в часе
  5. Секунды в минуту

struct tm содержит переменные-члены, которые должны находиться в этих диапазонах, но я не могу t найти определенные пределы в любом месте.

Я даже не уверен, есть ли определенные локали, в которых они не соответствовали бы обычному набору (12/7/24/60/60).

Даже если нет потенциальных пользователей с другими ограничениями диапазона, я бы предпочел использовать определение из стандартного пространства имен, а не произвольно определять свое собственное.

ИЗМЕНИТЬ:

Похоже, я не первый, кто просит об этом: http://david.tribble.com/text/c0xcalendar.html Я заметил, что в этом предложении есть упоминание о struct calendarinfo, который делает именно то, что я ищу.

Похоже, что последнее изменение было в 2009 году. Думаю, с тех пор ничего не произошло? Я предполагаю, что это также означает, что этот материал не всегда доступен для меня?

Дополнительная информация: boost::locale:: Calendar::maximum, кажется, выполняет именно то, что я ищу. Я не могу использовать Boost, но я уверен, что код в Boost является стандартом де-факто для определения этих ограничений. К сожалению, я не могу понять реализацию maximum. Может тут кто знает как?


person Jonathan Mee    schedule 16.02.2015    source источник
comment
Если вы посмотрите на еврейский календарь, то увидите, что он другой. en.wikipedia.org/wiki/Hebrew_calendar   -  person NathanOliver    schedule 16.02.2015
comment
@NathanOliver интересно, поэтому я предполагаю, что это может иметь реальный вариант использования, помимо стандартного определения предела?   -  person Jonathan Mee    schedule 16.02.2015


Ответы (2)


Стандарты C и C++ абсолютно ничего не говорят ни о каком календаре, кроме григорианского, да и о нем почти ничего.

1. месяцев в году

Единственное, что вы найдете, это комментарий в стандарте C рядом с членом tm_mon из tm:

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

Ну почти только. Вы также найдете спецификаторы %b и %B в strftime, которые соответствуют сокращенному и полному названию месяца текущей локали, соответствующему tm_mon.

2. дней в неделе

У тебя есть:

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

и %a, %A вместо strftime.

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], чтобы можно было добавить положительную дополнительную секунду. При этом ни одна известная мне ОС не реализует точный учет високосных секунд. Кажется, что все следуют Unix Time, которое отслеживает UTC, за исключением игнорирования високосных секунд. Когда происходит дополнительная секунда, все ОС, о которых я знаю, просто рассматривают это как обычную коррекцию часов. Известно, что Google рассматривает это как мазок исправлений в каком-то окне время.

Кроме того, вы можете последовательно и переносимо писать:

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

и получить 60.


Хотя это и не определено стандартами C или C++, каждая ОС, по-видимому, измеряет время с Нового 1970 года (пренебрегая високосными секундами). ). В С++ 11 это количество доступно через:

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

где tp будет иметь тип std::chrono::system_clock::time_point. Это time_point имеет неопределенную точность (две недели, секунды, фемтосекунды, что угодно). Точность определяется программно во время компиляции.


Если это будет полезно, эта ссылка содержит код, который может переводить tp в год/месяц/день час :минута:секунда и даже доли секунды (и наоборот). О, день недели, если хотите (и несколько других календарных трюков). Этот общедоступный код зависит от нестандартной, но де-факто портативной эпохи Нового 1970 года. Его можно легко адаптировать к другим эпохам, если когда-либо возникнет необходимость.

person Howard Hinnant    schedule 17.02.2015
comment
Когда я начал читать, я боялся, что вы просто извергнете информацию из моей struct tm ссылки. Но ваши комментарии к 4 и 5 были действительно гениальны. Интересно, есть ли способ сделать что-то подобное на 1, 2 и 3? - person Jonathan Mee; 17.02.2015
comment
@JonathanMee: Не уверен, что это то, что вы ищете, но вы можете создать свои собственные chrono::duration единицы, например: melpon.org/wandbox/permlink/IStPNCZvSfOH5Cfr, а затем разделите их, чтобы извлечь из них обратно константы преобразования. - person Howard Hinnant; 17.02.2015

Я считаю, что могу с уверенностью сказать, что нет определений ни для одного из этих чисел в namespace std.

Я основываю это утверждение на том факте, что gregorian.cpp жестко кодирует все эти значения в get_value

Если у вас есть Boost, вы можете использовать get_value для поиска «Месяцев в году», «Дней в неделе» и «Часов в дне», выполнив следующие действия:

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;

Что выводит:

Месяцев в году: 11
Дней в неделе: 7
Часов в сутках: 23

Обратите внимание на месяцы и часы, начинающиеся с 0, и дни, начинающиеся с 1. Это соответствует флагу %u put_time.

Если у вас нет Boost, вам нужно определить их самостоятельно.

Решение Говарда Хиннанта для нахождения "минут в часе" и "секунд в минуте" является на самом деле основано на определениях из 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;

Что выводит:

Минут в часе: 60
Секунд в минуте: 60

person Jonathan Mee    schedule 17.02.2015