6

I have a date in the form year (int), month (int) and day (int), for example, 2018, 10, 12 for October 12th, 2018.

Is there a way I can use C++ Chrono library with these integers to determine whether my "date" is a weekend day?

If not, what would be the simplest alternative way to achieve this?

intrigued_66
  • 16,082
  • 51
  • 118
  • 189
  • 1
    If you know that October 12, 2018 is a Friday, can't you simply calculate the offset in days from October 13 (sat) and see if it is a multiple of 7 or a multiple of 7 + 1? – Bas in het Veld Oct 12 '18 at 09:59
  • Do you need this to be locale-aware? Rest days differ around the world. – Lightness Races in Orbit Oct 12 '18 at 10:00
  • 1
    Possible duplicate of [Date to Day of the week algorithm?](https://stackoverflow.com/questions/5797814/date-to-day-of-the-week-algorithm) – hellow Oct 12 '18 at 10:01
  • Wow, this seems to be surprisingly difficult. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0355r3.html would make it easier. – Lightness Races in Orbit Oct 12 '18 at 10:05
  • @BasinhetVeld I was just using today as an example to explain my input data. I am looking at dates I do not know what day of the week they are. – intrigued_66 Oct 12 '18 at 10:08
  • @LightnessRacesinOrbit I just need to know given year, month, day whether it was a Saturday or Sunday, so not locale aware. – intrigued_66 Oct 12 '18 at 10:09
  • I was putting together a quick solution and gave up. It's hard enough to create a timepoint with the new tools, but getting calendar properties of it back out appears nigh impossible. Can you just do mktime then gmtime back again or something? It's not chrono but it's standard ... unless you want the safe version of gmtime of course. Ugh. – Lightness Races in Orbit Oct 12 '18 at 10:12
  • @LightnessRacesinOrbit Boost Datetime Gregorian is the answer :) – intrigued_66 Oct 12 '18 at 10:24
  • @mezamorphic Possibly - sadly DateTime is heavy (and requires build&link!) so Bas's arithmetic solution (combined with a mktime step) is probably what I'd do. – Lightness Races in Orbit Oct 12 '18 at 10:27
  • @LightnessRacesinOrbit Sorry I don't follow? The Boost solution is three lines of code. I'm really surprised nobody mentioned it. – intrigued_66 Oct 12 '18 at 10:36
  • 2
    This [date](https://github.com/HowardHinnant/date) library is up for standardization: https://github.com/HowardHinnant/date – Galik Oct 12 '18 at 10:37
  • std::chrono does not provide calenar services. The boost solution is fine if you happen to have boost around and don't mind its non-trivial footprint. – n. m. could be an AI Oct 12 '18 at 10:56
  • @mezamorphic The code part of it is great but the logistics are not, unless you're already using DateTime in your project, by comparison with the arithmetic method – Lightness Races in Orbit Oct 12 '18 at 11:03

1 Answers1

7

In C++20, you will be able to do this:

#include <chrono>

constexpr
bool
is_weekend(std::chrono::sys_days t)
{
    using namespace std::chrono;
    const weekday wd{t};
    return wd == Saturday || wd == Sunday;
}

int
main()
{
    using namespace std::chrono;
    static_assert(!is_weekend(year{2018}/10/12), "");
    static_assert( is_weekend(year{2018}/10/13), "");
}

Naturally if the input isn't constexpr, then the computation can't be either.

No one that I'm aware of is yet shipping this, however you can get a head start with this syntax using Howard Hinnant's datetime lib. You just need to #include "date/date.h" and change a few using namespace std::chrono; to using namespace date;.

#include "date/date.h"

constexpr
bool
is_weekend(date::sys_days t)
{
    using namespace date;
    const weekday wd{t};
    return wd == Saturday || wd == Sunday;
}

int
main()
{
    using namespace date;
    static_assert(!is_weekend(year{2018}/10/12), "");
    static_assert( is_weekend(year{2018}/10/13), "");
}

This will work with C++17, C++14, and if you remove the constexpr, C++11. It won't port to earlier than C++11 as it does depend on <chrono>.

For bonus points, the above function will also work with the current time (UTC):

    assert(!is_weekend(floor<days>(std::chrono::system_clock::now())));
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 1
    Can you clarify what part of this is C++20 specific? Just the `/` operator? The `weekday` part? – Cubic Oct 12 '18 at 14:25
  • Pretty much everything is C++20 specific: `sys_days`, `weekday`, `Saturday`, `Sunday`, `year`, the `operator/()`. – Howard Hinnant Oct 12 '18 at 14:31
  • "For bonus points, the above function will also work with the current time" I don't think this is quite correct—you'd need to [offset the current timezone](https://stackoverflow.com/questions/76561402/how-to-find-the-current-weekday-with-stdchrono/76561589#76561589) before you `floor()` and wouldn't be able to pass the resulting `local_time` directly to the `sys_days` – MHebes Jun 27 '23 at 17:04
  • "current time **(UTC)**". – Howard Hinnant Jun 27 '23 at 17:15
  • For the current _local_ `weekday`, see [this good answer](https://stackoverflow.com/a/76561589/576911) (which I've upvoted). ;-) – Howard Hinnant Jun 27 '23 at 17:53