web-dev-qa-db-fra.com

Algorithme pour ajouter ou soustraire des jours à une date?

J'essaie d'écrire une classe Date pour essayer d'apprendre le C++.

J'essaie de trouver un algorithme pour ajouter ou soustraire des jours à une date, où Day commence à 1 et Mois à partir de 1. Cela s'avère très complexe et Google ne s'affiche pas beaucoup,

Est-ce que quelqu'un sait d'un algorithme qui fait cela?

19
bcoughlan

Le moyen le plus simple consiste à écrire deux fonctions, l’une qui convertit le jour en un nombre de jours à partir d’une date de début donnée, puis une autre qui reconvertit une date. Une fois que la date est exprimée en nombre de jours, il est facile de l’additionner ou de la soustraire.

Vous pouvez trouver les algorithmes ici: http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html

19
Mark Ransom

Vous n'avez pas vraiment besoin d'un algorithme en tant que tel (du moins pas quelque chose de digne de ce nom), la bibliothèque standard peut faire le gros du travail lourd; les calculs de calendrier sont notoirement délicats. Tant que vous n'avez pas besoin de dates antérieures à 1900, alors:

#include <ctime>

// Adjust date by a number of days +/-
void DatePlusDays( struct tm* date, int days )
{
    const time_t ONE_DAY = 24 * 60 * 60 ;

    // Seconds since start of Epoch
    time_t date_seconds = mktime( date ) + (days * ONE_DAY) ;

    // Update caller's date
    // Use localtime because mktime converts to UTC so may change date
    *date = *localtime( &date_seconds ) ; ;
}

Exemple d'utilisation:

#include <iostream>

int main()
{
    struct tm date = { 0, 0, 12 } ;  // nominal time midday (arbitrary).
    int year = 2010 ;
    int month = 2 ;  // February
    int day = 26 ;   // 26th

    // Set up the date structure
    date.tm_year = year - 1900 ;
    date.tm_mon = month - 1 ;  // note: zero indexed
    date.tm_mday = day ;       // note: not zero indexed

    // Date, less 100 days
    DatePlusDays( &date, -100 ) ; 

    // Show time/date using default formatting
    std::cout << asctime( &date ) << std::endl ;
}
8
Clifford

Je suppose que c'est pour une sorte d'exercice, sinon vous utiliseriez une classe de temps qui vous a déjà été fournie. 

Vous pouvez enregistrer votre temps sous forme de millisecondes depuis une certaine date. Et vous pouvez ensuite ajouter la valeur appropriée et convertir celle-ci en date en appelant les accesseurs de votre classe.

3
Brian R. Bondy

Voici un croquis d'une approche très simple. Pour simplifier les idées, je supposerai que d, le nombre de jours à ajouter, est positif. Il est facile d'étendre ce qui suit ci-dessous aux cas où d est négatif.

d est inférieur à 365 ou d est supérieur ou égal à 365.

Si d est inférieur à 365:

m = 1;
while(d > numberOfDaysInMonth(m, y)) {
    d -= numberOfDaysInMonth(m, y);
    m++;
}
return date with year = y, month = m, day = d;

Si d est supérieur à 365:

while(d >= 365) {
    d -= 365;
    if(isLeapYear(y)) {
        d -= 1;
    }
    y++;
}
// now use the case where d is less than 365

Alternativement, vous pouvez exprimer la date sous la forme/par exemple forme julienne , puis simplement ajouter à la forme julienne et la convertir au format ymd.

2
jason

Essayez cette fonction. Il calcule correctement les additions ou les soustractions. L'argument dateTime doit être au format UTC.

tm* dateTimeAdd(const tm* const dateTime, const int& days, const int& hours, const int& mins, const int& secs) {
    tm* newTime = new tm;
    memcpy(newTime, dateTime, sizeof(tm));

    newTime->tm_mday += days;
    newTime->tm_hour += hours;
    newTime->tm_min += mins;
    newTime->tm_sec += secs;        

    time_t nt_seconds = mktime(newTime) - timezone;
    delete newTime;

    return gmtime(&nt_seconds);
}

Et il y a des exemples d'utilisation:

time_t t = time(NULL);
tm* utc = gmtime(&t);
tm* newUtc = dateTimeAdd(utc, -5, 0, 0, 0); //subtract 5 days
1
Eldar Agalarov

Une approche consiste à mapper la date au nombre Julian de la date, à effectuer vos opérations sur les entiers, puis à reconvertir.

Vous trouverez de nombreuses ressources pour les fonctions de Julian.

1
Dirk Eddelbuettel

