transcurridos - programa de fechas en c++
¿Algoritmo para sumar o restar días de una fecha? (8)
Estoy tratando de escribir una clase de fecha en un intento de aprender C ++.
Estoy tratando de encontrar un algoritmo para agregar o restar días a una fecha, donde Día comienza desde 1 y Mes comienza desde 1. Está demostrando ser muy complejo, y Google no aparece mucho,
¿Alguien sabe de un algoritmo que hace esto?
Aquí hay un bosquejo de un enfoque muy simple. Para la simplicidad de las ideas, asumiré que d
, el número de días para agregar, es positivo. Es fácil extender lo siguiente a los casos en que d
es negativo.
O bien d
es menor que 365 o d
es mayor o igual que 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
Alternativamente, puede expresar la fecha en, digamos, forma juliana y luego simplemente agregar a la forma juliana y convertir al formato ymd.
La forma más sencilla es escribir dos funciones, una que convierte el día en un número de días a partir de una fecha de inicio determinada, y otra que vuelve a una fecha. Una vez que la fecha se expresa como un número de días, es trivial agregarla o restarla.
Puede encontrar los algoritmos aquí: http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html
Prueba esta función. Calcula correctamente las sumas o restas. 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 ejemplos de uso de:
time_t t = time(NULL);
tm* utc = gmtime(&t);
tm* newUtc = dateTimeAdd(utc, -5, 0, 0, 0); //subtract 5 days
Realmente no necesita un algoritmo como tal (al menos no es digno de ese nombre), la biblioteca estándar puede hacer la mayor parte del trabajo pesado; Los cálculos del calendario son notoriamente complicados. Mientras no necesite 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 ;
}
Sé que esta es una pregunta muy antigua, pero es una pregunta interesante y común cuando se trata de trabajar con fechas y horarios. Así que pensé en compartir algo de código que calcula la nueva fecha sin usar ninguna funcionalidad de tiempo incorporada 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
Sugeriría escribir primero una rutina que convierta año-mes-día en un número de días desde la fecha fija, por ejemplo, desde 1.01.01. Y una rutina simétrica que lo convertiría de nuevo.
¡No olvides procesar correctamente los años bisiestos!
Teniendo esos dos, tu tarea sería trivial.
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 de ese a la fecha al llamar a los usuarios de su clase.
Un enfoque es asignar la fecha al número juliano de la fecha, hacer las operaciones de enteros y luego transformar de nuevo.
Encontrarás un montón de recursos para las funciones julianas.