forked from HowardHinnant/date
Compare commits
14 Commits
esp-idf-re
...
v3.0.1
Author | SHA1 | Date | |
---|---|---|---|
6e921e1b1d | |||
39b4edf279 | |||
2ef74cb41a | |||
ac6ca2a095 | |||
ae017078c9 | |||
156e0a786e | |||
9a9a42db74 | |||
b5b765f928 | |||
77bd6b92a4 | |||
654b97091f | |||
b899774303 | |||
0e08b942c8 | |||
811be52e1c | |||
1c285d6545 |
@ -49,7 +49,7 @@ To use `"tz.h"`, there is a single source file (`src/tz.cpp`) that needs to be c
|
||||
|
||||
One can run tests by cd'ing into the `test` subdirectory and running `testit`. There are known failures on all platforms except for macOS. And even on macOS if C++11 is used. If any of these failures present problems for you, there exist workarounds.
|
||||
|
||||
Additionally there is unsupported support for [vcpkg](https://github.com/Microsoft/vcpkg) and [CMake](https://cmake.org/). I don't personally use or maintain these systems as for me they cause more problems than they solve (for this small project). If you would like to contribute to these build systems please feel free to file a PR.
|
||||
Additionally there is _unsupported_ support for [vcpkg](https://github.com/Microsoft/vcpkg) and [CMake](https://cmake.org/). I don't personally use or maintain these systems as for me they cause more problems than they solve (for this small project). If you would like to contribute to these build systems please feel free to file a PR.
|
||||
|
||||
You can download and install Date using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
|
||||
|
||||
@ -66,7 +66,7 @@ You can optionally build using [CMake](https://cmake.org/). Here is a guide of h
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ../
|
||||
cmake -DENABLE_DATE_TESTING=ON -DBUILD_TZ_LIB=ON ../
|
||||
cmake --build . --target testit # Consider '-- -j4' for multithreading
|
||||
```
|
||||
## Projects using this library
|
||||
|
@ -136,7 +136,7 @@ namespace date
|
||||
#endif
|
||||
|
||||
#ifndef HAS_UNCAUGHT_EXCEPTIONS
|
||||
# if __cplusplus > 201703 || (defined(_MSVC_LANG) && _MSVC_LANG > 201703L)
|
||||
# if __cplusplus >= 201703 || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||
# define HAS_UNCAUGHT_EXCEPTIONS 1
|
||||
# else
|
||||
# define HAS_UNCAUGHT_EXCEPTIONS 0
|
||||
@ -1004,6 +1004,8 @@ struct is_clock<T, std::void_t<decltype(T::now()), typename T::rep, typename T::
|
||||
: std::true_type
|
||||
{};
|
||||
|
||||
template<class T> inline constexpr bool is_clock_v = is_clock<T>::value;
|
||||
|
||||
#endif // HAS_VOID_T
|
||||
|
||||
//----------------+
|
||||
@ -1020,6 +1022,7 @@ protected:
|
||||
std::basic_ios<CharT, Traits>& is_;
|
||||
CharT fill_;
|
||||
std::ios::fmtflags flags_;
|
||||
std::streamsize precision_;
|
||||
std::streamsize width_;
|
||||
std::basic_ostream<CharT, Traits>* tie_;
|
||||
std::locale loc_;
|
||||
@ -1029,6 +1032,7 @@ public:
|
||||
{
|
||||
is_.fill(fill_);
|
||||
is_.flags(flags_);
|
||||
is_.precision(precision_);
|
||||
is_.width(width_);
|
||||
is_.imbue(loc_);
|
||||
is_.tie(tie_);
|
||||
@ -1041,6 +1045,7 @@ public:
|
||||
: is_(is)
|
||||
, fill_(is.fill())
|
||||
, flags_(is.flags())
|
||||
, precision_(is.precision())
|
||||
, width_(is.width(0))
|
||||
, tie_(is.tie(nullptr))
|
||||
, loc_(is.getloc())
|
||||
@ -1501,16 +1506,29 @@ operator-(const day& x, const days& y) NOEXCEPT
|
||||
return x + -y;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const day& d)
|
||||
low_level_fmt(std::basic_ostream<CharT, Traits>& os, const day& d)
|
||||
{
|
||||
detail::save_ostream<CharT, Traits> _(os);
|
||||
os.fill('0');
|
||||
os.flags(std::ios::dec | std::ios::right);
|
||||
os.width(2);
|
||||
os << static_cast<unsigned>(d);
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const day& d)
|
||||
{
|
||||
detail::low_level_fmt(os, d);
|
||||
if (!d.ok())
|
||||
os << " is not a valid day";
|
||||
return os;
|
||||
@ -1628,10 +1646,12 @@ operator-(const month& x, const months& y) NOEXCEPT
|
||||
return x + -y;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const month& m)
|
||||
low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month& m)
|
||||
{
|
||||
if (m.ok())
|
||||
{
|
||||
@ -1639,7 +1659,20 @@ operator<<(std::basic_ostream<CharT, Traits>& os, const month& m)
|
||||
os << format(os.getloc(), fmt, m);
|
||||
}
|
||||
else
|
||||
os << static_cast<unsigned>(m) << " is not a valid month";
|
||||
os << static_cast<unsigned>(m);
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const month& m)
|
||||
{
|
||||
detail::low_level_fmt(os, m);
|
||||
if (!m.ok())
|
||||
os << " is not a valid month";
|
||||
return os;
|
||||
}
|
||||
|
||||
@ -1753,10 +1786,12 @@ operator-(const year& x, const years& y) NOEXCEPT
|
||||
return year{static_cast<int>(x) - y.count()};
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const year& y)
|
||||
low_level_fmt(std::basic_ostream<CharT, Traits>& os, const year& y)
|
||||
{
|
||||
detail::save_ostream<CharT, Traits> _(os);
|
||||
os.fill('0');
|
||||
@ -1764,6 +1799,17 @@ operator<<(std::basic_ostream<CharT, Traits>& os, const year& y)
|
||||
os.width(4 + (y < year{0}));
|
||||
os.imbue(std::locale::classic());
|
||||
os << static_cast<int>(y);
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const year& y)
|
||||
{
|
||||
detail::low_level_fmt(os, y);
|
||||
if (!y.ok())
|
||||
os << " is not a valid year";
|
||||
return os;
|
||||
@ -1889,10 +1935,12 @@ operator-(const weekday& x, const days& y) NOEXCEPT
|
||||
return x + -y;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd)
|
||||
low_level_fmt(std::basic_ostream<CharT, Traits>& os, const weekday& wd)
|
||||
{
|
||||
if (wd.ok())
|
||||
{
|
||||
@ -1900,7 +1948,20 @@ operator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd)
|
||||
os << format(fmt, wd);
|
||||
}
|
||||
else
|
||||
os << static_cast<unsigned>(wd.wd_) << " is not a valid weekday";
|
||||
os << wd.c_encoding();
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd)
|
||||
{
|
||||
detail::low_level_fmt(os, wd);
|
||||
if (!wd.ok())
|
||||
os << " is not a valid weekday";
|
||||
return os;
|
||||
}
|
||||
|
||||
@ -2009,15 +2070,26 @@ weekday_indexed::weekday_indexed(const date::weekday& wd, unsigned index) NOEXCE
|
||||
# pragma GCC diagnostic pop
|
||||
#endif // __GNUC__
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class CharT, class Traits>
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
low_level_fmt(std::basic_ostream<CharT, Traits>& os, const weekday_indexed& wdi)
|
||||
{
|
||||
return low_level_fmt(os, wdi.weekday()) << '[' << wdi.index() << ']';
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const weekday_indexed& wdi)
|
||||
{
|
||||
os << wdi.weekday() << '[' << wdi.index();
|
||||
if (!(1 <= wdi.index() && wdi.index() <= 5))
|
||||
os << " is not a valid index";
|
||||
os << ']';
|
||||
detail::low_level_fmt(os, wdi);
|
||||
if (!wdi.ok())
|
||||
os << " is not a valid weekday_indexed";
|
||||
return os;
|
||||
}
|
||||
|
||||
@ -2067,12 +2139,27 @@ operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class CharT, class Traits>
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
low_level_fmt(std::basic_ostream<CharT, Traits>& os, const weekday_last& wdl)
|
||||
{
|
||||
return low_level_fmt(os, wdl.weekday()) << "[last]";
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const weekday_last& wdl)
|
||||
{
|
||||
return os << wdl.weekday() << "[last]";
|
||||
detail::low_level_fmt(os, wdl);
|
||||
if (!wdl.ok())
|
||||
os << " is not a valid weekday_last";
|
||||
return os;
|
||||
}
|
||||
|
||||
CONSTCD11
|
||||
@ -2247,12 +2334,28 @@ operator-(const year_month& ym, const years& dy) NOEXCEPT
|
||||
return ym + -dy;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class CharT, class Traits>
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
low_level_fmt(std::basic_ostream<CharT, Traits>& os, const year_month& ym)
|
||||
{
|
||||
low_level_fmt(os, ym.year()) << '/';
|
||||
return low_level_fmt(os, ym.month());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const year_month& ym)
|
||||
{
|
||||
return os << ym.year() << '/' << ym.month();
|
||||
detail::low_level_fmt(os, ym);
|
||||
if (!ym.ok())
|
||||
os << " is not a valid year_month";
|
||||
return os;
|
||||
}
|
||||
|
||||
// month_day
|
||||
@ -2332,12 +2435,28 @@ operator>=(const month_day& x, const month_day& y) NOEXCEPT
|
||||
return !(x < y);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class CharT, class Traits>
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_day& md)
|
||||
{
|
||||
low_level_fmt(os, md.month()) << '/';
|
||||
return low_level_fmt(os, md.day());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const month_day& md)
|
||||
{
|
||||
return os << md.month() << '/' << md.day();
|
||||
detail::low_level_fmt(os, md);
|
||||
if (!md.ok())
|
||||
os << " is not a valid month_day";
|
||||
return os;
|
||||
}
|
||||
|
||||
// month_day_last
|
||||
@ -2394,12 +2513,27 @@ operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT
|
||||
return !(x < y);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class CharT, class Traits>
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_day_last& mdl)
|
||||
{
|
||||
return low_level_fmt(os, mdl.month()) << "/last";
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const month_day_last& mdl)
|
||||
{
|
||||
return os << mdl.month() << "/last";
|
||||
detail::low_level_fmt(os, mdl);
|
||||
if (!mdl.ok())
|
||||
os << " is not a valid month_day_last";
|
||||
return os;
|
||||
}
|
||||
|
||||
// month_weekday
|
||||
@ -2446,12 +2580,28 @@ operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class CharT, class Traits>
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_weekday& mwd)
|
||||
{
|
||||
low_level_fmt(os, mwd.month()) << '/';
|
||||
return low_level_fmt(os, mwd.weekday_indexed());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const month_weekday& mwd)
|
||||
{
|
||||
return os << mwd.month() << '/' << mwd.weekday_indexed();
|
||||
detail::low_level_fmt(os, mwd);
|
||||
if (!mwd.ok())
|
||||
os << " is not a valid month_weekday";
|
||||
return os;
|
||||
}
|
||||
|
||||
// month_weekday_last
|
||||
@ -2498,12 +2648,28 @@ operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class CharT, class Traits>
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_weekday_last& mwdl)
|
||||
{
|
||||
low_level_fmt(os, mwdl.month()) << '/';
|
||||
return low_level_fmt(os, mwdl.weekday_last());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const month_weekday_last& mwdl)
|
||||
{
|
||||
return os << mwdl.month() << '/' << mwdl.weekday_last();
|
||||
detail::low_level_fmt(os, mwdl);
|
||||
if (!mwdl.ok())
|
||||
os << " is not a valid month_weekday_last";
|
||||
return os;
|
||||
}
|
||||
|
||||
// year_month_day_last
|
||||
@ -2653,12 +2819,28 @@ operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT
|
||||
return !(x < y);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<class CharT, class Traits>
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
low_level_fmt(std::basic_ostream<CharT, Traits>& os, const year_month_day_last& ymdl)
|
||||
{
|
||||
low_level_fmt(os, ymdl.year()) << '/';
|
||||
return low_level_fmt(os, ymdl.month_day_last());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<class CharT, class Traits>
|
||||
inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day_last& ymdl)
|
||||
{
|
||||
return os << ymdl.year() << '/' << ymdl.month_day_last();
|
||||
detail::low_level_fmt(os, ymdl);
|
||||
if (!ymdl.ok())
|
||||
os << " is not a valid year_month_day_last";
|
||||
return os;
|
||||
}
|
||||
|
||||
template<class>
|
||||
@ -2889,12 +3071,13 @@ operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day& ymd)
|
||||
os.fill('0');
|
||||
os.flags(std::ios::dec | std::ios::right);
|
||||
os.imbue(std::locale::classic());
|
||||
os << ymd.year() << '-';
|
||||
os << static_cast<int>(ymd.year()) << '-';
|
||||
os.width(2);
|
||||
os << static_cast<unsigned>(ymd.month()) << '-';
|
||||
os << ymd.day();
|
||||
os.width(2);
|
||||
os << static_cast<unsigned>(ymd.day());
|
||||
if (!ymd.ok())
|
||||
os << " is not a valid date";
|
||||
os << " is not a valid year_month_day";
|
||||
return os;
|
||||
}
|
||||
|
||||
@ -3130,8 +3313,12 @@ inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_weekday& ymwdi)
|
||||
{
|
||||
return os << ymwdi.year() << '/' << ymwdi.month()
|
||||
<< '/' << ymwdi.weekday_indexed();
|
||||
detail::low_level_fmt(os, ymwdi.year()) << '/';
|
||||
detail::low_level_fmt(os, ymwdi.month()) << '/';
|
||||
detail::low_level_fmt(os, ymwdi.weekday_indexed());
|
||||
if (!ymwdi.ok())
|
||||
os << " is not a valid year_month_weekday";
|
||||
return os;
|
||||
}
|
||||
|
||||
template<class>
|
||||
@ -3307,7 +3494,12 @@ inline
|
||||
std::basic_ostream<CharT, Traits>&
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_weekday_last& ymwdl)
|
||||
{
|
||||
return os << ymwdl.year() << '/' << ymwdl.month() << '/' << ymwdl.weekday_last();
|
||||
detail::low_level_fmt(os, ymwdl.year()) << '/';
|
||||
detail::low_level_fmt(os, ymwdl.month()) << '/';
|
||||
detail::low_level_fmt(os, ymwdl.weekday_last());
|
||||
if (!ymwdl.ok())
|
||||
os << " is not a valid year_month_weekday_last";
|
||||
return os;
|
||||
}
|
||||
|
||||
template<class>
|
||||
@ -3810,6 +4002,7 @@ public:
|
||||
std::chrono::duration<rep> d = s_ + sub_s_;
|
||||
if (d < std::chrono::seconds{10})
|
||||
os << '0';
|
||||
os.precision(width+6);
|
||||
os << std::fixed << d.count();
|
||||
return os;
|
||||
}
|
||||
@ -4000,9 +4193,7 @@ make24(std::chrono::hours h, bool is_pm) NOEXCEPT
|
||||
template <class Duration>
|
||||
using time_of_day = hh_mm_ss<Duration>;
|
||||
|
||||
template <class Rep, class Period,
|
||||
class = typename std::enable_if
|
||||
<!std::chrono::treat_as_floating_point<Rep>::value>::type>
|
||||
template <class Rep, class Period>
|
||||
CONSTCD11
|
||||
inline
|
||||
hh_mm_ss<std::chrono::duration<Rep, Period>>
|
||||
@ -4015,8 +4206,7 @@ template <class CharT, class Traits, class Duration>
|
||||
inline
|
||||
typename std::enable_if
|
||||
<
|
||||
!std::chrono::treat_as_floating_point<typename Duration::rep>::value &&
|
||||
std::ratio_less<typename Duration::period, days::period>::value
|
||||
std::ratio_less<typename Duration::period, days::period>::value
|
||||
, std::basic_ostream<CharT, Traits>&
|
||||
>::type
|
||||
operator<<(std::basic_ostream<CharT, Traits>& os, const sys_time<Duration>& tp)
|
||||
@ -4779,7 +4969,7 @@ scan_keyword(std::basic_istream<CharT, Traits>& is, FwdIter kb, FwdIter ke)
|
||||
is.setstate(std::ios::eofbit);
|
||||
break;
|
||||
}
|
||||
auto c = static_cast<char>(toupper(ic));
|
||||
auto c = static_cast<char>(toupper(static_cast<unsigned char>(ic)));
|
||||
bool consume = false;
|
||||
// For each keyword which might match, see if the indx character is c
|
||||
// If a match if found, consume c
|
||||
@ -4792,7 +4982,7 @@ scan_keyword(std::basic_istream<CharT, Traits>& is, FwdIter kb, FwdIter ke)
|
||||
{
|
||||
if (*st == might_match)
|
||||
{
|
||||
if (c == static_cast<char>(toupper((*ky)[indx])))
|
||||
if (c == static_cast<char>(toupper(static_cast<unsigned char>((*ky)[indx]))))
|
||||
{
|
||||
consume = true;
|
||||
if (ky->size() == indx+1)
|
||||
@ -7655,6 +7845,8 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
|
||||
goto broken;
|
||||
}
|
||||
}
|
||||
else // I is ambiguous, AM or PM?
|
||||
goto broken;
|
||||
}
|
||||
}
|
||||
if (H != not_a_hour)
|
||||
|
@ -269,8 +269,76 @@ public:
|
||||
std::string name() const;
|
||||
|
||||
friend bool operator==(const time_zone& x, const time_zone& y);
|
||||
|
||||
private:
|
||||
date::sys_seconds get_start(date::year y) const;
|
||||
date::sys_seconds get_prev_start(date::year y) const;
|
||||
date::sys_seconds get_next_start(date::year y) const;
|
||||
date::sys_seconds get_end(date::year y) const;
|
||||
date::sys_seconds get_prev_end(date::year y) const;
|
||||
date::sys_seconds get_next_end(date::year y) const;
|
||||
date::sys_info contant_offset() const;
|
||||
};
|
||||
|
||||
inline
|
||||
date::sys_seconds
|
||||
time_zone::get_start(date::year y) const
|
||||
{
|
||||
return date::sys_seconds{(start_rule_(y) - offset_).time_since_epoch()};
|
||||
}
|
||||
|
||||
inline
|
||||
date::sys_seconds
|
||||
time_zone::get_prev_start(date::year y) const
|
||||
{
|
||||
return date::sys_seconds{(start_rule_(--y) - offset_).time_since_epoch()};
|
||||
}
|
||||
|
||||
inline
|
||||
date::sys_seconds
|
||||
time_zone::get_next_start(date::year y) const
|
||||
{
|
||||
return date::sys_seconds{(start_rule_(++y) - offset_).time_since_epoch()};
|
||||
}
|
||||
|
||||
inline
|
||||
date::sys_seconds
|
||||
time_zone::get_end(date::year y) const
|
||||
{
|
||||
return date::sys_seconds{(end_rule_(y) - (offset_ + save_)).time_since_epoch()};
|
||||
}
|
||||
|
||||
inline
|
||||
date::sys_seconds
|
||||
time_zone::get_prev_end(date::year y) const
|
||||
{
|
||||
return date::sys_seconds{(end_rule_(--y) - (offset_ + save_)).time_since_epoch()};
|
||||
}
|
||||
|
||||
inline
|
||||
date::sys_seconds
|
||||
time_zone::get_next_end(date::year y) const
|
||||
{
|
||||
return date::sys_seconds{(end_rule_(++y) - (offset_ + save_)).time_since_epoch()};
|
||||
}
|
||||
|
||||
date::sys_info
|
||||
time_zone::contant_offset() const
|
||||
{
|
||||
using date::year;
|
||||
using date::sys_info;
|
||||
using date::sys_days;
|
||||
using date::January;
|
||||
using date::December;
|
||||
using date::last;
|
||||
sys_info r;
|
||||
r.begin = sys_days{year::min()/January/1};
|
||||
r.end = sys_days{year::max()/December/last};
|
||||
r.abbrev = std_abbrev_;
|
||||
r.offset = offset_;
|
||||
return r;
|
||||
}
|
||||
|
||||
inline
|
||||
time_zone::time_zone(const detail::string_t& s)
|
||||
{
|
||||
@ -313,12 +381,10 @@ time_zone::get_info(date::sys_time<Duration> st) const
|
||||
{
|
||||
using date::sys_info;
|
||||
using date::year_month_day;
|
||||
using date::sys_seconds;
|
||||
using date::sys_days;
|
||||
using date::floor;
|
||||
using date::ceil;
|
||||
using date::days;
|
||||
using date::years;
|
||||
using date::year;
|
||||
using date::January;
|
||||
using date::December;
|
||||
@ -329,36 +395,59 @@ time_zone::get_info(date::sys_time<Duration> st) const
|
||||
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)
|
||||
auto start = get_start(y);
|
||||
auto end = get_end(y);
|
||||
if (start <= end) // (northern hemisphere)
|
||||
{
|
||||
r.begin = start;
|
||||
r.end = end;
|
||||
r.offset += save_;
|
||||
r.save = ceil<minutes>(save_);
|
||||
r.abbrev = dst_abbrev_;
|
||||
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 = get_prev_end(y);
|
||||
r.end = start;
|
||||
r.abbrev = std_abbrev_;
|
||||
}
|
||||
else // st >= end
|
||||
{
|
||||
r.begin = end;
|
||||
r.end = get_next_start(y);
|
||||
r.abbrev = std_abbrev_;
|
||||
}
|
||||
}
|
||||
else if (st < start)
|
||||
else // end < start (southern hemisphere)
|
||||
{
|
||||
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_;
|
||||
if (end <= st && st < start)
|
||||
{
|
||||
r.begin = end;
|
||||
r.end = start;
|
||||
r.abbrev = std_abbrev_;
|
||||
}
|
||||
else if (st < end)
|
||||
{
|
||||
r.begin = get_prev_start(y);
|
||||
r.end = end;
|
||||
r.offset += save_;
|
||||
r.save = ceil<minutes>(save_);
|
||||
r.abbrev = dst_abbrev_;
|
||||
}
|
||||
else // st >= start
|
||||
{
|
||||
r.begin = start;
|
||||
r.end = get_next_end(y);
|
||||
r.offset += save_;
|
||||
r.save = ceil<minutes>(save_);
|
||||
r.abbrev = dst_abbrev_;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // constant offset
|
||||
{
|
||||
r.begin = sys_days{year::min()/January/1};
|
||||
r.end = sys_days{year::max()/December/last};
|
||||
r.abbrev = std_abbrev_;
|
||||
}
|
||||
else
|
||||
r = contant_offset();
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -371,7 +460,6 @@ time_zone::get_info(date::local_time<Duration> tp) const
|
||||
using date::days;
|
||||
using date::sys_days;
|
||||
using date::sys_seconds;
|
||||
using date::years;
|
||||
using date::year;
|
||||
using date::ceil;
|
||||
using date::January;
|
||||
@ -384,19 +472,25 @@ time_zone::get_info(date::local_time<Duration> tp) const
|
||||
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 start = get_start(y);
|
||||
auto end = get_end(y);
|
||||
auto utcs = sys_seconds{floor<seconds>(tp - offset_).time_since_epoch()};
|
||||
auto utcd = sys_seconds{floor<seconds>(tp - (offset_ + save_)).time_since_epoch()};
|
||||
auto northern = start <= end;
|
||||
if ((utcs < start) != (utcd < start))
|
||||
{
|
||||
r.first.begin = sys_seconds{(end_rule_(y-years{1}) -
|
||||
(offset_ + save_)).time_since_epoch()};
|
||||
if (northern)
|
||||
r.first.begin = get_prev_end(y);
|
||||
else
|
||||
r.first.begin = end;
|
||||
r.first.end = start;
|
||||
r.first.offset = offset_;
|
||||
r.first.abbrev = std_abbrev_;
|
||||
r.second.begin = start;
|
||||
r.second.end = end;
|
||||
if (northern)
|
||||
r.second.end = end;
|
||||
else
|
||||
r.second.end = get_next_end(y);
|
||||
r.second.abbrev = dst_abbrev_;
|
||||
r.second.offset = offset_ + save_;
|
||||
r.second.save = ceil<minutes>(save_);
|
||||
@ -405,51 +499,29 @@ time_zone::get_info(date::local_time<Duration> tp) const
|
||||
}
|
||||
else if ((utcs < end) != (utcd < end))
|
||||
{
|
||||
r.first.begin = start;
|
||||
if (northern)
|
||||
r.first.begin = start;
|
||||
else
|
||||
r.first.begin = get_prev_start(y);
|
||||
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()};
|
||||
if (northern)
|
||||
r.second.end = get_next_start(y);
|
||||
else
|
||||
r.second.end = start;
|
||||
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()/January/1};
|
||||
r.first.end = sys_days{year::max()/December/last};
|
||||
r.first.abbrev = std_abbrev_;
|
||||
r.first.offset = offset_;
|
||||
r.first = get_info(utcs);
|
||||
}
|
||||
else
|
||||
r.first = contant_offset();
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -460,6 +532,7 @@ time_zone::to_sys(date::local_time<Duration> tp) const
|
||||
using date::local_info;
|
||||
using date::sys_time;
|
||||
using date::ambiguous_local_time;
|
||||
using date::nonexistent_local_time;
|
||||
auto i = get_info(tp);
|
||||
if (i.result == local_info::nonexistent)
|
||||
throw nonexistent_local_time(tp, i);
|
||||
|
27
src/tz.cpp
27
src/tz.cpp
@ -2846,18 +2846,24 @@ file_exists(const std::string& filename)
|
||||
|
||||
// CURL tools
|
||||
|
||||
static
|
||||
int
|
||||
curl_global()
|
||||
{
|
||||
if (::curl_global_init(CURL_GLOBAL_DEFAULT) != 0)
|
||||
throw std::runtime_error("CURL global initialization failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct curl_global_init_and_cleanup
|
||||
{
|
||||
~curl_global_init_and_cleanup()
|
||||
{
|
||||
::curl_global_cleanup();
|
||||
}
|
||||
curl_global_init_and_cleanup()
|
||||
{
|
||||
if (::curl_global_init(CURL_GLOBAL_DEFAULT) != 0)
|
||||
throw std::runtime_error("CURL global initialization failed");
|
||||
}
|
||||
curl_global_init_and_cleanup(curl_global_init_and_cleanup const&) = delete;
|
||||
curl_global_init_and_cleanup& operator=(curl_global_init_and_cleanup const&) = delete;
|
||||
};
|
||||
|
||||
struct curl_deleter
|
||||
{
|
||||
void operator()(CURL* p) const
|
||||
@ -2872,8 +2878,7 @@ static
|
||||
std::unique_ptr<CURL, curl_deleter>
|
||||
curl_init()
|
||||
{
|
||||
static const auto curl_is_now_initiailized = curl_global();
|
||||
(void)curl_is_now_initiailized;
|
||||
static const curl_global_init_and_cleanup _{};
|
||||
return std::unique_ptr<CURL, curl_deleter>{::curl_easy_init()};
|
||||
}
|
||||
|
||||
|
@ -623,6 +623,21 @@ test_p()
|
||||
assert(!in.bad());
|
||||
assert(tp == sys_days{2016_y/12/11} + hours{23});
|
||||
}
|
||||
{
|
||||
std::istringstream in{"1986-12-01 01:01:01 pm"};
|
||||
sys_time<seconds> tp;
|
||||
in >> parse("%Y-%m-%d %I:%M:%S %p", tp);
|
||||
assert(!in.fail());
|
||||
assert(!in.bad());
|
||||
assert(tp == sys_days{1986_y/12/01} + hours{13} + minutes{01} + seconds{01});
|
||||
}
|
||||
{
|
||||
std::istringstream in{"1986-12-01 01:01:01"};
|
||||
sys_time<seconds> tp;
|
||||
in >> parse("%Y-%m-%d %I:%M:%S", tp);
|
||||
// The test will fail because %I needs the %p option to shows if it is AM or PM
|
||||
assert(in.fail());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
108
test/posix/ptz.pass.cpp
Normal file
108
test/posix/ptz.pass.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2021 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.
|
||||
|
||||
// Test Posix::time_zone
|
||||
|
||||
#include "tz.h"
|
||||
#include "ptz.h"
|
||||
#include <cassert>
|
||||
|
||||
bool
|
||||
is_equal(date::sys_info const& x, date::sys_info const& y)
|
||||
{
|
||||
return x.begin == y.begin &&
|
||||
x.end == y.end &&
|
||||
x.offset == y.offset &&
|
||||
x.save == y.save &&
|
||||
x.abbrev == y.abbrev;
|
||||
}
|
||||
|
||||
bool
|
||||
is_equal(date::local_info const& x, date::local_info const& y)
|
||||
{
|
||||
return x.result == y.result && is_equal(x.first, y.first)
|
||||
&& is_equal(x.second, y.second);
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
using namespace date;
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
|
||||
auto tzi = locate_zone("Australia/Sydney");
|
||||
Posix::time_zone tzp{"AEST-10AEDT,M10.1.0,M4.1.0/3"};
|
||||
auto tp = local_days{2021_y/1/1} + 0s;
|
||||
assert(tzp.get_info(tp).result == local_info::unique);
|
||||
assert(is_equal(tzi->get_info(tp), tzp.get_info(tp)));
|
||||
|
||||
tp = local_days{2021_y/10/Sunday[1]} + 2h + 30min;
|
||||
assert(tzp.get_info(tp).result == local_info::nonexistent);
|
||||
assert(is_equal(tzi->get_info(tp), tzp.get_info(tp)));
|
||||
|
||||
tp = local_days{2021_y/4/Sunday[1]} + 2h + 30min;
|
||||
assert(tzp.get_info(tp).result == local_info::ambiguous);
|
||||
assert(is_equal(tzi->get_info(tp), tzp.get_info(tp)));
|
||||
|
||||
tp = local_days{2021_y/7/1};
|
||||
assert(tzp.get_info(tp).result == local_info::unique);
|
||||
assert(is_equal(tzi->get_info(tp), tzp.get_info(tp)));
|
||||
|
||||
|
||||
tzi = locate_zone("America/New_York");
|
||||
tzp = Posix::time_zone{"EST5EDT,M3.2.0,M11.1.0"};
|
||||
tp = local_days{2021_y/1/1};
|
||||
assert(tzp.get_info(tp).result == local_info::unique);
|
||||
assert(is_equal(tzi->get_info(tp), tzp.get_info(tp)));
|
||||
|
||||
tp = local_days{2021_y/3/Sunday[2]} + 2h + 30min;
|
||||
assert(tzp.get_info(tp).result == local_info::nonexistent);
|
||||
assert(is_equal(tzi->get_info(tp), tzp.get_info(tp)));
|
||||
|
||||
tp = local_days{2021_y/11/Sunday[1]} + 1h + 30min;
|
||||
assert(tzp.get_info(tp).result == local_info::ambiguous);
|
||||
assert(is_equal(tzi->get_info(tp), tzp.get_info(tp)));
|
||||
|
||||
tp = local_days{2021_y/7/1};
|
||||
assert(tzp.get_info(tp).result == local_info::unique);
|
||||
assert(is_equal(tzi->get_info(tp), tzp.get_info(tp)));
|
||||
|
||||
|
||||
tzi = locate_zone("Europe/Dublin");
|
||||
tzp = Posix::time_zone{"IST-1GMT0,M10.5.0,M3.5.0/1"};
|
||||
tp = local_days{2021_y/1/1};
|
||||
assert(tzp.get_info(tp).result == local_info::unique);
|
||||
assert(is_equal(tzi->get_info(tp), tzp.get_info(tp)));
|
||||
|
||||
tp = local_days{2021_y/3/Sunday[last]} + 1h + 30min;
|
||||
assert(tzp.get_info(tp).result == local_info::nonexistent);
|
||||
assert(is_equal(tzi->get_info(tp), tzp.get_info(tp)));
|
||||
|
||||
tp = local_days{2021_y/10/Sunday[last]} + 1h + 30min;
|
||||
assert(tzp.get_info(tp).result == local_info::ambiguous);
|
||||
assert(is_equal(tzi->get_info(tp), tzp.get_info(tp)));
|
||||
|
||||
tp = local_days{2021_y/7/1};
|
||||
assert(tzp.get_info(tp).result == local_info::unique);
|
||||
assert(is_equal(tzi->get_info(tp), tzp.get_info(tp)));
|
||||
}
|
Reference in New Issue
Block a user