Align time_of_day with hh_mm_ss

Per committee review
This commit is contained in:
Howard Hinnant 2019-03-19 19:50:30 -04:00
parent f782ae98f0
commit b5d025ea2f
8 changed files with 99 additions and 200 deletions

View File

@ -3650,7 +3650,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
fields<Duration>& fds, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr, fields<Duration>& fds, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
std::chrono::minutes* offset = nullptr); std::chrono::minutes* offset = nullptr);
// time_of_day // hh_mm_ss
namespace detail namespace detail
{ {
@ -3808,29 +3808,29 @@ abs(std::chrono::duration<Rep, Period> d)
} // namespace detail } // namespace detail
template <class Duration> template <class Duration>
class time_of_day class hh_mm_ss
{ {
using dfs = detail::decimal_format_seconds<typename std::common_type<Duration, using dfs = detail::decimal_format_seconds<typename std::common_type<Duration,
std::chrono::seconds>::type>; std::chrono::seconds>::type>;
enum state {is_24, am, pm};
std::chrono::hours h_; std::chrono::hours h_;
std::chrono::minutes m_; std::chrono::minutes m_;
dfs s_; dfs s_;
bool neg_; bool neg_;
state mode_ = is_24;
public: public:
static unsigned CONSTDATA fractional_width = dfs::width;
using precision = typename dfs::precision; using precision = typename dfs::precision;
CONSTCD11 time_of_day() = default; CONSTCD11 hh_mm_ss() NOEXCEPT
: hh_mm_ss(Duration::zero())
{}
CONSTCD11 explicit time_of_day(Duration d) NOEXCEPT CONSTCD11 explicit hh_mm_ss(Duration d) NOEXCEPT
: h_(std::chrono::duration_cast<std::chrono::hours>(detail::abs(d))) : h_(std::chrono::duration_cast<std::chrono::hours>(detail::abs(d)))
, m_(std::chrono::duration_cast<std::chrono::minutes>(detail::abs(d)) - h_) , m_(std::chrono::duration_cast<std::chrono::minutes>(detail::abs(d)) - h_)
, s_(detail::abs(d) - h_ - m_) , s_(detail::abs(d) - h_ - m_)
, neg_(d < precision{}) , neg_(d < Duration::zero())
{} {}
CONSTCD11 std::chrono::hours hours() const NOEXCEPT {return h_;} CONSTCD11 std::chrono::hours hours() const NOEXCEPT {return h_;}
@ -3839,17 +3839,11 @@ public:
CONSTCD14 std::chrono::seconds& CONSTCD14 std::chrono::seconds&
seconds(detail::undocumented) NOEXCEPT {return s_.seconds();} seconds(detail::undocumented) NOEXCEPT {return s_.seconds();}
CONSTCD11 precision subseconds() const NOEXCEPT {return s_.subseconds();} CONSTCD11 precision subseconds() const NOEXCEPT {return s_.subseconds();}
CONSTCD11 bool is_negative() const NOEXCEPT {return neg_;}
CONSTCD11 explicit operator precision() const NOEXCEPT {return to_duration();} CONSTCD11 explicit operator precision() const NOEXCEPT {return to_duration();}
CONSTCD11 precision to_duration() const NOEXCEPT CONSTCD11 precision to_duration() const NOEXCEPT
{return (make_24(mode_, h_) + m_ + s_.to_duration()) * (1-2*neg_);} {return (h_ + m_ + s_.to_duration()) * (1-2*neg_);}
CONSTCD14 void make24() NOEXCEPT
{
h_ = make_24(mode_, h_);
mode_ = is_24;
}
CONSTCD14 void make12() NOEXCEPT {make_12(mode_, h_);}
CONSTCD11 bool in_conventional_range() const NOEXCEPT CONSTCD11 bool in_conventional_range() const NOEXCEPT
{ {
@ -3860,89 +3854,21 @@ public:
private: private:
CONSTCD14
static
std::chrono::hours
make_24(state mode, std::chrono::hours h) NOEXCEPT
{
using namespace std;
if (mode != is_24)
{
if (mode == am)
{
if (h == chrono::hours{12})
h = chrono::hours{0};
}
else
{
if (h != chrono::hours{12})
h += chrono::hours{12};
}
}
return h;
}
CONSTCD14
static
void
make_12(state& mode, std::chrono::hours& h) NOEXCEPT
{
using namespace std;
if (mode == is_24)
{
if (h < chrono::hours{12})
{
if (h == chrono::hours{0})
h = chrono::hours{12};
mode = am;
}
else
{
if (h != chrono::hours{12})
h -= chrono::hours{12};
mode = pm;
}
}
}
template <class charT, class traits> template <class charT, class traits>
friend friend
std::basic_ostream<charT, traits>& std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, time_of_day const& tod) operator<<(std::basic_ostream<charT, traits>& os, hh_mm_ss const& tod)
{ {
using namespace detail; using namespace detail;
using namespace std; using namespace std;
if (tod.neg_) if (tod.is_negative())
os << '-'; os << '-';
if (tod.mode_ == is_24) if (tod.h_ < chrono::hours{10})
{ os << '0';
if (tod.h_ < chrono::hours{10}) os << tod.h_.count() << ':';
os << '0'; if (tod.m_ < chrono::minutes{10})
os << tod.h_.count() << ':'; os << '0';
if (tod.m_ < chrono::minutes{10}) os << tod.m_.count() << ':' << tod.s_;
os << '0';
os << tod.m_.count() << ':' << tod.s_;
}
else
{
os << tod.h_.count() << ':';
if (tod.m_ < chrono::minutes{10})
os << '0';
os << tod.m_.count() << ':' << tod.s_;
#if !ONLY_C_LOCALE
std::tm tm{};
tm.tm_hour = tod.make_24(tod.mode_, tod.h_).count();
auto& facet = use_facet<time_put<charT>>(os.getloc());
const charT f[] = {'%', 'p'};
facet.put(os, os, os.fill(), &tm, f, f+2);
#else
if (tod.mode_ == am)
os << 'A';
else
os << 'P';
os << 'M';
#endif
}
return os; return os;
} }
@ -3961,15 +3887,71 @@ private:
std::basic_string<CharT, Traits, Alloc>* abbrev, std::chrono::minutes* offset); std::basic_string<CharT, Traits, Alloc>* abbrev, std::chrono::minutes* offset);
}; };
inline
CONSTCD14
bool
is_am(std::chrono::hours const& h) NOEXCEPT
{
using namespace std::chrono;
return hours{0} <= h && h < hours{12};
}
inline
CONSTCD14
bool
is_pm(std::chrono::hours const& h) NOEXCEPT
{
using namespace std::chrono;
return hours{12} <= h && h < hours{24};
}
inline
CONSTCD14
std::chrono::hours
make12(std::chrono::hours h) NOEXCEPT
{
using namespace std::chrono;
if (h < hours{12})
{
if (h == hours{0})
h = hours{12};
}
else
{
if (h != hours{12})
h -= hours{12};
}
return h;
}
inline
CONSTCD14
std::chrono::hours
make24(std::chrono::hours h, bool is_pm) NOEXCEPT
{
using namespace std::chrono;
if (is_pm)
{
if (h != hours{12})
h += hours{12};
}
else if (h == hours{12})
h = hours{0};
return h;
}
template <class Duration>
using time_of_day = hh_mm_ss<Duration>;
template <class Rep, class Period, template <class Rep, class Period,
class = typename std::enable_if class = typename std::enable_if
<!std::chrono::treat_as_floating_point<Rep>::value>::type> <!std::chrono::treat_as_floating_point<Rep>::value>::type>
CONSTCD11 CONSTCD11
inline inline
time_of_day<std::chrono::duration<Rep, Period>> hh_mm_ss<std::chrono::duration<Rep, Period>>
make_time(const std::chrono::duration<Rep, Period>& d) make_time(const std::chrono::duration<Rep, Period>& d)
{ {
return time_of_day<std::chrono::duration<Rep, Period>>(d); return hh_mm_ss<std::chrono::duration<Rep, Period>>(d);
} }
template <class CharT, class Traits, class Duration> template <class CharT, class Traits, class Duration>
@ -4555,22 +4537,22 @@ struct fields
{ {
year_month_day ymd{nanyear/0/0}; year_month_day ymd{nanyear/0/0};
weekday wd{8u}; weekday wd{8u};
time_of_day<Duration> tod{}; hh_mm_ss<Duration> tod{};
bool has_tod = false; bool has_tod = false;
fields() = default; fields() = default;
fields(year_month_day ymd_) : ymd(ymd_) {} fields(year_month_day ymd_) : ymd(ymd_) {}
fields(weekday wd_) : wd(wd_) {} fields(weekday wd_) : wd(wd_) {}
fields(time_of_day<Duration> tod_) : tod(tod_), has_tod(true) {} fields(hh_mm_ss<Duration> tod_) : tod(tod_), has_tod(true) {}
fields(year_month_day ymd_, weekday wd_) : ymd(ymd_), wd(wd_) {} fields(year_month_day ymd_, weekday wd_) : ymd(ymd_), wd(wd_) {}
fields(year_month_day ymd_, time_of_day<Duration> tod_) : ymd(ymd_), tod(tod_), fields(year_month_day ymd_, hh_mm_ss<Duration> tod_) : ymd(ymd_), tod(tod_),
has_tod(true) {} has_tod(true) {}
fields(weekday wd_, time_of_day<Duration> tod_) : wd(wd_), tod(tod_), has_tod(true) {} fields(weekday wd_, hh_mm_ss<Duration> tod_) : wd(wd_), tod(tod_), has_tod(true) {}
fields(year_month_day ymd_, weekday wd_, time_of_day<Duration> tod_) fields(year_month_day ymd_, weekday wd_, hh_mm_ss<Duration> tod_)
: ymd(ymd_) : ymd(ymd_)
, wd(wd_) , wd(wd_)
, tod(tod_) , tod(tod_)
@ -5146,11 +5128,10 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
if (modified == CharT{}) if (modified == CharT{})
#endif #endif
{ {
if (*fmt == CharT{'I'}) auto h = *fmt == CharT{'I'} ? make12(hms.hours()) : hms.hours();
hms.make12(); if (h < hours{10})
if (hms.hours() < hours{10})
os << CharT{'0'}; os << CharT{'0'};
os << hms.hours().count(); os << h.count();
} }
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
else if (modified == CharT{'O'}) else if (modified == CharT{'O'})
@ -5303,7 +5284,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
tm.tm_hour = static_cast<int>(fds.tod.hours().count()); tm.tm_hour = static_cast<int>(fds.tod.hours().count());
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
#else #else
if (fds.tod.hours() < hours{12}) if (is_am(fds.tod.hours()))
os << ampm_names().first[0]; os << ampm_names().first[0];
else else
os << ampm_names().first[1]; os << ampm_names().first[1];
@ -5357,18 +5338,16 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
tm.tm_sec = static_cast<int>(fds.tod.seconds().count()); tm.tm_sec = static_cast<int>(fds.tod.seconds().count());
facet.put(os, os, os.fill(), &tm, begin(f), end(f)); facet.put(os, os, os.fill(), &tm, begin(f), end(f));
#else #else
time_of_day<seconds> tod(duration_cast<seconds>(fds.tod.to_duration())); hh_mm_ss<seconds> tod(duration_cast<seconds>(fds.tod.to_duration()));
tod.make12();
save_ostream<CharT, Traits> _(os); save_ostream<CharT, Traits> _(os);
os.fill('0'); os.fill('0');
os.width(2); os.width(2);
os << tod.hours().count() << CharT{':'}; os << make12(tod.hours()).count() << CharT{':'};
os.width(2); os.width(2);
os << tod.minutes().count() << CharT{':'}; os << tod.minutes().count() << CharT{':'};
os.width(2); os.width(2);
os << tod.seconds().count() << CharT{' '}; os << tod.seconds().count() << CharT{' '};
tod.make24(); if (is_am(tod.hours()))
if (tod.hours() < hours{12})
os << ampm_names().first[0]; os << ampm_names().first[0];
else else
os << ampm_names().first[1]; os << ampm_names().first[1];
@ -5959,7 +5938,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
{ {
using Duration = std::chrono::duration<Rep, Period>; using Duration = std::chrono::duration<Rep, Period>;
using CT = typename std::common_type<Duration, std::chrono::seconds>::type; using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
fields<CT> fds{time_of_day<CT>{d}}; fields<CT> fds{hh_mm_ss<CT>{d}};
return to_stream(os, fmt, fds); return to_stream(os, fmt, fds);
} }
@ -5971,7 +5950,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
{ {
using CT = typename std::common_type<Duration, std::chrono::seconds>::type; using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
auto ld = floor<days>(tp); auto ld = floor<days>(tp);
fields<CT> fds{year_month_day{ld}, time_of_day<CT>{tp-local_seconds{ld}}}; fields<CT> fds{year_month_day{ld}, hh_mm_ss<CT>{tp-local_seconds{ld}}};
return to_stream(os, fmt, fds, abbrev, offset_sec); return to_stream(os, fmt, fds, abbrev, offset_sec);
} }
@ -5985,7 +5964,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
const std::string abbrev("UTC"); const std::string abbrev("UTC");
CONSTDATA seconds offset{0}; CONSTDATA seconds offset{0};
auto sd = floor<days>(tp); auto sd = floor<days>(tp);
fields<CT> fds{year_month_day{sd}, time_of_day<CT>{tp-sys_seconds{sd}}}; fields<CT> fds{year_month_day{sd}, hh_mm_ss<CT>{tp-sys_seconds{sd}}};
return to_stream(os, fmt, fds, &abbrev, &offset); return to_stream(os, fmt, fds, &abbrev, &offset);
} }
@ -7590,7 +7569,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
if (H != not_a_hour) if (H != not_a_hour)
{ {
fds.has_tod = true; fds.has_tod = true;
fds.tod = time_of_day<Duration>{hours{H}}; fds.tod = hh_mm_ss<Duration>{hours{H}};
} }
if (M != not_a_minute) if (M != not_a_minute)
{ {

View File

@ -1922,14 +1922,14 @@ is_leap_second(date::utc_time<Duration> const& ut)
return {ls, ds}; return {ls, ds};
} }
struct get_leap_second_info_t struct leap_second_info
{ {
bool is_leap_second; bool is_leap_second;
std::chrono::seconds elapsed; std::chrono::seconds elapsed;
}; };
template <class Duration> template <class Duration>
get_leap_second_info_t leap_second_info
get_leap_second_info(date::utc_time<Duration> const& ut) get_leap_second_info(date::utc_time<Duration> const& ut)
{ {
auto p = is_leap_second(ut); auto p = is_leap_second(ut);

View File

@ -85,16 +85,10 @@ main()
ostringstream os; ostringstream os;
os << t2; os << t2;
assert(os.str() == "13:00:00"); assert(os.str() == "13:00:00");
t2.make12(); auto h = make12(t2.hours());
os.str(""); os.str("");
assert(t2.hours() == hours{1}); assert(h == hours{1});
assert(t2.to_duration() == t1.to_duration()); assert(t2.to_duration() == t1.to_duration());
os << t2; assert(!is_am(t2.hours()));
assert(os.str() == "1:00:00PM"); assert(is_pm(t2.hours()));
t2.make24();
os.str("");
assert(t2.hours() == hours{13});
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "13:00:00");
} }

