Skip to content

Commit

Permalink
[API BREAKING] Remove conversion from weekday to unsigned
Browse files Browse the repository at this point in the history
* There has been a great deal of anguish over the encoding of
  weekdays:  whether [0, 6] maps to [Sunday, Saturday] or
  [1, 7] maps to [Monday, Sunday].  This commit attempts
  to address that issue, but will break a small amount of
  code at compile-time.  See below on how to fix that.

* The weekday constructor used to accept [0, 6] to represent
  [Sunday, Saturday].  It now accepts [0, 7] to represent
  [Sunday, Saturday] with both 0 and 7 mapping to Sunday.

* The conversion from weekday to unsigned has been removed.

* To convert a weekday to unsigned replace:

      auto u = unsigned{wd};

  with:

      auto u = (wd - Sunday).count();

  This maps [Sunday, Saturday] to [0, 6], which is the
  C/POSIX mapping.  If you prefer the ISO mapping
  ([Monday, Sunday] -> [1, 7]), then do:

      auto u = (wd - Monday).count() + 1;
  • Loading branch information
HowardHinnant committed Jun 3, 2018
1 parent 6c4d333 commit 40b8365
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 34 deletions.
59 changes: 30 additions & 29 deletions include/date/date.h
Original file line number Diff line number Diff line change
Expand Up @@ -431,14 +431,21 @@ class weekday
CONSTCD14 weekday& operator+=(const days& d) NOEXCEPT;
CONSTCD14 weekday& operator-=(const days& d) NOEXCEPT;

CONSTCD11 explicit operator unsigned() const NOEXCEPT;
CONSTCD11 bool ok() const NOEXCEPT;

CONSTCD11 weekday_indexed operator[](unsigned index) const NOEXCEPT;
CONSTCD11 weekday_last operator[](last_spec) const NOEXCEPT;

private:
static CONSTCD11 unsigned char weekday_from_days(int z) NOEXCEPT;

friend CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT;
friend CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT;
friend CONSTCD14 weekday operator+(const weekday& x, const days& y) NOEXCEPT;
template<class CharT, class Traits>
friend std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd);
friend class weekday_indexed;
};

CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT;
Expand Down Expand Up @@ -1765,7 +1772,7 @@ weekday::weekday_from_days(int z) NOEXCEPT
CONSTCD11
inline
weekday::weekday(unsigned wd) NOEXCEPT
: wd_(static_cast<decltype(wd_)>(wd))
: wd_(static_cast<decltype(wd_)>(wd != 7 ? wd : 0))
{}

CONSTCD11
Expand Down Expand Up @@ -1803,21 +1810,14 @@ weekday::operator-=(const days& d) NOEXCEPT
return *this;
}

CONSTCD11
inline
weekday::operator unsigned() const NOEXCEPT
{
return static_cast<unsigned>(wd_);
}

CONSTCD11 inline bool weekday::ok() const NOEXCEPT {return wd_ <= 6;}

CONSTCD11
inline
bool
operator==(const weekday& x, const weekday& y) NOEXCEPT
{
return static_cast<unsigned>(x) == static_cast<unsigned>(y);
return x.wd_ == y.wd_;
}

CONSTCD11
Expand All @@ -1833,16 +1833,17 @@ inline
days
operator-(const weekday& x, const weekday& y) NOEXCEPT
{
auto const diff = static_cast<unsigned>(x) - static_cast<unsigned>(y);
return days{diff <= 6 ? diff : diff + 7};
auto const wdu = x.wd_ - y.wd_;
auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7;
return days{wdu - wk * 7};
}

CONSTCD14
inline
weekday
operator+(const weekday& x, const days& y) NOEXCEPT
{
auto const wdu = static_cast<long long>(static_cast<unsigned>(x)) + y.count();
auto const wdu = static_cast<long long>(static_cast<unsigned>(x.wd_)) + y.count();
auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7;
return weekday{static_cast<unsigned>(wdu - wk * 7)};
}
Expand Down Expand Up @@ -1874,7 +1875,7 @@ operator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd)
os << format(fmt, wd);
}
else
os << static_cast<unsigned>(wd) << " is not a valid weekday";
os << static_cast<unsigned>(wd.wd_) << " is not a valid weekday";
return os;
}

Expand Down Expand Up @@ -1939,13 +1940,13 @@ CONSTDATA date::month October{10};
CONSTDATA date::month November{11};
CONSTDATA date::month December{12};

