37 Commits

Author SHA1 Message Date
bf79dd5a81 Update README.md 2021-01-11 20:05:18 -05:00
26fc2bd372 Fix read_long_double with respect to decimal_point:
*  Respect locale settings when ONLY_C_LOCALE=0
*  Do not respect locale settings when ONLY_C_LOCALE=1
Fixes #637
2021-01-05 21:14:41 -05:00
97246a638a Silence lossy conversion warning
Fixes #620
2020-11-10 08:41:30 -05:00
432bab81f9 Skip "version" file and USE_OS_TZDB to return "unknown" if no version found (#616)
In commit commit 0b72599bd4 there
was a change to read "version" in addition to "+VERSION", so that
file shold also be ignored when scanning/reading zonefiles.

Also before the above mentioed commit get_version() would return
"unknown" if not on __APPLE__ and the version file was not found.
Put back that behaviour, for all USE_OS_TZDB users.

This last change changes the behaviour for __APPLE__ from throwing
an exception to returning "unknown".

Co-authored-by: Lars Gullik Bjønnes <lbjonnes@cisco.com>
2020-10-27 10:08:30 -04:00
215cacff56 Change all uses of round to detail::round_i
Fixes #613

detail::round_i is the same as round when the To::rep
is integral, and is just an implicit conversion when
To::rep is floating point.
2020-10-25 20:16:07 -04:00
3cbfa4318f Put back handling DISABLE_STRING_VIEW (#609)
* Put back handling DISABLE_STRING_VIEW
* Add HAS_DEDUCTION_GUIDES to interface library target
2020-10-08 19:22:15 -04:00
115dd428cf Proposed fix for issue #161
Header include should follow the same preprocessor rules as function definition.
2020-10-08 11:47:09 +03:00
7848566815 Fix a parse error for Visual Studio 2020-10-02 12:53:16 -04:00
393b52f21b Update README.md 2020-09-19 10:15:51 -04:00
0b72599bd4 For USE_OS_TZDB, look for version number in the files
version and +VERSION
2020-09-11 16:00:18 -04:00
ba99134b8a For USE_OS_TZDB, look for leap seconds in the files
leapseconds and leap-seconds.list
2020-09-11 15:53:07 -04:00
5e18488899 Fix subtle bug in fractional_width 2020-09-05 16:34:04 -04:00
313189b0a8 Correct lingering references to bare "tz" libname: (#600)
Fixes: #599
2020-08-25 16:57:00 -04:00
057b441ceb Use LLONG_MAX instead of std::numeric_limits<long long>::max() when constexpr is absent 2020-08-21 17:09:51 -04:00
d7a0bf1fa7 replace noexcept with NOEXCEPT macro 2020-08-21 17:09:51 -04:00
8140d979cd fix brace value initialization for msvc 18 2020-08-21 17:09:51 -04:00
7990eae740 fix user defined literals for compatibility with msvc 18 2020-08-21 17:09:47 -04:00
1ec2ea0295 Add test/tz_test/tzdb_list.pass.cpp 2020-08-17 21:34:20 -04:00
658a3b9495 Fix crasher for early local times and USE_OS_TZDB=1 2020-08-17 21:34:20 -04:00
e7969c32e8 Add Kotlin's datetime library to the list of projects using this (#593) 2020-08-14 09:53:14 -04:00
569b2d6785 Improve error message while parsing posix timezone string 2020-08-02 10:56:37 -04:00
abe3ada04f Update README.md 2020-07-28 17:00:00 -04:00
9537addfc4 fix ONLY_C_LOCALE export from cmake (#590)
* fix ONLY_C_LOCALE export from cmake

* add some comments

* remove all generator expressions for target output

* cmake: fewer variables, make it easier to read
2020-07-22 19:03:42 -04:00
6952fb50a6 Correct the value for not_a_year 2020-07-08 14:20:31 -04:00
fe2f9c7eac Change constexpr to CONSTDATA 2020-07-07 15:01:45 -04:00
a6243ce56f set cmake proj ver to 3.0: (#584)
FIXES: #583
2020-06-22 11:48:09 -04:00
a55f1a103b Update README.md 2020-06-15 15:18:20 -04:00
d544e5af25 Throw exception if zoned_time is constructed with nullptr 2020-06-14 19:30:23 -04:00
cac99da8dc For traits in constexpr context use ::value
* Fixes #542
2020-06-02 21:08:57 -04:00
a088baf9a5 Update README.md 2020-05-26 11:47:28 -04:00
e6adff6754 [cmake] Rename tz library to date-tz:
Fixes: #426
2020-05-24 21:31:18 -04:00
d784766640 iOS Simulator support 2020-05-24 21:31:18 -04:00
9343e31599 Give Posix::time_zone equality comparison 2020-05-24 21:31:18 -04:00
f43c39fcf1 Add member function name() const to Posix::time_zone
* Returns the minimal string that uniquely identifies this
  time_zone.  That is, it takes advantage of all defaults.
2020-05-06 22:12:15 -04:00
e12095f26f Revert change for floating point reps in decimal_format_seconds 2020-04-18 09:24:53 -04:00
7d811743e0 Fix parse of second offset in posix time zone 2020-04-18 09:24:22 -04:00
a2fdba1adc __GNUC_MINOR -> __GNUC_MINOR__
* Fixes #560
2020-03-30 12:50:37 -04:00
12 changed files with 621 additions and 237 deletions

View File

@ -7,7 +7,7 @@
include( FetchContent ) include( FetchContent )
FetchContent_Declare( date_src FetchContent_Declare( date_src
GIT_REPOSITORY https://github.com/HowardHinnant/date.git GIT_REPOSITORY https://github.com/HowardHinnant/date.git
GIT_TAG 2.4.2 # adjust tag/branch/commit as needed GIT_TAG v3.0.0 # adjust tag/branch/commit as needed
) )
FetchContent_MakeAvailable(date_src) FetchContent_MakeAvailable(date_src)
... ...
@ -17,7 +17,8 @@
cmake_minimum_required( VERSION 3.7 ) cmake_minimum_required( VERSION 3.7 )
project( date VERSION 2.4.1 ) project( date VERSION 3.0.0 )
set(ABI_VERSION 3) # used as SOVERSION, increment when ABI changes
include( GNUInstallDirs ) include( GNUInstallDirs )
@ -76,56 +77,84 @@ if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.15)
# public headers will get installed: # public headers will get installed:
set_target_properties( date PROPERTIES PUBLIC_HEADER include/date/date.h ) set_target_properties( date PROPERTIES PUBLIC_HEADER include/date/date.h )
endif () endif ()
target_compile_definitions( date INTERFACE
#To workaround libstdc++ issue https://github.com/HowardHinnant/date/issues/388 # These used to be set with generator expressions,
ONLY_C_LOCALE=$<IF:$<BOOL:${COMPILE_WITH_C_LOCALE}>,1,0> #
$<$<BOOL:${DISABLE_STRING_VIEW}>:HAS_STRING_VIEW=0> ) # ONLY_C_LOCALE=$<IF:$<BOOL:${COMPILE_WITH_C_LOCALE}>,1,0>
#
# which expand in the output target file to, e.g.
#
# ONLY_C_LOCALE=$<IF:$<BOOL:FALSE>,1,0>
#
# This string is then (somtimes?) not correctly interpreted.
if ( COMPILE_WITH_C_LOCALE )
# To workaround libstdc++ issue https://github.com/HowardHinnant/date/issues/388
target_compile_definitions( date INTERFACE ONLY_C_LOCALE=1 )
else()
target_compile_definitions( date INTERFACE ONLY_C_LOCALE=0 )
endif()
if ( DISABLE_STRING_VIEW )
target_compile_definitions( date INTERFACE HAS_STRING_VIEW=0 -DHAS_DEDUCTION_GUIDES=0 )
endif()
#[===================================================================[ #[===================================================================[
tz (compiled) library tz (compiled) library
#]===================================================================] #]===================================================================]
if( BUILD_TZ_LIB ) if( BUILD_TZ_LIB )
add_library( tz ) add_library( date-tz )
target_sources( tz target_sources( date-tz
PUBLIC PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>$<INSTALL_INTERFACE:include>/date/tz.h $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>$<INSTALL_INTERFACE:include>/date/tz.h
$<$<BOOL:${IOS}>:$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>$<INSTALL_INTERFACE:include>/date/ios.h>
PRIVATE PRIVATE
include/date/tz_private.h include/date/tz_private.h
$<$<BOOL:${IOS}>:src/ios.mm>
src/tz.cpp ) src/tz.cpp )
add_library( date::tz ALIAS tz ) if ( IOS )
target_link_libraries( tz PUBLIC date ) target_sources( date-tz
target_include_directories( tz PUBLIC PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>$<INSTALL_INTERFACE:include>/date/ios.h
PRIVATE
src/ios.mm )
endif()
add_library( date::date-tz ALIAS date-tz )
target_link_libraries( date-tz PUBLIC date )
target_include_directories( date-tz PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include> ) $<INSTALL_INTERFACE:include> )
target_compile_definitions( tz
PRIVATE if ( USE_SYSTEM_TZ_DB OR MANUAL_TZ_DB )
AUTO_DOWNLOAD=$<IF:$<OR:$<BOOL:${USE_SYSTEM_TZ_DB}>,$<BOOL:${MANUAL_TZ_DB}>>,0,1> target_compile_definitions( date-tz PRIVATE AUTO_DOWNLOAD=0 HAS_REMOTE_API=0 )
HAS_REMOTE_API=$<IF:$<OR:$<BOOL:${USE_SYSTEM_TZ_DB}>,$<BOOL:${MANUAL_TZ_DB}>>,0,1> else()
$<$<AND:$<BOOL:${WIN32}>,$<BOOL:${BUILD_SHARED_LIBS}>>:DATE_BUILD_DLL=1> target_compile_definitions( date-tz PRIVATE AUTO_DOWNLOAD=1 HAS_REMOTE_API=1 )
$<$<BOOL:${USE_TZ_DB_IN_DOT}>:INSTALL=.> endif()
PUBLIC
USE_OS_TZDB=$<IF:$<AND:$<BOOL:${USE_SYSTEM_TZ_DB}>,$<NOT:$<BOOL:${WIN32}>>,$<NOT:$<BOOL:${MANUAL_TZ_DB}>>>,1,0> if ( USE_SYSTEM_TZ_DB AND NOT WIN32 AND NOT MANUAL_TZ_DB )
INTERFACE target_compile_definitions( date-tz PRIVATE INSTALL=. PUBLIC USE_OS_TZDB=1 )
$<$<AND:$<BOOL:${WIN32}>,$<BOOL:${BUILD_SHARED_LIBS}>>:DATE_USE_DLL=1> ) else()
target_compile_definitions( date-tz PUBLIC USE_OS_TZDB=0 )
endif()
if ( WIN32 AND BUILD_SHARED_LIBS )
target_compile_definitions( date-tz PUBLIC DATE_BUILD_DLL=1 )
endif()
set(TZ_HEADERS include/date/tz.h) set(TZ_HEADERS include/date/tz.h)
if( IOS ) if( IOS )
list(APPEND TZ_HEADERS include/date/ios.h) list(APPEND TZ_HEADERS include/date/ios.h)
endif( ) endif( )
set_target_properties( tz PROPERTIES set_target_properties( date-tz PROPERTIES
POSITION_INDEPENDENT_CODE ON POSITION_INDEPENDENT_CODE ON
PUBLIC_HEADER "${TZ_HEADERS}" PUBLIC_HEADER "${TZ_HEADERS}"
VERSION "${PROJECT_VERSION}" VERSION "${PROJECT_VERSION}"
SOVERSION "${PROJECT_VERSION}" ) SOVERSION "${ABI_VERSION}" )
if( NOT MSVC ) if( NOT MSVC )
find_package( Threads ) find_package( Threads )
target_link_libraries( tz PUBLIC Threads::Threads ) target_link_libraries( date-tz PUBLIC Threads::Threads )
endif( ) endif( )
if( NOT USE_SYSTEM_TZ_DB AND NOT MANUAL_TZ_DB ) if( NOT USE_SYSTEM_TZ_DB AND NOT MANUAL_TZ_DB )
find_package( CURL REQUIRED ) find_package( CURL REQUIRED )
target_include_directories( tz SYSTEM PRIVATE ${CURL_INCLUDE_DIRS} ) target_include_directories( date-tz SYSTEM PRIVATE ${CURL_INCLUDE_DIRS} )
target_link_libraries( tz PRIVATE ${CURL_LIBRARIES} ) target_link_libraries( date-tz PRIVATE ${CURL_LIBRARIES} )
endif( ) endif( )
endif( ) endif( )
@ -150,13 +179,13 @@ if (CMAKE_VERSION VERSION_LESS 3.15)
endif () endif ()
if( BUILD_TZ_LIB ) if( BUILD_TZ_LIB )
install( TARGETS tz install( TARGETS date-tz
EXPORT dateConfig EXPORT dateConfig
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) # This is for Windows RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) # This is for Windows
export( TARGETS tz NAMESPACE date:: APPEND FILE dateTargets.cmake ) export( TARGETS date-tz NAMESPACE date:: APPEND FILE dateTargets.cmake )
endif( ) endif( )
if( WIN32 AND NOT CYGWIN) if( WIN32 AND NOT CYGWIN)
@ -179,7 +208,7 @@ if( ENABLE_DATE_TESTING )
enable_testing( ) enable_testing( )
add_custom_target( testit COMMAND ${CMAKE_CTEST_COMMAND} ) add_custom_target( testit COMMAND ${CMAKE_CTEST_COMMAND} )
add_dependencies( testit tz ) add_dependencies( testit date-tz )
function( add_pass_tests TEST_GLOB TEST_PREFIX ) function( add_pass_tests TEST_GLOB TEST_PREFIX )
file( GLOB_RECURSE FILENAMES ${TEST_GLOB} ) file( GLOB_RECURSE FILENAMES ${TEST_GLOB} )
@ -193,7 +222,7 @@ if( ENABLE_DATE_TESTING )
set( TST_NAME ${PREFIX}_test ) set( TST_NAME ${PREFIX}_test )
add_executable( ${BIN_NAME} EXCLUDE_FROM_ALL ${TEST_FILE} ) add_executable( ${BIN_NAME} EXCLUDE_FROM_ALL ${TEST_FILE} )
add_test( ${TST_NAME} ${BIN_NAME} ) add_test( ${TST_NAME} ${BIN_NAME} )
target_link_libraries( ${BIN_NAME} tz ) target_link_libraries( ${BIN_NAME} date-tz )
# HACK: because the test files don't use FQ includes: # HACK: because the test files don't use FQ includes:
target_include_directories( ${BIN_NAME} PRIVATE include/date ) target_include_directories( ${BIN_NAME} PRIVATE include/date )
add_dependencies( testit ${BIN_NAME} ) add_dependencies( testit ${BIN_NAME} )
@ -222,7 +251,7 @@ if( ENABLE_DATE_TESTING )
${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER}
-std=c++14 -std=c++14
-L${CMAKE_BINARY_DIR}/ -L${CMAKE_BINARY_DIR}/
-ltz -ldate-tz
-I${PROJECT_SOURCE_DIR}/include -I${PROJECT_SOURCE_DIR}/include
-I${PROJECT_SOURCE_DIR}/include/date -I${PROJECT_SOURCE_DIR}/include/date
-o ${BIN_NAME} -o ${BIN_NAME}

View File

@ -5,7 +5,7 @@
--- ---
**[Try it out on wandbox!](https://wandbox.org/permlink/L8MwjzSSC3fXXrMd)** **[Try it out on wandbox!](https://wandbox.org/permlink/oyXjibyF680HHoyS)**
## Summary ## Summary
@ -43,6 +43,14 @@ Slightly modified versions of `"date.h"` and `"tz.h"` were voted into the C++20
## Build & Test ## Build & Test
The recommended way to use any of these libraries besides `"tz.h"` is to just include it. These are header-only libraries (except `"tz.h"`).
To use `"tz.h"`, there is a single source file (`src/tz.cpp`) that needs to be compiled. Here are the recommended directions: https://howardhinnant.github.io/date/tz.html#Installation.
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.
You can download and install Date using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: You can download and install Date using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
git clone https://github.com/Microsoft/vcpkg.git git clone https://github.com/Microsoft/vcpkg.git
@ -68,5 +76,9 @@ cmake --build . --target testit # Consider '-- -j4' for multithreading
* https://github.com/ViewTouch/viewtouch * https://github.com/ViewTouch/viewtouch
* https://routinghub.com * https://routinghub.com
* https://github.com/valhalla * https://github.com/valhalla
* https://github.com/siodb/siodb
* https://github.com/KomodoPlatform/atomicDEX-Pro
* https://github.com/Kotlin/kotlinx-datetime
* https://github.com/royalbee/jewish_date
If you would like your project (or product) on this list, just let me know. If you would like your project (or product) on this list, just let me know.

View File

@ -1,8 +1,8 @@
include( CMakeFindDependencyMacro ) include( CMakeFindDependencyMacro )
include( "${CMAKE_CURRENT_LIST_DIR}/dateTargets.cmake" ) include( "${CMAKE_CURRENT_LIST_DIR}/dateTargets.cmake" )
if( NOT MSVC AND TARGET date::tz ) if( NOT MSVC AND TARGET date::date-tz )
find_dependency( Threads REQUIRED) find_dependency( Threads REQUIRED)
get_target_property( _tzill date::tz INTERFACE_LINK_LIBRARIES ) get_target_property( _tzill date::date-tz INTERFACE_LINK_LIBRARIES )
if( _tzill AND "${_tzill}" MATCHES "libcurl" ) if( _tzill AND "${_tzill}" MATCHES "libcurl" )
find_dependency( CURL ) find_dependency( CURL )
endif( ) endif( )

View File

@ -45,9 +45,7 @@
#include <cctype> #include <cctype>
#include <chrono> #include <chrono>
#include <climits> #include <climits>
#if !(__cplusplus >= 201402) #include <cmath>
# include <cmath>
#endif
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
@ -71,7 +69,7 @@
#ifdef __GNUC__ #ifdef __GNUC__
# pragma GCC diagnostic push # pragma GCC diagnostic push
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR > 7) # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 7)
# pragma GCC diagnostic ignored "-Wpedantic" # pragma GCC diagnostic ignored "-Wpedantic"
# endif # endif
# if __GNUC__ < 5 # if __GNUC__ < 5
@ -1166,7 +1164,11 @@ private:
static const std::intmax_t d1 = R1::den / gcd_d1_d2; static const std::intmax_t d1 = R1::den / gcd_d1_d2;
static const std::intmax_t n2 = R2::num / gcd_n1_n2; static const std::intmax_t n2 = R2::num / gcd_n1_n2;
static const std::intmax_t d2 = R2::den / gcd_d1_d2; static const std::intmax_t d2 = R2::den / gcd_d1_d2;
#ifdef __cpp_constexpr
static const std::intmax_t max = std::numeric_limits<std::intmax_t>::max(); static const std::intmax_t max = std::numeric_limits<std::intmax_t>::max();
#else
static const std::intmax_t max = LLONG_MAX;
#endif
template <std::intmax_t Xp, std::intmax_t Yp, bool overflow> template <std::intmax_t Xp, std::intmax_t Yp, bool overflow>
struct mul // overflow == false struct mul // overflow == false
@ -1354,6 +1356,47 @@ using std::chrono::abs;
#endif // HAS_CHRONO_ROUNDING #endif // HAS_CHRONO_ROUNDING
namespace detail
{
template <class To, class Rep, class Period>
CONSTCD14
inline
typename std::enable_if
<
!std::chrono::treat_as_floating_point<typename To::rep>::value,
To
>::type
round_i(const std::chrono::duration<Rep, Period>& d)
{
return round<To>(d);
}
template <class To, class Rep, class Period>
CONSTCD14
inline
typename std::enable_if
<
std::chrono::treat_as_floating_point<typename To::rep>::value,
To
>::type
round_i(const std::chrono::duration<Rep, Period>& d)
{
return d;
}
template <class To, class Clock, class FromDuration>
CONSTCD11
inline
std::chrono::time_point<Clock, To>
round_i(const std::chrono::time_point<Clock, FromDuration>& tp)
{
using std::chrono::time_point;
return time_point<Clock, To>{round_i<To>(tp.time_since_epoch())};
}
} // detail
// trunc towards zero // trunc towards zero
template <class To, class Clock, class FromDuration> template <class To, class Clock, class FromDuration>
CONSTCD11 CONSTCD11
@ -3681,11 +3724,12 @@ struct undocumented {explicit undocumented() = default;};
// Example: width<4>::value == 2 // Example: width<4>::value == 2
// Example: width<10>::value == 1 // Example: width<10>::value == 1
// Example: width<1000>::value == 3 // Example: width<1000>::value == 3
template <std::uint64_t n, std::uint64_t d = 10, unsigned w = 0, template <std::uint64_t n, std::uint64_t d, unsigned w = 0,
bool should_continue = !(n < 2) && d != 0 && (w < 19)> bool should_continue = n%d != 0 && (w < 19)>
struct width struct width
{ {
static CONSTDATA unsigned value = 1 + width<n, d%n*10, w+1>::value; static_assert(d > 0, "width called with zero denominator");
static CONSTDATA unsigned value = 1 + width<n%d*10, d, w+1>::value;
}; };
template <std::uint64_t n, std::uint64_t d, unsigned w> template <std::uint64_t n, std::uint64_t d, unsigned w>
@ -3714,9 +3758,10 @@ class decimal_format_seconds
{ {
using CT = typename std::common_type<Duration, std::chrono::seconds>::type; using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
using rep = typename CT::rep; using rep = typename CT::rep;
static unsigned CONSTDATA trial_width =
detail::width<CT::period::num, CT::period::den>::value;
public: public:
static unsigned constexpr width = detail::width<CT::period::den>::value < 19 ? static unsigned CONSTDATA width = trial_width < 19 ? trial_width : 6u;
detail::width<CT::period::den>::value : 6u;
using precision = std::chrono::duration<rep, using precision = std::chrono::duration<rep,
std::ratio<1, static_pow10<width>::value>>; std::ratio<1, static_pow10<width>::value>>;
@ -3732,8 +3777,7 @@ public:
CONSTCD11 explicit decimal_format_seconds(const Duration& d) NOEXCEPT CONSTCD11 explicit decimal_format_seconds(const Duration& d) NOEXCEPT
: s_(std::chrono::duration_cast<std::chrono::seconds>(d)) : s_(std::chrono::duration_cast<std::chrono::seconds>(d))
, sub_s_(std::chrono::treat_as_floating_point<rep>::value ? d - s_ : , sub_s_(std::chrono::duration_cast<precision>(d - s_))
std::chrono::duration_cast<precision>(d - s_))
{} {}
CONSTCD14 std::chrono::seconds& seconds() NOEXCEPT {return s_;} CONSTCD14 std::chrono::seconds& seconds() NOEXCEPT {return s_;}
@ -4149,10 +4193,10 @@ operator+(std::basic_string<CharT, Traits, Alloc> x, const string_literal<CharT,
&& (!defined(__SUNPRO_CC) || __SUNPRO_CC > 0x5150) && (!defined(__SUNPRO_CC) || __SUNPRO_CC > 0x5150)
template <class CharT, template <class CharT,
class = std::enable_if_t<std::is_same<CharT, char>{} || class = std::enable_if_t<std::is_same<CharT, char>::value ||
std::is_same<CharT, wchar_t>{} || std::is_same<CharT, wchar_t>::value ||
std::is_same<CharT, char16_t>{} || std::is_same<CharT, char16_t>::value ||
std::is_same<CharT, char32_t>{}>> std::is_same<CharT, char32_t>::value>>
CONSTCD14 CONSTCD14
inline inline
string_literal<CharT, 2> string_literal<CharT, 2>
@ -6123,9 +6167,16 @@ long double
read_long_double(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned M = 10) read_long_double(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned M = 10)
{ {
unsigned count = 0; unsigned count = 0;
unsigned fcount = 0;
unsigned long long i = 0;
unsigned long long f = 0;
bool parsing_fraction = false;
#if ONLY_C_LOCALE
typename Traits::int_type decimal_point = '.';
#else
auto decimal_point = Traits::to_int_type( auto decimal_point = Traits::to_int_type(
std::use_facet<std::numpunct<CharT>>(is.getloc()).decimal_point()); std::use_facet<std::numpunct<CharT>>(is.getloc()).decimal_point());
std::string buf; #endif
while (true) while (true)
{ {
auto ic = is.peek(); auto ic = is.peek();
@ -6133,18 +6184,25 @@ read_long_double(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned
break; break;
if (Traits::eq_int_type(ic, decimal_point)) if (Traits::eq_int_type(ic, decimal_point))
{ {
buf += '.';
decimal_point = Traits::eof(); decimal_point = Traits::eof();
is.get(); parsing_fraction = true;
} }
else else
{ {
auto c = static_cast<char>(Traits::to_char_type(ic)); auto c = static_cast<char>(Traits::to_char_type(ic));
if (!('0' <= c && c <= '9')) if (!('0' <= c && c <= '9'))
break; break;
buf += c; if (!parsing_fraction)
(void)is.get(); {
i = 10*i + static_cast<unsigned>(c - '0');
}
else
{
f = 10*f + static_cast<unsigned>(c - '0');
++fcount;
}
} }
(void)is.get();
if (++count == M) if (++count == M)
break; break;
} }
@ -6153,7 +6211,7 @@ read_long_double(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned
is.setstate(std::ios::failbit); is.setstate(std::ios::failbit);
return 0; return 0;
} }
return std::stold(buf); return i + f/std::pow(10.L, fcount);
} }
struct rs struct rs
@ -6310,6 +6368,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
using std::chrono::seconds; using std::chrono::seconds;
using std::chrono::minutes; using std::chrono::minutes;
using std::chrono::hours; using std::chrono::hours;
using detail::round_i;
typename std::basic_istream<CharT, Traits>::sentry ok{is, true}; typename std::basic_istream<CharT, Traits>::sentry ok{is, true};
if (ok) if (ok)
{ {
@ -6325,7 +6384,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
auto modified = CharT{}; auto modified = CharT{};
auto width = -1; auto width = -1;
CONSTDATA int not_a_year = numeric_limits<int>::min(); CONSTDATA int not_a_year = numeric_limits<short>::min();
CONSTDATA int not_a_2digit_year = 100; CONSTDATA int not_a_2digit_year = 100;
CONSTDATA int not_a_century = not_a_year / 100; CONSTDATA int not_a_century = not_a_year / 100;
CONSTDATA int not_a_month = 0; CONSTDATA int not_a_month = 0;
@ -6523,7 +6582,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
CharT{':'}, rld{S, 1, w}); CharT{':'}, rld{S, 1, w});
checked_set(H, tH, not_a_hour, is); checked_set(H, tH, not_a_hour, is);
checked_set(M, tM, not_a_minute, is); checked_set(M, tM, not_a_minute, is);
checked_set(s, round<Duration>(duration<long double>{S}), checked_set(s, round_i<Duration>(duration<long double>{S}),
not_a_second, is); not_a_second, is);
ws(is); ws(is);
int tY = not_a_year; int tY = not_a_year;
@ -6603,7 +6662,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
CharT{':'}, rld{S, 1, w}); CharT{':'}, rld{S, 1, w});
checked_set(H, tH, not_a_hour, is); checked_set(H, tH, not_a_hour, is);
checked_set(M, tM, not_a_minute, is); checked_set(M, tM, not_a_minute, is);
checked_set(s, round<Duration>(duration<long double>{S}), checked_set(s, round_i<Duration>(duration<long double>{S}),
not_a_second, is); not_a_second, is);
#endif #endif
} }
@ -6919,7 +6978,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
#else #else
auto nm = detail::ampm_names(); auto nm = detail::ampm_names();
auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;
tp = i; tp = static_cast<decltype(tp)>(i);
#endif #endif
checked_set(p, tp, not_a_ampm, is); checked_set(p, tp, not_a_ampm, is);
} }
@ -6960,7 +7019,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
CharT{':'}, rld{S, 1, w}); CharT{':'}, rld{S, 1, w});
checked_set(I, tI, not_a_hour_12_value, is); checked_set(I, tI, not_a_hour_12_value, is);
checked_set(M, tM, not_a_minute, is); checked_set(M, tM, not_a_minute, is);
checked_set(s, round<Duration>(duration<long double>{S}), checked_set(s, round_i<Duration>(duration<long double>{S}),
not_a_second, is); not_a_second, is);
ws(is); ws(is);
auto nm = detail::ampm_names(); auto nm = detail::ampm_names();
@ -7011,7 +7070,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;
long double S; long double S;
read(is, rld{S, 1, width == -1 ? w : static_cast<unsigned>(width)}); read(is, rld{S, 1, width == -1 ? w : static_cast<unsigned>(width)});
checked_set(s, round<Duration>(duration<long double>{S}), checked_set(s, round_i<Duration>(duration<long double>{S}),
not_a_second, is); not_a_second, is);
} }
#if !ONLY_C_LOCALE #if !ONLY_C_LOCALE
@ -7048,7 +7107,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
CharT{':'}, rld{S, 1, w}); CharT{':'}, rld{S, 1, w});
checked_set(H, tH, not_a_hour, is); checked_set(H, tH, not_a_hour, is);
checked_set(M, tM, not_a_minute, is); checked_set(M, tM, not_a_minute, is);
checked_set(s, round<Duration>(duration<long double>{S}), checked_set(s, round_i<Duration>(duration<long double>{S}),
not_a_second, is); not_a_second, is);
} }
else else
@ -7751,6 +7810,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
std::chrono::minutes* offset = nullptr) std::chrono::minutes* offset = nullptr)
{ {
using CT = typename std::common_type<Duration, std::chrono::seconds>::type; using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
using detail::round_i;
std::chrono::minutes offset_local{}; std::chrono::minutes offset_local{};
auto offptr = offset ? offset : &offset_local; auto offptr = offset ? offset : &offset_local;
fields<CT> fds{}; fields<CT> fds{};
@ -7759,7 +7819,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
if (!fds.ymd.ok() || !fds.tod.in_conventional_range()) if (!fds.ymd.ok() || !fds.tod.in_conventional_range())
is.setstate(std::ios::failbit); is.setstate(std::ios::failbit);
if (!is.fail()) if (!is.fail())
tp = round<Duration>(sys_days(fds.ymd) - *offptr + fds.tod.to_duration()); tp = round_i<Duration>(sys_days(fds.ymd) - *offptr + fds.tod.to_duration());
return is; return is;
} }
@ -7770,13 +7830,14 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
std::chrono::minutes* offset = nullptr) std::chrono::minutes* offset = nullptr)
{ {
using CT = typename std::common_type<Duration, std::chrono::seconds>::type; using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
using detail::round_i;
fields<CT> fds{}; fields<CT> fds{};
fds.has_tod = true; fds.has_tod = true;
from_stream(is, fmt, fds, abbrev, offset); from_stream(is, fmt, fds, abbrev, offset);
if (!fds.ymd.ok() || !fds.tod.in_conventional_range()) if (!fds.ymd.ok() || !fds.tod.in_conventional_range())
is.setstate(std::ios::failbit); is.setstate(std::ios::failbit);
if (!is.fail()) if (!is.fail())
tp = round<Duration>(local_seconds{local_days(fds.ymd)} + fds.tod.to_duration()); tp = round_i<Duration>(local_seconds{local_days(fds.ymd)} + fds.tod.to_duration());
return is; return is;
} }

