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.
I have been trying to solve this problem for an online judge system, which requires a time limit of 1000ms. I have tried a few variations of solutions, but I will post my best draft here. I was able to get my answers right, however, I am exceeding the time limit. The best solution I can come up with is O(n^2).
The Task problem
Once the programmer X was in China and noticed that Russian clocks “Zarya” are 10 times cheaper there than in Russia. X chose to do some shenanigans and bought a huge amount of clocks to bring it to his own country and sell them at half price (which actually means 5x times more expensive than he bought). But as soon as he came back home, he realized that many clocks go discordantly, moreover, they stop from a simple push (or start going if they were stopped before).
Obviously, the clocks were fake, just very accurate copies. To sell them really quickly, X wants to set them all to the same time (so it won’t matter if the time’s correct or not – he can say this is “the time of the manufacturer”) and just shake his bag to make them tick.
To set the time, he has to spin a winding crown that will make clock’s hands move: the hour hand moves 60 times slower than the minute hand and the minute hand is 60 times slower than the second hand. One full spin of a crown makes a full spin of the second hand; and although the spin takes just a second, it will take 6 minutes to change the time to 6 hours. It is allowed to spin a crown only clockwise to save fragile mechanism of a clock.
Help the programmer X minimize the effort put in preparing the clocks to be sold, choosing the optimal time to set all clocks to.
Input:
The first line contains a natural n (1 ≤ n ≤ 50000) – the quantity of clocks.
The next n lines contain the time of each clock in a format “h:mm:ss”, where h (1 ≤ h ≤ 12) means hours, mm and ss (00 ≤ mm,ss ≤ 59) – minutes and seconds.
Output:
The time all clocks need to be set to in the format presented above.
Example Input
3
11:30:00
12:10:01
6:10:18
Output
12:10:01
#include<iostream>
using namespace std;
struct Clock {
int hours;
int mins;
int secs;
Clock() {
hours = mins = secs = 0;
}
};
void strtotime(string str, Clock& clock) { //converts string input to time
if (str[1] == ':') {
clock.hours = (str[0] - 48);
clock.mins = (str[2] - 48) * 10 + (str[3] - 48);
clock.secs = (str[5] - 48) * 10 + (str[6] - 48);
}
else {
clock.hours = (str[0] - 48) * 10 + (str[1] - 48);
clock.mins = (str[3] - 48) * 10 + (str[4] - 48);
clock.secs = (str[6] - 48) * 10 + (str[7] - 48);
}
}
double calctime(Clock from, Clock to) {//calculates time taken to change one clock time to other's
//calculate time for hours
double minutes;
if (from.hours > to.hours) {
minutes = 12 - (from.hours - to.hours);
}
else {
minutes = to.hours - from.hours;
}
//calculate time for mins
double seconds;
if (from.mins > to.mins) {
seconds = 60 - (from.mins - to.mins);
}
else {
seconds = to.mins - from.mins;
}
//calculate time for secs
double seconds2;
if (from.secs > to.secs) {
seconds2 = 60 - (from.secs - to.secs);
}
else {
seconds2 = to.secs - from.secs;
}
double totalTime = minutes * 60 + seconds + (seconds2 / 60);
return totalTime;
}
int main() {
int n;
string str;
cin >> n;
Clock* clock = new Clock[n];
for (int x = 0; x < n; x++) {
cin >> str;
strtotime(str, clock[x]);
}
double totaltime;
double mintime;
int loc = 0;
bool first = true;
double* timearr = new double[n];
for (int x = 0; x < n; x++) {
totaltime = 0.0;
for (int y = 0; y < n; y++) {
if (x != y) {
totaltime += calctime(clock[y], clock[x]);
}
}
if (first) {
mintime = totaltime;
first = false;
}
else {
if (totaltime < mintime) {
mintime = totaltime;
loc = x;
}
}
}
cout << clock[loc].hours;
cout << ':';
if (clock[loc].mins < 10) {
cout << 0 << clock[loc].mins;
}
else {
cout << clock[loc].mins;
}
cout << ':';
if (clock[loc].secs < 10) {
cout << 0 << clock[loc].secs;
}
else {
cout << clock[loc].secs;
}
}
Sort the times
Calculate the difference between each two neighbors and the first and last element
Find the maximum difference and remove it (the solution is the left neighbor of this difference)
This program is supposed to store time in seconds since midnight and display it in standard and universal time. It runs, but the set Time function has an error in it, as the time never changes. I'm assuming that something isn't being returned right, but I can't find the error.
Header file :
#ifndef TIME_H
#define TIME_H
class Time
{
public:
Time(); //constructor
void setTime(int, int, int );
void printUniversal(); //print time in universal-time format
void printStandard(); // print time in standard-time format
private:
int secondsSinceMidnight;
};
#endif
.cpp file
Time::Time()//constructor
{
secondsSinceMidnight = 0;
}
void Time::setTime(int h, int m, int s)
{
if ((h >= 0 && h < 24) && (m >= 0 && m < 60) && (s >= 0) && (s < 60))
{
int hoursInSecs = (h * 3600);
int minutesInSecs = (m * 60);
secondsSinceMidnight = (minutesInSecs + hoursInSecs);
}
else
throw invalid_argument(
"hour, minute and/or second was out of range");
}
void Time::printUniversal()
{
int secondsSinceMidnight = 0;
int hours = (secondsSinceMidnight / 3600);
int remainder = (secondsSinceMidnight % 3600);
int minutes = (remainder / 60);
int seconds = (remainder % 60);
cout <<setfill('0')<<setw(2)<<hours<<":"
<<setw(2)<<minutes<<":"<<setw(2)<<seconds<<endl;
}
void Time::printStandard()
{
int secondsSinceMidnight = 0;
int hours = (secondsSinceMidnight / 3600);
int remainder = (secondsSinceMidnight % 3600);
int minutes = (remainder / 60);
int seconds = (remainder % 60);
cout<<((hours == 0 || hours == 12) ? 12 : hours % 12) << ":"
<< setfill('0') <<setw(2)<<minutes<< ":"<<setw(2)
<<seconds<<(hours < 12 ? "AM" : "PM")<<"\n";
}
And the main program :
int main()
{
Time t; //instantiate object t of class Time
//output Time object t's initial values
cout<<"The initial universal time is ";
t.printUniversal();
cout<<"\nThe initial standard time is ";
t.printStandard();
int h;
int m;
int s;
cout<<"\nEnter the hours, minutes and seconds to reset the time: "<<endl;
cin>>h>>m>>s;
t.setTime(h, m, s); //change time
//output Time object t's new values
cout<<"\n\nUniversal time after setTime is ";
t.printUniversal();
cout<<"\nStandard time after setTime is ";
t.printStandard();
}
In your print functions you have a local variable with the same name as your field secondsSinceMidnight. It is shadowing it.
Why there are
int secondsSinceMidnight = 0; at the beginning of printUniversal() and printStandard(), this variable would cover member variable.
At the beginning of both of your print functions, you set secondsSinceMidnight = 0. Leave that in the constructor, but remove it from the print functions.
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'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";
}