3

I am using C++ 14 and am trying to get the current day of week. After some reading I am using date.h by Howard E. Hinnant.

However I am struggling to get a day of the week (encoded as 0 thru 6).

Something like this prints out Thu:

 int main(void)
 {
     date::sys_days t;
     weekday wd{t};
     cout << wd << '\n';
 }

Many answers on this site regarding getting the current day of the week use chrono.

How can I print the current weekday as a range from 0-6 according to when the program is run, using date.h?

For example, if I run the program today (Tuesday) I would expect a value of 2.

Any suggestions would be appreciated.


Just to be clear about what I am trying to achieve, something similar in Java:

Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Europe/London"));
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
einpoklum
  • 118,144
  • 57
  • 340
  • 684
rrz0
  • 2,182
  • 5
  • 30
  • 65

2 Answers2

7

The problem with your code is that t is not being initialized to anything interesting. You just need to set it to "now". There's a slight hitch, though: now() returns a different kind of time point, that can't automagically be converted into a date::sys_days value.

So, here's the minimal change to make your program work:

#include "date.h"
#include <iostream>
#include <cstdint>
   
int main()
{
     auto now = std::chrono::system_clock::now();
     date::sys_days t { std::chrono::time_point_cast<date::days>(now) };
     date::weekday wd{t};
     std::cout << wd << '\n';
}

edit: Now let's do a bit more, and thanks @HowardHinnant for the informative comments.

Use more meaningful names

Replace the code for main() with

auto now = std::chrono::system_clock::now();
date::sys_days now_in_days { std::chrono::time_point_cast<date::days>(now) };
date::weekday weekday {now_in_days};
std::cout << weekday << '\n';

Get the weekday as a number

You said you wanted to get the weekday as a number. Well, we can do that:

auto weekday_index = weekday.c_encoding();

the type will be unsigned, and the value will be in the range 0...6

Get the weekday in your own timezone

Your code and mine, so far, is UTC. Which is good as a default, but may give you something surprising as the weekday. We can use zoned_time and write:

auto now = std::chrono::system_clock::now();
auto now_local = zoned_time{current_zone(), now}.get_local_time();
date::sys_days now_local_in_days { std::chrono::time_point_cast<date::days>(now_local) };
date::weekday weekday {now_local_in_days};
auto weekday_index = weekday.c_encoding();

Gotcha for dates before the epoch (1970)

This is super annoying, but time_point_cast() may not always do what you want! Howard says that for days before 1970 we need to use floor() instead:

date::sys_days now_local_in_days { std::chrono::floor<date::days>(now_local) };

Final program

#include "date.h"
#include <iostream>
#include <cstdint>
   
int main()
{
    auto now = std::chrono::system_clock::now();
    auto now_local = zoned_time{current_zone(), now}.get_local_time();
    date::sys_days now_local_in_days { std::chrono::floor<date::days>(now_local) };
    date::weekday weekday {now_local_in_days};
    auto weekday_index = weekday.c_encoding();
    std::cout << weekday_index << '\n';
}

And if today is Tuesday, the resulting output should be 2.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 2
    Further information and caveats: 1) You can convert the `weekday` `wd` to an `unsigned` in the range [0, 6] with `wd.c_encoding()`. 2) The above formulation returns the current `weekday` in UTC. To get the current `weekday` in local time, convert `now` to `local_time` with `zoned_time{current_zone(), now}.get_local_time()`, and _then_ truncate to `days` precision and convert to `weekday`. 3) `time_point_cast` will give you the right answer for all times past the 1970 epoch. To ensure the correct answer for all time points, use `floor` instead of `time_point_cast`. – Howard Hinnant Aug 20 '19 at 14:12
  • @HowardHinnant: Would you like to edit that into the answer, or shall I? – einpoklum Aug 20 '19 at 14:34
  • You are welcome to edit it in. My comments were just meant to be informational. Please feel free to use them however you want. I've upvoted your answer regardless. :-) – Howard Hinnant Aug 20 '19 at 14:53
  • 1
    Thank you @HowardHinnant for the informative comment and for `date.h` in general! – rrz0 Aug 21 '19 at 08:27
  • @einpoklum Looks like you forgot to convert `now_local_in_days` to a weekday (?) – Azmisov Aug 19 '21 at 07:15
  • 1
    @Azmisov: Looks like it slipped somewhere in the middle. Would you mind having another look? – einpoklum Aug 19 '21 at 08:34
2

This would give the index of the day using date.h:

using namespace date;
using namespace std::chrono;
auto now = system_clock::now();
std::cout << "The current time is " << now << " UTC\n";
auto current_day = (year_month_weekday{floor<days>(now)}.weekday() - Sunday).count();
std::cout << "current_day " << current_day << "\n";

you can also use std::time_get::get_weekday

#include <iostream>       // std::cout, std::ios
#include <sstream>        // std::istringstream
#include <ctime>          // std::tm
#include <locale>         // std::locale, std::time_get, std::use_facet

int main ()
{
  std::locale loc;        // classic "C" locale

  // get time_get facet:
  const std::time_get<char>& tmget = std::use_facet <std::time_get<char> > (loc);

  std::ios::iostate state;
  std::istringstream iss ("Friday");
  std::tm when;

  tmget.get_weekday (iss, std::time_get<char>::iter_type(), iss, state, &when);

  std::cout << "weekday: " << when.tm_wday << '\n';
  return 0;
}

or:

time_t t = time(nullptr);
tm* timePtr = localtime(&t);
uint32_t y = timePtr->tm_year + 1900;
uint32_t m = timePtr->tm_mon + 1;
uint32_t d = timePtr->tm_wday;
cout<< d<<endl;
Oblivion
  • 7,176
  • 2
  • 14
  • 33
  • This works but prints out the day of the week according to the hard coded `std::istringstream iss ("Friday");`. How can I achieve a similar output without hard coding the day myself? I want to be able to return a number 0-6 according to when the program is run. – rrz0 Aug 20 '19 at 09:01
  • Yes, this works as expected. However, my original question requires the use of `date.h` since I could not find how to implement correctly in this library. – rrz0 Aug 20 '19 at 09:09