I have been given a date, Which I am taking as an input like (day, month, year): 12, 03, 87
.
Now I need to find out the date after n
days.
I have written code for this, But its not efficient. Can you please tell me any good logic which works faster and have less complexity.
#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;
}
Can you please tell me any good logic which works faster and have less complexity.
If this exact thing is indeed a performance critical part of your application, you're likely doing something wrong. For the sake of clarity and correctness, you should stick to the existing solutions. Select the one that is most appropriate to your development environment.
The C approach:
#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;
}
The C++ without using Boost approach:
#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
}
The Boost.Date_Time approach:
#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
}
The standard library mktime
function includes a trick to make it easy to add a number of months or days into a given date: you can give it a date such as "45th of February" or "2nd day of the 40th month" and mktime
will normalize it into a proper date. Example:
#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);
}
Compared to doing the arithmetic in seconds using time_t
, this approach has the advantage that daylight savings transitions do not cause any problems.
Here's what the solution looks like using algorithms published here by Howard Hinnant.
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);
}
New date functionality has been approved for inclusion in C++20, though with a different API. A C++20 solution will probably look something like:
#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';
}
the easiest trick is to use time_t
type and corresponding functions.
mktime
will convert tm structure to time_t
. which is an integer value counting the seconds starting 01-Jan-1970.
After you have a time_t
value just add the seconds count you need (86400 per day).
To convert back, use gmtime
or localtime
Just add to a time_t object for how many days you want.
#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;
Can be implemented using C++ operators and in a quite OOP way by representing date as a class.
#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
It might be easier to do the math using seconds since the epoch instead of manipulating the date fields directly.
For example, this program prints the date 7 days from now:
#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);
}
This code will print the date coming after 10 days. Change the value to N for a user-defined number.
#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();
}
来源:https://stackoverflow.com/questions/15668638/arithmetics-on-calendar-dates-in-c-or-c-add-n-days-to-given-date