View File

@ -1655,9 +1655,12 @@ inline
bool bool
month_day::ok() const NOEXCEPT month_day::ok() const NOEXCEPT
{ {
CONSTDATA julian::day d[] = CONSTDATA julian::day d[] = {
{31_d, 29_d, 31_d, 30_d, 31_d, 30_d, 31_d, 31_d, 30_d, 31_d, 30_d, 31_d}; julian::day(31), julian::day(29), julian::day(31), julian::day(30),
return m_.ok() && 1_d <= d_ && d_ <= d[static_cast<unsigned>(m_)-1]; julian::day(31), julian::day(30), julian::day(31), julian::day(31),
julian::day(30), julian::day(31), julian::day(30), julian::day(31)
};
return m_.ok() && julian::day(1) <= d_ && d_ <= d[static_cast<unsigned>(m_)-1];
} }
CONSTCD11 CONSTCD11
@ -1946,9 +1949,12 @@ inline
day day
year_month_day_last::day() const NOEXCEPT year_month_day_last::day() const NOEXCEPT
{ {
CONSTDATA julian::day d[] = CONSTDATA julian::day d[] = {
{31_d, 28_d, 31_d, 30_d, 31_d, 30_d, 31_d, 31_d, 30_d, 31_d, 30_d, 31_d}; julian::day(31), julian::day(28), julian::day(31), julian::day(30),
return month() != feb || !y_.is_leap() ? d[static_cast<unsigned>(month())-1] : 29_d; julian::day(31), julian::day(30), julian::day(31), julian::day(31),
julian::day(30), julian::day(31), julian::day(30), julian::day(31)
};
return month() != feb || !y_.is_leap() ? d[static_cast<unsigned>(month())-1] : julian::day(29);
} }
CONSTCD14 CONSTCD14
@ -2190,7 +2196,7 @@ year_month_day::ok() const NOEXCEPT
{ {
if (!(y_.ok() && m_.ok())) if (!(y_.ok() && m_.ok()))
return false; return false;
return 1_d <= d_ && d_ <= (y_/m_/last).day(); return julian::day(1) <= d_ && d_ <= (y_/m_/last).day();
} }
CONSTCD11 CONSTCD11

