Move formatting and parsing

Moved formatting and parsing of sys_time and local_time from tz.h to
date.h in order to make this functionality available to a wider
audience.  Existing code does not need to change.  But future code
can #include "date.h" instead of "tz.h" and need not compile tz.cpp nor
link to curl.

Formatting zoned_time remains in tz.h.
This commit is contained in:
Howard Hinnant
2016-08-24 20:34:10 -04:00
parent 7e9d9075d9
commit ebc20c139b
2 changed files with 604 additions and 583 deletions

598
date.h
View File

@ -3919,6 +3919,604 @@ operator<<(std::basic_ostream<CharT, Traits>& os, const local_time<Duration>& ut
return os << sys_time<Duration>{ut.time_since_epoch()};
}
// format
namespace detail
{
template <class CharT, class Traits, class Duration>
std::basic_string<CharT, Traits>
format(const std::locale& loc, std::basic_string<CharT, Traits> fmt,
local_time<Duration> tp, const std::string* abbrev = nullptr,
const std::chrono::seconds* offset_sec = nullptr)
{
// Handle these specially
// %S append fractional seconds if tp has precision finer than seconds
// %T append fractional seconds if tp has precision finer than seconds
// %z replace with offset from zone on +/-hhmm format
// %Ez, %Oz replace with offset from zone on +/-hh:mm format
// %Z replace with abbreviation from zone
using namespace std;
using namespace std::chrono;
auto command = false;
auto modified = false;
for (std::size_t i = 0; i < fmt.size(); ++i)
{
switch (fmt[i])
{
case '%':
command = true;
modified = false;
break;
case 'O':
case 'E':
modified = true;
break;
case 'S':
case 'T':
if (command && !modified && ratio_less<typename Duration::period, ratio<1>>::value)
{
basic_ostringstream<CharT, Traits> os;
os.imbue(loc);
os << make_time(tp - floor<seconds>(tp));
auto s = os.str();
s.erase(0, 8);
fmt.insert(i+1, s);
i += s.size() - 1;
}
command = false;
modified = false;
break;
case 'z':
if (command)
{
if (offset_sec == nullptr)
throw std::runtime_error("Can not format local_time with %z");
else
{
auto offset = duration_cast<minutes>(*offset_sec);
basic_ostringstream<CharT, Traits> os;
if (offset >= minutes{0})
os << '+';
os << make_time(offset);
auto s = os.str();
if (!modified)
s.erase(s.find(':'), 1);
fmt.replace(i - 1 - modified, 2 + modified, s);
i += s.size() - 1;
}
}
command = false;
modified = false;
break;
case 'Z':
if (command && !modified)
{
if (abbrev == nullptr)
throw std::runtime_error("Can not format local_time with %Z");
else
{
fmt.replace(i - 1, 2,
std::basic_string<CharT, Traits>(abbrev->begin(), abbrev->end()));
i += abbrev->size() - 1;
}
}
command = false;
modified = false;
break;
default:
command = false;
modified = false;
break;
}
}
auto& f = use_facet<time_put<CharT>>(loc);
basic_ostringstream<CharT, Traits> os;
auto tt = system_clock::to_time_t(sys_time<Duration>{tp.time_since_epoch()});
std::tm tm{};
#ifndef _MSC_VER
gmtime_r(&tt, &tm);
#else
gmtime_s(&tm, &tt);
#endif
f.put(os, os, os.fill(), &tm, fmt.data(), fmt.data() + fmt.size());
return os.str();
}
} // namespace detail
template <class CharT, class Traits, class Duration>
inline
std::basic_string<CharT, Traits>
format(const std::locale& loc, std::basic_string<CharT, Traits> fmt,
local_time<Duration> tp)
{
return detail::format(loc, std::move(fmt), tp);
}
template <class CharT, class Traits, class Duration>
inline
std::basic_string<CharT, Traits>
format(std::basic_string<CharT, Traits> fmt, local_time<Duration> tp)
{
return detail::format(std::locale{}, std::move(fmt), tp);
}
template <class CharT, class Traits, class Duration>
inline
std::basic_string<CharT, Traits>
format(const std::locale& loc, std::basic_string<CharT, Traits> fmt,
sys_time<Duration> tp)
{
const std::string abbrev("UTC");
CONSTDATA std::chrono::seconds offset{0};
return detail::format(loc, std::move(fmt),
local_time<Duration>{tp.time_since_epoch()}, &abbrev, &offset);
}
template <class CharT, class Traits, class Duration>
inline
std::basic_string<CharT, Traits>
format(std::basic_string<CharT, Traits> fmt, sys_time<Duration> tp)
{
const std::string abbrev("UTC");
CONSTDATA std::chrono::seconds offset{0};
return detail::format(std::move(fmt), local_time<Duration>{tp.time_since_epoch()},
&abbrev, &offset);
}
// const CharT* formats
template <class CharT, class Duration>
inline
std::basic_string<CharT>
format(const std::locale& loc, const CharT* fmt, local_time<Duration> tp)
{
return detail::format(loc, std::basic_string<CharT>(fmt), tp);
}
template <class CharT, class Duration>
inline
std::basic_string<CharT>
format(const CharT* fmt, local_time<Duration> tp)
{
return detail::format(std::locale{}, std::basic_string<CharT>(fmt), tp);
}
template <class CharT, class Duration>
inline
std::basic_string<CharT>
format(const std::locale& loc, const CharT* fmt, sys_time<Duration> tp)
{
const std::string abbrev("UTC");
CONSTDATA std::chrono::seconds offset{0};
return detail::format(loc, std::basic_string<CharT>(fmt),
local_time<Duration>{tp.time_since_epoch()},
&abbrev, &offset);
}
template <class CharT, class Duration>
inline
std::basic_string<CharT>
format(const CharT* fmt, sys_time<Duration> tp)
{
const std::string abbrev("UTC");
CONSTDATA std::chrono::seconds offset{0};
return detail::format(std::locale{}, std::basic_string<CharT>(fmt),
local_time<Duration>{tp.time_since_epoch()},
&abbrev, &offset);
}
// parse
namespace detail
{
template <class CharT, class Traits, class Duration>
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev, std::chrono::minutes& offset)
{
using namespace std;
using namespace std::chrono;
typename basic_istream<CharT, Traits>::sentry ok{is};
if (ok)
{
auto& f = use_facet<time_get<CharT>>(is.getloc());
ios_base::iostate err = ios_base::goodbit;
std::tm tm{};
Duration subseconds{};
std::basic_string<CharT, Traits> temp_abbrev;
minutes temp_offset{};
auto b = format.data();
auto i = b;
auto e = b + format.size();
auto command = false;
auto modified = false;
for (; i < e; ++i)
{
switch (*i)
{
case '%':
command = true;
modified = false;
break;
case 'O':
case 'E':
modified = true;
break;
case 'T':
case 'S':
if (command && !modified)
{
f.get(is, 0, is, err, &tm, b, i-1);
b = i+1;
if (*i == 'T')
{
const CharT hm[] = {'%', 'H', ':', '%', 'M', ':'};
f.get(is, 0, is, err, &tm, hm, hm+6);
}
if (ratio_less<typename Duration::period, ratio<1>>::value)
{
auto decimal_point = Traits::to_int_type(
use_facet<numpunct<CharT>>(is.getloc()).decimal_point());
string buf;
while (true)
{
auto k = is.peek();
if (Traits::eq_int_type(k, Traits::eof()))
break;
if (Traits::eq_int_type(k, decimal_point))
{
buf += '.';
decimal_point = Traits::eof();
is.get();
}
else
{
auto c = static_cast<char>(Traits::to_char_type(k));
if (isdigit(c))
{
buf += c;
is.get();
}
else
{
break;
}
}
};
if (!buf.empty())
subseconds = round<Duration>(duration<double>{stod(buf)});
else
err |= ios_base::failbit;
}
else
{
const CharT hm[] = {'%', 'S'};
f.get(is, 0, is, err, &tm, hm, hm+2);
}
}
command = false;
modified = false;
break;
case 'z':
if (command)
{
f.get(is, 0, is, err, &tm, b, i-1-modified);
b = i+1;
if ((err & ios_base::failbit) == 0)
{
CharT sign{};
is >> sign;
if (!is.fail() && (sign == '+' || sign == '-'))
{
char h1, h0, m1, m0;
char colon = ':';
h1 = static_cast<char>(is.get());
h0 = static_cast<char>(is.get());
if (modified)
{
if (h0 == ':')
{
colon = h0;
h0 = h1;
h1 = '0';
}
else
colon = static_cast<char>(is.get());
}
m1 = static_cast<char>(is.get());
m0 = static_cast<char>(is.get());
if (!is.fail() && std::isdigit(h1) && std::isdigit(h0)
&& std::isdigit(m1) && std::isdigit(m0)
&& colon == ':')
{
temp_offset = 10*hours{h1 - '0'} + hours{h0 - '0'} +
10*minutes{m1 - '0'} + minutes{m0 - '0'};
if (sign == '-')
temp_offset = -temp_offset;
}
else
err |= ios_base::failbit;
}
else
err |= ios_base::failbit;
}
}
command = false;
modified = false;
break;
case 'Z':
if (command && !modified)
{
f.get(is, 0, is, err, &tm, b, i-1);
b = i+1;
if ((err & ios_base::failbit) == 0)
{
is >> temp_abbrev;
if (is.fail())
err |= ios_base::failbit;
}
}
command = false;
modified = false;
break;
default:
command = false;
modified = false;
break;
}
}
if ((err & ios_base::failbit) == 0)
{
if (b < e)
f.get(is, 0, is, err, &tm, b, e);
if ((err & ios_base::failbit) == 0)
{
#ifdef _WIN32
auto tt = _mkgmtime(&tm);
#else
auto tt = timegm(&tm);
#endif
tp = floor<Duration>(system_clock::from_time_t(tt) + subseconds);
abbrev = std::move(temp_abbrev);
offset = temp_offset;
}
}
is.setstate(err);
}
}
} // namespace detail
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp)
{
std::basic_string<CharT, Traits> abbrev;
std::chrono::minutes offset{};
detail::parse(is, format, tp, abbrev, offset);
if (!is.fail())
tp = floor<Duration>(tp - offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev)
{
std::chrono::minutes offset{};
detail::parse(is, format, tp, abbrev, offset);
if (!is.fail())
tp = floor<Duration>(tp - offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp,
std::chrono::minutes& offset)
{
std::basic_string<CharT, Traits> abbrev;
detail::parse(is, format, tp, abbrev, offset);
if (!is.fail())
tp = floor<Duration>(tp - offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev, std::chrono::minutes& offset)
{
detail::parse(is, format, tp, abbrev, offset);
if (!is.fail())
tp = floor<Duration>(tp - offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp,
std::chrono::minutes& offset, std::basic_string<CharT, Traits>& abbrev)
{
detail::parse(is, format, tp, abbrev, offset);
if (!is.fail())
tp = floor<Duration>(tp - offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp)
{
sys_time<Duration> st;
std::basic_string<CharT, Traits> abbrev;
std::chrono::minutes offset{};
detail::parse(is, format, st, abbrev, offset);
if (!is.fail())
tp = local_time<Duration>{st.time_since_epoch()};
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev)
{
sys_time<Duration> st;
std::chrono::minutes offset{};
detail::parse(is, format, st, abbrev, offset);
if (!is.fail())
tp = local_time<Duration>{st.time_since_epoch()};
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp,
std::chrono::minutes& offset)
{
sys_time<Duration> st;
std::basic_string<CharT, Traits> abbrev;
detail::parse(is, format, st, abbrev, offset);
if (!is.fail())
tp = local_time<Duration>{st.time_since_epoch()};
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev, std::chrono::minutes& offset)
{
sys_time<Duration> st;
detail::parse(is, format, st, abbrev, offset);
if (!is.fail())
tp = local_time<Duration>{st.time_since_epoch()};
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp,
std::chrono::minutes& offset, std::basic_string<CharT, Traits>& abbrev)
{
sys_time<Duration> st;
detail::parse(is, format, st, abbrev, offset);
if (!is.fail())
tp = local_time<Duration>{st.time_since_epoch()};
}
// const CharT* formats
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp)
{
parse(is, std::basic_string<CharT, Traits>(format), tp);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, abbrev);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp,
std::chrono::minutes& offset)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev, std::chrono::minutes& offset)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, abbrev, offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp,
std::chrono::minutes& offset, std::basic_string<CharT, Traits>& abbrev)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, abbrev, offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
local_time<Duration>& tp)
{
parse(is, std::basic_string<CharT, Traits>(format), tp);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
local_time<Duration>& tp, std::basic_string<CharT, Traits>& abbrev)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, abbrev);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
local_time<Duration>& tp, std::chrono::minutes& offset)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
local_time<Duration>& tp, std::basic_string<CharT, Traits>& abbrev,
std::chrono::minutes& offset)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, abbrev, offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
local_time<Duration>& tp, std::chrono::minutes& offset,
std::basic_string<CharT, Traits>& abbrev)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, abbrev, offset);
}
} // namespace date
#endif // DATE_H