View File

@ -108,12 +108,4 @@ main()
ostringstream os; ostringstream os;
os << t2; os << t2;
assert(os.str() == "13:07:06.0480"); assert(os.str() == "13:07:06.0480");
t2.make12();
os.str("");
os << t2;
assert(os.str() == "1:07:06.0480PM");
t2.make24();
os.str("");
os << t2;
assert(os.str() == "13:07:06.0480");
} }

View File

@ -101,22 +101,4 @@ main()
ostringstream os; ostringstream os;
os << t2; os << t2;
assert(os.str() == "13:07:05.022"); assert(os.str() == "13:07:05.022");
t2.make12();
os.str("");
assert(t2.hours() == hours{1});
assert(t2.minutes() == minutes{7});
assert(t2.seconds() == seconds{5});
assert(t2.subseconds() == milliseconds{22});
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "1:07:05.022PM");
t2.make24();
os.str("");
assert(t2.hours() == hours{13});
assert(t2.minutes() == minutes{7});
assert(t2.seconds() == seconds{5});
assert(t2.subseconds() == milliseconds{22});
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "13:07:05.022");
} }

View File

@ -89,18 +89,4 @@ main()
ostringstream os; ostringstream os;
os << t2; os << t2;
assert(os.str() == "13:07:00"); assert(os.str() == "13:07:00");
t2.make12();
os.str("");
assert(t2.hours() == hours{1});
assert(t2.minutes() == minutes{7});
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "1:07:00PM");
t2.make24();
os.str("");
assert(t2.hours() == hours{13});
assert(t2.minutes() == minutes{7});
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "13:07:00");
} }

