Создание `std :: chrono :: time_point` из календарной даты, известной во время компиляции - PullRequest
0 голосов
/ 08 сентября 2018

Этот ответ показывает, как выполнить синтаксический анализ строки в std::chrono::time_point следующим образом:

std::tm tm = {};
std::stringstream ss("Jan 9 2014 12:35:34");
ss >> std::get_time(&tm, "%b %d %Y %H:%M:%S");
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));

Если я хочу создать std::chrono::time_point из (григорианской) календарной даты, чей год, месяц и день месяца известны во время компиляции, есть ли более простой способ, чем анализировать ее из строки, как предложено выше

Ответы [ 2 ]

0 голосов
/ 09 сентября 2018

Да, вы можете выполнить все вычисления во время компиляции, создав constexpr system_clock::time_point с использованием библиотеки дат / времени Говарда Хиннанта .

#include "date/date.h"
#include <chrono>

int
main()
{
    using namespace date;
    using namespace std::chrono;
    constexpr system_clock::time_point tp = sys_days{January/9/2014} + 12h + 35min + 34s;
    static_assert(tp == system_clock::time_point{1389270934s}, "");
}

Предполагается, что дата / время указаны в формате UTC. Если это не так, вам придется вручную добавить / вычесть смещение UTC, чтобы сделать это. Поскольку правила часовых поясов постоянно меняются по прихоти политиков, надежды сделать их constexpr мало. Даже исторические правила часового пояса обновляются, когда выявляются недоразумения.

Также эта программа будет портировать на C ++ 20 путем удаления #include "date/date.h" и using namespace date;. Также для использования библиотеки дат / времени Говарда Хиннанта требуется C ++ 14 constexpr мышца. C ++ 11 constexpr недостаточно (но вы можете сделать это во время выполнения, удалив constexpr и static_assert).

0 голосов
/ 09 сентября 2018

Если у вас есть c ++ 20, или вы будете использовать библиотеку дат / времени Говарда Хиннанта, то ответ Говарда Хэннанта будет лучше, так как он дает вам точку времени constexpr.

Однако, если у вас еще нет c ++ 20 и вы хотите избежать добавления дополнительных внешних библиотек, тогда этот ответ по-прежнему полезен.

Вы можете установить элементы std::tm индивидуально в инициализаторе, чтобы избежать анализа строки.

// 9th January, 2014
#define DAY 9
#define MONTH 1
#define YEAR 2014

std::tm tm = { .tm_sec  = 0,
               .tm_min  = 0,
               .tm_hour = 0,
               .tm_mday = (DAY),
               .tm_mon  = (MONTH) - 1,
               .tm_year = (YEAR) - 1900,
             };
tm.tm_isdst = -1; // Use DST value from local time zone
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));

Инициализация нулевых полей для времени дня происходит только из-за ограничения gcc на нетривиально назначенные инициализаторы в коде C ++ и может быть опущена, если требуется полуночи для скомпилированной даты.

Важно отметить, что mktime будет интерпретировать tm как местное время , а не по Гринвичу или UTC. Если tm_isdst не установлен в -1, это будет местное стандартное время, даже если в указанное местное время будет использоваться летнее время (летнее время).

Получение момента времени UTC из std::tm, проблема, которой поделился ваш пример, решается в других вопросах, таких как Простой способ преобразования struct tm (выраженной в UTC) в тип time_t

...