2015-11-12 3 views
3

У меня есть пользовательская дата Epoc, которая отличается от жесткого кодированного Epoc в STL. Я хочу узнать новую дату, которая начинается через определенное количество дней.Расчет даты, заданного количества дней после пользовательских Epoc

std::string ReturnDateTimeAsString(long double NumberOfDaysSinceEpoc) 
{ 
    std::istringstream iss("1200-01-01.00:00:00"); // My custom Epoc 
    std::tm Time; 
    iss >> std::get_time(&Time, "%Y-%m-%d.%H:%M:%S"); 
    std::chrono::system_clock::time_point MyEpoc = std::chrono::system_clock::from_time_t(std::mktime(&Time)); 
    std::chrono::duration<long double, std::ratio<86400, 1>> Days(NumberOfDaysSinceEpoc); // 86400: Seconds in a day 
    std::chrono::system_clock::time_point DateTime = MyEpoc + Days; // I get the error here! 
    std::time_t TimeType = std::chrono::system_clock::to_time_t(DateTime); 
    return std::string(std::ctime(&TimeType)); 
} 

Аргумент функции может быть десятичным. Например, если я передаю 4.25 этой функции, я хочу получить из нее строку "1200-01-05.06:00:00" (через 4 дня и 6 часов после Epoc).

Я получаю сообщение об ошибке ниже в строке, где я пытаюсь добавить переменную Epoc и Days.

Cannot convert from 'std::chrono::time_point<std::chrono::system_clock,std::chrono::duration<long double,std::ratio<0x01,0x0989680>>>' 
to 
'std::chrono::time_point<std::chrono::system_clock,std::chrono::system_clock::duration>' 

No suitable user-defined conversion from 
"std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<long double, std::ratio<1i64, 10000000i64>>>" 
to 
"std::chrono::system_clock::time_point" 

Как исправить этот код?

ответ

0

Игнорирование пространств имен, MyEpoc имеет тип system_clock::time_point и Days имеет тип duration<long double, ratio<86400>>. Сумма этих двух типов будет иметь тип:

time_point<system_clock, duration<long double, system_clock::period>> 

Вы пытаетесь присвоить этот тип к:

system_clock::time_point 

, который то же самое:

time_point<system_clock, system_clock::duration> 

system_clock::duration указан для некоторого подписанного интегрального типа (обычно long long). Таким образом, вся проблема заключается в попытке конвертировать long double на основе time_point в интегральный time_point. Это может быть сделано с time_point_cast:

std::chrono::system_clock::time_point DateTime = 
    std::chrono::time_point_cast<std::chrono::system_clock::duration>(MyEpoc + Days); 

ли, что делает ваша функция правильно или нет, это другой вопрос. Но это приводит к тому, что система типов работает.


Используя этот date library, я могу легко видеть, что по крайней мере на моей системе, ваша эпоха не то, что вы хотите быть:

#include "date.h" 

std::string 
ReturnDateTimeAsString(long double NumberOfDaysSinceEpoc) 
{ 
    using namespace std; 
    using namespace std::chrono; 

    istringstream iss("1200-01-01.00:00:00"); // My custom Epoc 
    tm Time; 
    iss >> get_time(&Time, "%Y-%m-%d.%H:%M:%S"); 
    system_clock::time_point MyEpoc = system_clock::from_time_t(mktime(&Time)); 
    { 
     using namespace date; 
     std::cout << MyEpoc << '\n'; 
    } 
    duration<long double, ratio<86400, 1>> Days(NumberOfDaysSinceEpoc); // 86400: Seconds in a day 
    system_clock::time_point DateTime = time_point_cast<system_clock::duration>(MyEpoc + Days); // I get the error here! 
    time_t TimeType = system_clock::to_time_t(DateTime); 
    return string(ctime(&TimeType)); 
} 

Это выходы для эпохи:

1969-12-31 23:59:59.000000 

mtkime, по крайней мере, в моей системе, возможно, недействителен к 1200-01-01.

Как оказалось, в моей системе эта операция ограничена numeric_limits<int32_t>::min() секундами (-2'147'483'648s). И sys_days{1970_y/1/1} - 2'147'483'648s - 1901-12-13 20:45:52. Попробуйте установить эпоху раньше, чем моя система (OS X).

Используя этот date library, я упростил вашу функцию, и тестирует правильно, при условии, что вы хотели вашу эпоху в UTC часовой пояс (если нет, то можно легко изменить, что):

#include "date.h" 

using days_ld = std::chrono::duration<long double, std::ratio<86400>>; 

std::string 
ReturnDateTimeAsString(days_ld Days) 
{ 
    using namespace std; 
    using namespace std::chrono; 
    using namespace date; 

    constexpr auto MyEpoc = sys_days{1200_y/1/1}; 
    auto DateTime = round<seconds>(MyEpoc + Days); 
    ostringstream out; 
    out << DateTime; 
    return out.str(); 
} 

int 
main() 
{ 
    std::cout << ReturnDateTimeAsString(days_ld{4.25}) << '\n'; 
} 

Это выводит:

1200-01-05 06:00:00 

Я взял на себя смелость округления вашего long double входа в ближайший seconds. Если вы предпочитаете что-то более тонкие, скажем milliseconds, что простое изменение:

auto DateTime = round<milliseconds>(MyEpoc + Days); 

который изменяет вывод:

1200-01-05 06:00:00.000 

Или:

auto DateTime = round<minutes>(MyEpoc + Days); 

который изменяет вывод :

1200-01-05 06:00 

Изменяя аргумент функции на желаемый тип продолжительности (days_ld), теперь ваша функция более безопасна и более гибкая. Например ваш клиент теперь может также ввести std::chrono::hours:

using namespace std::chrono_literals; 
    std::cout << ReturnDateTimeAsString(102h) << '\n'; 

и получить одинаковый выход.

Если вы предпочитаете какой-либо другой формат для выходной строки, это тоже очень просто. Более подробная информация по этим ссылкам:

http://howardhinnant.github.io/date/date.html

https://github.com/HowardHinnant/date/wiki

Смежные вопросы