View File

@ -101,22 +101,4 @@ main()
ostringstream os; ostringstream os;
os << t2; os << t2;
assert(os.str() == "13:07:05.000000022"); assert(os.str() == "13:07:05.000000022");
t2.make12();
os.str("");
assert(t2.hours() == hours{1});
assert(t2.minutes() == minutes{7});
assert(t2.seconds() == seconds{5});
assert(t2.subseconds() == nanoseconds{22});
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "1:07:05.000000022PM");
t2.make24();
os.str("");
assert(t2.hours() == hours{13});
assert(t2.minutes() == minutes{7});
assert(t2.seconds() == seconds{5});
assert(t2.subseconds() == nanoseconds{22});
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "13:07:05.000000022");
} }

View File

@ -93,20 +93,4 @@ main()
ostringstream os; ostringstream os;
os << t2; os << t2;
assert(os.str() == "13:07:05"); assert(os.str() == "13:07:05");
t2.make12();
os.str("");
assert(t2.hours() == hours{1});
assert(t2.minutes() == minutes{7});
assert(t2.seconds() == seconds{5});
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "1:07:05PM");
t2.make24();
os.str("");
assert(t2.hours() == hours{13});
assert(t2.minutes() == minutes{7});
assert(t2.seconds() == seconds{5});
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "13:07:05");
} }