c++ day of week for given date
Asked Answered
R

8

18

I am trying to write a simple program in c++ that returns the day of the week for a given date.

The input format is day, month, year. I cannot get it to work with leap years. I tried subtracting one from the a variable when the input year is a leap year, but the program just ends up crashing without an error message.

I would appreciate any suggestions, but please try to remain simple, I am still a beginner. Apologies for the stupid question, and please excuse my mistakes, this is the first time I post on this site.

#include <iostream>
#include <string>
#include <vector>
#include <cmath>
using namespace std;


int d;
int m;
int y;


string weekday(int d, int m, int y){
    int LeapYears = (int) y/ 4;
    long a = (y - LeapYears)*365 + LeapYears * 366;
    if(m >= 2) a += 31;
    if(m >= 3 && (int)y/4 == y/4) a += 29;
    else if(m >= 3) a += 28;
    if(m >= 4) a += 31;
    if(m >= 5) a += 30;
    if(m >= 6) a += 31;
    if(m >= 7) a += 30;
    if(m >= 8) a += 31;
    if(m >= 9) a += 31;
    if(m >= 10) a += 30;
    if(m >= 11) a += 31;
    if(m == 12) a += 30;
    a += d;
    int b = (a - 2)  % 7;
    switch (b){
    case 1:
        return "Monday";
    case 2:
        return "Tuesday";
    case 3:
        return "Wednesday";
    case 4:
        return "Thursday";
    case 5:
        return "Friday";
    case 6:
        return "Saturday";
    case 7:
        return "Sunday";
    }
}

int main(){
    cin >> d >> m >> y;
    cout << weekday(d, m, y);
}
Reams answered 9/11, 2016 at 22:39 Comment(8)
What happens when you step through it in your debugger?Conformity
There is no such thing as a simple program when it comes to dates (go ask jon skeet). That functionality already exists why reinvent it.Phrenic
There's a simple formula for performing the calculation. See en.wikipedia.org/wiki/Determination_of_the_day_of_the_weekHurdygurdy
Search the internet for "c++ calculate day of week" to find a plethora of examples.Publias
y is already an int. Consequently the cast (int) y/ 4 is redundant, and (int)y/4 == y/4 is always trueExtensile
Here is a good collection of low-level date algorithms: howardhinnant.github.io/date_algorithms.htmlPaule
Thanks for all the comments, they are very much appreciated.Reams
@Paul Rooney: I am not trying to reinvent a function that already exists, all I did was trying to solve a common problem that did not seem very difficult by myself. @Dan Nagle: I have seen the formula for the calculation, but as I have already mentioned, I wanted to be inventive rather than just copy something that has already been done. @StoryTeller: Thank you! What I meant to write was: (int) (y/4) == y/4Reams
P
24

First: Do not write your own function, if there already are standardized functions that can handle the same problem. Point is that you might easily make a mistake (and I can already see one in the first line of your weekday() function as it is now), whereas implementations of standardized functions have been tested thoroughly and you can be confident that they deliver the result you are expected to get.

That being said, here is a possible approach using std::localtime and std::mktime:

#include <ctime>
#include <iostream>

int main()
{
  std::tm time_in = { 0, 0, 0, // second, minute, hour
      9, 10, 2016 - 1900 }; // 1-based day, 0-based month, year since 1900

  std::time_t time_temp = std::mktime(&time_in);

  //Note: Return value of localtime is not threadsafe, because it might be
  // (and will be) reused in subsequent calls to std::localtime!
  const std::tm * time_out = std::localtime(&time_temp);

  //Sunday == 0, Monday == 1, and so on ...
  std::cout << "Today is this day of the week: " << time_out->tm_wday << "\n";
  std::cout << "(Sunday is 0, Monday is 1, and so on...)\n";

  return 0;
}
Patrickpatrilateral answered 9/11, 2016 at 23:4 Comment(8)
Thank you for your suggestion, however the whole point of writing this program is to practice programming and try to get a grasp of the syntax of c++. I cannot blame you for suggesting a completely different approach though, since I did not mention this in my post. But if I ever need something like this when writing a more complex program with more experience, I will make sure to consider this method!Reams
One year, ~1800 views, and not a single upvote oO. Just fixed it. @Reams please accept this (or another) answer by clicking the green checkmark near its score.Polacca
A solution about std::localtime is to make a copy of its return as soon as possible: const std::tm time_out = *std::localtime(&time_temp);.Polacca
@Patrickpatrilateral why are you using mktime? Why not use strftime directly?Petey
@Patrickpatrilateral You have also not provided tm_wday, tm_yday, tm_isdst.Petey
YSC: while that helps one can still get a corrupted tmSeaplane
aderchox: tm_wday and tm_yday are ignored by mktime. tm_isdst is irrelevant when it comes to dates.Seaplane
This seems to to be the only proper answer to this question among many bad answers. Thank you.Fritillary
P
8

