http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/8777ab5f/thirdparty/date/include/date/ptz.h
----------------------------------------------------------------------
diff --git a/thirdparty/date/include/date/ptz.h
b/thirdparty/date/include/date/ptz.h
new file mode 100644
index 0000000..78be1d2
--- /dev/null
+++ b/thirdparty/date/include/date/ptz.h
@@ -0,0 +1,592 @@
+#ifndef PTZ_H
+#define PTZ_H
+
+// 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.
+
+// This header allows Posix-style time zones as specified for TZ here:
+//
http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03
+//
+// Posix::time_zone can be constructed with a posix-style string and then used
in
+// a zoned_time like so:
+//
+// zoned_time<system_clock::duration, Posix::time_zone>
zt{"EST5EDT,M3.2.0,M11.1.0",
+//
system_clock::now()};
+// or:
+//
+// Posix::time_zone tz{"EST5EDT,M3.2.0,M11.1.0"};
+// zoned_time<system_clock::duration, Posix::time_zone> zt{tz,
system_clock::now()};
+//
+// Note, Posix-style time zones are not recommended for all of the reasons
described here:
+// https://stackoverflow.com/tags/timezone/info
+//
+// They are provided here as a non-trivial custom time zone example, and if
you really
+// have to have Posix time zones, you're welcome to use this one.
+
+#include "date/tz.h"
+#include <cctype>
+#include <ostream>
+#include <string>
+
+namespace Posix
+{
+
+namespace detail
+{
+
+#if HAS_STRING_VIEW
+
+using string_t = std::string_view;
+
+#else // !HAS_STRING_VIEW
+
+using string_t = std::string;
+
+#endif // !HAS_STRING_VIEW
+
+class rule;
+
+void throw_invalid(const string_t& s, unsigned i, const string_t& message);
+unsigned read_date(const string_t& s, unsigned i, rule& r);
+unsigned read_name(const string_t& s, unsigned i, std::string& name);
+unsigned read_signed_time(const string_t& s, unsigned i, std::chrono::seconds&
t);
+unsigned read_unsigned_time(const string_t& s, unsigned i,
std::chrono::seconds& t);
+unsigned read_unsigned(const string_t& s, unsigned i, unsigned limit,
unsigned& u);
+
+class rule
+{
+ enum {off, J, M, N};
+
+ date::month m_;
+ date::weekday wd_;
+ unsigned short n_ : 14;
+ unsigned short mode_ : 2;
+ std::chrono::duration<std::int32_t> time_ = std::chrono::hours{2};
+
+public:
+ rule() : mode_(off) {}
+
+ bool ok() const {return mode_ != off;}
+ date::local_seconds operator()(date::year y) const;
+
+ friend std::ostream& operator<<(std::ostream& os, const rule& r);
+ friend unsigned read_date(const string_t& s, unsigned i, rule& r);
+};
+
+inline
+date::local_seconds
+rule::operator()(date::year y) const
+{
+ using namespace date;
+ using sec = std::chrono::seconds;
+ date::local_seconds t;
+ switch (mode_)
+ {
+ case J:
+ t = local_days{y/jan/0} + days{n_ + (y.is_leap() && n_ > 59)} +
sec{time_};
+ break;
+ case M:
+ t = (n_ == 5 ? local_days{y/m_/wd_[last]} : local_days{y/m_/wd_[n_]})
+ sec{time_};
+ break;
+ case N:
+ t = local_days{y/jan/1} + days{n_} + sec{time_};
+ break;
+ default:
+ assert(!"rule called with bad mode");
+ }
+ return t;
+}
+
+inline
+std::ostream&
+operator<<(std::ostream& os, const rule& r)
+{
+ switch (r.mode_)
+ {
+ case rule::J:
+ os << 'J' << r.n_ << date::format(" %T", r.time_);
+ break;
+ case rule::M:
+ if (r.n_ == 5)
+ os << r.m_/r.wd_[date::last];
+ else
+ os << r.m_/r.wd_[r.n_];
+ os << date::format(" %T", r.time_);
+ break;
+ case rule::N:
+ os << r.n_ << date::format(" %T", r.time_);
+ break;
+ default:
+ break;
+ }
+ return os;
+}
+
+} // namespace detail
+
+class time_zone
+{
+ std::string std_abbrev_;
+ std::string dst_abbrev_ = {};
+ std::chrono::seconds offset_;
+ std::chrono::seconds save_ = std::chrono::hours{1};
+ detail::rule start_rule_;
+ detail::rule end_rule_;
+
+public:
+ explicit time_zone(const detail::string_t& name);
+
+ template <class Duration>
+ date::sys_info get_info(date::sys_time<Duration> st) const;
+ template <class Duration>
+ date::local_info get_info(date::local_time<Duration> tp) const;
+
+ template <class Duration>
+ date::sys_time<typename std::common_type<Duration,
std::chrono::seconds>::type>
+ to_sys(date::local_time<Duration> tp) const;
+
+ template <class Duration>
+ date::sys_time<typename std::common_type<Duration,
std::chrono::seconds>::type>
+ to_sys(date::local_time<Duration> tp, date::choose z) const;
+
+ template <class Duration>
+ date::local_time<typename std::common_type<Duration,
std::chrono::seconds>::type>
+ to_local(date::sys_time<Duration> tp) const;
+
+ friend std::ostream& operator<<(std::ostream& os, const time_zone& z);
+
+ const time_zone* operator->() const {return this;}
+};
+
+inline
+time_zone::time_zone(const detail::string_t& s)
+{
+ using namespace detail;
+ auto i = read_name(s, 0, std_abbrev_);
+ i = read_signed_time(s, i, offset_);
+ offset_ = -offset_;
+ if (i != s.size())
+ {
+ i = read_name(s, i, dst_abbrev_);
+ if (i != s.size())
+ {
+ if (s[i] != ',')
+ i = read_signed_time(s, i, save_);
+ if (i != s.size())
+ {
+ if (s[i] != ',')
+ throw_invalid(s, i, "Expecting end of string or ',' to
start rule");
+ ++i;
+ i = read_date(s, i, start_rule_);
+ if (i == s.size() || s[i] != ',')
+ throw_invalid(s, i, "Expecting ',' and then the ending
rule");
+ ++i;
+ i = read_date(s, i, end_rule_);
+ if (i != s.size())
+ throw_invalid(s, i, "Found unexpected trailing
characters");
+ }
+ }
+ }
+}
+
+template <class Duration>
+date::sys_info
+time_zone::get_info(date::sys_time<Duration> st) const
+{
+ using namespace date;
+ using namespace std::chrono;
+ sys_info r{};
+ r.offset = offset_;
+ if (start_rule_.ok())
+ {
+ auto y = year_month_day{floor<days>(st)}.year();
+ auto start = sys_seconds{(start_rule_(y) -
offset_).time_since_epoch()};
+ auto end = sys_seconds{(end_rule_(y) - (offset_ +
save_)).time_since_epoch()};
+ if (start <= st && st < end)
+ {
+ r.begin = start;
+ r.end = end;
+ r.offset += save_;
+ r.save = ceil<minutes>(save_);
+ r.abbrev = dst_abbrev_;
+ }
+ else if (st < start)
+ {
+ r.begin = sys_seconds{(end_rule_(y-years{1}) -
+ (offset_ + save_)).time_since_epoch()};
+ r.end = start;
+ r.abbrev = std_abbrev_;
+ }
+ else // st >= end
+ {
+ r.begin = end;
+ r.end = sys_seconds{(start_rule_(y+years{1}) -
offset_).time_since_epoch()};
+ r.abbrev = std_abbrev_;
+ }
+ }
+ else // constant offset
+ {
+ r.begin = sys_days{year::min()/jan/1};
+ r.end = sys_days{year::max()/dec/last};
+ r.abbrev = std_abbrev_;
+ }
+ return r;
+}
+
+template <class Duration>
+date::local_info
+time_zone::get_info(date::local_time<Duration> tp) const
+{
+ using namespace date;
+ using namespace std::chrono;
+ local_info r{};
+ if (start_rule_.ok())
+ {
+ auto y = year_month_day{floor<days>(tp)}.year();
+ auto start = sys_seconds{(start_rule_(y) -
offset_).time_since_epoch()};
+ auto end = sys_seconds{(end_rule_(y) - (offset_ +
save_)).time_since_epoch()};
+ auto utcs = sys_seconds{floor<seconds>(tp -
offset_).time_since_epoch()};
+ auto utcd = sys_seconds{floor<seconds>(tp - (offset_ +
save_)).time_since_epoch()};
+ if ((utcs < start) != (utcd < start))
+ {
+ r.first.begin = sys_seconds{(end_rule_(y-years{1}) -
+ (offset_ +
save_)).time_since_epoch()};
+ r.first.end = start;
+ r.first.offset = offset_;
+ r.first.abbrev = std_abbrev_;
+ r.second.begin = start;
+ r.second.end = end;
+ r.second.abbrev = dst_abbrev_;
+ r.second.offset = offset_ + save_;
+ r.second.save = ceil<minutes>(save_);
+ r.result = save_ > seconds{0} ? local_info::nonexistent
+ : local_info::ambiguous;
+ }
+ else if ((utcs < end) != (utcd < end))
+ {
+ r.first.begin = start;
+ r.first.end = end;
+ r.first.offset = offset_ + save_;
+ r.first.save = ceil<minutes>(save_);
+ r.first.abbrev = dst_abbrev_;
+ r.second.begin = end;
+ r.second.end = sys_seconds{(start_rule_(y+years{1}) -
+ offset_).time_since_epoch()};
+ r.second.abbrev = std_abbrev_;
+ r.second.offset = offset_;
+ r.result = save_ > seconds{0} ? local_info::ambiguous
+ : local_info::nonexistent;
+ }
+ else if (utcs < start)
+ {
+ r.first.begin = sys_seconds{(end_rule_(y-years{1}) -
+ (offset_ + save_)).time_since_epoch()};
+ r.first.end = start;
+ r.first.offset = offset_;
+ r.first.abbrev = std_abbrev_;
+ }
+ else if (utcs < end)
+ {
+ r.first.begin = start;
+ r.first.end = end;
+ r.first.offset = offset_ + save_;
+ r.first.save = ceil<minutes>(save_);
+ r.first.abbrev = dst_abbrev_;
+ }
+ else
+ {
+ r.first.begin = end;
+ r.first.end = sys_seconds{(start_rule_(y+years{1}) -
+ offset_).time_since_epoch()};
+ r.first.abbrev = std_abbrev_;
+ r.first.offset = offset_;
+ }
+ }
+ else // constant offset
+ {
+ r.first.begin = sys_days{year::min()/jan/1};
+ r.first.end = sys_days{year::max()/dec/last};
+ r.first.abbrev = std_abbrev_;
+ r.first.offset = offset_;
+ }
+ return r;
+}
+
+template <class Duration>
+date::sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
+time_zone::to_sys(date::local_time<Duration> tp) const
+{
+ using namespace date;
+ auto i = get_info(tp);
+ if (i.result == local_info::nonexistent)
+ throw nonexistent_local_time(tp, i);
+ else if (i.result == local_info::ambiguous)
+ throw ambiguous_local_time(tp, i);
+ return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset;
+}
+
+template <class Duration>
+date::sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
+time_zone::to_sys(date::local_time<Duration> tp, date::choose z) const
+{
+ using namespace date;
+ auto i = get_info(tp);
+ if (i.result == local_info::nonexistent)
+ {
+ return i.first.end;
+ }
+ else if (i.result == local_info::ambiguous)
+ {
+ if (z == choose::latest)
+ return sys_time<Duration>{tp.time_since_epoch()} - i.second.offset;
+ }
+ return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset;
+}
+
+template <class Duration>
+date::local_time<typename std::common_type<Duration,
std::chrono::seconds>::type>
+time_zone::to_local(date::sys_time<Duration> tp) const
+{
+ using namespace date;
+ using namespace std::chrono;
+ using LT = local_time<typename std::common_type<Duration, seconds>::type>;
+ auto i = get_info(tp);
+ return LT{(tp + i.offset).time_since_epoch()};
+}
+
+inline
+std::ostream&
+operator<<(std::ostream& os, const time_zone& z)
+{
+ using date::operator<<;
+ os << '{';
+ os << z.std_abbrev_ << ", " << z.dst_abbrev_ << date::format(", %T, ",
z.offset_)
+ << date::format("%T, [", z.save_) << z.start_rule_ << ", " <<
z.end_rule_ << ")}";
+ return os;
+}
+
+namespace detail
+{
+
+inline
+void
+throw_invalid(const string_t& s, unsigned i, const string_t& message)
+{
+ throw std::runtime_error(std::string("Invalid time_zone initializer.\n") +
+ std::string(message) + ":\n" +
+ s + '\n' +
+ "\x1b[1;32m" +
+ std::string(i, '~') + '^' +
+ std::string(s.size()-i-1, '~') +
+ "\x1b[0m");
+}
+
+inline
+unsigned
+read_date(const string_t& s, unsigned i, rule& r)
+{
+ using namespace date;
+ if (i == s.size())
+ throw_invalid(s, i, "Expected rule but found end of string");
+ if (s[i] == 'J')
+ {
+ ++i;
+ unsigned n;
+ i = read_unsigned(s, i, 3, n);
+ r.mode_ = rule::J;
+ r.n_ = n;
+ }
+ else if (s[i] == 'M')
+ {
+ ++i;
+ unsigned m;
+ i = read_unsigned(s, i, 2, m);
+ if (i == s.size() || s[i] != '.')
+ throw_invalid(s, i, "Expected '.' after month");
+ ++i;
+ unsigned n;
+ i = read_unsigned(s, i, 1, n);
+ if (i == s.size() || s[i] != '.')
+ throw_invalid(s, i, "Expected '.' after weekday index");
+ ++i;
+ unsigned wd;
+ i = read_unsigned(s, i, 1, wd);
+ r.mode_ = rule::M;
+ r.m_ = month{m};
+ r.wd_ = weekday{wd};
+ r.n_ = n;
+ }
+ else if (std::isdigit(s[i]))
+ {
+ unsigned n;
+ i = read_unsigned(s, i, 3, n);
+ r.mode_ = rule::N;
+ r.n_ = n;
+ }
+ else
+ throw_invalid(s, i, "Expected 'J', 'M', or a digit to start rule");
+ if (i != s.size() && s[i] == '/')
+ {
+ ++i;
+ std::chrono::seconds t;
+ i = read_unsigned_time(s, i, t);
+ r.time_ = t;
+ }
+ return i;
+}
+
+inline
+unsigned
+read_name(const string_t& s, unsigned i, std::string& name)
+{
+ if (i == s.size())
+ throw_invalid(s, i, "Expected a name but found end of string");
+ if (s[i] == '<')
+ {
+ ++i;
+ while (true)
+ {
+ if (i == s.size())
+ throw_invalid(s, i,
+ "Expected to find closing '>', but found end of
string");
+ if (s[i] == '>')
+ break;
+ name.push_back(s[i]);
+ ++i;
+ }
+ ++i;
+ }
+ else
+ {
+ while (i != s.size() && std::isalpha(s[i]))
+ {
+ name.push_back(s[i]);
+ ++i;
+ }
+ }
+ if (name.size() < 3)
+ throw_invalid(s, i, "Found name to be shorter than 3 characters");
+ return i;
+}
+
+inline
+unsigned
+read_signed_time(const string_t& s, unsigned i,
+ std::chrono::seconds& t)
+{
+ if (i == s.size())
+ throw_invalid(s, i, "Expected to read signed time, but found end of
string");
+ bool negative = false;
+ if (s[i] == '-')
+ {
+ negative = true;
+ ++i;
+ }
+ else if (s[i] == '+')
+ ++i;
+ i = read_unsigned_time(s, i, t);
+ if (negative)
+ t = -t;
+ return i;
+}
+
+inline
+unsigned
+read_unsigned_time(const string_t& s, unsigned i, std::chrono::seconds& t)
+{
+ using namespace std::chrono;
+ if (i == s.size())
+ throw_invalid(s, i, "Expected to read unsigned time, but found end of
string");
+ unsigned x;
+ i = read_unsigned(s, i, 2, x);
+ t = hours{x};
+ if (i != s.size() && s[i] == ':')
+ {
+ ++i;
+ i = read_unsigned(s, i, 2, x);
+ t += minutes{x};
+ if (i != s.size() && s[i] == ':')
+ {
+ ++i;
+ i = read_unsigned(s, i, 2, x);
+ t += seconds{x};
+ }
+ }
+ return i;
+}
+
+inline
+unsigned
+read_unsigned(const string_t& s, unsigned i, unsigned limit, unsigned& u)
+{
+ if (i == s.size() || !std::isdigit(s[i]))
+ throw_invalid(s, i, "Expected to find a decimal digit");
+ u = static_cast<unsigned>(s[i] - '0');
+ unsigned count = 1;
+ for (++i; count < limit && i != s.size() && std::isdigit(s[i]); ++i,
++count)
+ u = u * 10 + static_cast<unsigned>(s[i] - '0');
+ return i;
+}
+
+} // namespace detail
+
+} // namespace Posix
+
+namespace date
+{
+
+template <>
+struct zoned_traits<Posix::time_zone>
+{
+
+#if HAS_STRING_VIEW
+
+ static
+ Posix::time_zone
+ locate_zone(std::string_view name)
+ {
+ return Posix::time_zone{name};
+ }
+
+#else // !HAS_STRING_VIEW
+
+ static
+ Posix::time_zone
+ locate_zone(const std::string& name)
+ {
+ return Posix::time_zone{name};
+ }
+
+ static
+ Posix::time_zone
+ locate_zone(const char* name)
+ {
+ return Posix::time_zone{name};
+ }
+
+#endif // !HAS_STRING_VIEW
+
+};
+
+} // namespace date
+
+#endif // PTZ_H