View File

@ -36,6 +36,9 @@
// Posix::time_zone tz{"EST5EDT,M3.2.0,M11.1.0"}; // Posix::time_zone tz{"EST5EDT,M3.2.0,M11.1.0"};
// zoned_time<system_clock::duration, Posix::time_zone> zt{tz, system_clock::now()}; // zoned_time<system_clock::duration, Posix::time_zone> zt{tz, system_clock::now()};
// //
// If the rule set is missing (everything starting with ','), then the rule is that the
// alternate offset is never enabled.
//
// Note, Posix-style time zones are not recommended for all of the reasons described here: // Note, Posix-style time zones are not recommended for all of the reasons described here:
// https://stackoverflow.com/tags/timezone/info // https://stackoverflow.com/tags/timezone/info
// //
@ -70,7 +73,8 @@ 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_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_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_time(const string_t& s, unsigned i, std::chrono::seconds& t);
unsigned read_unsigned(const string_t& s, unsigned i, unsigned limit, unsigned& u); unsigned read_unsigned(const string_t& s, unsigned i, unsigned limit, unsigned& u,
const string_t& message = string_t{});
class rule class rule
{ {
@ -87,11 +91,38 @@ public:
bool ok() const {return mode_ != off;} bool ok() const {return mode_ != off;}
date::local_seconds operator()(date::year y) const; date::local_seconds operator()(date::year y) const;
std::string to_string() const;
friend std::ostream& operator<<(std::ostream& os, const rule& r); friend std::ostream& operator<<(std::ostream& os, const rule& r);
friend unsigned read_date(const string_t& s, unsigned i, rule& r); friend unsigned read_date(const string_t& s, unsigned i, rule& r);
friend bool operator==(const rule& x, const rule& y);
}; };
inline
bool
operator==(const rule& x, const rule& y)
{
if (x.mode_ != y.mode_)
return false;
switch (x.mode_)
{
case rule::J:
case rule::N:
return x.n_ == y.n_;
case rule::M:
return x.m_ == y.m_ && x.n_ == y.n_ && x.wd_ == y.wd_;
default:
return true;
}
}
inline
bool
operator!=(const rule& x, const rule& y)
{
return !(x == y);
}
inline inline
date::local_seconds date::local_seconds
rule::operator()(date::year y) const rule::operator()(date::year y) const
@ -119,6 +150,62 @@ rule::operator()(date::year y) const
return t; return t;
} }
inline
std::string
rule::to_string() const
{
using namespace std::chrono;
auto print_offset = [](seconds off)
{
std::string nm;
if (off != hours{2})
{
date::hh_mm_ss<seconds> offset{off};
nm = '/';
nm += std::to_string(offset.hours().count());
if (offset.minutes() != minutes{0} || offset.seconds() != seconds{0})
{
nm += ':';
if (offset.minutes() < minutes{10})
nm += '0';
nm += std::to_string(offset.minutes().count());
if (offset.seconds() != seconds{0})
{
nm += ':';
if (offset.seconds() < seconds{10})
nm += '0';
nm += std::to_string(offset.seconds().count());
}
}
}
return nm;
};
std::string nm;
switch (mode_)
{
case rule::J:
nm = 'J';
nm += std::to_string(n_);
break;
case rule::M:
nm = 'M';
nm += std::to_string(static_cast<unsigned>(m_));
nm += '.';
nm += std::to_string(n_);
nm += '.';
nm += std::to_string(wd_.c_encoding());
break;
case rule::N:
nm = std::to_string(n_);
break;
default:
break;
}
nm += print_offset(time_);
return nm;
}
inline inline
std::ostream& std::ostream&
operator<<(std::ostream& os, const rule& r) operator<<(std::ostream& os, const rule& r)
@ -178,6 +265,10 @@ public:
friend std::ostream& operator<<(std::ostream& os, const time_zone& z); friend std::ostream& operator<<(std::ostream& os, const time_zone& z);
const time_zone* operator->() const {return this;} const time_zone* operator->() const {return this;}
std::string name() const;
friend bool operator==(const time_zone& x, const time_zone& y);
}; };
inline inline
@ -195,7 +286,10 @@ time_zone::time_zone(const detail::string_t& s)
if (i != s.size()) if (i != s.size())
{ {
if (s[i] != ',') if (s[i] != ',')
{
i = read_signed_time(s, i, save_); i = read_signed_time(s, i, save_);
save_ = -save_ - offset_;
}
if (i != s.size()) if (i != s.size())
{ {
if (s[i] != ',') if (s[i] != ',')
@ -416,6 +510,72 @@ operator<<(std::ostream& os, const time_zone& z)
return os; return os;
} }
inline
std::string
time_zone::name() const
{
using namespace date;
using namespace std::chrono;
auto nm = std_abbrev_;
auto print_offset = [](seconds off)
{
std::string nm;
hh_mm_ss<seconds> offset{-off};
if (offset.is_negative())
nm += '-';
nm += std::to_string(offset.hours().count());
if (offset.minutes() != minutes{0} || offset.seconds() != seconds{0})
{
nm += ':';
if (offset.minutes() < minutes{10})
nm += '0';
nm += std::to_string(offset.minutes().count());
if (offset.seconds() != seconds{0})
{
nm += ':';
if (offset.seconds() < seconds{10})
nm += '0';
nm += std::to_string(offset.seconds().count());
}
}
return nm;
};
nm += print_offset(offset_);
if (!dst_abbrev_.empty())
{
nm += dst_abbrev_;
if (save_ != hours{1})
nm += print_offset(offset_+save_);
if (start_rule_.ok())
{
nm += ',';
nm += start_rule_.to_string();
nm += ',';
nm += end_rule_.to_string();
}
}
return nm;
}
inline
bool
operator==(const time_zone& x, const time_zone& y)
{
return x.std_abbrev_ == y.std_abbrev_ &&
x.dst_abbrev_ == y. dst_abbrev_ &&
x.offset_ == y.offset_ &&
x.save_ == y.save_ &&
x.start_rule_ == y.start_rule_ &&
x.end_rule_ == y.end_rule_;
}
inline
bool
operator!=(const time_zone& x, const time_zone& y)
{
return !(x == y);
}
namespace detail namespace detail
{ {
@ -428,7 +588,7 @@ throw_invalid(const string_t& s, unsigned i, const string_t& message)
std::string(s) + '\n' + std::string(s) + '\n' +
"\x1b[1;32m" + "\x1b[1;32m" +
std::string(i, '~') + '^' + std::string(i, '~') + '^' +
std::string(s.size()-i-1, '~') + std::string(i < s.size() ? s.size()-i-1 : 0, '~') +
"\x1b[0m"); "\x1b[0m");
} }
@ -444,7 +604,7 @@ read_date(const string_t& s, unsigned i, rule& r)
{ {
++i; ++i;
unsigned n; unsigned n;
i = read_unsigned(s, i, 3, n); i = read_unsigned(s, i, 3, n, "Expected to find the Julian day [1, 365]");
r.mode_ = rule::J; r.mode_ = rule::J;
r.n_ = n; r.n_ = n;
} }
@ -452,17 +612,17 @@ read_date(const string_t& s, unsigned i, rule& r)
{ {
++i; ++i;
unsigned m; unsigned m;
i = read_unsigned(s, i, 2, m); i = read_unsigned(s, i, 2, m, "Expected to find month [1, 12]");
if (i == s.size() || s[i] != '.') if (i == s.size() || s[i] != '.')
throw_invalid(s, i, "Expected '.' after month"); throw_invalid(s, i, "Expected '.' after month");
++i; ++i;
unsigned n; unsigned n;
i = read_unsigned(s, i, 1, n); i = read_unsigned(s, i, 1, n, "Expected to find week number [1, 5]");
if (i == s.size() || s[i] != '.') if (i == s.size() || s[i] != '.')
throw_invalid(s, i, "Expected '.' after weekday index"); throw_invalid(s, i, "Expected '.' after weekday index");
++i; ++i;
unsigned wd; unsigned wd;
i = read_unsigned(s, i, 1, wd); i = read_unsigned(s, i, 1, wd, "Expected to find day of week [0, 6]");
r.mode_ = rule::M; r.mode_ = rule::M;
r.m_ = month{m}; r.m_ = month{m};
r.wd_ = weekday{wd}; r.wd_ = weekday{wd};
@ -552,17 +712,17 @@ read_unsigned_time(const string_t& s, unsigned i, std::chrono::seconds& t)
if (i == s.size()) if (i == s.size())
throw_invalid(s, i, "Expected to read unsigned time, but found end of string"); throw_invalid(s, i, "Expected to read unsigned time, but found end of string");
unsigned x; unsigned x;
i = read_unsigned(s, i, 2, x); i = read_unsigned(s, i, 2, x, "Expected to find hours [0, 24]");
t = hours{x}; t = hours{x};
if (i != s.size() && s[i] == ':') if (i != s.size() && s[i] == ':')
{ {
++i; ++i;
i = read_unsigned(s, i, 2, x); i = read_unsigned(s, i, 2, x, "Expected to find minutes [0, 59]");
t += minutes{x}; t += minutes{x};
if (i != s.size() && s[i] == ':') if (i != s.size() && s[i] == ':')
{ {
++i; ++i;
i = read_unsigned(s, i, 2, x); i = read_unsigned(s, i, 2, x, "Expected to find seconds [0, 59]");
t += seconds{x}; t += seconds{x};
} }
} }
@ -571,10 +731,11 @@ read_unsigned_time(const string_t& s, unsigned i, std::chrono::seconds& t)
inline inline
unsigned unsigned
read_unsigned(const string_t& s, unsigned i, unsigned limit, unsigned& u) read_unsigned(const string_t& s, unsigned i, unsigned limit, unsigned& u,
const string_t& message)
{ {
if (i == s.size() || !std::isdigit(s[i])) if (i == s.size() || !std::isdigit(s[i]))
throw_invalid(s, i, "Expected to find a decimal digit"); throw_invalid(s, i, message);
u = static_cast<unsigned>(s[i] - '0'); u = static_cast<unsigned>(s[i] - '0');
unsigned count = 1; unsigned count = 1;
for (++i; count < limit && i != s.size() && std::isdigit(s[i]); ++i, ++count) for (++i; count < limit && i != s.size() && std::isdigit(s[i]); ++i, ++count)

View File

@ -1707,9 +1707,13 @@ inline
bool bool
month_day::ok() const NOEXCEPT month_day::ok() const NOEXCEPT
{ {
CONSTDATA solar_hijri::day d[] = CONSTDATA solar_hijri::day d[] = {
{31_d, 31_d, 31_d, 31_d, 31_d, 31_d, 30_d, 30_d, 30_d, 30_d, 30_d, 30_d}; solar_hijri::day(31), solar_hijri::day(31), solar_hijri::day(31),
return m_.ok() && 1_d <= d_ && d_ <= d[static_cast<unsigned>(m_)-1]; solar_hijri::day(31), solar_hijri::day(31), solar_hijri::day(31),
solar_hijri::day(30), solar_hijri::day(30), solar_hijri::day(30),
solar_hijri::day(30), solar_hijri::day(30), solar_hijri::day(30)
};
return m_.ok() && solar_hijri::day(1) <= d_ && d_ <= d[static_cast<unsigned>(m_)-1];
} }
CONSTCD11 CONSTCD11
@ -1998,10 +2002,14 @@ inline
day day
year_month_day_last::day() const NOEXCEPT year_month_day_last::day() const NOEXCEPT
{ {
CONSTDATA solar_hijri::day d[] = CONSTDATA solar_hijri::day d[] = {
{31_d, 31_d, 31_d, 31_d, 31_d, 31_d, 30_d, 30_d, 30_d, 30_d, 30_d, 29_d}; solar_hijri::day(31), solar_hijri::day(31), solar_hijri::day(31),
solar_hijri::day(31), solar_hijri::day(31), solar_hijri::day(31),
solar_hijri::day(30), solar_hijri::day(30), solar_hijri::day(30),
solar_hijri::day(30), solar_hijri::day(30), solar_hijri::day(29)
};
return month() != esf || !y_.is_leap() ? return month() != esf || !y_.is_leap() ?
d[static_cast<unsigned>(month())-1] : 30_d; d[static_cast<unsigned>(month()) - 1] : solar_hijri::day(30);
} }
CONSTCD14 CONSTCD14
@ -2260,7 +2268,7 @@ year_month_day::ok() const NOEXCEPT
{ {
if (!(y_.ok() && m_.ok())) if (!(y_.ok() && m_.ok()))
return false; return false;
return 1_d <= d_ && d_ <= (y_/m_/last).day(); return solar_hijri::day(1) <= d_ && d_ <= (y_/m_/last).day();
} }
CONSTCD11 CONSTCD11

View File

@ -86,15 +86,6 @@ static_assert(HAS_REMOTE_API == 0 ? AUTO_DOWNLOAD == 0 : true,
# ifdef _WIN32 # ifdef _WIN32
# error "USE_OS_TZDB can not be used on Windows" # error "USE_OS_TZDB can not be used on Windows"
# endif # endif
# ifndef MISSING_LEAP_SECONDS
# ifdef __APPLE__
# define MISSING_LEAP_SECONDS 1
# else
# define MISSING_LEAP_SECONDS 0
# endif
# endif
#else
# define MISSING_LEAP_SECONDS 0
#endif #endif
#ifndef HAS_DEDUCTION_GUIDES #ifndef HAS_DEDUCTION_GUIDES
@ -703,6 +694,11 @@ public:
private: private:
template <class D, class T> friend class zoned_time; template <class D, class T> friend class zoned_time;
template <class TimeZonePtr2>
static
TimeZonePtr2&&
check(TimeZonePtr2&& p);
}; };
using zoned_seconds = zoned_time<std::chrono::seconds>; using zoned_seconds = zoned_time<std::chrono::seconds>;
@ -990,8 +986,6 @@ inline bool operator>=(const time_zone_link& x, const time_zone_link& y) {return
#endif // !USE_OS_TZDB #endif // !USE_OS_TZDB
#if !MISSING_LEAP_SECONDS
class leap_second class leap_second
{ {
private: private:
@ -1115,8 +1109,6 @@ operator>=(const sys_time<Duration>& x, const leap_second& y)
using leap = leap_second; using leap = leap_second;
#endif // !MISSING_LEAP_SECONDS
#ifdef _WIN32 #ifdef _WIN32
namespace detail namespace detail
@ -1162,9 +1154,7 @@ struct tzdb
#if !USE_OS_TZDB #if !USE_OS_TZDB
std::vector<time_zone_link> links; std::vector<time_zone_link> links;
#endif #endif
#if !MISSING_LEAP_SECONDS
std::vector<leap_second> leap_seconds; std::vector<leap_second> leap_seconds;
#endif
#if !USE_OS_TZDB #if !USE_OS_TZDB
std::vector<detail::Rule> rules; std::vector<detail::Rule> rules;
#endif #endif
@ -1221,31 +1211,31 @@ class tzdb_list
public: public:
~tzdb_list(); ~tzdb_list();
tzdb_list() = default; tzdb_list() = default;
tzdb_list(tzdb_list&& x) noexcept; tzdb_list(tzdb_list&& x) NOEXCEPT;
const tzdb& front() const noexcept {return *head_;} const tzdb& front() const NOEXCEPT {return *head_;}
tzdb& front() noexcept {return *head_;} tzdb& front() NOEXCEPT {return *head_;}
class const_iterator; class const_iterator;
const_iterator begin() const noexcept; const_iterator begin() const NOEXCEPT;
const_iterator end() const noexcept; const_iterator end() const NOEXCEPT;
const_iterator cbegin() const noexcept; const_iterator cbegin() const NOEXCEPT;
const_iterator cend() const noexcept; const_iterator cend() const NOEXCEPT;
const_iterator erase_after(const_iterator p) noexcept; const_iterator erase_after(const_iterator p) NOEXCEPT;
struct undocumented_helper; struct undocumented_helper;
private: private:
void push_front(tzdb* tzdb) noexcept; void push_front(tzdb* tzdb) NOEXCEPT;
}; };
class tzdb_list::const_iterator class tzdb_list::const_iterator
{ {
tzdb* p_ = nullptr; tzdb* p_ = nullptr;
explicit const_iterator(tzdb* p) noexcept : p_{p} {} explicit const_iterator(tzdb* p) NOEXCEPT : p_{p} {}
public: public:
const_iterator() = default; const_iterator() = default;
@ -1255,20 +1245,20 @@ public:
using pointer = const value_type*; using pointer = const value_type*;
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
reference operator*() const noexcept {return *p_;} reference operator*() const NOEXCEPT {return *p_;}
pointer operator->() const noexcept {return p_;} pointer operator->() const NOEXCEPT {return p_;}
const_iterator& operator++() noexcept {p_ = p_->next; return *this;} const_iterator& operator++() NOEXCEPT {p_ = p_->next; return *this;}
const_iterator operator++(int) noexcept {auto t = *this; ++(*this); return t;} const_iterator operator++(int) NOEXCEPT {auto t = *this; ++(*this); return t;}
friend friend
bool bool
operator==(const const_iterator& x, const const_iterator& y) noexcept operator==(const const_iterator& x, const const_iterator& y) NOEXCEPT
{return x.p_ == y.p_;} {return x.p_ == y.p_;}
friend friend
bool bool
operator!=(const const_iterator& x, const const_iterator& y) noexcept operator!=(const const_iterator& x, const const_iterator& y) NOEXCEPT
{return !(x == y);} {return !(x == y);}
friend class tzdb_list; friend class tzdb_list;
@ -1276,28 +1266,28 @@ public:
inline inline
tzdb_list::const_iterator tzdb_list::const_iterator
tzdb_list::begin() const noexcept tzdb_list::begin() const NOEXCEPT
{ {
return const_iterator{head_}; return const_iterator{head_};
} }
inline inline
tzdb_list::const_iterator tzdb_list::const_iterator
tzdb_list::end() const noexcept tzdb_list::end() const NOEXCEPT
{ {
return const_iterator{nullptr}; return const_iterator{nullptr};
} }
inline inline
tzdb_list::const_iterator tzdb_list::const_iterator
tzdb_list::cbegin() const noexcept tzdb_list::cbegin() const NOEXCEPT
{ {
return begin(); return begin();
} }
inline inline
tzdb_list::const_iterator tzdb_list::const_iterator
tzdb_list::cend() const noexcept tzdb_list::cend() const NOEXCEPT
{ {
return end(); return end();
} }
@ -1328,7 +1318,7 @@ namespace detail
template <class T> template <class T>
inline inline
T* T*
to_raw_pointer(T* p) noexcept to_raw_pointer(T* p) NOEXCEPT
{ {
return p; return p;
} }
@ -1336,7 +1326,7 @@ to_raw_pointer(T* p) noexcept
template <class Pointer> template <class Pointer>
inline inline
auto auto
to_raw_pointer(Pointer p) noexcept to_raw_pointer(Pointer p) NOEXCEPT
-> decltype(detail::to_raw_pointer(p.operator->())) -> decltype(detail::to_raw_pointer(p.operator->()))
{ {
return detail::to_raw_pointer(p.operator->()); return detail::to_raw_pointer(p.operator->());
@ -1344,13 +1334,25 @@ to_raw_pointer(Pointer p) noexcept
} // namespace detail } // namespace detail
template <class Duration, class TimeZonePtr>
template <class TimeZonePtr2>
inline
TimeZonePtr2&&
zoned_time<Duration, TimeZonePtr>::check(TimeZonePtr2&& p)
{
if (detail::to_raw_pointer(p) == nullptr)
throw std::runtime_error(
"zoned_time constructed with a time zone pointer == nullptr");
return std::forward<TimeZonePtr2>(p);
}
template <class Duration, class TimeZonePtr> template <class Duration, class TimeZonePtr>
#if !defined(_MSC_VER) || (_MSC_VER > 1916) #if !defined(_MSC_VER) || (_MSC_VER > 1916)
template <class T, class> template <class T, class>
#endif #endif
inline inline
zoned_time<Duration, TimeZonePtr>::zoned_time() zoned_time<Duration, TimeZonePtr>::zoned_time()
: zone_(zoned_traits<TimeZonePtr>::default_zone()) : zone_(check(zoned_traits<TimeZonePtr>::default_zone()))
{} {}
template <class Duration, class TimeZonePtr> template <class Duration, class TimeZonePtr>
@ -1359,15 +1361,15 @@ template <class T, class>
#endif #endif
inline inline
zoned_time<Duration, TimeZonePtr>::zoned_time(const sys_time<Duration>& st) zoned_time<Duration, TimeZonePtr>::zoned_time(const sys_time<Duration>& st)
: zone_(zoned_traits<TimeZonePtr>::default_zone()) : zone_(check(zoned_traits<TimeZonePtr>::default_zone()))
, tp_(st) , tp_(st)
{} {}
template <class Duration, class TimeZonePtr> template <class Duration, class TimeZonePtr>
inline inline
zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z) zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z)
: zone_(std::move(z)) : zone_(check(std::move(z)))
{assert(detail::to_raw_pointer(zone_) != nullptr);} {}
#if HAS_STRING_VIEW #if HAS_STRING_VIEW
@ -1402,7 +1404,7 @@ zoned_time<Duration, TimeZonePtr>::zoned_time(const zoned_time<Duration2, TimeZo
template <class Duration, class TimeZonePtr> template <class Duration, class TimeZonePtr>
inline inline
zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const sys_time<Duration>& st) zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const sys_time<Duration>& st)
: zone_(std::move(z)) : zone_(check(std::move(z)))
, tp_(st) , tp_(st)
{} {}
@ -1412,7 +1414,7 @@ template <class T, class>
#endif #endif
inline inline
zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const local_time<Duration>& t) zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const local_time<Duration>& t)
: zone_(std::move(z)) : zone_(check(std::move(z)))
, tp_(zone_->to_sys(t)) , tp_(zone_->to_sys(t))
{} {}
@ -1423,7 +1425,7 @@ template <class T, class>
inline inline
zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const local_time<Duration>& t, zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, const local_time<Duration>& t,
choose c) choose c)
: zone_(std::move(z)) : zone_(check(std::move(z)))
, tp_(zone_->to_sys(t, c)) , tp_(zone_->to_sys(t, c))
{} {}
@ -1432,7 +1434,7 @@ template <class Duration2, class TimeZonePtr2, class>
inline inline
zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z, zoned_time<Duration, TimeZonePtr>::zoned_time(TimeZonePtr z,
const zoned_time<Duration2, TimeZonePtr2>& zt) const zoned_time<Duration2, TimeZonePtr2>& zt)
: zone_(std::move(z)) : zone_(check(std::move(z)))
, tp_(zt.tp_) , tp_(zt.tp_)
{} {}
@ -1847,8 +1849,6 @@ operator<<(std::basic_ostream<CharT, Traits>& os, const zoned_time<Duration, Tim
return to_stream(os, fmt, t); return to_stream(os, fmt, t);
} }
#if !MISSING_LEAP_SECONDS
class utc_clock class utc_clock
{ {
public: public:
@ -2787,8 +2787,6 @@ to_gps_time(const tai_time<Duration>& t)
return gps_clock::from_utc(tai_clock::to_utc(t)); return gps_clock::from_utc(tai_clock::to_utc(t));
} }
#endif // !MISSING_LEAP_SECONDS
} // namespace date } // namespace date
#endif // TZ_H #endif // TZ_H

