2015-11-14 2 views
3

У меня есть функция, называемая int differenceDatesInDays(string& date). Эта функция должна получать строковое значение как дату (ГГГГ-ММ-ДД) и сравнивать его с сегодняшней датой.C++ Дни между данной датой и сегодняшней датой

Я не знаю, есть ли что-то внутри STL, я не смог найти соответствующий алгоритм. Я только узнал, что у boost есть решение для этого, но я не хочу использовать boost.

Итак, это мой код до сих пор:

int differenceDatesInDays(string& date) { 
    string year = date.substr(0, 4); 
    string month = date.substr(5,2); 
    string day = date.substr(8, string::npos); 

    int y = stoi(year); 
    int m = stoi(month); 
    int d = stoi(day); 

    time_t time_now = time(0); 
    tm* now = localtime(&time_now); 

    int diffY = y - (now->tm_year + 1900); 
    int diffM = m - (now->tm_mon + 1); 
    int diffD = d - (now->tm_mday); 

    int difference = (diffY * 365) + (diffM * 30) + diffD; 

    return difference; 
} 

Я не знаю, как узнать, если в месяце 30, 31 или 28 дней.

+0

Есть только 12 месяцев, поэтому вы можете настроить массив const, который хранит дни каждого месяца. Индексируйте его к месяцу. Для февраля, который обычно имеет 28 дней, вам нужно будет определить, является ли это високосным годом, и в этом случае он имеет 29 дней. –

ответ

2

Что-то вдоль этих линий, может быть:

int differenceDatesInDays(string& date) { 
    // Parse `date` as in your code 
    int y = ...; 
    int m = ...; 
    int d = ...; 

    tm then = {0}; 
    then.tm_year = y - 1900; 
    then.tm_mon = m - 1; 
    then.tm_day = d; 
    time_t then_secs = mktime(&then); 

    time_t time_now = time(0); 
    tm* now = localtime(&time_now); 
    tm today = {0}; 
    today.tm_year = now->tm_year; 
    today.tm_mon = now->tm_mon; 
    today.tm_day = now->tm_day; 
    time_t today_secs = mktime(&today); 

    return (today_secs - then_secs)/(24*60*60); 
} 
+0

Восстанавливает ли ваш код, если месяц имеет 30, 31 или 28 дней? – user3653164

+0

Да, в некотором смысле, путем вызова 'mktime'. –

+0

Хе-хе. Конечно, простой ответ самый быстрый :) Я бы предпочел использовать средства Boost, так как вопрос был помечен для него ... – sehe

4

Поскольку вы помечать его с Boost, почему бы вам не использовать его и получить все вещи бесплатно:

Live On Coliru

#include <boost/date_time/gregorian/gregorian.hpp> 

int differenceDatesInDays(std::string const& s) { 
    using namespace boost::gregorian; 
    return (day_clock::local_day() - from_string(s)).days(); 
} 

int main() { 
    return differenceDatesInDays("2015-01-01"); 
} 

Печать

317 
+0

Это гораздо полезнее, чем принятый ответ; Жаль, что ОП не хотел использовать boost (несмотря на тег). – Walter

5

После того, как у вас есть два интегральных тройки: {y1, m1, d1} и {y0, m0, d0}, наиболее эффективный способ, чтобы вычислить разницу между ними заключается в использовании функции общественного домена days_from_civil вычислить серийный отсчет дня каждые тройной, и вычитать им:

diff = days_from_civil(y1, m1, d1) - days_from_civil(y0, m0, d0); 

Здесь повторяется days_from_civil:

// Returns number of days since civil 1970-01-01. Negative values indicate 
// days prior to 1970-01-01. 
// Preconditions: y-m-d represents a date in the civil (Gregorian) calendar 
//     m is in [1, 12] 
//     d is in [1, last_day_of_month(y, m)] 
//     y is "approximately" in 
//     [numeric_limits<Int>::min()/366, numeric_limits<Int>::max()/366] 
//     Exact range of validity is: 
//     [civil_from_days(numeric_limits<Int>::min()), 
//     civil_from_days(numeric_limits<Int>::max()-719468)] 
template <class Int> 
constexpr 
Int 
days_from_civil(Int y, unsigned m, unsigned d) noexcept 
{ 
    static_assert(std::numeric_limits<unsigned>::digits >= 18, 
      "This algorithm has not been ported to a 16 bit unsigned integer"); 
    static_assert(std::numeric_limits<Int>::digits >= 20, 
      "This algorithm has not been ported to a 16 bit signed integer"); 
    y -= m <= 2; 
    const Int era = (y >= 0 ? y : y-399)/400; 
    const unsigned yoe = static_cast<unsigned>(y - era * 400);  // [0, 399] 
    const unsigned doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d-1; // [0, 365] 
    const unsigned doe = yoe * 365 + yoe/4 - yoe/100 + doy;   // [0, 146096] 
    return era * 146097 + static_cast<Int>(doe) - 719468; 
} 

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

+0

Хахаха. Полностью тривиальный материал :) Мне это нравится. Я буду использовать это в тот день, когда я не могу использовать стандартную библиотечную реализацию этого. – sehe

+0

Говард, вы должны быть полным наркоманом C++ - провести субботнюю ночь, чтобы дать такие ответы здесь. - Я лучше закрою свой терминал сейчас ...Кстати, я медленно догоняю вас на [этом] (http://stackoverflow.com/questions/5008804/generating-random-integer-from-a-range/19728404#19728404) – Walter

+0

@Walter Он писал библиотеки времени/времени для стандартной библиотеки и в других местах. Он связал с «библиотекой», что он написал это поначалу :) Возможно, вы, вероятно, доверяете этому коду по этой причине! – sehe

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