forked from HowardHinnant/date
Add range checking for the time-of-day fields during parse.
* Also refactor the leap-second logic used in utc_time.
This commit is contained in:
43
date.h
43
date.h
@@ -3494,6 +3494,12 @@ public:
|
|||||||
return s_ + sub_s_;
|
return s_ + sub_s_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CONSTCD11 bool in_conventional_range() const NOEXCEPT
|
||||||
|
{
|
||||||
|
using namespace std::chrono;
|
||||||
|
return sub_s_ < std::chrono::seconds{1} && s_ < minutes{1};
|
||||||
|
}
|
||||||
|
|
||||||
template <class CharT, class Traits>
|
template <class CharT, class Traits>
|
||||||
friend
|
friend
|
||||||
std::basic_ostream<CharT, Traits>&
|
std::basic_ostream<CharT, Traits>&
|
||||||
@@ -3532,6 +3538,12 @@ public:
|
|||||||
CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_;}
|
CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_;}
|
||||||
CONSTCD14 precision to_duration() const NOEXCEPT {return s_;}
|
CONSTCD14 precision to_duration() const NOEXCEPT {return s_;}
|
||||||
|
|
||||||
|
CONSTCD11 bool in_conventional_range() const NOEXCEPT
|
||||||
|
{
|
||||||
|
using namespace std::chrono;
|
||||||
|
return s_ < minutes{1};
|
||||||
|
}
|
||||||
|
|
||||||
template <class CharT, class Traits>
|
template <class CharT, class Traits>
|
||||||
friend
|
friend
|
||||||
std::basic_ostream<CharT, Traits>&
|
std::basic_ostream<CharT, Traits>&
|
||||||
@@ -3622,6 +3634,11 @@ protected:
|
|||||||
CONSTCD14 void make12() NOEXCEPT;
|
CONSTCD14 void make12() NOEXCEPT;
|
||||||
|
|
||||||
CONSTCD14 std::chrono::hours to24hr() const;
|
CONSTCD14 std::chrono::hours to24hr() const;
|
||||||
|
|
||||||
|
CONSTCD11 bool in_conventional_range() const NOEXCEPT
|
||||||
|
{
|
||||||
|
return !neg_ && h_ < days{1};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
CONSTCD14
|
CONSTCD14
|
||||||
@@ -3717,6 +3734,11 @@ public:
|
|||||||
CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;}
|
CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;}
|
||||||
CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;}
|
CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;}
|
||||||
|
|
||||||
|
CONSTCD11 bool in_conventional_range() const NOEXCEPT
|
||||||
|
{
|
||||||
|
return base::in_conventional_range();
|
||||||
|
}
|
||||||
|
|
||||||
template<class CharT, class Traits>
|
template<class CharT, class Traits>
|
||||||
friend
|
friend
|
||||||
std::basic_ostream<CharT, Traits>&
|
std::basic_ostream<CharT, Traits>&
|
||||||
@@ -3795,6 +3817,11 @@ public:
|
|||||||
CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;}
|
CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;}
|
||||||
CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;}
|
CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;}
|
||||||
|
|
||||||
|
CONSTCD11 bool in_conventional_range() const NOEXCEPT
|
||||||
|
{
|
||||||
|
return base::in_conventional_range() && m_ < std::chrono::hours{1};
|
||||||
|
}
|
||||||
|
|
||||||
template<class CharT, class Traits>
|
template<class CharT, class Traits>
|
||||||
friend
|
friend
|
||||||
std::basic_ostream<CharT, Traits>&
|
std::basic_ostream<CharT, Traits>&
|
||||||
@@ -3879,6 +3906,12 @@ public:
|
|||||||
CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;}
|
CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;}
|
||||||
CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;}
|
CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;}
|
||||||
|
|
||||||
|
CONSTCD11 bool in_conventional_range() const NOEXCEPT
|
||||||
|
{
|
||||||
|
return base::in_conventional_range() && m_ < std::chrono::hours{1} &&
|
||||||
|
s_.in_conventional_range();
|
||||||
|
}
|
||||||
|
|
||||||
template<class CharT, class Traits>
|
template<class CharT, class Traits>
|
||||||
friend
|
friend
|
||||||
std::basic_ostream<CharT, Traits>&
|
std::basic_ostream<CharT, Traits>&
|
||||||
@@ -3983,6 +4016,12 @@ public:
|
|||||||
CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;}
|
CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;}
|
||||||
CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;}
|
CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;}
|
||||||
|
|
||||||
|
CONSTCD11 bool in_conventional_range() const NOEXCEPT
|
||||||
|
{
|
||||||
|
return base::in_conventional_range() && m_ < std::chrono::hours{1} &&
|
||||||
|
s_.in_conventional_range();
|
||||||
|
}
|
||||||
|
|
||||||
template<class CharT, class Traits>
|
template<class CharT, class Traits>
|
||||||
friend
|
friend
|
||||||
std::basic_ostream<CharT, Traits>&
|
std::basic_ostream<CharT, Traits>&
|
||||||
@@ -6425,7 +6464,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
|
|||||||
auto offptr = offset ? offset : &offset_local;
|
auto offptr = offset ? offset : &offset_local;
|
||||||
fields<CT> fds{};
|
fields<CT> fds{};
|
||||||
from_stream(is, fmt, fds, abbrev, offptr);
|
from_stream(is, fmt, fds, abbrev, offptr);
|
||||||
if (!fds.ymd.ok())
|
if (!fds.ymd.ok() || !fds.tod.in_conventional_range())
|
||||||
is.setstate(ios::failbit);
|
is.setstate(ios::failbit);
|
||||||
if (!is.fail())
|
if (!is.fail())
|
||||||
tp = sys_days(fds.ymd) + duration_cast<Duration>(fds.tod.to_duration() - *offptr);
|
tp = sys_days(fds.ymd) + duration_cast<Duration>(fds.tod.to_duration() - *offptr);
|
||||||
@@ -6442,7 +6481,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
|
|||||||
using CT = typename common_type<Duration, seconds>::type;
|
using CT = typename common_type<Duration, seconds>::type;
|
||||||
fields<CT> fds{};
|
fields<CT> fds{};
|
||||||
from_stream(is, fmt, fds, abbrev, offset);
|
from_stream(is, fmt, fds, abbrev, offset);
|
||||||
if (!fds.ymd.ok())
|
if (!fds.ymd.ok() || !fds.tod.in_conventional_range())
|
||||||
is.setstate(ios::failbit);
|
is.setstate(ios::failbit);
|
||||||
if (!is.fail())
|
if (!is.fail())
|
||||||
tp = local_days(fds.ymd) + duration_cast<Duration>(fds.tod.to_duration());
|
tp = local_days(fds.ymd) + duration_cast<Duration>(fds.tod.to_duration());
|
||||||
|
85
tz.h
85
tz.h
@@ -1119,6 +1119,35 @@ to_utc_time(const sys_time<Duration>& st)
|
|||||||
return utc_time<duration>{st.time_since_epoch() + seconds{lt-leaps.begin()}};
|
return utc_time<duration>{st.time_since_epoch() + seconds{lt-leaps.begin()}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return pair<is_leap_second, seconds{number_of_leap_seconds_since_1970}>
|
||||||
|
// first is true if ut is during a leap second insertion, otherwise false.
|
||||||
|
// If ut is during a leap second insertion, that leap second is included in the count
|
||||||
|
template <class Duration>
|
||||||
|
std::pair<bool, std::chrono::seconds>
|
||||||
|
is_leap_second(date::utc_time<Duration> const& ut)
|
||||||
|
{
|
||||||
|
using namespace date;
|
||||||
|
using namespace std::chrono;
|
||||||
|
using duration = typename std::common_type<Duration, seconds>::type;
|
||||||
|
auto const& leaps = get_tzdb().leaps;
|
||||||
|
auto tp = sys_time<duration>{ut.time_since_epoch()};
|
||||||
|
auto const lt = std::upper_bound(leaps.begin(), leaps.end(), tp);
|
||||||
|
auto ds = seconds{lt-leaps.begin()};
|
||||||
|
tp -= ds;
|
||||||
|
auto ls = false;
|
||||||
|
if (lt > leaps.begin())
|
||||||
|
{
|
||||||
|
if (tp < lt[-1])
|
||||||
|
{
|
||||||
|
if (tp >= lt[-1].date() - seconds{1})
|
||||||
|
ls = true;
|
||||||
|
else
|
||||||
|
--ds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {ls, ds};
|
||||||
|
}
|
||||||
|
|
||||||
template <class Duration>
|
template <class Duration>
|
||||||
inline
|
inline
|
||||||
sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
||||||
@@ -1127,19 +1156,10 @@ to_sys_time(const utc_time<Duration>& ut)
|
|||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
using duration = typename std::common_type<Duration, seconds>::type;
|
using duration = typename std::common_type<Duration, seconds>::type;
|
||||||
auto const& leaps = get_tzdb().leaps;
|
auto const& leaps = get_tzdb().leaps;
|
||||||
auto tp = sys_time<duration>{ut.time_since_epoch()};
|
auto ls = is_leap_second(ut);
|
||||||
if (tp >= leaps.front())
|
auto tp = sys_time<duration>{ut.time_since_epoch() - ls.second};
|
||||||
{
|
if (ls.first)
|
||||||
auto const lt = std::upper_bound(leaps.begin(), leaps.end(), tp);
|
tp = floor<seconds>(tp) + seconds{1} - duration{1};
|
||||||
tp -= seconds{lt-leaps.begin()};
|
|
||||||
if (tp < lt[-1])
|
|
||||||
{
|
|
||||||
if (tp >= lt[-1].date() - seconds{1})
|
|
||||||
tp = lt[-1].date() - duration{1};
|
|
||||||
else
|
|
||||||
tp += seconds{1};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tp;
|
return tp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1162,26 +1182,14 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
|
|||||||
const string abbrev("UTC");
|
const string abbrev("UTC");
|
||||||
CONSTDATA seconds offset{0};
|
CONSTDATA seconds offset{0};
|
||||||
auto const& leaps = get_tzdb().leaps;
|
auto const& leaps = get_tzdb().leaps;
|
||||||
auto tp = sys_time<CT>{t.time_since_epoch()};
|
|
||||||
year_month_day ymd;
|
year_month_day ymd;
|
||||||
time_of_day<CT> time;
|
time_of_day<CT> time;
|
||||||
seconds ls{0};
|
auto ls = is_leap_second(t);
|
||||||
if (tp >= leaps.front())
|
auto tp = sys_time<CT>{t.time_since_epoch() - ls.second};
|
||||||
{
|
|
||||||
auto const lt = std::upper_bound(leaps.begin(), leaps.end(), tp);
|
|
||||||
tp -= seconds{lt-leaps.begin()};
|
|
||||||
if (tp < lt[-1])
|
|
||||||
{
|
|
||||||
if (tp >= lt[-1].date() - seconds{1})
|
|
||||||
ls = seconds{1};
|
|
||||||
else
|
|
||||||
tp += seconds{1};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto const sd = floor<days>(tp);
|
auto const sd = floor<days>(tp);
|
||||||
ymd = sd;
|
ymd = sd;
|
||||||
time = make_time(tp - sd);
|
time = make_time(tp - sd);
|
||||||
time.seconds() += ls;
|
time.seconds() += seconds{ls.first};
|
||||||
fields<CT> fds{ymd, time};
|
fields<CT> fds{ymd, time};
|
||||||
to_stream(os, fmt, fds, &abbrev, &offset);
|
to_stream(os, fmt, fds, &abbrev, &offset);
|
||||||
}
|
}
|
||||||
@@ -1211,13 +1219,18 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
|
|||||||
is.setstate(ios::failbit);
|
is.setstate(ios::failbit);
|
||||||
if (!is.fail())
|
if (!is.fail())
|
||||||
{
|
{
|
||||||
bool is_leap_second = fds.tod.seconds() == seconds{60};
|
bool is_60_sec = fds.tod.seconds() == seconds{60};
|
||||||
if (is_leap_second)
|
if (is_60_sec)
|
||||||
fds.tod.seconds() -= seconds{1};
|
fds.tod.seconds() -= seconds{1};
|
||||||
tp = to_utc_time(sys_days(fds.ymd) +
|
auto tmp = to_utc_time(sys_days(fds.ymd) + (fds.tod.to_duration() - *offptr));
|
||||||
duration_cast<Duration>(fds.tod.to_duration() - *offptr));
|
if (is_60_sec)
|
||||||
if (is_leap_second)
|
tmp += seconds{1};
|
||||||
tp += seconds{1};
|
if (is_60_sec != is_leap_second(tmp).first || !fds.tod.in_conventional_range())
|
||||||
|
{
|
||||||
|
is.setstate(ios::failbit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tp = time_point_cast<Duration>(tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1319,7 +1332,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
|
|||||||
auto offptr = offset ? offset : &offset_local;
|
auto offptr = offset ? offset : &offset_local;
|
||||||
fields<CT> fds{};
|
fields<CT> fds{};
|
||||||
from_stream(is, fmt, fds, abbrev, offptr);
|
from_stream(is, fmt, fds, abbrev, offptr);
|
||||||
if (!fds.ymd.ok())
|
if (!fds.ymd.ok() || !fds.tod.in_conventional_range())
|
||||||
is.setstate(ios::failbit);
|
is.setstate(ios::failbit);
|
||||||
if (!is.fail())
|
if (!is.fail())
|
||||||
tp = tai_time<Duration>{duration_cast<Duration>(
|
tp = tai_time<Duration>{duration_cast<Duration>(
|
||||||
@@ -1425,7 +1438,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
|
|||||||
auto offptr = offset ? offset : &offset_local;
|
auto offptr = offset ? offset : &offset_local;
|
||||||
fields<CT> fds{};
|
fields<CT> fds{};
|
||||||
from_stream(is, fmt, fds, abbrev, offptr);
|
from_stream(is, fmt, fds, abbrev, offptr);
|
||||||
if (!fds.ymd.ok())
|
if (!fds.ymd.ok() || !fds.tod.in_conventional_range())
|
||||||
is.setstate(ios::failbit);
|
is.setstate(ios::failbit);
|
||||||
if (!is.fail())
|
if (!is.fail())
|
||||||
tp = gps_time<Duration>{duration_cast<Duration>(
|
tp = gps_time<Duration>{duration_cast<Duration>(
|
||||||
|
Reference in New Issue
Block a user