Перевод времени эпохи с часовым поясом в формат Excel? - PullRequest
0 голосов
/ 08 июня 2018

Мне нужно преобразовать время эпохи в время Excel.Почему Excel, потому что работа с числовым временем Excel быстрее, чем любой разбор, выполняемый на форматах отображения.

Текущее время 2018-06-08 12:46:58 CDT с UTC 1528480019 должно дать 0,5326157 .Но преобразованное в время New_York или 2018-06-08 13:46:58 EDT даст 0.574282367 .Мне нужно только преобразовать поле времени в стиль Excel.

Вот мой неполный код:

double GetTime(Datetime currtime, std::string tz = "TZ=America/New_York")
{
  std::time_t t = currtime;
  //tzset(tz);
  std::tm tm = *std::localtime(&t);
  return ((tm.tm_hour * 3600 + (tm.tm_min) * 60.0 + tm.tm_sec) / 86400.0);
}

Код работает, но только для местного времени, которое "Америка / Чикаго".Мне не удалось установить часовой пояс, который мне может понадобиться.Также tm, кажется, ограничен секундами, но мне нужно также обрабатывать миллисекунды и микросекунды.

Кроме того, мне нужно, чтобы оно было быстрым, и текущая реализация разбивает время на отдельные поля, а затем я объединяю егов то, что мне нужно, что, кажется, делает много дополнительной работы.

1 Ответ

0 голосов
/ 09 июня 2018

Эту проблему можно легко решить с помощью бесплатной библиотеки дат / времени / часовых поясов Говарда Хиннанта с открытым исходным кодом , которая очень эффективна.Эта библиотека также находится в текущем рабочем проекте 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';

И выдает тот же вывод, что и раньше.

...