Rewrite format and parse in terms of detail::fields<Duration>

* Add format and parse to utc_time<Duration>.
* Added more tests.
This commit is contained in:
Howard Hinnant 2017-02-25 20:44:59 -05:00
parent 3233cbaf9a
commit e9d36c6200
13 changed files with 1205 additions and 861 deletions

1272
date.h

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,145 @@
// The MIT License (MIT)
//
// Copyright (c) 2017 Howard Hinnant
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// template <class Duration,
// unsigned w = width<std::common_type<
// Duration,
// std::chrono::seconds>::type::period::den>::value>
// class decimal_format_seconds
// {
// public:
// using precision = typename make_precision<w>::type;
// static auto constexpr width = make_precision<w>::width;
//
// private:
// std::chrono::seconds s_;
// precision sub_s_;
//
// public:
// constexpr explicit decimal_format_seconds(const Duration& d) noexcept;
//
// constexpr std::chrono::seconds& seconds() noexcept;
// constexpr std::chrono::seconds seconds() const noexcept;
// constexpr precision subseconds() const noexcept;
// constexpr precision to_duration() const noexcept;
//
// template <class CharT, class Traits>
// friend
// std::basic_ostream<CharT, Traits>&
// operator<<(std::basic_ostream<CharT, Traits>& os, const decimal_format_seconds& x);
// };
#include "date.h"
#include <cassert>
#include <sstream>
#include <type_traits>
using fortnights = std::chrono::duration<date::weeks::rep,
std::ratio_multiply<std::ratio<2>,
date::weeks::period>>;
using microfortnights = std::chrono::duration<std::int64_t,
std::ratio_multiply<fortnights::period,
std::micro>>;
int
main()
{
using namespace date::detail;
using namespace std;
using namespace std::chrono;
{
using D = decimal_format_seconds<minutes>;
static_assert(is_same<D::precision, seconds>{}, "");
static_assert(D::width == 0, "");
D dfs{minutes{3}};
assert(dfs.seconds() == seconds{180});
assert(dfs.to_duration() == seconds{180});
ostringstream out;
out << dfs;
assert(out.str() == "180");
}
{
using D = decimal_format_seconds<seconds>;
static_assert(is_same<D::precision, seconds>{}, "");
static_assert(D::width == 0, "");
D dfs{seconds{3}};
assert(dfs.seconds() == seconds{3});
assert(dfs.to_duration() == seconds{3});
ostringstream out;
out << dfs;
assert(out.str() == "03");
}
{
using D = decimal_format_seconds<milliseconds>;
static_assert(D::width == 3, "");
static_assert(is_same<D::precision, make_precision<D::width>::type>{}, "");
D dfs{seconds{3}};
assert(dfs.seconds() == seconds{3});
assert(dfs.to_duration() == seconds{3});
assert(dfs.subseconds() == milliseconds{0});
ostringstream out;
out << dfs;
assert(out.str() == "03.000");
}
{
using D = decimal_format_seconds<milliseconds>;
static_assert(D::width == 3, "");
static_assert(is_same<D::precision, make_precision<D::width>::type>{}, "");
D dfs{milliseconds{3}};
assert(dfs.seconds() == seconds{0});
assert(dfs.to_duration() == milliseconds{3});
assert(dfs.subseconds() == milliseconds{3});
ostringstream out;
out << dfs;
assert(out.str() == "00.003");
}
{
using D = decimal_format_seconds<microfortnights>;
static_assert(D::width == 4, "");
using S = make_precision<D::width>::type;
static_assert(is_same<D::precision, S>{}, "");
D dfs{microfortnights{3}};
assert(dfs.seconds() == seconds{3});
assert(dfs.to_duration() == S{36288});
assert(dfs.subseconds() == S{6288});
ostringstream out;
out << dfs;
assert(out.str() == "03.6288");
}
{
using CT = common_type<seconds, microfortnights>::type;
using D = decimal_format_seconds<CT>;
static_assert(D::width == 4, "");
using S = make_precision<D::width>::type;
static_assert(is_same<D::precision, S>{}, "");
D dfs{microfortnights{3}};
assert(dfs.seconds() == seconds{3});
assert(dfs.to_duration() == S{36288});
assert(dfs.subseconds() == S{6288});
ostringstream out;
out << dfs;
assert(out.str() == "03.6288");
}
}

View File