Je suggèrerais d’écrire d’abord une routine qui convertit année-mois-jour en un nombre de jours depuis une date fixe, par exemple depuis 1.01.01. Et une routine symétrique qui le reconvertirait.

N'oubliez pas de traiter les années bissextiles correctement!

Ayant ces deux, votre tâche serait triviale.

0
Vlad

Je sais que la question est très ancienne, mais qu’elle est intéressante et courante lorsqu’il s’agit de travailler avec des dates et des heures. J'ai donc pensé à partager un code qui calcule la nouvelle date sans utiliser aucune fonctionnalité temporelle intégrée en C++.

#include <iostream>
#include <string>

using namespace std;

class Date {
public:
    Date(size_t year, size_t month, size_t day):m_year(year), m_month(month), m_day(day) {}
    ~Date() {}

    // Add specified number of days to date
    Date operator + (size_t days) const;

    // Subtract specified number of days from date
    Date operator - (size_t days) const;

    size_t Year()  { return m_year; }
    size_t Month() { return m_month; }
    size_t Day()   { return m_day; }

    string DateStr();
private:
    // Leap year check 
    inline bool LeapYear(int year) const
        { return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); }

    // Holds all max days in a general year
    static const int MaxDayInMonth[13];

    // Private members
    size_t m_year;
    size_t m_month;
    size_t m_day;   
};

// Define MaxDayInMonth
const int Date::MaxDayInMonth[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

//===========================================================================================
/// Add specified number of days to date
Date Date::operator + (size_t days) const {
    // Maximum days in the month
    int nMaxDays(MaxDayInMonth[m_month] + (m_month == 2 && LeapYear(m_year) ? 1 : 0));

    // Initialize the Year, Month, Days
    int nYear(m_year);
    int nMonth(m_month);
    int nDays(m_day + days);

    // Iterate till it becomes a valid day of a month
    while (nDays > nMaxDays) {
        // Subtract the max number of days of current month
        nDays -= nMaxDays;

        // Advance to next month
        ++nMonth;

        // Falls on to next year?
        if (nMonth > 12) {
            nMonth = 1; // January
            ++nYear;    // Next year
        }

        // Update the max days of the new month
        nMaxDays = MaxDayInMonth[nMonth] + (nMonth == 2 && LeapYear(nYear) ? 1 : 0);
    }

    // Construct date
    return Date(nYear, nMonth, nDays);
}

//===========================================================================================
/// Subtract specified number of days from date
Date Date::operator - (size_t days) const {
    // Falls within the same month?
    if (0 < (m_day - days)) {
        return Date(m_year, m_month, m_day - days);
    }

    // Start from this year
    int nYear(m_year);

    // Start from specified days and go back to first day of this month
    int nDays(days);
    nDays -= m_day;

    // Start from previous month and check if it falls on to previous year
    int nMonth(m_month - 1);
    if (nMonth < 1) {
        nMonth = 12; // December
        --nYear;     // Previous year
    }

    // Maximum days in the current month
    int nDaysInMonth = MaxDayInMonth[nMonth] + (nMonth == 2 && LeapYear(nYear) ? 1 : 0);

    // Iterate till it becomes a valid day of a month
    while (nDays >= 0) {
        // Subtract the max number of days of current month
        nDays -= nDaysInMonth;

        // Falls on to previous month?
        if (nDays > 0) {
            // Go to previous month
            --nMonth;

            // Falls on to previous year?
            if (nMonth < 1) {
                nMonth = 12; // December
                --nYear;     // Previous year
            }
        }

        // Update the max days of the new month
        nDaysInMonth = MaxDayInMonth[nMonth] + (nMonth == 2 && LeapYear(nYear) ? 1 : 0);
    }

    // Construct date
    return Date(nYear, nMonth, (0 < nDays ? nDays : -nDays));
}

//===========================================================================================
/// Get the date string in yyyy/mm/dd format
string Date::DateStr() {
    return to_string(m_year) 
        + string("/")
        + string(m_month < 10 ? string("0") + to_string(m_month) : to_string(m_month))
        + string("/")
        + string(m_day < 10 ? string("0") + to_string(m_day) : to_string(m_day)); 
}


int main() {
    // Add n days to a date
    cout << Date(2017, 6, 25).DateStr() << " + 10 days = "
         << (Date(2017, 6, 25) /* Given Date */ + 10 /* Days to add */).DateStr() << endl;

    // Subtract n days from a date
    cout << Date(2017, 6, 25).DateStr() << " - 10 days = "
         << (Date(2017, 6, 25) /* Given Date */ - 10 /* Days to subract */).DateStr() << endl;

    return 0;
}

Output
2017/06/25 + 10 days = 2017/07/05
2017/06/25 - 10 days = 2017/06/15
0
SajithP