Specify exception constructors

* For nonexistent_local_time and ambiguous_local_time.
* Simplify the constructors.
* Make these exceptions usable for custom time zones.
This commit is contained in:
Howard Hinnant 2017-10-24 12:07:27 -04:00
parent 5563d31b2e
commit 9381e894a5
2 changed files with 76 additions and 107 deletions

View File

@ -32,6 +32,7 @@ This is actually several separate C++11/C++14 libraries:
`"date.h"` and `"tz.h"` are now being proposed for standardization: `"date.h"` and `"tz.h"` are now being proposed for standardization:
* Current proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0355r4.html * Current proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0355r4.html
* Draft revision: http://howardhinnant.github.io/date/d0355r5.html
List of projects using this library: List of projects using this library:

View File

@ -151,101 +151,6 @@ namespace detail
struct undocumented; struct undocumented;
} }
class nonexistent_local_time
: public std::runtime_error
{
public:
template <class Duration>
nonexistent_local_time(local_time<Duration> tp, local_seconds first,
const std::string& first_abbrev, local_seconds last,
const std::string& last_abbrev, sys_seconds time_sys);
private:
template <class Duration>
static
std::string
make_msg(local_time<Duration> tp,
local_seconds first, const std::string& first_abbrev,
local_seconds last, const std::string& last_abbrev,
sys_seconds time_sys);
};
template <class Duration>
inline
nonexistent_local_time::nonexistent_local_time(local_time<Duration> tp,
local_seconds begin,
const std::string& first_abbrev,
local_seconds end,
const std::string& last_abbrev,
sys_seconds time_sys)
: std::runtime_error(make_msg(tp, begin, first_abbrev, end, last_abbrev, time_sys))
{}
template <class Duration>
std::string
nonexistent_local_time::make_msg(local_time<Duration> tp, local_seconds begin,
const std::string& first_abbrev, local_seconds end,
const std::string& last_abbrev, sys_seconds time_sys)
{
using namespace date;
std::ostringstream os;
os << tp << " is in a gap between\n"
<< begin << ' ' << first_abbrev << " and\n"
<< end << ' ' << last_abbrev
<< " which are both equivalent to\n"
<< time_sys << " UTC";
return os.str();
}
class ambiguous_local_time
: public std::runtime_error
{
public:
template <class Duration>
ambiguous_local_time(local_time<Duration> tp, std::chrono::seconds first_offset,
const std::string& first_abbrev,
std::chrono::seconds second_offset,
const std::string& second_abbrev);
private:
template <class Duration>
static
std::string
make_msg(local_time<Duration> tp,
std::chrono::seconds first_offset, const std::string& first_abbrev,
std::chrono::seconds second_offset, const std::string& second_abbrev);
};
template <class Duration>
inline
ambiguous_local_time::ambiguous_local_time(
local_time<Duration> tp,
std::chrono::seconds first_offset,
const std::string& first_abbrev,
std::chrono::seconds second_offset,
const std::string& second_abbrev)
: std::runtime_error(make_msg(tp, first_offset, first_abbrev, second_offset,
second_abbrev))
{}
template <class Duration>
std::string
ambiguous_local_time::make_msg(local_time<Duration> tp,
std::chrono::seconds first_offset,
const std::string& first_abbrev,
std::chrono::seconds second_offset,
const std::string& second_abbrev)
{
using namespace date;
std::ostringstream os;
os << tp << " is ambiguous. It could be\n"
<< tp << ' ' << first_abbrev << " == "
<< tp - first_offset << " UTC or\n"
<< tp << ' ' << second_abbrev << " == "
<< tp - second_offset << " UTC";
return os.str();
}
struct sys_info struct sys_info
{ {
sys_seconds begin; sys_seconds begin;
@ -291,6 +196,79 @@ operator<<(std::basic_ostream<CharT, Traits>& os, const local_info& r)
return os; return os;
} }
class nonexistent_local_time
: public std::runtime_error
{
public:
template <class Duration>
nonexistent_local_time(local_time<Duration> tp, const local_info& i);
private:
template <class Duration>
static
std::string
make_msg(local_time<Duration> tp, const local_info& i);
};
template <class Duration>
inline
nonexistent_local_time::nonexistent_local_time(local_time<Duration> tp,
const local_info& i)
: std::runtime_error(make_msg(tp, i))
{
}
template <class Duration>
std::string
nonexistent_local_time::make_msg(local_time<Duration> tp, const local_info& i)
{
assert(i.result == local_info::nonexistent);
std::ostringstream os;
os << tp << " is in a gap between\n"
<< local_seconds{i.first.end.time_since_epoch()} + i.first.offset << ' '
<< i.first.abbrev << " and\n"
<< local_seconds{i.second.begin.time_since_epoch()} + i.second.offset << ' '
<< i.second.abbrev
<< " which are both equivalent to\n"
<< i.first.end << " UTC";
return os.str();
}
class ambiguous_local_time
: public std::runtime_error
{
public:
template <class Duration>
ambiguous_local_time(local_time<Duration> tp, const local_info& i);
private:
template <class Duration>
static
std::string
make_msg(local_time<Duration> tp, const local_info& i);
};
template <class Duration>
inline
ambiguous_local_time::ambiguous_local_time(local_time<Duration> tp, const local_info& i)
: std::runtime_error(make_msg(tp, i))
{
}
template <class Duration>
std::string
ambiguous_local_time::make_msg(local_time<Duration> tp, const local_info& i)
{
assert(i.result == local_info::ambiguous);
std::ostringstream os;
os << tp << " is ambiguous. It could be\n"
<< tp << ' ' << i.first.abbrev << " == "
<< tp - i.first.offset << " UTC or\n"
<< tp << ' ' << i.second.abbrev << " == "
<< tp - i.second.offset << " UTC";
return os.str();
}
class time_zone; class time_zone;
#if HAS_STRING_VIEW #if HAS_STRING_VIEW
@ -958,19 +936,9 @@ time_zone::to_sys_impl(local_time<Duration> tp, choose, std::true_type) const
using namespace std::chrono; using namespace std::chrono;
auto i = get_info(tp); auto i = get_info(tp);
if (i.result == local_info::nonexistent) if (i.result == local_info::nonexistent)
{ throw nonexistent_local_time(tp, i);
auto prev_end = local_seconds{i.first.end.time_since_epoch()} +
i.first.offset;
auto next_begin = local_seconds{i.second.begin.time_since_epoch()} +
i.second.offset;
throw nonexistent_local_time(tp, prev_end, i.first.abbrev,
next_begin, i.second.abbrev, i.first.end);
}
else if (i.result == local_info::ambiguous) else if (i.result == local_info::ambiguous)
{ throw ambiguous_local_time(tp, i);
throw ambiguous_local_time(tp, i.first.offset, i.first.abbrev,
i.second.offset, i.second.abbrev);
}
return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset; return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset;
} }