I'm trying to write a Date class in an attempt to learn C++.
I'm trying to find an algorithm to add or subtract days to a date, where Day starts from 1 and Month starts from 1. It's proving to be very complex, and google doesn't turn up much,
Does anyone know of an algorithm which does this?
The easiest way is to actually write two functions, one which converts the day to a number of days from a given start date, then another which converts back to a date. Once the date is expressed as a number of days, it's trivial to add or subtract to it.
You can find the algorithms here: http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html
You don't really need an algorithm as such (at least not something worthy of the name), the standard library can do most of the heavy lifting; calender calculations are notoriously tricky. So long as you don't need dates earlier than 1900, then:
#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 ) ; ;
}
Example usage:
#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 ;
}
I'm assuming this is for some kind of an exercise, otherwise you would use a time class that's already provided to you.
You could store your time as the number of milliseconds since a certain date. And then you can add the appropriate value and convert from that to the date upon calling the accessors of your class.
Here's a sketch of a very simple approach. For simplicity of ideas I will assume that d, the number of days to add, is positive. It is easy to extend the below to cases where d is negative.
Either d is less than 365 or d is greater than or equal to 365.
If d is less than 365:
m = 1;
while(d > numberOfDaysInMonth(m, y)) {
d -= numberOfDaysInMonth(m, y);
m++;
}
return date with year = y, month = m, day = d;
If d is greater than 365:
while(d >= 365) {
d -= 365;
if(isLeapYear(y)) {
d -= 1;
}
y++;
}
// now use the case where d is less than 365
Alternatively, you could express the date in, say, Julian form and then merely add to the Julian form and conver to ymd format.
One approach is to map the date to the Julian number of the date, do your integer operations and then transform back.
You will find plenty of resources for the julian functions.
Try this function. It correctly calculates additions or subtractions. dateTime argument must be in UTC format.
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);
}
And there are example of using:
time_t t = time(NULL);
tm* utc = gmtime(&t);
tm* newUtc = dateTimeAdd(utc, -5, 0, 0, 0); //subtract 5 days
I know this is a very old question but it's an interesting and some common one when it comes to working with dates and times. So I thought of sharing some code which calculates the new date without using any inbuilt time functionality in 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
I would suggest writing first a routine which converts year-month-day into a number of days since fixed date, say, since 1.01.01. And a symmetric routine which would convert it back.
Don't forget to process leap years correctly!
Having those two, your task would be trivial.
I know it is an old question asked almost a decade before. But a few days before I came across the same for an assignment, and here is the answer as in here
// C++ program to find date after adding
// given number of days.
#include<bits/stdc++.h>
using namespace std;
// Return if year is leap year or not.
bool isLeap(int y)
{
if (y%100 != 0 && y%4 == 0 || y %400 == 0)
return true;
return false;
}
// Given a date, returns number of days elapsed
// from the beginning of the current year (1st
// jan).
int offsetDays(int d, int m, int y)
{
int offset = d;
switch (m - 1)
{
case 11:
offset += 30;
case 10:
offset += 31;
case 9:
offset += 30;
case 8:
offset += 31;
case 7:
offset += 31;
case 6:
offset += 30;
case 5:
offset += 31;
case 4:
offset += 30;
case 3:
offset += 31;
case 2:
offset += 28;
case 1:
offset += 31;
}
if (isLeap(y) && m > 2)
offset += 1;
return offset;
}
// Given a year and days elapsed in it, finds
// date by storing results in d and m.
void revoffsetDays(int offset, int y, int *d, int *m)
{
int month[13] = { 0, 31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31 };
if (isLeap(y))
month[2] = 29;
int i;
for (i = 1; i <= 12; i++)
{
if (offset <= month[i])
break;
offset = offset - month[i];
}
*d = offset;
*m = i;
}
// Add x days to the given date.
void addDays(int d1, int m1, int y1, int x)
{
int offset1 = offsetDays(d1, m1, y1);
int remDays = isLeap(y1)?(366-offset1):(365-offset1);
// y2 is going to store result year and
// offset2 is going to store offset days
// in result year.
int y2, offset2;
if (x <= remDays)
{
y2 = y1;
offset2 = offset1 + x;
}
else
{
// x may store thousands of days.
// We find correct year and offset
// in the year.
x -= remDays;
y2 = y1 + 1;
int y2days = isLeap(y2)?366:365;
while (x >= y2days)
{
x -= y2days;
y2++;
y2days = isLeap(y2)?366:365;
}
offset2 = x;
}
// Find values of day and month from
// offset of result year.
int m2, d2;
revoffsetDays(offset2, y2, &d2, &m2);
cout << "d2 = " << d2 << ", m2 = " << m2
<< ", y2 = " << y2;
}
// Driven Program
int main()
{
int d = 14, m = 3, y = 2015;
int x = 366;
addDays(d, m, y, x);
return 0;
}
Don't know if this helps or not. I was working on a scheduling system which (in the first simple draft) calculated start date as due date - days lead time. I worked with seconds elapsed (since epoch) to allow greater precision in future drafts of the code.
#include <iostream>
#include <ctime>
int main() {
// lead time in days
int lead_time = 20;
// assign a due_date of (midnight on) 3rd November 2020
tm tm_due_date = { 0, 0, 0, 3, 11, 2020-1900};
// convert due_date to seconds elapsed (since epoch)
time_t tt_due_date = mktime(&tm_due_date);
// subtract lead time seconds
tt_due_date -= 60 * 60 * 24 * lead_time;
// convert back (to local time)
tm *start_date = localtime(&tt_due_date);
// otput the result as something we can readily read
std::cout << asctime(start_date) << "\n";
}
Related
i am working on a code to parse cron format
After going through the different syntax i got stuck on the 'L' operator, specifically on the '3L' which will give me the last Wednesday of the month (e.g the last Wednesday of September 2021 is going to be 29th )
the number 3 is the number of day :
0 = Sunday
1 = Monday
.
.
6 = Saturday
i looked through the internet and i cant find anything that can help me (i dont want use any libraries)
i found this code which calculates the last Friday of every month, i want to change it so i can get the last week day of my choice of any month i want.
EDITED
#include <iostream>
using namespace std;
class lastFriday
{
int lastDay[12]; //to store last day of all month//хранить последний день всего месяца
int year; //for given year//за данный год
string m[12]; // to store names of all 12 months//хранить имя всех 12 месяцев
bool isleap; // to check given year is leap year or not//проверить, является ли год високосным или нет
private:
//function to find leap year//функция поиска високосного года
void isleapyear()
{
if ((year % 4))
{
if (year % 100)
isleap = true;
else if ((year % 400))
isleap = true;
}
}
// to display last friday of each month
void display()
{
for (int x = 0; x < 12; x++)
cout << m[x] << lastDay[x] << endl;
}
//function to find last friday for a given month
int getWeekDay(int m, int d)
{
int y = year;
int f = y + d + 3 * m - 1;
m++;
if (m < 3)
y--;
else
f -= int(.4 * m + 2.3);
f += int(y / 4) - int((y / 100 + 7) * 0.75);
f %= 7;
return f;
}
public:
//set name of 12 months
lastFriday()
{
m[0] = "JANUARY: "; m[1] = "FEBRUARY: "; m[2] = "MARCH: "; m[3] = "APRIL: ";
m[4] = "MAY: "; m[5] = "JUNE: "; m[6] = "JULY: "; m[7] = "AUGUST: ";
m[8] = "SEPTEMBER: "; m[9] = "OCTOBER: "; m[10] = "NOVEMBER: "; m[11] = "DECEMBER: ";
}
//function to find last fridays
void findLastFriday(int y)
{
year = y;
//to check given year is leap year or not
isleapyear();
//if given year is leap year then feb has 28 else 29
int days[] = { 31, isleap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; // to set number of days for each month
int d;
//for all 12 months we have to find last friday
for (int i = 0; i < 12; i++)
{
d = days[i];
while (true)
{
if (!getWeekDay(i, d))
break;
d--;
}
lastDay[i] = d;
}
//function call to print display dates of last friday for each month
display();
}
};
int main()
{
int year; //to store year given by user
lastFriday LF;
cout << "Enter the year in the range 1970 to 2037 : ";
cin >> year;
//validation for year between 1970 to 2037
if (year>2037|year<1970)
{
cout << "Not available for this year";
}
else
{
LF.findLastFriday(year);
}
return 0;
}
can anyone help me understand interpreting this code.
thanks!
Fwiw, here's the C++20 solution:
#include <chrono>
#include <iostream>
void
lastFriday(int y)
{
using namespace std;
using namespace std::chrono;
month m = January;
do
{
cout << m << " : " << sys_days{Friday[last]/m/y} << '\n';
} while (++m != January);
}
int
main()
{
lastFriday(2021);
}
Output:
Jan : 2021-01-29
Feb : 2021-02-26
Mar : 2021-03-26
Apr : 2021-04-30
May : 2021-05-28
Jun : 2021-06-25
Jul : 2021-07-30
Aug : 2021-08-27
Sep : 2021-09-24
Oct : 2021-10-29
Nov : 2021-11-26
Dec : 2021-12-31
If you don't have C++20, but you have C++11 or later, you can still do this using this free, open-source, header-only C++20 chrono preview library. Just add #include "date/date.h" and using namespace date;.
This will output the correct values for the civil calendar when y is in the range [-32767, 32767].
If you need to extract integral values for month, day and year, that is easy to do from the object resulting from this expression: sys_days{Friday[last]/m/y}
I found a solution for my problem and I want to share it with you, maybe someone can find it helpful.
I mentioned in my question that i want to get the day of month of the last weekday of any month.
First, in the cron format, if you want to specify that you could write it like this: "0 14 10 ? SEP 3L ?" this means, execute every last Wednesday of September on 10:14:00.
For that to work in my code, I need to get which day of month is on Wednesday,
This code is a portion of my project, but I will try explaining everything,
else if (contains(str[5],'L'))
{
if (str[5] == "L") bdaysOfWeekDesc[6]=6;
else
{
int diff;
auto parts = split(str[5],'L');
auto LDoM = LastDay(stoi(monthReplaced),currentYear);
tm time_in = { 0, 0, 0, LDoM, stoi(monthReplaced)-1, currentYear - 1900};
time_t time_temp = mktime(&time_in);
const tm * time_out = localtime(&time_temp);
if (stoi(parts[0].data()) == time_out->tm_wday)
{
bdaysOfMonthsDesc[time_out->tm_mday] = time_out->tm_mday;
}
else if ((stoi(parts[0].data()) > time_out->tm_wday) || time_out->tm_wday ==0 )
{
diff = time_out->tm_wday - stoi(parts[0].data());
for(size_t j=0;j<=sizeof(bdaysOfMonthsDesc) / sizeof(bdaysOfMonthsDesc[0]);j++)
{
bdaysOfMonthsDesc[j]=0;
bdaysOfMonthsDesc[time_out->tm_mday + abs(diff) - 7] = time_out->tm_mday + abs(diff) - 7;
}
}
else if (stoi(parts[0].data()) < time_out->tm_wday)
{
diff = time_out->tm_wday - stoi(parts[0].data());
for(size_t j=0; j <= sizeof(bdaysOfMonthsDesc) / sizeof(bdaysOfMonthsDesc[0]); j++)
{
bdaysOfMonthsDesc[j] = 0;
bdaysOfMonthsDesc[time_out->tm_mday - abs(diff)] = time_out->tm_mday - abs(diff);
}
}
}
}
the split function is for splitting the field according to the separator given
e.g: auto parts = split("3L", 'L');
parts[0] equals to "3"
the contains function checks if a character exists in a string or not
e.g: contains("3L", 'L');
the split and contains functions are from the croncpp
The LastDay function returns the last day (30 or 31 or 28 or 29) of the month given. This function is from #saqlain response on an other thread
At first, I need to get the date for last day of the month
so:
tm time_in = {seconds, minutes, hours, dayOfMonth, Month, year-1900}
seconds: 0-based,
minutes: 0-based,
hours: 0-based,
DOM: 1-based day,
Month: 0-based month ( the -1 in the code is because my month's field is 1-based)
year: year since 1900
with the mktime() and localtime() functions I can get which weekday is on the 30th or 31st of the month
After that, I tested if the week day I am requesting in the cron format is the same as the weekday of the last day of month,
or if it's superior or inferior.
With this code, my problem was solved, and maybe it can help someone else.
How do I able to get which day by input date?
Input Date example: 15-08-2012
How do I know if its monday, tuesday or which day using C++.
I am trying to omit out weekends from the date available of a month, so If i input e.g the month of August 2012, i want to check which day is saturday and which day is sunday, so i can omit it out from the available date for my program.
Code that I tried for getting the amount of days in a month:
if (month == 4 || month == 6 || month == 9 || month == 11)
{
maxDay = 30;
}
else if (month == 2)
//{
// bool isLeapYear = (year% 4 == 0 && year % 100 != 0) || (year % 400 == 0);
// if (isLeapYear)
// {
// maxDay = 29;
// }
//else
{
maxDay = 28;
}
The next thing i want to know is in that month, which day are weekend so i can omit that from result.
#include <ctime>
std::tm time_in = { 0, 0, 0, // second, minute, hour
4, 9, 1984 - 1900 }; // 1-based day, 0-based month, year since 1900
std::time_t time_temp = std::mktime( & time_in );
// the return value from localtime is a static global - do not call
// this function from more than one thread!
std::tm const *time_out = std::localtime( & time_temp );
std::cout << "I was born on (Sunday = 0) D.O.W. " << time_out->tm_wday << '\n';
Date to Day of the week algorithm?
I'd use mktime(). Given day, month and year, fill out a tm, then
call mktime on it:
tm timeStruct = {};
timeStruct.tm_year = year - 1900;
timeStruct.tm_mon = month - 1;
timeStruct.tm_mday = day;
timeStruct.tm_hour = 12; // To avoid any doubts about summer time, etc.
mktime( &timeStruct );
return timeStruct.tm_wday; // 0...6 for Sunday...Saturday
Here is a simpler and probably better implementation as it does not need any extra library imports.
The result returned is an int from 0 to 6 (Sunday, Mon, Tue... Saturday).
#include <iostream>
int dayofweek(int d, int m, int y){
static int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
y -= m < 3;
return ( y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
}
/* Driver function to test above function */
int main(){
int day = dayofweek(23, 10, 2013);
// Above statement finds the week day for 10/23/2013
//dayofweek(<day in month>,<month>,<year>)
std::cout << day;
return 0;
}
You should use mktime and ctime and extract the tm_wday field of the tm structure. It is guaranteed that mktime doesn't require that field, so you can populate a skeleton tm structure, process it and decompose it back into a complete structure:
#include <ctime>
std::tm t = {};
t.tm_mday = 15;
t.tm_mon = 8;
t.tm_year = 2012;
std::tm * p = std::localtime(std::mktime(&t));
// result is p->tm_wday
#include <stdio.h>
#include <time.h>
int main ()
{
char *str = "15-08-2012";
struct tm tm;
if (strptime (str, "%d-%m-%Y", &tm) == NULL) {
/* Bad format !! */
}
char buffer [80];
strftime (buffer, 80, "Day is %a", &tm);
puts (buffer);
return 0;
}
How do I calculate the starting and ending date/time (YYYY-mm-DD HH:MM::SS) for a given year and ISO week number of the year?
I searched SO before asking this kind of question again. Surely, there were some threads concerning to the conversion from (year, weeknumber) to (datetime) on SO. But they were answered by speaking Perl, PHP, JAVA, SQL, C#, .NET, Excel, and and other programming languages except the C/C++.
I am afraid there is no short solution to this problem using simple C++. However it shouldn't be a tough job writing the solution. You just need to take care of exceptional cases (like the first and last week, february, leap year). An approach can be
From the week number for a year, get the day numbers (ie, start and end day number) for that year. (take care of the first and last week here)
Now it is simple to find the month and date in with the day numbers lie. (take care of february here)
You could start with code below and adjust it a bit (what is your definition of first week: first full week or first partial week). Also you have to handle special cases of first and last week.
int const year = 2012;
int const week = 24;
boost::gregorian::greg_weekday const firstDayOfWeek = boost::gregorian::Monday;
boost::gregorian::date const jan1st(year, boost::gregorian::Jan, 1);
boost::gregorian::first_day_of_the_week_after const firstDay2ndWeek(firstDayOfWeek);
boost::gregorian::date const begin2ndWeek = firstDay2ndWeek.get_date(jan1st);
boost::gregorian::date const end2ndWeek = begin2ndWeek + boost::gregorian::days(6);
boost::gregorian::date const beginNthWeek = begin2ndWeek + boost::gregorian::weeks(week - 2);
boost::gregorian::date const endNthWeek = end2ndWeek + boost::gregorian::weeks(week - 2);
std::cout << boost::gregorian::to_iso_extended_string(jan1st) << std::endl;
std::cout << boost::gregorian::to_iso_extended_string(begin2ndWeek) << std::endl;
std::cout << boost::gregorian::to_iso_extended_string(end2ndWeek) << std::endl;
std::cout << boost::gregorian::to_iso_extended_string(beginNthWeek) << std::endl;
std::cout << boost::gregorian::to_iso_extended_string(endNthWeek) << std::endl;
In order to help other people, I want to answer my own question as follows:
COleDateTime YearWeekDayToCalendarDate(int nYear, int nWeekNumber, int nWeekDay)
{
// This method requires that one know the weekday of 4 January of the year in question
int nFirstWeekDay = WeekDay(nYear, 1, 4);
// Add 3 to the number of this weekday, giving a correction to be used for dates within this year
int nDaysOffset = nFirstWeekDay + 3;
// Multiply the week number by 7, then add the weekday.
int nOrdinalDayNumber = (nWeekNumber * 7) + nWeekDay;
// From this sum subtract the correction for the year.
nOrdinalDayNumber = nOrdinalDayNumber - nDaysOffset;
// If the ordinal date thus obtained is zero or negative, the date belongs to the previous calendar year;
if (nOrdinalDayNumber <= 0)
nYear--;
int nTotalDaysInTheYear = 365;
if ( LeapYear(nYear) )
nTotalDaysInTheYear++;
// If greater than the number of days in the year, to the following year.
if (nOrdinalDayNumber > nTotalDaysInTheYear)
nYear++;
// The result is the ordinal date, which can be converted into a calendar date using the following function
unsigned int nMonth, nDay;
YearDayToMonthDay(nOrdinalDayNumber, nYear, nDay, nMonth);
COleDateTime dtCalendar(nYear, nMonth, nDay, 0, 0, 0);
return dtCalendar;
}
int WeekDay(int nYear, int nMonth, int nDay)
{
// Find the DayOfYearNumber for the specified nYear, nMonth, and nDay
const int AccumulateDaysToMonth [] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
// Set DayofYear Number for nYear, nMonth, and nDay
int nDayOfYearNumber = nDay + AccumulateDaysToMonth[nMonth - 1];
// Increase of Dayof Year Number by 1, if year is leapyear and month greater than February
//if ( LeapYear(nYear) && (nMonth == 2) )
if ( LeapYear(nYear) && (nMonth > 2) )
nDayOfYearNumber += 1;
// Find the Jan1Weekday for nYear (Monday = 1, Sunday = 7)
int i, j, k, l, nJan1Weekday, nWeekday;
i = (nYear - 1) % 100;
j = (nYear - 1) - i;
k = i + i / 4;
nJan1Weekday = 1 + (((((j / 100) % 4) * 5) + k) % 7);
// Calcuate the WeekDay for the given date
l = nDayOfYearNumber + (nJan1Weekday - 1);
nWeekday = 1 + ((l - 1) % 7);
return nWeekday;
}
void YearDayToMonthDay(unsigned int nYearDay, unsigned int nYear,
unsigned int& nMonthDay, unsigned int& nMonth)
{
// Day is the day between 1 and 366
// Year is the year you wish
unsigned int nMonthTable[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
unsigned int nMonthDays = 0;
if ((nYear % 4 == 0) && ((!(nYear % 100 == 0)) || (nYear % 400 == 0)))
nMonthTable[1] = 29;
else
nMonthTable[1] = 28;
nMonth = 0;
while (nYearDay > nMonthDays)
nMonthDays += nMonthTable[nMonth++];
nMonthDay = nYearDay - nMonthDays + nMonthTable[nMonth - 1];
}
inline bool LeapYear( int nYear )
{
// Find if nYear is LeapYear
if ( (nYear % 4 == 0 && nYear % 100 != 0) || nYear % 400 == 0)
return true;
else
return false;
}
I'm trying to figure out a way for my program to take a date (like February 2nd, 2003) and show the difference between the two with another date (like April 2nd, 2012), excluding leap years. So far I've only been able to figure it out if the dates are in the same month, just by subtracting the "day". In this program I use 2 sets of "month", "day" and "year" integers. I'm pretty much at a loss from where to go from here. This is a completely optional part of my assignment but I'd like to get an idea on how to get it to work. It seems like a hassle to me, but maybe there's a simple math formula I'm not thinking about?
Sorry, I don't have any pre-existing code for this part because the rest of the assignment just deals with having the user enter dates and then adding and subtracting a single day.
Using just the standard library, you can convert a moderately insane date structure into a count of seconds since an arbitrary zero point; then subtract and convert into days:
#include <ctime>
// Make a tm structure representing this date
std::tm make_tm(int year, int month, int day)
{
std::tm tm = {0};
tm.tm_year = year - 1900; // years count from 1900
tm.tm_mon = month - 1; // months count from January=0
tm.tm_mday = day; // days count from 1
return tm;
}
// Structures representing the two dates
std::tm tm1 = make_tm(2012,4,2); // April 2nd, 2012
std::tm tm2 = make_tm(2003,2,2); // February 2nd, 2003
// Arithmetic time values.
// On a posix system, these are seconds since 1970-01-01 00:00:00 UTC
std::time_t time1 = std::mktime(&tm1);
std::time_t time2 = std::mktime(&tm2);
// Divide by the number of seconds in a day
const int seconds_per_day = 60*60*24;
std::time_t difference = (time1 - time2) / seconds_per_day;
// To be fully portable, we shouldn't assume that these are Unix time;
// instead, we should use "difftime" to give the difference in seconds:
double portable_difference = std::difftime(time1, time2) / seconds_per_day;
Using Boost.Date_Time is a little less weird:
#include "boost/date_time/gregorian/gregorian_types.hpp"
using namespace boost::gregorian;
date date1(2012, Apr, 2);
date date2(2003, Feb, 2);
long difference = (date1 - date2).days();
It seems like a hassle to me, but maybe there's a simple math formula I'm not thinking about?
It is indeed a hassle, but there is a formula, if you want to do the calculation yourself.
Here is a complete code to calculating date difference in y/m/d.
Assuming that to and from are date types, and that months and days start from 1 (similar to Qt):
static int increment[12] = { 1, -2, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1 };
int daysInc = 0;
if (to.day() - from.day() < 0)
{
int month = to.month() - 2; // -1 from zero, -1 previous month.
if (month < 0)
month = 11; // Previous month is December.
daysInc = increment[month];
if ( (month == 1) && (to.year()%4 == 0) )
daysInc++; // Increment days for leap year.
}
int total1 = from.year()*360 + from.month()*30 + from.day();
int total2 = to.year()*360 + to.month()*30 + to.day();
int diff = total2 - total1;
int years = diff/360;
int months = (diff - years*360)/30;
int days = diff - years*360 - months*30 + daysInc;
// Extra calculation when we can pass one month instead of 30 days.
if (from.day() == 1 && to.day() == 31) {
months--;
days = 30;
}
I tried this algorithm and it is working okay. Let me know if you have troubles using/understanding it.
Since you are looking for mathematical formula , it will help you to find a solution to your problem. Let Y be the year,M be the month and D be the day. Do this calculation for both the dates.
Total = Y* 365 + M*30 + D ,then find the difference between 2 totals of the corresponding dates.
While multiplying 30 with M value ,you have to give the number of days in that month. You can do it with #define value or if loop. Similarly you can do for leap year too by multiplying 366 with Y .
Hope this will help u....
New answer for an old question:
chrono-Compatible Low-Level Date Algorithms
has formulas for converting a {year, month, day} triple to a serial count of days and back. You can use it to calculate the number of days between two dates like this:
std::cout << days_from_civil(2012, 4, 2) - days_from_civil(2003, 2, 2) << '\n';
which outputs:
3347
The paper is a how-to manual, not a library. It uses C++14 to demonstrate the formulas. Each formula comes with a detailed description and derivation, that you only have to read if you care about knowing how the formula works.
The formulas are very efficient, and valid over an extremely large range. For example using 32 bit arithmetic, +/- 5 million years (more than enough).
The serial day count is a count of days since (or prior to for negative values) New Years 1970, making the formulas compatible with Unix Time and all known implementations of std::chrono::system_clock.
The days_from_civil algorithm is not novel, and it should look very similar to other algorithms for doing the same thing. But going the other way, from a count of days back to a {year, month, day} triple is trickier. This is the formula documented by civil_from_days and I have not seen other formulations that are as compact as this one.
The paper includes example uses showing typical computations, std::chrono interoperability, and extensive unit tests demonstrating the correctness over +/- 1 million years (using a proleptic Gregorian calendar).
All of the formulas and software are in the public domain.
I'm not sure what platform are you on? Windows, Linux? But let us pretend that you would like to have a platform independent solution and the langugage is standard C++.
If you can use libraries you can use the Boost::Date_Time library (http://www.boost.org/doc/libs/1_49_0/doc/html/date_time.html)
If you cannot use libraries to solve your assignment, you will need to find a common simple ground. Maybe you could convert all the dates to seconds, or days substract them and then convert that back to the data again. Substracting days or months as integers will not help as it will lead to incorrect results unless you do not take into account the rest.
Hope that helps.
Like dbrank0 pointed it out. :)
There is another way round...
Given two dates, take the year of the earlier date as the reference year.
Then calculate no. of days between each of the two given dates and that 1/1/<that year>
Keep a separate function that tells the number of days elapsed till a specific month.
The absolute difference of those two no. of days will give the difference between the two given dates.
Also, do not forget to consider leap years!
The code:
#include<stdio.h>
#include<math.h>
typedef struct
{
int d, m, y;
} Date;
int isLeap (int y)
{
return (y % 4 == 0) && ( y % 100 != 0) || (y % 400 == 0);
}
int diff (Date d1, Date d2) //logic here!
{
int dd1 = 0, dd2 = 0, y, yref; //dd1 and dd2 store the <i>no. of days</i> between d1, d2 and the reference year
yref = (d1.y < d2.y)? d1.y: d2.y; //that <b>reference year</b>
for (y = yref; y < d1.y; y++)
if (isLeap(y)) //check if there is any leap year between the reference year and d1's year (exclusive)
dd1++;
if (isLeap(d1.y) && d1.m > 2) dd1++; //add another day if the date is past a leap year's February
dd1 += daysTill(d1.m) + d1.d + (d1.y - yref) * 365; //sum up all the tiny bits (days)
for (y = yref; y < d2.y; y++) //repeat for d2
if(isLeap(y))
dd2++;
if (isLeap(y) && d2.m > 2) dd2++;
dd2 += daysTill(d2.m) + d2.d + (d2.y - yref) * 365;
return abs(dd2 - dd1); //return the absolute difference between the two <i>no. of days elapsed past the reference year</i>
}
int daysTill (int month) //some logic here too!!
{
int days = 0;
switch (month)
{
case 1: days = 0;
break;
case 2: days = 31;
break;
case 3: days = 59;
break;
case 4: days = 90; //number of days elapsed before April in a non-leap year
break;
case 5: days = 120;
break;
case 6: days = 151;
break;
case 7: days = 181;
break;
case 8: days = 212;
break;
case 9: days = 243;
break;
case 10:days = 273;
break;
case 11:days = 304;
break;
case 12:days = 334;
break;
}
return days;
}
main()
{
int t; //no. of test cases
Date d1, d2; //d1 is the first date, d2 is the second one! obvious, duh!?
scanf ("%d", &t);
while (t--)
{
scanf ("%d %d %d", &d1.d, &d1.m, &d1.y);
scanf ("%d %d %d", &d2.d, &d2.m, &d2.y);
printf ("%d\n", diff(d1, d2));
}
}
Standard Input:
1
23 9 1960
11 3 2015
Standard Output:
19892
Code in action: https://ideone.com/RrADFR
Better algorithms, optimizations and edits are always welcome!
If you need to do it yourself, then one way to do this pretty easy is by converting dates into a Julian Day. You get formulas at that link, and from conversion on, you only work with floats, where each day is 1 unit.
I've made similar program but it count only days in border of one year or couple years
PS I'm in c++ programming only about two month
#include<iostream>
int calculateDaysInYears(int intYear, int endYear);
int checkYear(int intYear);
int checkMonth(int i, int intYear);
int getUserData()
{
int dayOrMonthOrYear;
std::cin >> dayOrMonthOrYear;
return dayOrMonthOrYear;
}
int calculateMonthInYears(int initialMonth, int endMonth, int initialYear)
{
//Подсчет дней начальной даты для варианта с несколькими годами
int x(0);
initialMonth++;
for (int i = initialMonth; i <= endMonth; i++)
x += checkMonth(i, initialYear);
return x;
}
int calculateMonth(int startMonth, int endMonth, int initialYear)
{
//Формула для подсчета кол-вa дней промежуточных месяцев
//Расчет в пределах года
startMonth++;
int x(0);
for (int i = startMonth; i < endMonth; i++)
x += checkMonth(i, initialYear);
return x;
}
int calculateMonthForEndYear(int endMonth, int endYear)
{
//Подсчет дней в конечном году
int x(0);
//Декремент кол-ва конечных месяцев для компенсации дней последнего месяца
--endMonth;
for (int i = 1; i <= endMonth; i++)
x += checkMonth(i, endYear);
return x;
}
int checkMonth(int i, int intYear)
{
if (i == 1 || i == 3 || i == 5 || i == 7 || i == 8 || i == 10 || i == 12)
return 31;
else
if (i == 2)
{
//Если год високосный, то делится на 4 и 400 без остатка, а на 100 с остатком
if ((intYear % 4 == 0) && (intYear % 100 != 0 ) || (intYear % 400 == 0))
return 29;
else
return 28;
}
else
return 30;
}
int calculateAmountOfDays(int initialDay, int initialMonth, int initialYear)
{
//Подсчет дней до конца стартового месяца
int month = checkMonth(initialMonth, initialYear);
int days = month - initialDay;
return days;
}
int allDays(int initilDays, int endDays, int midleMonth)
{
int totalDays;
//Подсчет всех дней от начала до конца
totalDays = midleMonth + initilDays + endDays;
return totalDays;
}
int checkYear(int intYear)
{
if ((intYear % 4 == 0) && (intYear % 100 != 0) || (intYear % 400 == 0))
return 366;//Високосный год
else
return 365;//Невисокосный год
}
int calculateDaysInYears(int intYear, int endYear)
{
//Начальное кол-во дней. Необходимо для запуска счетчика
int amountDays(0);
//Инкремент начального года для компенсации кол-ва дней промежуточных годов
intYear++;
for (int i = intYear; i < endYear; i++)
amountDays += checkYear(i);
return amountDays;
}
int main()
{
int initialDay;
int initialMonth;
int initialYear;
int endDay;
int endMonth;
int endYear;
std::cout << "Hello! I'm your calendar calculator." << std::endl <<
"Here some rules: " << std::endl <<
"you should enter a data like(d.m.y): 23.8.2020." << std::endl <<
"Also you can ask me to calculate for couple years or in border of one year. Good luck! " << std::endl;
std::cout << "" << std::endl;
//Начальная дата
std::cout << "Enter an initial day: ";
initialDay = getUserData();
std::cout << "Enter an initial month: ";
initialMonth = getUserData();
std::cout << "Enter an initial year: ";
initialYear = getUserData();
std::cout << "" << std::endl;//Пропуск строки
//Конечная дата
std::cout << "Enter an end day: ";
endDay = getUserData();
std::cout << "Enter an end month: ";
endMonth = getUserData();
std::cout << "Enter an end year: ";
endYear = getUserData();
//Проверка кол-ва годов
if ((endYear - initialYear) >= 1)
{
//Подсчет дней до конца начального года
int daysToTheEndOfStartYear = calculateMonthInYears(initialMonth, 12, initialYear) + calculateAmountOfDays(initialDay, initialMonth, initialYear);
//Подсчет дней до конца конечного месяца
int daysToTheEndOfEndYear = calculateMonthForEndYear(endMonth, endYear) + endDay;
//Подсчет дней между годами
int whalDays = calculateDaysInYears(initialYear, endYear);
//Подсчет конечной цыфры
int allDay = whalDays + daysToTheEndOfEndYear + daysToTheEndOfStartYear;
//Вывод в консоль
std::cout << allDay;
}
else
{
//Дни месяцев между начальным и конечным месяцами
int daysInMonths = calculateMonth(initialMonth, endMonth, initialYear);
//Подсчет дней до конца начального месяца
int daysInFirstMonth = calculateAmountOfDays(initialDay, initialMonth, initialYear);
//Подсчет конечной цыфры
int allDay = daysInMonths + daysInFirstMonth + endDay;
//Вывод в консоль
std::cout << allDay;
}
return 0;
}
You should look at the DateTime class.
Also the msdn reference for C++ syntax.
I have some code that uses the Oracle function add_months to increment a Date by X number of months.
I now need to re-implement the same logic in a C / C++ function. For reasons I don't want/need to go into I can't simply issue a query to oracle to get the new date.
Does anyone know of a simple and reliable way of adding X number of months to a time_t?
Some examples of the types of calculations are shown below.
30/01/2009 + 1 month = 28/02/2009
31/01/2009 + 1 month = 28/02/2009
27/02/2009 + 1 month = 27/03/2009
28/02/2009 + 1 month = 31/03/2009
31/01/2009 + 50 months = 31/03/2013
You can use Boost.GregorianDate for this.
More specifically, determine the month by adding the correct date_duration, and then use end_of_month_day() from the date algorithms
Convert time_t to struct tm, add X to month, add months > 12 to years, convert back. tm.tm_mon is an int, adding 32000+ months shouldn't be a problem.
[edit] You might find that matching Oracle is tricky once you get to the harder cases, like adding 12 months to 29/02/2008. Both 01/03/2009 and 28/02/2008 are reasonable.
Really new answer to a really old question!
Using this free and open source library, and a C++14 compiler (such as clang) I can now write this:
#include "date.h"
constexpr
date::year_month_day
add(date::year_month_day ymd, date::months m) noexcept
{
using namespace date;
auto was_last = ymd == ymd.year()/ymd.month()/last;
ymd = ymd + m;
if (!ymd.ok() || was_last)
ymd = ymd.year()/ymd.month()/last;
return ymd;
}
int
main()
{
using namespace date;
static_assert(add(30_d/01/2009, months{ 1}) == 28_d/02/2009, "");
static_assert(add(31_d/01/2009, months{ 1}) == 28_d/02/2009, "");
static_assert(add(27_d/02/2009, months{ 1}) == 27_d/03/2009, "");
static_assert(add(28_d/02/2009, months{ 1}) == 31_d/03/2009, "");
static_assert(add(31_d/01/2009, months{50}) == 31_d/03/2013, "");
}
And it compiles.
Note the remarkable similarity between the actual code, and the OP's pseudo-code:
30/01/2009 + 1 month = 28/02/2009
31/01/2009 + 1 month = 28/02/2009
27/02/2009 + 1 month = 27/03/2009
28/02/2009 + 1 month = 31/03/2009
31/01/2009 + 50 months = 31/03/2013
Also note that compile-time information in leads to compile-time information out.
Method AddMonths_OracleStyle does what you need.
Perhaps you would want to replace IsLeapYear and GetDaysInMonth to some librarian methods.
#include <ctime>
#include <assert.h>
bool IsLeapYear(int year)
{
if (year % 4 != 0) return false;
if (year % 400 == 0) return true;
if (year % 100 == 0) return false;
return true;
}
int daysInMonths[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int GetDaysInMonth(int year, int month)
{
assert(month >= 0);
assert(month < 12);
int days = daysInMonths[month];
if (month == 1 && IsLeapYear(year)) // February of a leap year
days += 1;
return days;
}
tm AddMonths_OracleStyle(const tm &d, int months)
{
bool isLastDayInMonth = d.tm_mday == GetDaysInMonth(d.tm_year, d.tm_mon);
int year = d.tm_year + months / 12;
int month = d.tm_mon + months % 12;
if (month > 11)
{
year += 1;
month -= 12;
}
int day;
if (isLastDayInMonth)
day = GetDaysInMonth(year, month); // Last day of month maps to last day of result month
else
day = std::min(d.tm_mday, GetDaysInMonth(year, month));
tm result = tm();
result.tm_year = year;
result.tm_mon = month;
result.tm_mday = day;
result.tm_hour = d.tm_hour;
result.tm_min = d.tm_min;
result.tm_sec = d.tm_sec;
return result;
}
time_t AddMonths_OracleStyle(const time_t &date, int months)
{
tm d = tm();
localtime_s(&d, &date);
tm result = AddMonths_OracleStyle(d, months);
return mktime(&result);
}