Я делаю много вычислений со временем, строю объекты времени относительно других объектов времени, добавляя секунды. Код должен работать на встроенных устройствах и серверах. Большинство документов говорят о time_t
что это какой-то арифметический тип, хранящий обычно время с эпохи. Насколько безопасно предполагать, что time_t
хранить количество секунд, так как что-то? Если мы можем предположить, что мы можем просто использовать сложение и вычитание, а не localtime
, mktime
а также difftime
,
До сих пор я решил проблему с помощью constexpr bool time_tUsesSeconds
, обозначая, можно ли считать, что time_t
использует секунды. Если это непереносимо предположить time_t
в секундах, есть ли способ автоматически инициализировать эту константу?
time_t timeByAddingSeconds(time_t theTime, int timeIntervalSeconds) {
if (Time_tUsesSeconds){
return theTime + timeIntervalSeconds;
} else {
tm timeComponents = *localtime(&theTime);
timeComponents.tm_sec += timeIntervalSeconds;
return mktime(&timeComponents);
}
}
Факт, что это в секундах, установлен Спецификация POSIX, так что, если вы программируете для POSIX-совместимых сред, вы можете положиться на это.
Стандарт C ++ также гласит, что time_t
должен быть арифметическим типом.
В любом случае, система синхронизации Unix (вторая после эпохи) будет переполнена в 2038 году. Таким образом, весьма вероятно, что до этой даты реализации C ++ переключатся на другие не-int типы данных (либо 64-битные int, либо более сложные типы данных). ). В любом случае, переключение на 64b int нарушит двоичную совместимость с предыдущим кодом (поскольку для этого требуются большие переменные), и все должно быть перекомпилировано. Использование непрозрачных дескрипторов 32b не нарушит бинарную совместимость, вы можете изменить базовую библиотеку, и все по-прежнему работает, но time_t
не будет больше времени в секундах, это будет индекс для массива раз в секундах. По этой причине предлагается использовать функции, которые вы упомянули, для манипулирования значениями time_t, и не предполагать, что time_t
,
Вместо того чтобы определить, time_t
в секундах, так как time_t
является арифметическим типом, вы можете вместо этого вычислить time_t
значение, которое представляет одну секунду, и работать с этим. Этот ответ я написал раньше объясняет метод и имеет некоторые предостережения, вот пример кода (bad_time()
класс пользовательских исключений, здесь):
time_t get_sec_diff() {
std::tm datum_day;
datum_day.tm_sec = 0;
datum_day.tm_min = 0;
datum_day.tm_hour = 12;
datum_day.tm_mday = 2;
datum_day.tm_mon = 0;
datum_day.tm_year = 30;
datum_day.tm_isdst = -1;
const time_t datum_time = mktime(&datum_day);
if ( datum_time == -1 ) {
throw bad_time();
}
datum_day.tm_sec += 1;
const time_t next_sec_time = mktime(&datum_day);
if ( next_sec_time == -1 ) {
throw bad_time();
}
return (next_sec_time - datum_time);
}
Вы можете вызвать функцию один раз и сохранить значение в const, а затем просто использовать его всякий раз, когда вам нужно time_t
второй. Я не думаю, что это будет работать в constexpr
хоть.
Мои два цента: на Windows это в секундах через некоторое время но время, необходимое для перехода к следующей секунде, обычно составляет 18 * 54,925 мс, а иногда 19 * 54,925. Причина этого объясняется в эта почта.
В стандарте C или стандарте C ++ нет требований к единицам, которые time_t
представляет собой. Для работы с секундами переносимо нужно использовать struct tm
, Вы можете конвертировать между time_t
а также struct tm
с mktime
а также localtime
,
(Отвечая на собственный вопрос)
Один ответ предполагает, что пока кто-то использует posix, time_t
в секундах и арифметика на time_t
должно сработать.
Второй ответ вычисляет time_t в секунду и использует его как фактор при выполнении арифметики. Но есть еще некоторые предположения о time_t
сделал.
В конце концов я решил, что переносимость важнее, я не хочу, чтобы мой код молчал на каком-то встроенном устройстве. Поэтому я использовал третий способ. Это включает в себя сохранение целого числа, обозначающего время с момента запуска программы. То есть Я определяю
const static time_t time0 = time(nullptr);
static tm time0Components = *localtime(&time0);
Все значения времени, используемые в программе, являются целыми числами, обозначающими разницу во времени с time0
, Идти от time_t
до этой дельты секунды, я использую difftime
, Вернуться к time_t
Я использую что-то вроде этого:
time_t getTime_t(int timeDeltaSeconds) {
tm components = time0Components;
components.tm_sec += timeDeltaSeconds;
return mktime(&components);
}
Такой подход позволяет делать такие операции, как +
,-
дешево, но возвращаюсь time_t
дорогой. Обратите внимание, что значения дельта времени имеют смысл только для текущего запуска программы. Также обратите внимание, что time0Components должен обновляться при изменении часового пояса.