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

Reply via email to