Каждый из них представляет количество дней с начала эпохи (то есть за много лет до 0 в календаре ISO 8601).
Допустим, вы имеете в виду эпоху Юлианского Дня № . Эта эпоха соответствует вашему описанию. Ссылка говорит, что эта эпоха - 24 ноября 4714 г. до н.э. в грипористическом календаре. Вместо того, чтобы использовать систему "BC", я считаю удобным использовать систему с отрицательными годами, чтобы обеспечить плавный математический переход через год 0. В этой системе эпоха - 24 ноября -4713.
Используя бесплатную библиотеку дат Говарда Хиннанта с открытым исходным кодом, содержащую только заголовки , это очень легко сделать. Если у меня неправильная эпоха, просто замените правильную в очевидном месте.
#include "date/date.h"
#include <iostream>
date::sys_days
to_sys_days(int i)
{
using namespace date;
return sys_days{days{i} -
(sys_days{1970_y/January/1} - sys_days{-4713_y/November/24})};
}
Тип возврата date::sys_days
- std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<int, std::ratio<86400>>>
. Или по-английски: это system_clock
на основе time_point
с точностью до days
. Это time_point
будет неявно преобразовано в system_clock::time_point
.
вашей платформы.
Теперь вы можете передать int
в to_sys_days
и передать результат функции, принимающей system_clock::time_point
. Например:
void
display(std::chrono::system_clock::time_point tp)
{
using date::operator<<;
std::cout << tp << '\n';
}
int
main()
{
display(to_sys_days(2'458'674));
}
Это выводит:
2019-07-09 00:00:00.000000
to_sys_days
- это очень дешевая операция. Вы можете позволить себе делать это каждый раз, когда читаете один элемент данных. Все, что он делает, это вычитает 2440588 из i
. Оптимизированный машинный код для to_sys_days
(clang ++ -O3) буквально:
leal -2440588(%rdi), %eax
т.е. все операции по изменению типов происходят во время компиляции . Это бесплатно. Единственное, что происходит во время выполнения, - это корректировка смещения эпохи. Это самый необходимый минимум, который нужно сделать независимо от того, что выровнять свою эпоху с system_clock
эпохой.
Итак, если у вас есть массив int
в качестве ваших данных, вам не нужно делать копию всего массива. Вы просто трансформируете каждый его элемент по требованию. Например:
int
main()
{
int data[] = {2'458'674, 2'458'675, 2'458'676, 2'458'677, 2'458'678};
for (auto i : data)
display(to_sys_days(i));
}
Выход:
2019-07-09 00:00:00.000000
2019-07-10 00:00:00.000000
2019-07-11 00:00:00.000000
2019-07-12 00:00:00.000000
2019-07-13 00:00:00.000000
Если вы не хотите использовать библиотеку дат , вы все равно можете выполнить работу, это просто немного больше работы.
Сначала создайте тип duration
, который означает дни:
using days = std::chrono::duration
<int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;
Затем подсчитайте количество дней между 1970-01-01 и вашей эпохой.
Затем возьмите свое интегральное значение i
, оберните его в days
и вычтите разницу в времени. Затем вы можете построить system_clock::time_point
со значением days
.
Примечание. Важно выполнить настройку эпохи в единицах days
вместо преобразования сначала в единицы system_clock::time_point
, а затем выполнить настройку. Эта последняя стратегия будет переполнена на некоторых платформах. Вы защищены от переполнения, если вы делаете смещение эпохи с точностью days
.
Я настоятельно не рекомендую использовать инструмент reinterpret_cast
для выполнения этой работы. Это кажется ненужным и опасным.
Обновление
Я забыл о части, в которой говорится, что юлианская эпоха - это полдень, а не полночь. Если вы хотите принять это во внимание, это очень просто с date lib :
auto
to_sys_days(int i)
{
using namespace date;
using namespace std::chrono;
return sys_time<hours>{days{i} -
(sys_days{1970_y/January/1} - sys_days{-4713_y/November/24} - 12h)};
}
Я просто вычел 12 часов из разности эпох и позволил auto
определить для меня тип возврата (который теперь system_clock
на основе time_point
с точностью hours
).
Точно такая же функция display
с тем же входом теперь выводит:
2019-07-09 12:00:00.000000