c++11 difftime() calculating leap year incorrectly? - c++

I make a simple program to calculate the number of day between two days:
#include <stdio.h>
#include <iostream>
#include <ctime>
#include <utility>
using namespace std;
int main(){
struct tm t1 = {0,0,0,28,2,104};
struct tm t2 = {0,0,0,1,3,104};
time_t x = mktime(&t1);
time_t y = mktime(&t2);
cout << difftime(y,x)/3600/24 << endl;
}
The output is 4 however, my expected result is 1. May I know where is the problem is ?

In a struct tm, months are counted from 0 to 11 (not 1 to 12), thus 2 is March and 3 is April, you code output the number of days between March the 28th and April 1st, which is 4.
The correct version would be:
struct tm t1 = {0, 0, 0, 28, 1, 104};
struct tm t2 = {0, 0, 0, 1, 2, 104};
By the way, 2004 is a leap year and thus February had 29 days, there were two days between February the 28th and March the 1st (not one).
difftime gives you the number of seconds between 02/28/2004 00:00:00 and 03/01/2004 00:00:00 (the first day is accounted for in the difference).

Related

how to sorting date in array C++

I have a date in the form of ddmmyyyy in array
int checkIn[n], checkOut[n];
int a = sizeof(checkIn) / sizeof(checkIn[0]);
int a2 = sizeof(checkOut) / sizeof(checkOut[0]);
sort(checkIn, checkIn + a);
sort(checkOut, checkOut + a2);
Input:
3
08022022 15022022
10022025 14022025
15032022 20032022
Output:
8022022 10022025 15032022
How to fix. Thank you
I think the best idea to solve this date sort in C++ is to use this struct:
struct tm {
int tm_sec; // seconds of minutes from 0 to 61
int tm_min; // minutes of hour from 0 to 59
int tm_hour; // hours of day from 0 to 24
int tm_mday; // day of month from 1 to 31
int tm_mon; // month of year from 0 to 11
int tm_year; // year since 1900
int tm_wday; // days since sunday
int tm_yday; // days since January 1st
int tm_isdst; // hours of daylight savings time
}
You should load the dates you want to sort in this struct and then you can use mktime() to get the time_t for using the following function:
double difftime (time_t end, time_t beginning);
(https://www.cplusplus.com/reference/ctime/difftime/)
This function will calculate the difference between the time_t's. Then you can sort the list or the array. For example for the list you can do: https://www.cplusplus.com/reference/list/list/sort/

Getting the day of the week a year starts at

I was making a function in C++ to get the day of the week given the day, month and year (from 1900 on). The way I have to do it (I'm following orders, it's an exercise) is with the modulus of 7 of the total of days passed.
For example, 21 November 2018 will be the 325th day of that year (Taking into account leap years). The day of the week will be 325 % 7, which will give a number between 0 and 6, 0 being Sunday, 1 being Monday and so on, until 6 which would be Saturday.
But this will only work in years that start on Monday. 2018 works, but 2019 will be off by 1 day, as it starts on Tuesday.
My idea of fixing this is by knowing on what day that year starts and adding it to the 0-6 number given (fixing it if it's higher than 6), but I'd have to use the function for the year before, which would do so until it reaches 1900, which would be set to Monday. It sounds terrible, and I can't figure out another way of doing it.
Thanks in advance
If you don't want to use any libraries and do it purely by calculation, here is a solution.
http://mathforum.org/dr.math/faq/faq.calendar.html (Web Archive page)
or a easy explanation video.
What you can do is convert this logic into your program and find out the day of the week.
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;
}
Code Source.
http://www.cplusplus.com/reference/ctime/tm/
http://www.cplusplus.com/reference/ctime/mktime/
int weakDayOfYearBegin(int year)
{
std::tm t {};
t.tm_year = year - 1900;
t.tm_mday = 1;
std::mktime(&t);
return t.tm_wday;
}
https://wandbox.org/permlink/1ZnByeurgMrEF3fA

How to find the day of the week `tm_wday` from a given date?

To find the day (number) for a given date, I wrote below code using <ctime>:
tm time {ANY_SECOND, ANY_MINUTE, ANY_HOUR, 21, 7, 2015 - 1900};
mktime(&time); // today's date
PRINT(time.tm_wday); // prints 5 instead of 2 for Tuesday
According to the documentation, tm_wday can hold value among [0-6], where 0 is Sunday. Hence for Tuesday (today), it should print 2; but it prints 5.
Actually tm_wday gives consistent results, but with a difference of 3 days.
What is wrong here?
You got the month wrong, tm_mon is the offset since January, so July is 6. From the manpage:
tm_mon The number of months since January, in the range 0 to 11.
This outputs 2:
#include <stdio.h>
#include <string.h>
#include <time.h>
int main(void) {
struct tm time;
memset(&time, 0, sizeof(time));
time.tm_mday = 21;
time.tm_mon = 6;
time.tm_year = 2015-1900;
mktime(&time);
printf("%d\n", time.tm_wday);
return 0;
}
Note that you should initialize the other fields to 0 with memset(3) or similar.
The reason you are getting invalid output is that you are using the wrong month. tm_mon starts at 0 and not 1. you can see tghis by using this code:
tm time {50, 50, 12, 21, 7, 2015 - 1900};
time_t epoch = mktime(&time);
printf("%s", asctime(gmtime(&epoch)));
Output:
Fri Aug 21 12:50:50 2015
Live Example

Get the number of trading days in between two days

i'm trying to get the number of trading dates between two dates which will only exclude the weekends and won't consider any holidays. I'm using Boost and c++11 standards.
using namespace boost::gregorian;
long dateDifference( string start_date, string end_date ) {
date _start_date(from_simple_string(start_date));
date _end_date(from_simple_string(end_date));
long difference = ( _start_date - _end_date ).days();
return difference;
}
This just returns the number of days between two dates without considering weekends. Can someone point me in the right direction. I can't seem to figure out the solution.
Thanks,
Maxx
O(1) solution with no loops:
#include <boost/date_time.hpp>
using namespace std;
using namespace boost::gregorian;
long countWeekDays( string d0str, string d1str ) {
date d0(from_simple_string(d0str));
date d1(from_simple_string(d1str));
long ndays = (d1-d0).days() + 1; // +1 for inclusive
long nwkends = 2*( (ndays+d0.day_of_week())/7 ); // 2*Saturdays
if( d0.day_of_week() == boost::date_time::Sunday ) ++nwkends;
if( d1.day_of_week() == boost::date_time::Saturday ) --nwkends;
return ndays - nwkends;
}
The basic idea is to first count all Saturdays, which is conveniently given by the formula (ndays+d0.day_of_week())/7. Doubling this gives you all Saturdays and Sundays, except in the cases when the start and end dates may fall on a weekend, which is adjusted for by 2 simple tests.
To test it:
#include <iostream>
#include <cassert>
#include <string>
// January 2014
// Su Mo Tu We Th Fr Sa
// 1 2 3 4
// 5 6 7 8 9 10 11
// 12 13 14 15 16 17 18
// 19 20 21 22 23 24 25
// 26 27 28 29 30 31
int main()
{
assert(countWeekDays("2014-01-01","2014-01-01") == 1);
assert(countWeekDays("2014-01-01","2014-01-02") == 2);
assert(countWeekDays("2014-01-01","2014-01-03") == 3);
assert(countWeekDays("2014-01-01","2014-01-04") == 3);
assert(countWeekDays("2014-01-01","2014-01-05") == 3);
assert(countWeekDays("2014-01-01","2014-01-06") == 4);
assert(countWeekDays("2014-01-01","2014-01-10") == 8);
assert(countWeekDays("2014-01-01","2014-01-11") == 8);
assert(countWeekDays("2014-01-01","2014-01-12") == 8);
assert(countWeekDays("2014-01-01","2014-01-13") == 9);
assert(countWeekDays("2014-01-02","2014-01-13") == 8);
assert(countWeekDays("2014-01-03","2014-01-13") == 7);
assert(countWeekDays("2014-01-04","2014-01-13") == 6);
assert(countWeekDays("2014-01-05","2014-01-13") == 6);
assert(countWeekDays("2014-01-06","2014-01-13") == 6);
assert(countWeekDays("2014-01-07","2014-01-13") == 5);
cout << "All tests pass." << endl;
return 0;
}
This works for any date range in the Gregorian calendar, which boost currently supports for years 1400-10000. Note that different countries have adopted the Gregorian calendar at different times. For example the British switched from the Julian to the Gregorian calendar in September of 1752, so their calendar for that month looks like
September 1752
Su Mo Tu We Th Fr Sa
1 2 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Just run a day iterator and calculate the weekdays manually:
#include <boost/date_time.hpp>
using namespace boost::gregorian;
long dateDifference( string start_date, string end_date )
{
date _start_date(from_simple_string(start_date));
date _end_date(from_simple_string(end_date));
// counter for weekdays
int cnt=0;
for(day_iterator iter = _start_date; iter!=_end_date; ++iter)
{
// increment counter if it's no saturday and no sunday
if( iter->day_of_week() != boost::date_time::Saturday
&& iter->day_of_week() != boost::date_time::Sunday)
++cnt;
}
return cnt;
}
Answer ported from this answer: https://stackoverflow.com/a/7342989/3187827
The simplest approach is to use the boost::gregorian::day_of_week() function and iterate through every day between your start date and your end date, incrementing only when it's not a Saturday nor a Sunday.
A more efficient approach would be to iterate from start_date to the next Monday (say), iterate from end_date to the previous Monday, then with a simple division find out how many week-ends you've got in between.
Finally, a "real world" solution would involve finding proper calendar data with the holidays that apply to your case, and integrate it with your algorithm.
I didn't find any O(1) solutions which satisfied me so here is what I did:
int get_weekdays_count(const boost::gregorian::date& a,const boost::gregorian::date& b)
{
int na=(a<b) ? a.day_of_week().as_number() : b.day_of_week().as_number();
int diff=(a-b).days();
if(diff!=0){
if(diff<0) diff*=-1;
int rslt=diff/7; //number of saturdays
rslt*=2; // times 2 for sundays
rslt+= (diff%7) >=(boost::gregorian::Saturday-na)%7 ? 1 : 0; // handle special case for saturdays
rslt+= (diff%7) >=(boost::gregorian::Sunday-na)%7 ? 1 : 0; //special case for sundays
return 1+diff-rslt;
}
else return (na==boost::gregorian::Saturday || na==boost::gregorian::Sunday) ? 0 : 1;
};
This work even if a > b , just put two separate time and here you go.
Speed in a for loop: 25 nanosec/call on VS2012 Release mode // proc i5 4690K

Date to Day of the week algorithm?

What is the algorithm that, given a day, month and year, returns a day of the week?
This can be done using the std::mktime and std::localtime functions. These functions are not just POSIX, they are mandated by the C++ Standard (C++03 ยง20.5).
#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';
You need a starting point. Today is fine. Hard-code it.
Then, you need to represent the number of days in a month. This is 31, 28, 31, 30, 31, 30, ... . So you can start adding and subtracting 365 % 7 to the day of the week for each year, and (sum of days in difference of month) % 7 again. And so on.
The caveat: Leap years occur on every 4th year, but not every 100th, unless that year is also a multiple of 400.
One of the easiest algorithm for this is Tomohiko Sakamoto Algorithm:
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;
}
Check this out: https://iq.opengenus.org/tomohiko-sakamoto-algorithm/
I found Wang's method also interesting
w = (d - d^(m) + y^ - y* + [y^/4 - y*/2] - 2( c mod 4)) mod 7
http://rmm.ludus-opuscula.org/PDF_Files/Wang_Day_5_8(3_2015)_high.pdf This pdf is really helpful too.
Thanks!