New answer for old question because the tools they are a changing...

The C++20 spec says the following will have identical functionality to the intention of the code in the question:

#include <chrono>
#include <format>
#include <iostream>

int
main()
{
    using namespace std;
    using namespace std::chrono;
    year_month_day dmy;
    cin >> parse("%d %m %Y", dmy);
    cout << format("{:%A}", weekday{dmy}) << '\n';
}

One can experiment today with this syntax by using this free, open-source date/time library, except that the date objects are in namespace date instead of namespace std::chrono, and the syntax of the format string is slightly altered.

#include "date/date.h"
#include <iostream>

int
main()
{
    using namespace std;
    using namespace date;
    year_month_day dmy;
    cin >> parse("%d %m %Y", dmy);
    cout << format("%A", weekday{dmy}) << '\n';
}
Paule answered 16/6, 2019 at 2:49 Comment(2)
Thanks for the code Howard. Unfortunately, it seems for the latest g++ and clang++ the parse and format are still not ready (with -std=c++20). By latest I mean g++-11 and clang++ 13. I am talking about the code part without header "date/date.h" : (Nielsen
This now ships in g++-14. clang is in the implementation phase. MSVC has shipped it for several years now. My free, open-source preview of this part of C++20 is still available.Paule
T
7

Your understanding of what constitutes a leap year is incorrect:

A leap year is every 4 years EXCEPT if it's divisible by 100, BUT even then it's still a leap year if it's divisible by 400.

A clear and concise explanation of how to calculate the "day number" (dn) can be found here.

Once you have the day number (dn), just perform a modulus 7. The result will be the day of week (dow).

Here's an example implementation (doesn't check if date is valid input):

#include <iostream>
#include <iomanip>

typedef unsigned long ul;
typedef unsigned int ui;

// ----------------------------------------------------------------------
// Given the year, month and day, return the day number.
// (see: https://alcor.concordia.ca/~gpkatch/gdate-method.html)
// ----------------------------------------------------------------------
ul CalcDayNumFromDate(ui y, ui m, ui d)
{
  m = (m + 9) % 12;
  y -= m / 10;
  ul dn = 365*y + y/4 - y/100 + y/400 + (m*306 + 5)/10 + (d - 1);

  return dn;
}

// ----------------------------------------------------------------------
// Given year, month, day, return the day of week (string).
// ----------------------------------------------------------------------
std::string CalcDayOfWeek(int y, ul m, ul d)
{
  std::string day[] = {
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
    "Sunday",
    "Monday",
    "Tuesday"
  };

  ul dn = CalcDayNumFromDate(y, m, d);

  return day[dn % 7];
}

// ----------------------------------------------------------------------
// Program entry point.
// ----------------------------------------------------------------------
int main(int argc, char **argv)
{
  ui y = 2017, m = 8, d = 29; // 29th August, 2017.
  std::string dow = CalcDayOfWeek(y, m, d);

  std::cout << std::setfill('0') << std::setw(4) << y << "/";
  std::cout << std::setfill('0') << std::setw(2) << m << "/";
  std::cout << std::setfill('0') << std::setw(2) << d << ": ";
  std::cout << dow << std::endl;

  return 0;
}
Timberlake answered 29/8, 2017 at 22:5 Comment(0)
A
6

You can use the Gregorian Date System from the Boost C++ library to find the day of week of a given date. Here is a simple example:

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

const static std::string daysOfWeek[] = {
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday"
};

int getDayOfWeekIndex(int day, int month, int year) {
    boost::gregorian::date d(year, month, day);
    return d.day_of_week();
}

int main()
{
    const int index = getDayOfWeekIndex(30, 07, 2018);
    std::cout << daysOfWeek[index] << '\n';
}

This code prints Monday.

Alterable answered 30/7, 2018 at 3:4 Comment(0)
H
3

I had the same problem, and I was able to find a simple solution.