CONSTDATA date::weekday Sunday{0u};
CONSTDATA date::weekday Monday{1u};
CONSTDATA date::weekday Tuesday{2u};
CONSTDATA date::weekday Wednesday{3u};
CONSTDATA date::weekday Thursday{4u};
CONSTDATA date::weekday Friday{5u};
CONSTDATA date::weekday Saturday{6u};
CONSTDATA date::weekday Monday{1};
CONSTDATA date::weekday Tuesday{2};
CONSTDATA date::weekday Wednesday{3};
CONSTDATA date::weekday Thursday{4};
CONSTDATA date::weekday Friday{5};
CONSTDATA date::weekday Saturday{6};
CONSTDATA date::weekday Sunday{7};

// weekday_indexed

Expand Down Expand Up @@ -1975,7 +1976,7 @@ weekday_indexed::ok() const NOEXCEPT
CONSTCD11
inline
weekday_indexed::weekday_indexed(const date::weekday& wd, unsigned index) NOEXCEPT
: wd_(static_cast<decltype(wd_)>(static_cast<unsigned>(wd)))
: wd_(static_cast<decltype(wd_)>(static_cast<unsigned>(wd.wd_)))
, index_(static_cast<decltype(index_)>(index))
{}

Expand Down Expand Up @@ -4337,20 +4338,20 @@ extract_weekday(std::basic_ostream<CharT, Traits>& os, const fields<Duration>& f
os.setstate(std::ios::failbit);
return 7;
}
unsigned wd;
weekday wd;
if (fds.ymd.ok())
{
wd = static_cast<unsigned>(weekday{fds.ymd});
if (fds.wd.ok() && wd != static_cast<unsigned>(fds.wd))
wd = weekday{fds.ymd};
if (fds.wd.ok() && wd != fds.wd)
{
// fds.ymd and fds.wd are inconsistent
os.setstate(std::ios::failbit);
return 7;
}
}
else
wd = static_cast<unsigned>(fds.wd);
return wd;
wd = fds.wd;
return static_cast<unsigned>((wd - Sunday).count());
}

template <class CharT, class Traits, class Duration>
Expand Down Expand Up @@ -7216,8 +7217,8 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
if (ymd.ok())
{
if (wd == not_a_weekday)
wd = static_cast<int>(static_cast<unsigned>(weekday(ymd)));
else if (wd != static_cast<int>(static_cast<unsigned>(weekday(ymd))))
wd = static_cast<int>((weekday(ymd) - Sunday).count());
else if (wd != static_cast<int>((weekday(ymd) - Sunday).count()))
goto broken;
if (!computed)
{
Expand Down
2 changes: 1 addition & 1 deletion include/date/iso_week.h
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ weekday::weekday(unsigned wd) NOEXCEPT
CONSTCD11
inline
weekday::weekday(date::weekday wd) NOEXCEPT
: wd_(to_iso_encoding(static_cast<unsigned>(wd)))
: wd_((wd-date::Monday).count() + 1)
{}

CONSTCD11
Expand Down
5 changes: 2 additions & 3 deletions test/date_test/weekday.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,9 @@ static_assert( std::is_trivially_move_assignable<date::weekday>{}, "");

static_assert( std::is_nothrow_constructible<date::weekday, unsigned>{}, "");
static_assert( std::is_nothrow_constructible<date::weekday, date::sys_days>{}, "");
static_assert( std::is_nothrow_constructible<unsigned, date::weekday>{}, "");
static_assert(!std::is_convertible<unsigned, date::weekday>{}, "");
static_assert( std::is_convertible<date::sys_days, date::weekday>{}, "");
static_assert(!std::is_convertible<date::weekday, unsigned>{}, "");
static_assert(static_cast<unsigned>(date::weekday{1u}) == 1, "");

static_assert( date::weekday{0u}.ok(), "");
static_assert( date::weekday{1u}.ok(), "");
Expand All @@ -90,7 +88,8 @@ static_assert( date::weekday{3u}.ok(), "");
static_assert( date::weekday{4u}.ok(), "");
static_assert( date::weekday{5u}.ok(), "");
static_assert( date::weekday{6u}.ok(), "");
static_assert(!date::weekday{7u}.ok(), "");
static_assert( date::weekday{7u}.ok(), "");
static_assert(!date::weekday{8u}.ok(), "");

void
test_weekday_arithmetic()
Expand Down
2 changes: 1 addition & 1 deletion test/iso_week/weekday.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ test_with_date_weekday()
auto constexpr d1 = iso_week::sun;
static_assert(unsigned{d1} == 7, "");
auto constexpr d2 = date::weekday{d1};
static_assert(unsigned{d2} == 0, "");
static_assert(d2 == date::Sunday, "");
auto constexpr d3 = iso_week::weekday{d2};
static_assert(unsigned{d3} == 7, "");
}
Expand Down

0 comments on commit 40b8365

Please sign in to comment.