Арифметика календарных дат в C или C ++ (добавьте N дней к заданной дате)

Мне дали дату, которую я принимаю в качестве входных данных (день, месяц, год): 12, 03, 87,

Теперь мне нужно узнать дату после n дней.

Я написал код для этого, но это не эффективно. Подскажите, пожалуйста, какую-нибудь хорошую логику, которая работает быстрее и имеет меньшую сложность.

#include <stdio.h>

static int days_in_month[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int day, month, year;

unsigned short day_counter;

int is_leap(int y) {
return ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0);
}

next_day()
{
day += 1; day_counter++;
if (day > days_in_month[month]) {
day = 1;
month += 1;
if (month > 12) {
month = 1;
year += 1;
if (is_leap(year)) {
days_in_month[2] = 29;
} else {
days_in_month[2] = 28;
}
}
}
}

set_date(int d, int m, int y)
{
m < 1 ? m = 1 : 0;
m > 12 ? m = 12 : 0;
d < 1 ? d = 1 : 0;
d > days_in_month[m] ? d = days_in_month[m] : 0;
if (is_leap(y)){
days_in_month[2] = 29;
}
else {
days_in_month[2] = 28;
}
day = d;
month = m;
year = y;
}

skip_days(int x)
{
int i;
for (i=0;i<x;i++) next_day();
}

print_date()
{
printf ("day: %d month: %d year: %d\n", day, month, year);
}

int main(int argc, char **argv)
{
int i;

set_date(5, 2, 1980);
skip_days(40);
day_counter = 0;
/* after this call next_day each day */

print_date();
return 0;
}

5

Решение

Подскажите, пожалуйста, какую-нибудь хорошую логику, которая работает быстрее и имеет меньшую сложность.

Если это именно то, что действительно является важной частью вашего приложения, вы, вероятно, делаете что-то не так. Ради ясности и правильности следует придерживаться существующих решений. Выберите тот, который наиболее подходит для вашей среды разработки.


Подход C:

#include <stdio.h>
#include <time.h>

int main()
{
/* initialize */
int y=1980, m=2, d=5;
struct tm t = { .tm_year=y-1900, .tm_mon=m-1, .tm_mday=d };
/* modify */
t.tm_mday += 40;
mktime(&t);
/* show result */
printf("%s", asctime(&t)); /* prints: Sun Mar 16 00:00:00 1980 */
return 0;
}

C ++ без использования подхода Boost:

#include <ctime>
#include <iostream>

int main()
{
// initialize
int y=1980, m=2, d=5;
std::tm t = {};
t.tm_year = y-1900;
t.tm_mon  = m-1;
t.tm_mday = d;
// modify
t.tm_mday += 40;
std::mktime(&t);
// show result
std::cout << std::asctime(&t); // prints: Sun Mar 16 00:00:00 1980
}

Boost.Date_Time подход:

#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

int main()
{
using namespace boost::gregorian;
// initialize
date d(1980,2,5);
// modify
d += days(40);
// show result
std::cout << d << '\n'; // prints: 1980-Mar-16
}
12

Другие решения

Стандартная библиотека mktime Функция включает в себя трюк, позволяющий легко добавлять количество месяцев или дней к заданной дате: вы можете присвоить ей такую ​​дату, как «45 февраля» или «2-й день 40-го месяца» и mktime нормализует это в надлежащую дату. Пример:

#include <time.h>
#include <stdio.h>

int main() {
int y = 1980;
int m = 2;
int d = 5;
int skip = 40;

// Represent the date as struct tm.
// The subtractions are necessary for historical reasons.
struct tm  t = { 0 };
t.tm_mday = d;
t.tm_mon = m-1;
t.tm_year = y-1900;

// Add 'skip' days to the date.
t.tm_mday += skip;
mktime(&t);

// Print the date in ISO-8601 format.
char buffer[30];
strftime(buffer, 30, "%Y-%m-%d", &t);
puts(buffer);
}

По сравнению с выполнением арифметики за считанные секунды time_tэтот подход имеет то преимущество, что переходы на летнее время не вызывают никаких проблем.

5

Вот как выглядит решение с использованием опубликованных алгоритмов. Вот Говард Хиннант.

int main() {
int day_count = days_from_civil(1980, 5, 2);
auto [year, month, day] = civil_from_days(day_count + 40);
printf("%04i-%02i-%02-i\n", (int)year, (int)month, (int)day);
}

Новая функциональность даты была одобрена для включения в C ++ 20, хотя и с другим API. Решение C ++ 20, вероятно, будет выглядеть примерно так:

#include <chrono>

int main() {
using namespace std::chrono;
sys_days in_days = year_month_day{1980y, may, 2d};
std::cout << year_month_day(in_days + days(40)) << '\n';
}
1

самый простой трюк заключается в использовании time_t тип и соответствующие функции.

mktime превратит структуру тм в time_t, которое представляет собой целое число, считающее секунды, начиная с 01 января 1970 года.

После того, как у вас есть time_t значение просто добавьте необходимое количество секунд (86400 в день).

Чтобы конвертировать обратно, используйте gmtime или же localtime

0

Просто добавьте к объекту time_t количество дней, которое вы хотите.

#define SECOND              1
#define MINUTE              60 * SECOND
#define HOUR                60 * MINUTE
#define DAY                 24 * HOUR
time_t curTime;
time_t futureTime;

time( & curTime );

futureTime = curTime + (5 * DAY);

struct tm * futureDate = gmtime(&futureTime);
std::cout<<"5 days from now will be: "<<futureDate->tm_mday<<"/"<<futureDate->tm_mon+1<<"/"<<futureDate->tm_year+1900<<std::endl;
0

Может быть реализовано с использованием операторов 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;

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

/// 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;

return 0;
}

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

Может быть проще сделать математику, используя секунды, начиная с эпохи, а не напрямую манипулируя полями даты.

Например, эта программа печатает дату 7 дней отныне:

#include <stdio.h>
#include <time.h>

main()
{
time_t t;
struct tm *tmp;

time(&t);

/* add a week to today */
t += 7 * 24 * 60 * 60;

tmp = localtime(&t);
printf("%02d/%02d/%02d\n", tmp->tm_mon+1, tmp->tm_mday,
tmp->tm_year % 100);
}
-1

Этот код напечатает дату, наступившую через 10 дней. Измените значение на N для определенного пользователем числа.

#include< iostream.h>

#include< conio.h>

struct date{int d,m,y;};

void main()

{

date d1;

void later (date);

cout<<"ENTER A VALID DATE (dd/mm/yy)";

cin>>d1.d>>d1.m>>d1.y;

later(d1);

getch();

}

void later(date d1)

{

int mdays[12]={31,28,31,30,31,30,31,31,30,31,30,31};

if(((d1.y%4==0) && (d1.y%100!=0))||(d1.y%400==0))
mdays[1]=29;
d1.d=d1.d+10;

if(d1.d>mdays[d1.m-1])

{

d1.d=d1.d-mdays[d1.m-1];

d1.m++;

if(d1.m>12)

{d1.m=1;

d1.y++;

}

}
cout<<"DATE AFTER TEN DAYS IS "<<d1.d<<"\t"<<d1.m<<"\t"<<d1.y;

getch();

}
-2
По вопросам рекламы [email protected]