@ -0,0 +1,63 @@
// The MIT License (MIT)
//
// Copyright (c) 2017 Howard Hinnant
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// template <unsigned w>
// struct make_precision
// {
// using type = std::chrono::duration<std::int64_t,
// std::ratio<1, static_pow10<w>::value>>;
// static constexpr unsigned width = w;
// };
#include "date.h"
#include <cstdint>
#include <type_traits>
int
main()
{
using namespace date::detail;
using namespace std;
using namespace std::chrono;
static_assert(make_precision<0>::width == 0, "");
static_assert(is_same<make_precision<0>::type, duration<int64_t, ratio<1, 1>>>{}, "");
static_assert(make_precision<1>::width == 1, "");
static_assert(is_same<make_precision<1>::type, duration<int64_t, ratio<1, 10>>>{}, "");
static_assert(make_precision<2>::width == 2, "");
static_assert(is_same<make_precision<2>::type, duration<int64_t, ratio<1, 100>>>{}, "");
static_assert(make_precision<3>::width == 3, "");
static_assert(is_same<make_precision<3>::type, duration<int64_t, ratio<1, 1000>>>{}, "");
static_assert(make_precision<18>::width == 18, "");
static_assert(is_same<make_precision<18>::type, duration<int64_t, ratio<1, 1000000000000000000>>>{}, "");
static_assert(make_precision<19>::width == 6, "");
static_assert(is_same<make_precision<19>::type, microseconds>{}, "");
static_assert(make_precision<20>::width == 6, "");
static_assert(is_same<make_precision<20>::type, microseconds>{}, "");
}

View File

@ -0,0 +1,50 @@
// The MIT License (MIT)
//
// Copyright (c) 2017 Howard Hinnant
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// template <unsigned exp>
// struct static_pow10
// {
// static constepxr std::uint64_t value = ...;
// };
#include "date.h"
#include <cassert>
#include <sstream>
#include <type_traits>
int
main()
{
using namespace date::detail;
static_assert(static_pow10<0>::value == 1, "");
static_assert(static_pow10<1>::value == 10, "");
static_assert(static_pow10<2>::value == 100, "");
static_assert(static_pow10<3>::value == 1000, "");
static_assert(static_pow10<4>::value == 10000, "");
static_assert(static_pow10<5>::value == 100000, "");
static_assert(static_pow10<6>::value == 1000000, "");
static_assert(static_pow10<7>::value == 10000000, "");
static_assert(static_pow10<8>::value == 100000000, "");
static_assert(static_pow10<9>::value == 1000000000, "");
static_assert(static_pow10<10>::value == 10000000000, "");
}

View File

@ -0,0 +1,64 @@
// The MIT License (MIT)
//
// Copyright (c) 2017 Howard Hinnant
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// width<n>::value is the number of fractional decimal digits in 1/n
// width<0>::value and width<1>::value are defined to be 0
// If 1/n takes more than 18 fractional decimal digits,
// the result is truncated to 19.
// Example: width<2>::value == 1
// Example: width<3>::value == 19
// Example: width<4>::value == 2
// Example: width<10>::value == 1
// Example: width<1000>::value == 3
// template <std::uint64_t n>
//
// struct width
// {
// static constexpr unsigned value = ...;
// };
#include "date.h"
#include <cassert>
#include <sstream>
#include <type_traits>
int
main()
{
using namespace date::detail;
static_assert(width<0>::value == 0, "");
static_assert(width<1>::value == 0, "");
static_assert(width<2>::value == 1, "");
static_assert(width<3>::value == 19, "");
static_assert(width<4>::value == 2, "");
static_assert(width<5>::value == 1, "");
static_assert(width<6>::value == 19, "");
static_assert(width<7>::value == 19, "");
static_assert(width<8>::value == 3, "");
static_assert(width<9>::value == 19, "");
static_assert(width<10>::value == 1, "");
static_assert(width<100>::value == 2, "");
static_assert(width<1000>::value == 3, "");
static_assert(width<10000>::value == 4, "");
static_assert(width<625>::value == 4, "");
}

View File