View File

@ -95,9 +95,9 @@ private:
U& operator=(const pair& x); U& operator=(const pair& x);
} u; } u;
std::chrono::hours h_{}; std::chrono::hours h_{0};
std::chrono::minutes m_{}; std::chrono::minutes m_{0};
std::chrono::seconds s_{}; std::chrono::seconds s_{0};
tz zone_{tz::local}; tz zone_{tz::local};
public: public:
@ -245,7 +245,7 @@ struct zonelet
sys_seconds until_utc_; sys_seconds until_utc_;
local_seconds until_std_; local_seconds until_std_;
local_seconds until_loc_; local_seconds until_loc_;
std::chrono::minutes initial_save_{}; std::chrono::minutes initial_save_{0};
std::string initial_abbrev_; std::string initial_abbrev_;
std::pair<const Rule*, date::year> first_rule_{nullptr, date::year::min()}; std::pair<const Rule*, date::year> first_rule_{nullptr, date::year::min()};
std::pair<const Rule*, date::year> last_rule_{nullptr, date::year::max()}; std::pair<const Rule*, date::year> last_rule_{nullptr, date::year::max()};

View File

@ -89,6 +89,7 @@
# include "date/ios.h" # include "date/ios.h"
#else #else
# define TARGET_OS_IPHONE 0 # define TARGET_OS_IPHONE 0
# define TARGET_OS_SIMULATOR 0
#endif #endif
#if USE_OS_TZDB #if USE_OS_TZDB
@ -140,7 +141,7 @@
# endif // HAS_REMOTE_API # endif // HAS_REMOTE_API
#else // !_WIN32 #else // !_WIN32
# include <unistd.h> # include <unistd.h>
# if !USE_OS_TZDB # if !USE_OS_TZDB && !defined(INSTALL)
# include <wordexp.h> # include <wordexp.h>
# endif # endif
# include <limits.h> # include <limits.h>
@ -361,7 +362,11 @@ discover_tz_dir()
throw runtime_error("discover_tz_dir failed to find zoneinfo\n"); throw runtime_error("discover_tz_dir failed to find zoneinfo\n");
# else // __APPLE__ # else // __APPLE__
# if TARGET_OS_IPHONE # if TARGET_OS_IPHONE
# if TARGET_OS_SIMULATOR
return "/usr/share/zoneinfo";
# else
return "/var/db/timezone/zoneinfo"; return "/var/db/timezone/zoneinfo";
# endif
# else # else
CONSTDATA auto timezone = "/etc/localtime"; CONSTDATA auto timezone = "/etc/localtime";
if (!(lstat(timezone, &sb) == 0 && S_ISLNK(sb.st_mode) && sb.st_size > 0)) if (!(lstat(timezone, &sb) == 0 && S_ISLNK(sb.st_mode) && sb.st_size > 0))
@ -415,20 +420,20 @@ tzdb_list::~tzdb_list()
} }
} }
tzdb_list::tzdb_list(tzdb_list&& x) noexcept tzdb_list::tzdb_list(tzdb_list&& x) NOEXCEPT
: head_{x.head_.exchange(nullptr)} : head_{x.head_.exchange(nullptr)}
{ {
} }
void void
tzdb_list::push_front(tzdb* tzdb) noexcept tzdb_list::push_front(tzdb* tzdb) NOEXCEPT
{ {
tzdb->next = head_; tzdb->next = head_;
head_ = tzdb; head_ = tzdb;
} }
tzdb_list::const_iterator tzdb_list::const_iterator
tzdb_list::erase_after(const_iterator p) noexcept tzdb_list::erase_after(const_iterator p) NOEXCEPT
{ {
auto t = p.p_->next; auto t = p.p_->next;
p.p_->next = p.p_->next->next; p.p_->next = p.p_->next->next;
@ -438,7 +443,7 @@ tzdb_list::erase_after(const_iterator p) noexcept
struct tzdb_list::undocumented_helper struct tzdb_list::undocumented_helper
{ {
static void push_front(tzdb_list& db_list, tzdb* tzdb) noexcept static void push_front(tzdb_list& db_list, tzdb* tzdb) NOEXCEPT
{ {
db_list.push_front(tzdb); db_list.push_front(tzdb);
} }
@ -460,6 +465,32 @@ get_tzdb_list()
return tz_db; return tz_db;
} }
static
std::string
parse3(std::istream& in)
{
std::string r(3, ' ');
ws(in);
r[0] = static_cast<char>(in.get());
r[1] = static_cast<char>(in.get());
r[2] = static_cast<char>(in.get());
return r;
}
static
unsigned
parse_month(std::istream& in)
{
CONSTDATA char*const month_names[] =
{"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
auto s = parse3(in);
auto m = std::find(std::begin(month_names), std::end(month_names), s) - month_names;
if (m >= std::end(month_names) - std::begin(month_names))
throw std::runtime_error("oops: bad month name: " + s);
return static_cast<unsigned>(++m);
}
#if !USE_OS_TZDB #if !USE_OS_TZDB
#ifdef _WIN32 #ifdef _WIN32
@ -674,18 +705,6 @@ load_timezone_mappings_from_xml_file(const std::string& input_path)
// Parsing helpers // Parsing helpers
static
std::string
parse3(std::istream& in)
{
std::string r(3, ' ');
ws(in);
r[0] = static_cast<char>(in.get());
r[1] = static_cast<char>(in.get());
r[2] = static_cast<char>(in.get());
return r;
}
static static
unsigned unsigned
parse_dow(std::istream& in) parse_dow(std::istream& in)
@ -699,20 +718,6 @@ parse_dow(std::istream& in)
return static_cast<unsigned>(dow); return static_cast<unsigned>(dow);
} }
static
unsigned
parse_month(std::istream& in)
{
CONSTDATA char*const month_names[] =
{"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
auto s = parse3(in);
auto m = std::find(std::begin(month_names), std::end(month_names), s) - month_names;
if (m >= std::end(month_names) - std::begin(month_names))
throw std::runtime_error("oops: bad month name: " + s);
return static_cast<unsigned>(++m);
}
static static
std::chrono::seconds std::chrono::seconds
parse_unsigned_time(std::istream& in) parse_unsigned_time(std::istream& in)
@ -2120,14 +2125,25 @@ time_zone::load_sys_info(std::vector<detail::transition>::const_iterator i) cons
{ {
using namespace std::chrono; using namespace std::chrono;
assert(!transitions_.empty()); assert(!transitions_.empty());
assert(i != transitions_.begin());
sys_info r; sys_info r;
r.begin = i[-1].timepoint; if (i != transitions_.begin())
r.end = i != transitions_.end() ? i->timepoint : {
sys_seconds(sys_days(year::max()/max_day)); r.begin = i[-1].timepoint;
r.offset = i[-1].info->offset; r.end = i != transitions_.end() ? i->timepoint :
r.save = i[-1].info->is_dst ? minutes{1} : minutes{0}; sys_seconds(sys_days(year::max()/max_day));
r.abbrev = i[-1].info->abbrev; r.offset = i[-1].info->offset;
r.save = i[-1].info->is_dst ? minutes{1} : minutes{0};
r.abbrev = i[-1].info->abbrev;
}
else
{
r.begin = sys_days(year::min()/min_day);
r.end = i+1 != transitions_.end() ? i[1].timepoint :
sys_seconds(sys_days(year::max()/max_day));
r.offset = i[0].info->offset;
r.save = i[0].info->is_dst ? minutes{1} : minutes{0};
r.abbrev = i[0].info->abbrev;
}
return r; return r;
} }
@ -2162,7 +2178,7 @@ time_zone::get_info_impl(local_seconds tp) const
{ {
i.second = load_sys_info(--tr); i.second = load_sys_info(--tr);
tps = sys_seconds{(tp - i.second.offset).time_since_epoch()}; tps = sys_seconds{(tp - i.second.offset).time_since_epoch()};
if (tps < i.second.end) if (tps < i.second.end && i.first.end != i.second.end)
{ {
i.result = local_info::ambiguous; i.result = local_info::ambiguous;
std::swap(i.first, i.second); std::swap(i.first, i.second);
@ -2205,15 +2221,11 @@ operator<<(std::ostream& os, const time_zone& z)
return os; return os;
} }
#if !MISSING_LEAP_SECONDS
leap_second::leap_second(const sys_seconds& s, detail::undocumented) leap_second::leap_second(const sys_seconds& s, detail::undocumented)
: date_(s) : date_(s)
{ {
} }
#endif // !MISSING_LEAP_SECONDS
#else // !USE_OS_TZDB #else // !USE_OS_TZDB
time_zone::time_zone(const std::string& s, detail::undocumented) time_zone::time_zone(const std::string& s, detail::undocumented)
@ -2610,8 +2622,6 @@ operator<<(std::ostream& os, const time_zone& z)
#endif // !USE_OS_TZDB #endif // !USE_OS_TZDB
#if !MISSING_LEAP_SECONDS
std::ostream& std::ostream&
operator<<(std::ostream& os, const leap_second& x) operator<<(std::ostream& os, const leap_second& x)
{ {
@ -2619,11 +2629,8 @@ operator<<(std::ostream& os, const leap_second& x)
return os << x.date_ << " +"; return os << x.date_ << " +";
} }
#endif // !MISSING_LEAP_SECONDS
#if USE_OS_TZDB #if USE_OS_TZDB
# ifdef __APPLE__
static static
std::string std::string
get_version() get_version()
@ -2632,12 +2639,99 @@ get_version()
auto path = get_tz_dir() + string("/+VERSION"); auto path = get_tz_dir() + string("/+VERSION");
ifstream in{path}; ifstream in{path};
string version; string version;
in >> version; if (in)
if (in.fail()) {
throw std::runtime_error("Unable to get Timezone database version from " + path); in >> version;
return version; return version;
}
in.clear();
in.open(get_tz_dir() + std::string(1, folder_delimiter) + "version");
if (in)
{
in >> version;
return version;
}
return "unknown";
}
static
std::vector<leap_second>
find_read_and_leap_seconds()
{
std::ifstream in(get_tz_dir() + std::string(1, folder_delimiter) + "leapseconds",
std::ios_base::binary);
if (in)
{
std::vector<leap_second> leap_seconds;
std::string line;
while (in)
{
std::getline(in, line);
if (!line.empty() && line[0] != '#')
{
std::istringstream in(line);
in.exceptions(std::ios::failbit | std::ios::badbit);
std::string word;
in >> word;
if (word == "Leap")
{
int y, m, d;
in >> y;
m = static_cast<int>(parse_month(in));
in >> d;
leap_seconds.push_back(leap_second(sys_days{year{y}/m/d} + days{1},
detail::undocumented{}));
}
else
{
std::cerr << line << '\n';
}
}
}
return leap_seconds;
}
in.clear();
in.open(get_tz_dir() + std::string(1, folder_delimiter) + "leap-seconds.list",
std::ios_base::binary);
if (in)
{
std::vector<leap_second> leap_seconds;
std::string line;
const auto offset = sys_days{1970_y/1/1}-sys_days{1900_y/1/1};
while (in)
{
std::getline(in, line);
if (!line.empty() && line[0] != '#')
{
std::istringstream in(line);
in.exceptions(std::ios::failbit | std::ios::badbit);
using seconds = std::chrono::seconds;
seconds::rep s;
in >> s;
if (s == 2272060800)
continue;
leap_seconds.push_back(leap_second(sys_seconds{seconds{s}} - offset,
detail::undocumented{}));
}
}
return leap_seconds;
}
in.clear();
in.open(get_tz_dir() + std::string(1, folder_delimiter) + "right/UTC",
std::ios_base::binary);
if (in)
{
return load_just_leaps(in);
}
in.clear();
in.open(get_tz_dir() + std::string(1, folder_delimiter) + "UTC",
std::ios_base::binary);
if (in)
{
return load_just_leaps(in);
}
return {};
} }
# endif
static static
std::unique_ptr<tzdb> std::unique_ptr<tzdb>
@ -2666,6 +2760,7 @@ init_tzdb()
strcmp(d->d_name, "iso3166.tab") == 0 || strcmp(d->d_name, "iso3166.tab") == 0 ||
strcmp(d->d_name, "right") == 0 || strcmp(d->d_name, "right") == 0 ||
strcmp(d->d_name, "+VERSION") == 0 || strcmp(d->d_name, "+VERSION") == 0 ||
strcmp(d->d_name, "version") == 0 ||
strcmp(d->d_name, "zone.tab") == 0 || strcmp(d->d_name, "zone.tab") == 0 ||
strcmp(d->d_name, "zone1970.tab") == 0 || strcmp(d->d_name, "zone1970.tab") == 0 ||
strcmp(d->d_name, "tzdata.zi") == 0 || strcmp(d->d_name, "tzdata.zi") == 0 ||
@ -2693,28 +2788,8 @@ init_tzdb()
} }
db->zones.shrink_to_fit(); db->zones.shrink_to_fit();
std::sort(db->zones.begin(), db->zones.end()); std::sort(db->zones.begin(), db->zones.end());
# if !MISSING_LEAP_SECONDS db->leap_seconds = find_read_and_leap_seconds();
std::ifstream in(get_tz_dir() + std::string(1, folder_delimiter) + "right/UTC",
std::ios_base::binary);
if (in)
{
in.exceptions(std::ios::failbit | std::ios::badbit);
db->leap_seconds = load_just_leaps(in);
}
else
{
in.clear();
in.open(get_tz_dir() + std::string(1, folder_delimiter) +
"UTC", std::ios_base::binary);
if (!in)
throw std::runtime_error("Unable to extract leap second information");
in.exceptions(std::ios::failbit | std::ios::badbit);
db->leap_seconds = load_just_leaps(in);
}
# endif // !MISSING_LEAP_SECONDS
# ifdef __APPLE__
db->version = get_version(); db->version = get_version();
# endif
return db; return db;
} }
@ -3289,8 +3364,8 @@ remote_download(const std::string& version, char* error_buffer)
{ {
auto mapping_file = get_download_mapping_file(version); auto mapping_file = get_download_mapping_file(version);
result = download_to_file( result = download_to_file(
"https://raw.githubusercontent.com/unicode-org/cldr/master/" "https://raw.githubusercontent.com/unicode-org/cldr/master/"
"common/supplemental/windowsZones.xml", "common/supplemental/windowsZones.xml",
mapping_file, download_file_options::text, error_buffer); mapping_file, download_file_options::text, error_buffer);
} }
# endif // _WIN32 # endif // _WIN32
@ -3564,11 +3639,9 @@ operator<<(std::ostream& os, const tzdb& db)
os << "Version: " << db.version << "\n\n"; os << "Version: " << db.version << "\n\n";
for (const auto& x : db.zones) for (const auto& x : db.zones)
os << x << '\n'; os << x << '\n';
#if !MISSING_LEAP_SECONDS
os << '\n'; os << '\n';
for (const auto& x : db.leap_seconds) for (const auto& x : db.leap_seconds)
os << x << '\n'; os << x << '\n';
#endif // !MISSING_LEAP_SECONDS
return os; return os;
} }

