2010-02-26 75 views
15

Estoy tratando de escribir una clase de fecha en un intento de aprender C++.Algoritmo para sumar o restar días de una fecha?

Estoy tratando de encontrar un algoritmo para sumar o restar días a una fecha, donde el día comienza a partir de 1 mes y comienza a partir de 1. Está demostrando ser muy complejo, y Google no aparece mucho,

¿Alguien sabe de un algoritmo que hace esto?

+0

Me sorprende que esta pregunta exista sin una respuesta "Use Boost" acompañada de un enlace a la documentación. – jww

Respuesta

16

La manera más fácil es escribir dos funciones, una que convierta el día a varios días a partir de una fecha de inicio dada, y luego otra que se convierta nuevamente en una fecha. Una vez que la fecha se expresa como una cantidad de días, es trivial sumarla o restarla.

Puede encontrar los algoritmos aquí: http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html

+0

¡Gracias, esto es justo lo que estaba buscando, por alguna razón no pude encontrar el algoritmo mientras buscaba en la red! – bcoughlan

+0

desafortunadamente estas funciones no son muy precisas ... o al menos cuando comparé mis resultados con wolfram alpha, estuve fuera un día más o menos. – aimango

+0

Aquí: http://home.roadrunner.com/~hinnant/date_algorithms.html son algoritmos que son precisos. Se ha probado que su validez es precisa en un calendario gregoriano proléptico en el rango +/- 5.8 millones de años usando aritmética de 32 bits. Cuentan días antes o después de 1970-01-01. –

3

Supongo que esto es para algún tipo de ejercicio, de lo contrario utilizaría una clase de tiempo que ya se le proporcionó.

Puede almacenar su tiempo como el número de milisegundos desde una fecha determinada. Y luego puede agregar el valor apropiado y convertir desde eso a la fecha al llamar a los usuarios de su clase.

+0

¿Por qué milisegundos? Parece que solo quiere fechas, no tiempos, y ciertamente no precisión en milisegundos. Eso incluso insinúa contar los segundos intercalares. – Steve314

1

Un enfoque es asignar la fecha al número Juliano de la fecha, realizar operaciones enteras y luego volver a transformar.

Encontrará muchos recursos para las funciones de julian.

0

Yo sugeriría escribir primero una rutina que convierte año-mes-día en un número de días desde la fecha fijada, por ejemplo, desde el 1.01.01. Y una rutina simétrica que lo convertiría de nuevo.

¡No olvide procesar los años bisiestos correctamente!

Tener esos dos, su tarea sería trivial.

2

Aquí hay un esquema de un enfoque muy simple. Por simplicidad de ideas asumiré que d, el número de días para agregar, es positivo. Es fácil extender la siguiente información a los casos en que d es negativo.

Cualquiera de d es menor que 365 o d es mayor que o igual a 365.

Si d es menor que 365:

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

Si d es mayor que 365:

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

Como alternativa, puede expresar la fecha en, por ejemplo, Julian form y luego simplemente agregue a la forma Julian y converse al formato ymd.

+0

funciona para mí, gracias! – aimango

7

Realmente no necesita un algoritmo como tal (al menos no es algo digno del nombre), la biblioteca estándar puede hacer la mayor parte del trabajo pesado; los cálculos del calendario son notoriamente complicados.Siempre y cuando no es necesario fechas anteriores a 1900, entonces:

#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) ; ; 
} 

Ejemplo de uso:

#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 ; 
} 
+0

Gracias por publicar esto. Muy útil. – ForeverLearning

+0

¿Los segundos saltarán este cálculo? – vargonian

+0

@vargonian: una buena pregunta; La época de UNIX es del 1 de enero de 1970 y no cuenta los segundos intercalares. Sin embargo, establecer la hora nominal del día al mediodía evitará cualquier problema potencial durante varias decenas de miles de años. – Clifford

1

Pruebe esta función. Calcula correctamente las adiciones o sustracciones. El argumento dateTime debe estar en formato 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); 
} 

Y hay ejemplo del uso:

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

Sé que esto es una pregunta muy antigua pero es una interesante y algo común uno cuando se trata de trabajar con fechas y horas. Así que pensé compartir un código que calcula la nueva fecha sin usar ninguna funcionalidad de tiempo incorporado 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 
Cuestiones relacionadas