@ -34,7 +34,7 @@ test_a()
// correct abbreviation
std::istringstream in{"Sun 2016-12-11"};
sys_days tp;
parse(in, "%a %F", tp);
in >> parse("%a %F", tp);
assert(!in.fail());
assert(!in.bad());
assert(!in.eof());
@ -44,7 +44,7 @@ test_a()
// correct abbreviation
std::istringstream in{"Sun 2016-12-11"};
sys_days tp;
parse(in, "%A %F", tp);
in >> parse("%A %F", tp);
assert(!in.fail());
assert(!in.bad());
assert(!in.eof());
@ -54,7 +54,7 @@ test_a()
// correct full name
std::istringstream in{"Sunday 2016-12-11"};
sys_days tp;
parse(in, "%a %F", tp);
in >> parse("%a %F", tp);
assert(!in.fail());
assert(!in.bad());
assert(!in.eof());
@ -64,7 +64,7 @@ test_a()
// correct full name
std::istringstream in{"Sunday 2016-12-11"};
sys_days tp;
parse(in, "%A %F", tp);
in >> parse("%A %F", tp);
assert(!in.fail());
assert(!in.bad());
assert(!in.eof());
@ -74,7 +74,7 @@ test_a()
// not a valid name
std::istringstream in{"Dec 2016-12-11"};
sys_days tp;
parse(in, "%a %F", tp);
in >> parse("%a %F", tp);
assert( in.fail());
assert(!in.bad());
assert(!in.eof());
@ -84,7 +84,7 @@ test_a()
// wrong name
std::istringstream in{"Sat 2016-12-11"};
sys_days tp;
parse(in, "%a %F", tp);
in >> parse("%a %F", tp);
assert( in.fail());
assert(!in.bad());
assert(!in.eof());
@ -94,7 +94,7 @@ test_a()
// extra ws in input
std::istringstream in{"Sun 2016-12-11"};
sys_days tp;
parse(in, "%a %F", tp);
in >> parse("%a %F", tp);
assert(!in.fail());
assert(!in.bad());
assert(!in.eof());
@ -104,7 +104,7 @@ test_a()
// extra ws in format
std::istringstream in{"Sun 2016-12-11"};
sys_days tp;
parse(in, "%a %F", tp);
in >> parse("%a %F", tp);
assert(!in.fail());
assert(!in.bad());
assert(!in.eof());
@ -120,7 +120,7 @@ test_b()
// correct abbreviation
std::istringstream in{"Dec 11 2016"};
sys_days tp;
parse(in, "%b %d %Y", tp);
in >> parse("%b %d %Y", tp);
assert(!in.fail());
assert(!in.bad());
assert(!in.eof());
@ -130,7 +130,7 @@ test_b()
// correct abbreviation
std::istringstream in{"Dec 11 2016"};
sys_days tp;
parse(in, "%B %d %Y", tp);
in >> parse("%B %d %Y", tp);
assert(!in.fail());
assert(!in.bad());
assert(!in.eof());
@ -140,7 +140,7 @@ test_b()
// correct abbreviation
std::istringstream in{"Dec 11 2016"};
sys_days tp;
parse(in, "%h %d %Y", tp);
in >> parse("%h %d %Y", tp);
assert(!in.fail());
assert(!in.bad());
assert(!in.eof());
@ -150,7 +150,7 @@ test_b()
// correct full name
std::istringstream in{"December 11 2016"};
sys_days tp;
parse(in, "%b %d %Y", tp);
in >> parse("%b %d %Y", tp);
assert(!in.fail());
assert(!in.bad());
assert(!in.eof());
@ -160,7 +160,7 @@ test_b()
// correct full name
std::istringstream in{"December 11 2016"};
sys_days tp;
parse(in, "%B %d %Y", tp);
in >> parse("%B %d %Y", tp);
assert(!in.fail());
assert(!in.bad());
assert(!in.eof());
@ -170,7 +170,7 @@ test_b()
// correct full name
std::istringstream in{"December 11 2016"};
sys_days tp;
parse(in, "%h %d %Y", tp);
in >> parse("%h %d %Y", tp);
assert(!in.fail());
assert(!in.bad());
assert(!in.eof());
@ -180,7 +180,7 @@ test_b()
// incorrect abbreviation
std::istringstream in{"Dece 11 2016"};
sys_days tp;
parse(in, "%b %d %Y", tp);
in >> parse("%b %d %Y", tp);
assert( in.fail());
assert(!in.bad());
assert(!in.eof());
@ -197,7 +197,7 @@ test_c()
// correct abbreviation
std::istringstream in{"Sun Dec 11 14:02:43 2016"};
sys_seconds tp;
parse(in, "%c", tp);
in >> parse("%c", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + hours{14} + minutes{2} + seconds{43});
@ -213,7 +213,7 @@ test_x()
// correct abbreviation
std::istringstream in{"12/11/16"};
sys_seconds tp;
parse(in, "%x", tp);
in >> parse("%x", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11});
@ -229,7 +229,7 @@ test_X()
// correct abbreviation
std::istringstream in{"2016-12-11 14:02:43"};
sys_seconds tp;
parse(in, "%F %X", tp);
in >> parse("%F %X", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + hours{14} + minutes{2} + seconds{43});
@ -244,7 +244,7 @@ test_C()
{
std::istringstream in{"20 16 12 11"};
sys_days tp;
parse(in, "%C %y %m %d", tp);
in >> parse("%C %y %m %d", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == 2016_y/12/11);
@ -252,7 +252,7 @@ test_C()
{
std::istringstream in{"-2 1 12 11"};
sys_days tp;
parse(in, "%C %y %m %d", tp);
in >> parse("%C %y %m %d", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == -101_y/12/11);
@ -260,7 +260,7 @@ test_C()
{
std::istringstream in{"-1 0 12 11"};
sys_days tp;
parse(in, "%C %y %m %d", tp);
in >> parse("%C %y %m %d", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == -100_y/12/11);
@ -268,7 +268,7 @@ test_C()
{
std::istringstream in{"-1 99 12 11"};
sys_days tp;
parse(in, "%C %y %m %d", tp);
in >> parse("%C %y %m %d", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == -99_y/12/11);
@ -276,7 +276,7 @@ test_C()
{
std::istringstream in{"-1 1 12 11"};
sys_days tp;
parse(in, "%C %y %m %d", tp);
in >> parse("%C %y %m %d", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == -1_y/12/11);
@ -284,7 +284,7 @@ test_C()
{
std::istringstream in{"0 0 12 11"};
sys_days tp;
parse(in, "%C %y %m %d", tp);
in >> parse("%C %y %m %d", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == 0_y/12/11);
@ -292,7 +292,7 @@ test_C()
{
std::istringstream in{"0 1 12 11"};
sys_days tp;
parse(in, "%C %y %m %d", tp);
in >> parse("%C %y %m %d", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == 1_y/12/11);
@ -300,7 +300,7 @@ test_C()
{
std::istringstream in{"0 99 12 11"};
sys_days tp;
parse(in, "%C %y %m %d", tp);
in >> parse("%C %y %m %d", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == 99_y/12/11);
@ -308,7 +308,7 @@ test_C()
{
std::istringstream in{"1 0 12 11"};
sys_days tp;
parse(in, "%C %y %m %d", tp);
in >> parse("%C %y %m %d", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == 100_y/12/11);
@ -316,7 +316,7 @@ test_C()
{
std::istringstream in{"1 1 12 11"};
sys_days tp;
parse(in, "%C %y %m %d", tp);
in >> parse("%C %y %m %d", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == 101_y/12/11);
@ -331,7 +331,7 @@ test_d()
{
std::istringstream in{"2016 09 12"};
sys_days tp;
parse(in, "%Y %d %m", tp);
in >> parse("%Y %d %m", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == 2016_y/12/9);
@ -339,7 +339,7 @@ test_d()
{
std::istringstream in{"2016 09 12"};
sys_days tp;
parse(in, "%Y %e %m", tp);
in >> parse("%Y %e %m", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == 2016_y/12/9);
@ -347,7 +347,7 @@ test_d()
{
std::istringstream in{"2016 9 12"};
sys_days tp;
parse(in, "%Y %d %m", tp);
in >> parse("%Y %d %m", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == 2016_y/12/9);
@ -355,7 +355,7 @@ test_d()
{
std::istringstream in{"2016 9 12"};
sys_days tp;
parse(in, "%Y %e %m", tp);
in >> parse("%Y %e %m", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == 2016_y/12/9);
@ -370,7 +370,7 @@ test_D()
{
std::istringstream in{"12/11/16"};
sys_days tp;
parse(in, "%D", tp);
in >> parse("%D", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == 2016_y/12/11);
@ -385,7 +385,7 @@ test_F()
{
std::istringstream in{"2016-12-13"};
sys_days tp;
parse(in, "%F", tp);
in >> parse("%F", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == 2016_y/12/13);
@ -400,7 +400,7 @@ test_H()
{
std::istringstream in{"2016-12-11 15"};
sys_time<hours> tp;
parse(in, "%F %H", tp);
in >> parse("%F %H", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + hours{15});
@ -415,7 +415,7 @@ test_Ip()
{
std::istringstream in{"2016-12-11 1 pm"};
sys_time<hours> tp;
parse(in, "%F %I %p", tp);
in >> parse("%F %I %p", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + hours{13});
@ -423,7 +423,7 @@ test_Ip()
{
std::istringstream in{"2016-12-11 1 am"};
sys_time<hours> tp;
parse(in, "%F %I %p", tp);
in >> parse("%F %I %p", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + hours{1});
@ -438,7 +438,7 @@ test_j()
{
std::istringstream in{"2016 361"};
sys_days tp;
parse(in, "%Y %j", tp);
in >> parse("%Y %j", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/26});
@ -453,7 +453,7 @@ test_m()
{
std::istringstream in{"2016 12 09"};
sys_days tp;
parse(in, "%Y %d %m", tp);
in >> parse("%Y %d %m", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == 2016_y/9/12);
@ -461,7 +461,7 @@ test_m()
{
std::istringstream in{"2016 12 9"};
sys_days tp;
parse(in, "%Y %d %m", tp);
in >> parse("%Y %d %m", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == 2016_y/9/12);
@ -476,7 +476,7 @@ test_M()
{
std::istringstream in{"2016-12-11 15"};
sys_time<minutes> tp;
parse(in, "%F %M", tp);
in >> parse("%F %M", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + minutes{15});
@ -491,7 +491,7 @@ test_S()
{
std::istringstream in{"2016-12-11 15"};
sys_seconds tp;
parse(in, "%F %S", tp);
in >> parse("%F %S", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + seconds{15});
@ -499,7 +499,7 @@ test_S()
{
std::istringstream in{"2016-12-11 15.001"};
sys_time<milliseconds> tp;
parse(in, "%F %S", tp);
in >> parse("%F %S", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + seconds{15} + milliseconds{1});
@ -514,7 +514,7 @@ test_T()
{
std::istringstream in{"2016-12-11 15:43:22"};
sys_seconds tp;
parse(in, "%F %T", tp);
in >> parse("%F %T", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + hours{15} + minutes{43} + seconds{22});
@ -522,7 +522,7 @@ test_T()
{
std::istringstream in{"2016-12-11 15:43:22.001"};
sys_time<milliseconds> tp;
parse(in, "%F %T", tp);
in >> parse("%F %T", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + hours{15} + minutes{43} + seconds{22} +
@ -531,11 +531,19 @@ test_T()
{
std::istringstream in{"2016-12-11 15:43:22"};
sys_time<milliseconds> tp;
parse(in, "%F %T", tp);
in >> parse("%F %T", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + hours{15} + minutes{43} + seconds{22});
}
{
std::istringstream in{"15:43:22.001"};
milliseconds d;
in >> parse("%T", d);
assert(!in.fail());
assert(!in.bad());
assert(d == hours{15} + minutes{43} + seconds{22} + milliseconds{1});
}
}
void
@ -546,7 +554,7 @@ test_p()
{
std::istringstream in{"2016-12-11 11pm"};
sys_time<hours> tp;
parse(in, "%F %I%p", tp);
in >> parse("%F %I%p", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + hours{23});
@ -561,7 +569,7 @@ test_r()
{
std::istringstream in{"2016-12-26 1:36:57 pm"};
sys_seconds tp;
parse(in, "%F %r", tp);
in >> parse("%F %r", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/26} + hours{13} + minutes{36} + seconds{57});
@ -576,7 +584,7 @@ test_R()
{
std::istringstream in{"2016-12-26 13:36"};
sys_seconds tp;
parse(in, "%F %R", tp);
in >> parse("%F %R", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/26} + hours{13} + minutes{36});
@ -591,7 +599,7 @@ test_U()
{
std::istringstream in{"2016-52-1"};
sys_days tp;
parse(in, "%Y-%U-%w", tp);
in >> parse("%Y-%U-%w", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/26});
@ -606,7 +614,7 @@ test_W()
{
std::istringstream in{"2016-52-1"};
sys_days tp;
parse(in, "%Y-%W-%w", tp);
in >> parse("%Y-%W-%w", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/26});
@ -621,7 +629,7 @@ test_GV()
{
std::istringstream in{"2016-52-1"};
sys_days tp;
parse(in, "%G-%V-%w", tp);
in >> parse("%G-%V-%w", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/26});
@ -629,7 +637,7 @@ test_GV()
{
std::istringstream in{"2016-52-1"};
sys_days tp;
parse(in, "%G-%V-%w", tp);
in >> parse("%G-%V-%w", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/26});
@ -637,7 +645,7 @@ test_GV()
{
std::istringstream in{"20 16-52-1"};
sys_days tp;
parse(in, "%C %g-%V-%w", tp);
in >> parse("%C %g-%V-%w", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/26});
@ -645,7 +653,7 @@ test_GV()
{
std::istringstream in{"20 16-52-1"};
sys_days tp;
parse(in, "%C %g-%V-%u", tp);
in >> parse("%C %g-%V-%u", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/26});
@ -660,7 +668,7 @@ test_z()
{
std::istringstream in{"2016-12-26 15:53:22 -0500"};
sys_seconds tp;
parse(in, "%F %T %z", tp);
in >> parse("%F %T %z", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/26} + hours{20} + minutes{53} + seconds{22});
@ -668,7 +676,7 @@ test_z()
{
std::istringstream in{"2016-12-26 15:53:22 -0500"};
local_seconds tp;
parse(in, "%F %T %z", tp);
in >> parse("%F %T %z", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == local_days{2016_y/12/26} + hours{15} + minutes{53} + seconds{22});
@ -676,7 +684,7 @@ test_z()
{
std::istringstream in{"2016-12-26 15:53:22 -05:00"};
sys_seconds tp;
parse(in, "%F %T %Ez", tp);
in >> parse("%F %T %Ez", tp);
assert(!in.fail());
assert(!in.bad());
assert(tp == sys_days{2016_y/12/26} + hours{20} + minutes{53} + seconds{22});
@ -692,7 +700,7 @@ test_Z()
std::string a;
std::istringstream in{"2016-12-26 15:53:22 word"};
local_seconds tp;
parse(in, "%F %T %Z", tp, a);
in >> parse("%F %T %Z", tp, a);
assert(!in.fail());
assert(!in.bad());
assert(tp == local_days{2016_y/12/26} + hours{15} + minutes{53} + seconds{22});

View File

@ -60,7 +60,7 @@ main()
static_assert(is_same<tod::precision, hours>{}, "");
static_assert( is_trivially_destructible<tod>{}, "");
static_assert(!is_default_constructible<tod>{}, "");
static_assert( is_default_constructible<tod>{}, "");
static_assert( is_trivially_copy_constructible<tod>{}, "");
static_assert( is_trivially_copy_assignable<tod>{}, "");
static_assert( is_trivially_move_constructible<tod>{}, "");

View File

@ -0,0 +1,119 @@
// The MIT License (MIT)
//
// Copyright (c) 2015, 2016 Howard Hinnant
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// enum {am = 1, pm};
// template <class Rep, class Period>
// class time_of_day<std::chrono::duration<Rep, Period>>
// {
// public:
// using precision = std::chrono::std::chrono::duration<Rep, Period>;
//
// constexpr explicit time_of_day(precision since_midnight) noexcept;
// constexpr time_of_day(std::chrono::hours h, std::chrono::minutes m,
// std::chrono::seconds s, precision sub_s,
// unsigned md) noexcept;
//
// constexpr std::chrono::hours hours() const noexcept;
// constexpr std::chrono::minutes minutes() const noexcept;
// constexpr std::chrono::seconds seconds() const noexcept;
// constexpr precision subseconds() const noexcept;
// constexpr unsigned mode() const noexcept;
//
// constexpr explicit operator precision() const noexcept;
// constexpr precision to_duration() const noexcept;
//
// void make24() noexcept;
// void make12() noexcept;
// };
// template <class Rep, class Period>
// std::ostream&
// operator<<(std::ostream& os, const time_of_day<std::chrono::duration<Rep, Period>>& t);
#include "date.h"
#include <cassert>
#include <sstream>
#include <type_traits>
using fortnights = std::chrono::duration<date::weeks::rep,
std::ratio_multiply<std::ratio<2>,
date::weeks::period>>;
using microfortnights = std::chrono::duration<std::int64_t,
std::ratio_multiply<fortnights::period,
std::micro>>;
int
main()
{
using namespace date;
using namespace std;
using namespace std::chrono;
using tod = time_of_day<typename common_type<hours, minutes, microfortnights>::type>;
static_assert(is_same<tod::precision::period, ratio<1, 10000>>{}, "");
static_assert( is_trivially_destructible<tod>{}, "");
static_assert( is_default_constructible<tod>{}, "");
static_assert( is_trivially_copy_constructible<tod>{}, "");
static_assert( is_trivially_copy_assignable<tod>{}, "");
static_assert( is_trivially_move_constructible<tod>{}, "");
static_assert( is_trivially_move_assignable<tod>{}, "");
static_assert(is_constructible<tod, microfortnights>{}, "");
static_assert(!is_convertible<microfortnights, tod>{}, "");
static_assert(is_nothrow_constructible<tod::precision, tod>{}, "");
static_assert(!is_convertible<tod, tod::precision>{}, "");
constexpr tod t1 = tod{hours{13} + minutes{7} + microfortnights{5}};
static_assert(t1.hours() == hours{13}, "");
static_assert(t1.minutes() == minutes{7}, "");
static_assert(t1.seconds() == seconds{6}, "");
static_assert(t1.subseconds() == tod::precision{480}, "");
#if __cplusplus >= 201402
static_assert(static_cast<tod::precision>(t1) == hours{13} + minutes{7}
+ microfortnights{5}, "");
static_assert(t1.to_duration() == hours{13} + minutes{7} + microfortnights{5}, "");
#endif
auto t2 = t1;
assert(t2.hours() == t1.hours());
assert(t2.minutes() == t1.minutes());
assert(t2.seconds() == t1.seconds());
assert(t2.subseconds() == t1.subseconds());
assert(t2.to_duration() == t1.to_duration());
ostringstream os;
os << t2;
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

@ -68,7 +68,7 @@ main()
static_assert(is_same<tod::precision, milliseconds>{}, "");
static_assert( is_trivially_destructible<tod>{}, "");
static_assert(!is_default_constructible<tod>{}, "");
static_assert( is_default_constructible<tod>{}, "");
static_assert( is_trivially_copy_constructible<tod>{}, "");
static_assert( is_trivially_copy_assignable<tod>{}, "");
static_assert( is_trivially_move_constructible<tod>{}, "");

View File

@ -62,7 +62,7 @@ main()
static_assert(is_same<tod::precision, minutes>{}, "");
static_assert( is_trivially_destructible<tod>{}, "");
static_assert(!is_default_constructible<tod>{}, "");
static_assert( is_default_constructible<tod>{}, "");
static_assert( is_trivially_copy_constructible<tod>{}, "");
static_assert( is_trivially_copy_assignable<tod>{}, "");
static_assert( is_trivially_move_constructible<tod>{}, "");

View File

@ -68,7 +68,7 @@ main()
static_assert(is_same<tod::precision, nanoseconds>{}, "");
static_assert( is_trivially_destructible<tod>{}, "");
static_assert(!is_default_constructible<tod>{}, "");
static_assert( is_default_constructible<tod>{}, "");
static_assert( is_trivially_copy_constructible<tod>{}, "");
static_assert( is_trivially_copy_assignable<tod>{}, "");
static_assert( is_trivially_move_constructible<tod>{}, "");

View File

@ -63,7 +63,7 @@ main()
static_assert(is_same<tod::precision, seconds>{}, "");
static_assert( is_trivially_destructible<tod>{}, "");
static_assert(!is_default_constructible<tod>{}, "");
static_assert( is_default_constructible<tod>{}, "");
static_assert( is_trivially_copy_constructible<tod>{}, "");
static_assert( is_trivially_copy_assignable<tod>{}, "");
static_assert( is_trivially_move_constructible<tod>{}, "");

217
tz.h
View File

@ -1108,13 +1108,20 @@ utc_clock::now()
}
template <class CharT, class Traits, class Duration>
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const utc_time<Duration>& t)
void
to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
const utc_time<Duration>& t)
{
using namespace std;
using namespace std::chrono;
using duration = typename std::common_type<Duration, seconds>::type;
using CT = typename common_type<Duration, seconds>::type;
const string abbrev("UTC");
CONSTDATA seconds offset{0};
auto const& leaps = get_tzdb().leaps;
auto tp = sys_time<duration>{t.time_since_epoch()};
auto tp = sys_time<CT>{t.time_since_epoch()};
year_month_day ymd;
time_of_day<CT> time;
seconds ls{0};
if (tp >= leaps.front())
{
auto const lt = std::upper_bound(leaps.begin(), leaps.end(), tp);
@ -1122,17 +1129,205 @@ operator<<(std::basic_ostream<CharT, Traits>& os, const utc_time<Duration>& t)
if (tp < lt[-1])
{
if (tp >= lt[-1].date() - seconds{1})
{
auto const dp = floor<days>(tp);
auto time = make_time(tp-dp);
time.seconds() += seconds{1};
return os << year_month_day(dp) << ' ' << time;
}
ls = seconds{1};
else
tp += seconds{1};
}
}
return os << tp;
auto const sd = floor<days>(tp);
ymd = sd;
time = make_time(tp - sd);
time.seconds() += ls;
detail::fields<CT> fds{ymd, time};
detail::to_stream(os, fmt, fds, &abbrev, &offset);
}
template <class CharT, class Traits, class Duration>
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const utc_time<Duration>& t)
{
to_stream(os, "%F %T", t);
return os;
}
template <class CharT, class Duration>
std::basic_string<CharT>
format(const std::locale& loc, const CharT* fmt, const utc_time<Duration>& tp)
{
std::basic_ostringstream<CharT> os;
os.imbue(loc);
to_stream(os, fmt, tp);
return os.str();
}
template <class CharT, class Duration>
std::basic_string<CharT>
format(const CharT* fmt, const utc_time<Duration>& tp)
{
std::basic_ostringstream<CharT> os;
to_stream(os, fmt, tp);
return os.str();
}
template <class CharT, class Traits, class Duration>
std::basic_string<CharT, Traits>
format(const std::locale& loc, const std::basic_string<CharT, Traits>& fmt,
const utc_time<Duration>& tp)
{
std::basic_ostringstream<CharT, Traits> os;
os.imbue(loc);
to_stream(os, fmt.c_str(), tp);
return os.str();
}
template <class CharT, class Traits, class Duration>
std::basic_string<CharT, Traits>
format(const std::basic_string<CharT, Traits>& fmt, const utc_time<Duration>& tp)
{
std::basic_ostringstream<CharT, Traits> os;
to_stream(os, fmt.c_str(), tp);
return os.str();
}
namespace detail
{
template <class Duration, class CharT, class Traits = std::char_traits<CharT>>
struct parse_utc_manip
{
const std::basic_string<CharT, Traits> format_;
utc_time<Duration>& tp_;
std::basic_string<CharT, Traits>* abbrev_;
std::chrono::minutes* offset_;
public:
parse_utc_manip(std::basic_string<CharT, Traits> format,
utc_time<Duration>& tp, std::basic_string<CharT, Traits>* abbrev = nullptr,
std::chrono::minutes* offset = nullptr)
: format_(std::move(format))
, tp_(tp)
, abbrev_(abbrev)
, offset_(offset)
{}
};
template <class Duration, class CharT, class Traits>
std::basic_istream<CharT, Traits>&
operator>>(std::basic_istream<CharT, Traits>& is,
const parse_utc_manip<Duration, CharT, Traits>& x)
{
using namespace std;
using namespace std::chrono;
using CT = typename common_type<Duration, seconds>::type;
minutes offset{};
auto offptr = x.offset_ ? x.offset_ : &offset;
fields<CT> fds{};
parse(is, x.format_.c_str(), fds, x.abbrev_, offptr);
if (!fds.ymd.ok())
is.setstate(ios::failbit);
if (!is.fail())
{
bool is_leap_second = fds.tod.seconds() == seconds{60};
if (is_leap_second)
fds.tod.seconds() -= seconds{1};
x.tp_ = to_utc_time(sys_days(fds.ymd) +
duration_cast<Duration>(fds.tod.to_duration() - *offptr));
if (is_leap_second)
x.tp_ += seconds{1};
}
return is;
}
} // namespace detail
template <class Duration, class CharT, class Traits>
inline
detail::parse_utc_manip<Duration, CharT, Traits>
parse(const std::basic_string<CharT, Traits>& format, utc_time<Duration>& tp)
{
return {format, tp};
}
template <class Duration, class CharT, class Traits>
inline
detail::parse_utc_manip<Duration, CharT, Traits>
parse(const std::basic_string<CharT, Traits>& format, utc_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev)
{
return {format, tp, &abbrev};
}
template <class Duration, class CharT, class Traits>
inline
detail::parse_utc_manip<Duration, CharT, Traits>
parse(const std::basic_string<CharT, Traits>& format, utc_time<Duration>& tp,
std::chrono::minutes& offset)
{
return {format, tp, nullptr, &offset};
}
template <class Duration, class CharT, class Traits>
inline
detail::parse_utc_manip<Duration, CharT, Traits>
parse(const std::basic_string<CharT, Traits>& format, utc_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev, std::chrono::minutes& offset)
{
return {format, tp, &abbrev, &offset};
}
template <class Duration, class CharT, class Traits>
inline
detail::parse_utc_manip<Duration, CharT, Traits>
parse(const std::basic_string<CharT, Traits>& format, utc_time<Duration>& tp,
std::chrono::minutes& offset, std::basic_string<CharT, Traits>& abbrev)
{
return {format, tp, &abbrev, &offset};
}
// const CharT* formats
template <class Duration, class CharT>
inline
detail::parse_utc_manip<Duration, CharT>
parse(const CharT* format, utc_time<Duration>& tp)
{
return {format, tp};
}
template <class Duration, class CharT, class Traits>
inline
detail::parse_utc_manip<Duration, CharT, Traits>
parse(const CharT* format, utc_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev)
{
return {format, tp, &abbrev};
}
template <class Duration, class CharT>
inline
detail::parse_utc_manip<Duration, CharT>
parse(const CharT* format, utc_time<Duration>& tp, std::chrono::minutes& offset)
{
return {format, tp, nullptr, &offset};
}
template <class Duration, class CharT, class Traits>
inline
detail::parse_utc_manip<Duration, CharT, Traits>
parse(const CharT* format, utc_time<Duration>& tp,
std::basic_string<CharT, Traits>& abbrev, std::chrono::minutes& offset)
{
return {format, tp, &abbrev, &offset};
}
template <class Duration, class CharT, class Traits>
inline
detail::parse_utc_manip<Duration, CharT, Traits>
parse(const CharT* format, utc_time<Duration>& tp,
std::chrono::minutes& offset, std::basic_string<CharT, Traits>& abbrev)
{
return {format, tp, &abbrev, &offset};
}
// tai_clock