View File

@ -46,19 +46,19 @@ int
main() main()
{ {
using namespace date::detail; using namespace date::detail;
static_assert(width<0>::value == 0, ""); static_assert(width<0, 1>::value == 0, "");
static_assert(width<1>::value == 0, ""); static_assert(width<1, 1>::value == 0, "");
static_assert(width<2>::value == 1, ""); static_assert(width<1, 2>::value == 1, "");
static_assert(width<3>::value == 19, ""); static_assert(width<1, 3>::value == 19, "");
static_assert(width<4>::value == 2, ""); static_assert(width<1, 4>::value == 2, "");
static_assert(width<5>::value == 1, ""); static_assert(width<1, 5>::value == 1, "");
static_assert(width<6>::value == 19, ""); static_assert(width<1, 6>::value == 19, "");
static_assert(width<7>::value == 19, ""); static_assert(width<1, 7>::value == 19, "");
static_assert(width<8>::value == 3, ""); static_assert(width<1, 8>::value == 3, "");
static_assert(width<9>::value == 19, ""); static_assert(width<1, 9>::value == 19, "");
static_assert(width<10>::value == 1, ""); static_assert(width<1, 10>::value == 1, "");
static_assert(width<100>::value == 2, ""); static_assert(width<1, 100>::value == 2, "");
static_assert(width<1000>::value == 3, ""); static_assert(width<1, 1000>::value == 3, "");
static_assert(width<10000>::value == 4, ""); static_assert(width<1, 10000>::value == 4, "");
static_assert(width<625>::value == 4, ""); static_assert(width<756, 625>::value == 4, "");
} }

View File

@ -0,0 +1,36 @@
// The MIT License (MIT)
//
// Copyright (c) 2020 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.
#include "tz.h"
#include <type_traits>
int
main()
{
using namespace date;
static_assert( std::is_nothrow_destructible<tzdb_list>{}, "");
static_assert( std::is_nothrow_default_constructible<tzdb_list>{}, "");
static_assert(!std::is_copy_constructible<tzdb_list>{}, "");
static_assert(!std::is_copy_assignable<tzdb_list>{}, "");
static_assert( std::is_nothrow_move_constructible<tzdb_list>{}, "");
static_assert(!std::is_move_assignable<tzdb_list>{}, "");
}