Create %Ez & %Oz to put ':' in offset for format and parse.

This commit is contained in:
Howard Hinnant 2016-06-01 23:25:07 -04:00
parent 3293637e70
commit 09cf3bba8d

134
tz.h
View File

@ -48,6 +48,8 @@ On Windows, the names are never "Standard" so mapping is always required.
Technically any OS may use the mapping process but currently only Windows does use it. Technically any OS may use the mapping process but currently only Windows does use it.
*/ */
#include <iostream>
#ifdef _WIN32 #ifdef _WIN32
#ifndef TIMEZONE_MAPPING #ifndef TIMEZONE_MAPPING
#define TIMEZONE_MAPPING 1 #define TIMEZONE_MAPPING 1
@ -1091,31 +1093,44 @@ format(const std::locale& loc, std::basic_string<CharT, Traits> format,
// Handle these specially // Handle these specially
// %S append fractional seconds if tp has precision finer than seconds // %S append fractional seconds if tp has precision finer than seconds
// %T 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 // %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 // %Z replace with abbreviation from zone
using namespace std; using namespace std;
using namespace std::chrono; using namespace std::chrono;
auto command = false;
auto modified = false;
for (std::size_t i = 0; i < format.size(); ++i) for (std::size_t i = 0; i < format.size(); ++i)
{ {
if (format[i] == '%' && i < format.size()-1) switch (format[i])
{ {
switch (format[i+1]) 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);
format.insert(i+1, s);
i += s.size() - 1;
}
command = false;
modified = false;
break;
case 'z':
if (command)
{ {
case 'S':
case 'T':
if (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);
format.insert(i+2, s);
i += 2 + s.size() - 1;
}
break;
case 'z':
if (zone == nullptr) if (zone == nullptr)
throw std::runtime_error("Can not format local_time with %z"); throw std::runtime_error("Can not format local_time with %z");
else else
@ -1127,12 +1142,18 @@ format(const std::locale& loc, std::basic_string<CharT, Traits> format,
os << '+'; os << '+';
os << make_time(offset); os << make_time(offset);
auto s = os.str(); auto s = os.str();
s.erase(s.find(':'), 1); if (!modified)
format.replace(i, 2, s); s.erase(s.find(':'), 1);
format.replace(i - 1 - modified, 2 + modified, s);
i += s.size() - 1; i += s.size() - 1;
} }
break; }
case 'Z': command = false;
modified = false;
break;
case 'Z':
if (command && !modified)
{
if (zone == nullptr) if (zone == nullptr)
throw std::runtime_error("Can not format local_time with %z"); throw std::runtime_error("Can not format local_time with %z");
else else
@ -1142,8 +1163,14 @@ format(const std::locale& loc, std::basic_string<CharT, Traits> format,
(info.abbrev.begin(), info.abbrev.end())); (info.abbrev.begin(), info.abbrev.end()));
i += info.abbrev.size() - 1; i += info.abbrev.size() - 1;
} }
break;
} }
command = false;
modified = false;
break;
default:
command = false;
modified = false;
break;
} }
} }
auto& f = use_facet<time_put<CharT>>(loc); auto& f = use_facet<time_put<CharT>>(loc);
@ -1296,21 +1323,30 @@ parse(std::basic_istream<CharT, Traits>& is,
auto b = format.data(); auto b = format.data();
auto i = b; auto i = b;
auto e = b + format.size(); auto e = b + format.size();
auto command = false;
auto modified = false;
for (; i < e; ++i) for (; i < e; ++i)
{ {
if (*i == '%' && i < e-1) switch (*i)
{ {
switch (i[1]) case '%':
command = true;
modified = false;
break;
case 'O':
case 'E':
modified = true;
break;
case 'T':
case 'S':
if (command && !modified)
{ {
case 'T': f.get(is, 0, is, err, &tm, b, i-1);
case 'S':
f.get(is, 0, is, err, &tm, b, i);
++i;
b = i+1; b = i+1;
if (*i == 'T') if (*i == 'T')
{ {
const CharT hm[] = {'%', 'H', ':', '%', 'M', ':', 0}; const CharT hm[] = {'%', 'H', ':', '%', 'M', ':'};
f.get(is, 0, is, err, &tm, hm, hm); f.get(is, 0, is, err, &tm, hm, hm+6);
} }
if (ratio_less<typename Duration::period, ratio<1>>::value) if (ratio_less<typename Duration::period, ratio<1>>::value)
{ {
@ -1326,10 +1362,14 @@ parse(std::basic_istream<CharT, Traits>& is,
const CharT hm[] = {'%', 'S'}; const CharT hm[] = {'%', 'S'};
f.get(is, 0, is, err, &tm, hm, hm+2); f.get(is, 0, is, err, &tm, hm, hm+2);
} }
break; }
case 'z': command = false;
f.get(is, 0, is, err, &tm, b, i); modified = false;
++i; break;
case 'z':
if (command)
{
f.get(is, 0, is, err, &tm, b, i-1-modified);
b = i+1; b = i+1;
if ((err & ios_base::failbit) == 0) if ((err & ios_base::failbit) == 0)
{ {
@ -1338,12 +1378,16 @@ parse(std::basic_istream<CharT, Traits>& is,
if (!is.fail() && (sign == '+' || sign == '-')) if (!is.fail() && (sign == '+' || sign == '-'))
{ {
char h1, h0, m1, m0; char h1, h0, m1, m0;
char colon = '\0';
h1 = static_cast<char>(is.get()); h1 = static_cast<char>(is.get());
h0 = static_cast<char>(is.get()); h0 = static_cast<char>(is.get());
if (modified)
colon = static_cast<char>(is.get());
m1 = static_cast<char>(is.get()); m1 = static_cast<char>(is.get());
m0 = static_cast<char>(is.get()); m0 = static_cast<char>(is.get());
if (!is.fail() && std::isdigit(h1) && std::isdigit(h0) if (!is.fail() && std::isdigit(h1) && std::isdigit(h0)
&& std::isdigit(m1) && std::isdigit(m0)) && std::isdigit(m1) && std::isdigit(m0)
&& (!modified || colon == ':'))
{ {
temp_offset = 10*hours{h1 - '0'} + hours{h0 - '0'} + temp_offset = 10*hours{h1 - '0'} + hours{h0 - '0'} +
10*minutes{m1 - '0'} + minutes{m0 - '0'}; 10*minutes{m1 - '0'} + minutes{m0 - '0'};
@ -1356,10 +1400,14 @@ parse(std::basic_istream<CharT, Traits>& is,
else else
err |= ios_base::failbit; err |= ios_base::failbit;
} }
break; }
case 'Z': command = false;
f.get(is, 0, is, err, &tm, b, i); modified = false;
++i; break;
case 'Z':
if (command && !modified)
{
f.get(is, 0, is, err, &tm, b, i-1);
b = i+1; b = i+1;
if ((err & ios_base::failbit) == 0) if ((err & ios_base::failbit) == 0)
{ {
@ -1367,8 +1415,14 @@ parse(std::basic_istream<CharT, Traits>& is,
if (is.fail()) if (is.fail())
err |= ios_base::failbit; err |= ios_base::failbit;
} }
break;
} }
command = false;
modified = false;
break;
default:
command = false;
modified = false;
break;
} }
} }
if ((err & ios_base::failbit) == 0) if ((err & ios_base::failbit) == 0)