Эту проблему можно легко решить с помощью бесплатной библиотеки дат / времени / часовых поясов Говарда Хиннанта с открытым исходным кодом , которая очень эффективна.Эта библиотека также находится в текущем рабочем проекте C ++ 20 под namespace std::chrono
.Поэтому в будущем портирование вашего кода для использования только std :: lib должно быть таким же простым, как и изменение нескольких пространств имен.
double
GetTime(std::chrono::system_clock::time_point currtime,
date::time_zone const* tz = date::current_zone())
{
using namespace date;
using namespace std::chrono;
zoned_time<system_clock::duration> zt{tz, currtime};
auto lt = zt.get_local_time();
auto ld = floor<days>(lt);
using ExcelTime = duration<double, days::period>;
ExcelTime tod = lt - ld;
return tod.count();
}
Вместо Datetime
требуется std::chrono::system_clock::time_point
,и вместо std::string
, date::time_zone const*
.
На трех больших платформах (llvm / gcc / MSVS) самая грубая system_clock::time_point
- это микросекунды, которые соответствуют вашим точным целям.
Шаг первый - создать zoned_time
, который представляет собой пару time_point
с time_zone
.Из этого можно получить local_time
.
floor<days>
, усекающее точность от time_point
до days
.Если вычесть дневную точность time_point
из более точной time_point
, вы получите местное время суток.
Если вы сохраните это местное время в chrono::duration
который имеет double
в качестве своего представления и период 1 день, тогда вы получите формат времени Excel.
Это можно использовать как:
int
main()
{
using namespace date;
using namespace std::chrono;
std::cout << std::fixed << std::setprecision(9);
std::cout << GetTime(sys_seconds{1528480019s}, locate_zone("America/Chicago")) << '\n';
zoned_time<system_clock::duration> zt{"America/New_York",
local_days{2018_y/6/8} + 13h + 46min + 58s};
std::cout << GetTime(zt.get_sys_time(), zt.get_time_zone()) << '\n';
}
который выводит:
0.532627315
0.574282407
Выше я изо всех сил пытался максимально приблизиться к существующему API.Однако, если вы примете эту библиотеку, вы можете сделать ее еще проще и чуть более эффективной, приняв «более родной» API:
std::chrono::duration<double, date::days::period>
GetTime(const date::zoned_time<std::chrono::system_clock::duration>& zt)
{
using namespace date;
auto lt = zt.get_local_time();
return lt - floor<days>(lt);
}
Теперь GetTime
принимает только один параметр типа zoned_time<system_clock::duration>
и возвращает duration<double, days::period>
.Все, что остается для GetTime
, это усечь местное время с точностью до дней и вычесть, чтобы получить время суток.
Демонстрация в main
также упрощена:
std::cout << GetTime({"America/Chicago", sys_seconds{1528480019s}}).count() << '\n';
std::cout << GetTime({"America/New_York",
local_days{2018_y/6/8} + 13h + 46min + 58s}).count() << '\n';
И выдает тот же вывод, что и раньше.