According to this post:
"Following is a simple function suggested by Sakamoto, Lachman, Keith and Craver to calculate day. The following function returns 0 for Sunday, 1 for Monday, etc."

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;  
}
Honeyhoneybee answered 7/2, 2021 at 23:35 Comment(3)
Does it take leap seconds and such into account? Will it account for future leap seconds? Looks too simple to be pedantically correct.Fritillary
Per Wikipedia, the function in this answer is due solely to Tomohiko Sakamoto: "Posted by Tomohiko Sakamoto on the comp.lang.c Usenet newsgroup in 1992, it is accurate for any Gregorian date." What is meant by "Gregorian date" is unclear. Historically, that varies by country. Mathematically, however, the function in this answer is valid for dates after year 0 on the proleptic Gregorian calendar. It makes no adjustment for leap seconds.Yorick
To extend its validity to all dates on the proleptic Gregorian calendar, the value of y must be adjusted to be a non-negative number (after, that is, its initial adjustment, i.e., after y -= m < 3;). This can be accomplished by repeatedly adding 400 years: while (y < 0) y += 400; (There are, of course, more efficient ways to accomplish this adjustment.) For dates on the proleptic Gregorian calendar, adding 400 years does not change the day of the week.Yorick
O
1

What happens when a number is perfectly divisible by 7?

14 / 7 = 2 14 % 7 = 0

The modulo operator (% n) will return a number from 0 to n -1

if n is divided by 7 the remainder can never be 7 so

int b = (a - 2)  % 7;
    switch (b){
    case 1:
        return "Monday";
    case 2:
        return "Tuesday";
    case 3:
        return "Wednesday";
    case 4:
        return "Thursday";
    case 5:
        return "Friday";
    case 6:
        return "Saturday";
    case 7:
        return "Sunday";
    }
}

In this case it can never be Sunday

Try this

int b = (a - 2)  % 7;
        switch (b){
        case 0:
            return "Sunday";
        case 1:
            return "Monday";
        case 2:
            return "Tuesday";
        case 3:
            return "Wednesday";
        case 4:
            return "Thursday";
        case 5:
            return "Friday";
        case 6:
            return "Saturday";
        default:
            return "Error";
        }
Ostmark answered 9/11, 2016 at 23:3 Comment(4)
Don't listen to people that say not to use your own function.Ostmark
For all we know you area doing this for fun, or for a learning experience.Ostmark
Also, please bear in mind, that your eventual program will be incorrect as to the day of the week. That is because leap years are tricky things that don't ALWAYS happen every 4 years. Example leap years don't happen on year 100 but they do happen on year 400. So yeah, calendars can get tricky really fast. My answer is primarily to help you finds the cause as to why your program is crashing.Ostmark
Thank you, I never even considered that a could be a multiple of seven, I will make sure to look into that.Reams
D
0

try using the CTime class

Exemple:

const CTime currTime = CTime::GetCurrentTime();
const int nWeekDay = currTime.GetDayOfWeek();

switch (nWeekDay)
{
    case 1:
        return "Monday";
    case 2:
        return "Tuesday";
    case 3:
        return "Wednesday";
    case 4:
        return "Thursday";
    case 5:
        return "Friday";
    case 6:
        return "Saturday";
    case 7:
        return "Sunday";
}

in the example above I'm using the current time, but you can do it differently, with the time you want example:

const CTime currTime = CTime(year,month, day, hours, minutes, seconds );
Divergent answered 12/5, 2022 at 13:0 Comment(1)
According to Microsoft Learn, class CTime is restricted to a small range of dates: "The upper date limit is 12/31/3000. The lower limit is 1/1/1970 12:00:00 AM GMT."Yorick
O
-2
int dayofweek(int day,int month,int year)
{
    int arr[] = {0,3,2,5,3,5,1,4,6,2,4};
    if(month<3)
        year--;
    return ((year+year/4-year/100+year/400+arr[month-1]+day)%7);
}

int main()
{
    int day,month,year;
    cout<<"Enter the Date for which day of the week need to be find (DD/MM/YYYY)."<<endl;
    cin>>day>>month>>year;
    int x = dayofweek(day,month,year);
    if(x==0)
        cout<<"Sunday"<<endl;
    else if(x==1)
        cout<<"Monday"<<endl;
    else if(x==2)
        cout<<"Tuesday"<<endl;
    else if(x==3)
        cout<<"Wednesday"<<endl;
    else if(x==4)
        cout<<"Thursday"<<endl;
    else if(x==5)
        cout<<"Friday"<<endl;
    else if(x==6)
        cout<<"Saturday"<<endl;

}
Orthohydrogen answered 1/2, 2018 at 1:28 Comment(2)
Although I am not a down-voter, I think there are two reasons this answer has garnered some down-votes: (1) Code-only answers are of limited value, especially for questioners who do not understand the problem. So, add some explanation of what this is, and why it works. (2) Function dayofweek, presented in this answer, is buggy. There are only 11 initializers for the array arr. It should have 12: int arr[] = {0,3,2,5,0,3,5,1,4,6,2,4};.Yorick
The function dayofweek presented here is due to Tomohiko Sakamoto. To learn more, including the range of dates for which it is valid, see my comments below this answer.Yorick

© 2022 - 2025 — McMap. All rights reserved.