6

I'm just trying to print the current weekday (local time) using C++20 std::chrono.

Seems easy enough (one, two, three):

#include <chrono>
#include <iostream>

int main() {
  using namespace std::chrono;

  system_clock::time_point now = system_clock::now();
  // system_clock::time_point now = sys_days{June / 26d / 2023y} + 12h;

  weekday wd{floor<days>(now)};

#ifdef _WIN32
  std::cout << wd << "\n";
#else
  std::cout << wd.c_encoding() << " (Sunday = " << Sunday.c_encoding() << ")\n";
#endif

  return 0;
}

However, this prints Tue for me (it's monday). If I switch the comment to the manually-defined date (this question posted on June 26th 2023 -0400), it prints Mon.

  1. How do I do this correctly for the current date?

  2. Why is the now() date behaving differently than the sys_days/year_month_day one?


Edit: I believe this is a time-zone thing, as my three link suggests. I can't get this to compile with std::chrono though:

#include <chrono>
#include <iostream>

int main() {
  using namespace std::chrono;

  auto now = std::chrono::system_clock::now();
  auto now_local = zoned_time{current_zone(), now}.get_local_time();
  sys_days now_local_in_days{floor<days>(now_local)}; // !!! no constructor available
  weekday wd{now_local_in_days};

#ifdef _WIN32
  std::cout << wd << "\n";
#else
  std::cout << wd.c_encoding() << "\n";
#endif

  return 0;
}

So I guess I'm adding:

  1. How do I convert a local_time to a weekday?
MHebes
  • 2,290
  • 1
  • 16
  • 29
  • Hm. Something with timezones. My [three](https://stackoverflow.com/a/57570690/3554391) link mentions that. However I can't get the `sys_days` constructor to accept the `local_time` as its argument. – MHebes Jun 27 '23 at 03:41
  • `now_local_in_days` needs to have type `local_days`, not `sys_days`. – cpplearner Jun 27 '23 at 04:32

1 Answers1

6

I think I figured it out.

  1. How do I do this correctly for the current date?

This appears to work:

#include <chrono>
#include <iostream>

int main() {
  using namespace std::chrono;

  auto now = std::chrono::system_clock::now();
  auto now_local = current_zone()->to_local(now);
  weekday wd{floor<days>(now_local)};

#ifdef _WIN32
  std::cout << wd << "\n";
#else
  std::cout << wd.c_encoding() << "\n";
#endif

  return 0;
}
  1. Why is the now() date behaving differently than the sys_days/year_month_day one?

system_clock::time_points are stored in UTC time.

When you call now() it means "now in GMT". Any casting or flooring you do from there on is all in GMT. It was late enough when I wrote this that while locally it was Monday, in GMT it was already Tuesday.

When you define a time manually, it's also in UTC, and it's accepted exactly as-is. So I gave it a calendar date of a Monday, implicitly using GMT, and it worked great.

  1. How do I convert a local_time to a weekday?

See above. Not sure what changed between the posts I linked to (with HH's date library) and C++20, but my final above solution makes sense. You use the current time zone to offset the underlying time_since_epoch() by 4 hours, then whittle it down to a day/weekday.

All this is obvious in retrospect but figured I'd leave the explanation for posterity.

MHebes
  • 2,290
  • 1
  • 16
  • 29
  • 1
    Glad you got it sorted. The only reference to GMT/UTC you didn't use in the write-up was Zulu -- so we will throw that in for good measure `:)` Good luck with your coding. – David C. Rankin Jun 27 '23 at 06:29