589
tz.h
View File

@ -1336,127 +1336,6 @@ to_gps_time(tai_time<Duration> t)
// format
namespace detail
{
template <class CharT, class Traits, class Duration>
std::basic_string<CharT, Traits>
format(const std::locale& loc, std::basic_string<CharT, Traits> fmt,
local_time<Duration> tp, const sys_info* info = nullptr)
{
// Handle these specially
// %S append fractional seconds if tp has precision finer than seconds
// %T append fractional seconds if tp has precision finer than seconds
// %z replace with offset from zone on +/-hhmm format
// %Ez, %Oz replace with offset from zone on +/-hh:mm format
// %Z replace with abbreviation from zone
using namespace std;
using namespace std::chrono;
auto command = false;
auto modified = false;
for (std::size_t i = 0; i < fmt.size(); ++i)
{
switch (fmt[i])
{
case '%':
command = true;
modified = false;
break;
case 'O':
case 'E':
modified = true;
break;
case 'S':
case 'T':
if (command && !modified && ratio_less<typename Duration::period, ratio<1>>::value)
{
basic_ostringstream<CharT, Traits> os;
os.imbue(loc);
os << make_time(tp - floor<seconds>(tp));
auto s = os.str();
s.erase(0, 8);
fmt.insert(i+1, s);
i += s.size() - 1;
}
command = false;
modified = false;
break;
case 'z':
if (command)
{
if (info == nullptr)
throw std::runtime_error("Can not format local_time with %z");
else
{
auto offset = duration_cast<minutes>(info->offset);
basic_ostringstream<CharT, Traits> os;
if (offset >= minutes{0})
os << '+';
os << make_time(offset);
auto s = os.str();
if (!modified)
s.erase(s.find(':'), 1);
fmt.replace(i - 1 - modified, 2 + modified, s);
i += s.size() - 1;
}
}
command = false;
modified = false;
break;
case 'Z':
if (command && !modified)
{
if (info == nullptr)
throw std::runtime_error("Can not format local_time with %Z");
else
{
fmt.replace(i - 1, 2, std::basic_string<CharT, Traits>
(info->abbrev.begin(), info->abbrev.end()));
i += info->abbrev.size() - 1;
}
}
command = false;
modified = false;
break;
default:
command = false;
modified = false;
break;
}
}
auto& f = use_facet<time_put<CharT>>(loc);
basic_ostringstream<CharT, Traits> os;
auto tt = system_clock::to_time_t(sys_time<Duration>{tp.time_since_epoch()});
std::tm tm{};
#ifndef _MSC_VER
gmtime_r(&tt, &tm);
#else
gmtime_s(&tm, &tt);
#endif
f.put(os, os, os.fill(), &tm, fmt.data(), fmt.data() + fmt.size());
return os.str();
}
} // namespace detail
template <class CharT, class Traits, class Duration>
inline
std::basic_string<CharT, Traits>
format(const std::locale& loc, std::basic_string<CharT, Traits> fmt,
local_time<Duration> tp)
{
return detail::format(loc, std::move(fmt), tp);
}
template <class CharT, class Traits, class Duration>
inline
std::basic_string<CharT, Traits>
format(std::basic_string<CharT, Traits> fmt, local_time<Duration> tp)
{
return detail::format(std::locale{}, std::move(fmt), tp);
}
template <class CharT, class Traits, class Duration>
inline
std::basic_string<CharT, Traits>
@ -1464,7 +1343,8 @@ format(const std::locale& loc, std::basic_string<CharT, Traits> fmt,
const zoned_time<Duration>& tp)
{
auto const info = tp.get_info();
return detail::format(loc, std::move(fmt), tp.get_local_time(), &info);
return detail::format(loc, std::move(fmt), tp.get_local_time(),
&info.abbrev, &info.offset);
}
template <class CharT, class Traits, class Duration>
@ -1473,44 +1353,12 @@ std::basic_string<CharT, Traits>
format(std::basic_string<CharT, Traits> fmt, const zoned_time<Duration>& tp)
{
auto const info = tp.get_info();
return detail::format(std::locale{}, std::move(fmt), tp.get_local_time(), &info);
}
template <class CharT, class Traits, class Duration>
inline
std::basic_string<CharT, Traits>
format(const std::locale& loc, std::basic_string<CharT, Traits> fmt,
sys_time<Duration> tp)
{
return format(loc, std::move(fmt), make_zoned(locate_zone("UTC"), tp));
}
template <class CharT, class Traits, class Duration>
inline
std::basic_string<CharT, Traits>
format(std::basic_string<CharT, Traits> fmt, sys_time<Duration> tp)
{
return format(std::move(fmt), make_zoned(locate_zone("UTC"), tp));
return detail::format(std::locale{}, std::move(fmt), tp.get_local_time(),
&info.abbrev, &info.offset);
}
// const CharT* formats
template <class CharT, class Duration>
inline
std::basic_string<CharT>
format(const std::locale& loc, const CharT* fmt, local_time<Duration> tp)
{
return detail::format(loc, std::basic_string<CharT>(fmt), tp);
}
template <class CharT, class Duration>
inline
std::basic_string<CharT>
format(const CharT* fmt, local_time<Duration> tp)
{
return detail::format(std::locale{}, std::basic_string<CharT>(fmt), tp);
}
template <class CharT, class Duration>
inline
std::basic_string<CharT>
@ -1518,7 +1366,7 @@ format(const std::locale& loc, const CharT* fmt, const zoned_time<Duration>& tp)
{
auto const info = tp.get_info();
return detail::format(loc, std::basic_string<CharT>(fmt), tp.get_local_time(),
&info);
&info.abbrev, &info.offset);
}
template <class CharT, class Duration>
@ -1528,432 +1376,7 @@ format(const CharT* fmt, const zoned_time<Duration>& tp)
{
auto const info = tp.get_info();
return detail::format(std::locale{}, std::basic_string<CharT>(fmt),
tp.get_local_time(), &info);
}
template <class CharT, class Duration>
inline
std::basic_string<CharT>
format(const std::locale& loc, const CharT* fmt, sys_time<Duration> tp)
{
return format(loc, fmt, make_zoned(locate_zone("UTC"), tp));
}
template <class CharT, class Duration>
inline
std::basic_string<CharT>
format(const CharT* fmt, sys_time<Duration> tp)
{
return format(fmt, make_zoned(locate_zone("UTC"), tp));
}
// parse
namespace detail
{
template <class CharT, class Traits, class Duration>
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev, std::chrono::minutes& offset)
{
using namespace std;
using namespace std::chrono;
typename basic_istream<CharT, Traits>::sentry ok{is};
if (ok)
{
auto& f = use_facet<time_get<CharT>>(is.getloc());
ios_base::iostate err = ios_base::goodbit;
std::tm tm{};
Duration subseconds{};
std::basic_string<CharT, Traits> temp_abbrev;
minutes temp_offset{};
auto b = format.data();
auto i = b;
auto e = b + format.size();
auto command = false;
auto modified = false;
for (; i < e; ++i)
{
switch (*i)
{
case '%':
command = true;
modified = false;
break;
case 'O':
case 'E':
modified = true;
break;
case 'T':
case 'S':
if (command && !modified)
{
f.get(is, 0, is, err, &tm, b, i-1);
b = i+1;
if (*i == 'T')
{
const CharT hm[] = {'%', 'H', ':', '%', 'M', ':'};
f.get(is, 0, is, err, &tm, hm, hm+6);
}
if (ratio_less<typename Duration::period, ratio<1>>::value)
{
auto decimal_point = Traits::to_int_type(
use_facet<numpunct<CharT>>(is.getloc()).decimal_point());
string buf;
while (true)
{
auto k = is.peek();
if (Traits::eq_int_type(k, Traits::eof()))
break;
if (Traits::eq_int_type(k, decimal_point))
{
buf += '.';
decimal_point = Traits::eof();
is.get();
}
else
{
auto c = static_cast<char>(Traits::to_char_type(k));
if (isdigit(c))
{
buf += c;
is.get();
}
else
{
break;
}
}
};
if (!buf.empty())
subseconds = round<Duration>(duration<double>{stod(buf)});
else
err |= ios_base::failbit;
}
else
{
const CharT hm[] = {'%', 'S'};
f.get(is, 0, is, err, &tm, hm, hm+2);
}
}
command = false;
modified = false;
break;
case 'z':
if (command)
{
f.get(is, 0, is, err, &tm, b, i-1-modified);
b = i+1;
if ((err & ios_base::failbit) == 0)
{
CharT sign{};
is >> sign;
if (!is.fail() && (sign == '+' || sign == '-'))
{
char h1, h0, m1, m0;
char colon = ':';
h1 = static_cast<char>(is.get());
h0 = static_cast<char>(is.get());
if (modified)
{
if (h0 == ':')
{
colon = h0;
h0 = h1;
h1 = '0';
}
else
colon = static_cast<char>(is.get());
}
m1 = static_cast<char>(is.get());
m0 = static_cast<char>(is.get());
if (!is.fail() && std::isdigit(h1) && std::isdigit(h0)
&& std::isdigit(m1) && std::isdigit(m0)
&& colon == ':')
{
temp_offset = 10*hours{h1 - '0'} + hours{h0 - '0'} +
10*minutes{m1 - '0'} + minutes{m0 - '0'};
if (sign == '-')
temp_offset = -temp_offset;
}
else
err |= ios_base::failbit;
}
else
err |= ios_base::failbit;
}
}
command = false;
modified = false;
break;
case 'Z':
if (command && !modified)
{
f.get(is, 0, is, err, &tm, b, i-1);
b = i+1;
if ((err & ios_base::failbit) == 0)
{
is >> temp_abbrev;
if (is.fail())
err |= ios_base::failbit;
}
}
command = false;
modified = false;
break;
default:
command = false;
modified = false;
break;
}
}
if ((err & ios_base::failbit) == 0)
{
if (b < e)
f.get(is, 0, is, err, &tm, b, e);
if ((err & ios_base::failbit) == 0)
{
#ifdef _WIN32
auto tt = _mkgmtime(&tm);
#else
auto tt = timegm(&tm);
#endif
tp = floor<Duration>(system_clock::from_time_t(tt) + subseconds);
abbrev = std::move(temp_abbrev);
offset = temp_offset;
}
}
is.setstate(err);
}
}
} // namespace detail
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp)
{
std::basic_string<CharT, Traits> abbrev;
std::chrono::minutes offset{};
detail::parse(is, format, tp, abbrev, offset);
if (!is.fail())
tp = floor<Duration>(tp - offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev)
{
std::chrono::minutes offset{};
detail::parse(is, format, tp, abbrev, offset);
if (!is.fail())
tp = floor<Duration>(tp - offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp,
std::chrono::minutes& offset)
{
std::basic_string<CharT, Traits> abbrev;
detail::parse(is, format, tp, abbrev, offset);
if (!is.fail())
tp = floor<Duration>(tp - offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev, std::chrono::minutes& offset)
{
detail::parse(is, format, tp, abbrev, offset);
if (!is.fail())
tp = floor<Duration>(tp - offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp,
std::chrono::minutes& offset, std::basic_string<CharT, Traits>& abbrev)
{
detail::parse(is, format, tp, abbrev, offset);
if (!is.fail())
tp = floor<Duration>(tp - offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp)
{
sys_time<Duration> st;
std::basic_string<CharT, Traits> abbrev;
std::chrono::minutes offset{};
detail::parse(is, format, st, abbrev, offset);
if (!is.fail())
tp = local_time<Duration>{st.time_since_epoch()};
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev)
{
sys_time<Duration> st;
std::chrono::minutes offset{};
detail::parse(is, format, st, abbrev, offset);
if (!is.fail())
tp = local_time<Duration>{st.time_since_epoch()};
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp,
std::chrono::minutes& offset)
{
sys_time<Duration> st;
std::basic_string<CharT, Traits> abbrev;
detail::parse(is, format, st, abbrev, offset);
if (!is.fail())
tp = local_time<Duration>{st.time_since_epoch()};
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev, std::chrono::minutes& offset)
{
sys_time<Duration> st;
detail::parse(is, format, st, abbrev, offset);
if (!is.fail())
tp = local_time<Duration>{st.time_since_epoch()};
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is,
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp,
std::chrono::minutes& offset, std::basic_string<CharT, Traits>& abbrev)
{
sys_time<Duration> st;
detail::parse(is, format, st, abbrev, offset);
if (!is.fail())
tp = local_time<Duration>{st.time_since_epoch()};
}
// const CharT* formats
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp)
{
parse(is, std::basic_string<CharT, Traits>(format), tp);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, abbrev);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp,
std::chrono::minutes& offset)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev, std::chrono::minutes& offset)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, abbrev, offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp,
std::chrono::minutes& offset, std::basic_string<CharT, Traits>& abbrev)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, abbrev, offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
local_time<Duration>& tp)
{
parse(is, std::basic_string<CharT, Traits>(format), tp);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
local_time<Duration>& tp, std::basic_string<CharT, Traits>& abbrev)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, abbrev);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
local_time<Duration>& tp, std::chrono::minutes& offset)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
local_time<Duration>& tp, std::basic_string<CharT, Traits>& abbrev,
std::chrono::minutes& offset)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, abbrev, offset);
}
template <class CharT, class Traits, class Duration>
inline
void
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
local_time<Duration>& tp, std::chrono::minutes& offset,
std::basic_string<CharT, Traits>& abbrev)
{
parse(is, std::basic_string<CharT, Traits>(format), tp, abbrev, offset);
tp.get_local_time(), &info.abbrev, &info.offset);
}
} // namespace date