44 Commits

Author SHA1 Message Date
1658637448 C++23 enable in CMakeLists.txt 2023-04-27 14:26:47 +02:00
4bbbffdf4c Merge pull request #1 from zaporozhets/feature/add_linux_build_support
Add linux build support
2023-04-25 14:13:35 +02:00
8ec7f3a36d Add linux build support 2023-04-13 19:03:31 +02:00
b1a75847d5 Added qmake helper file to use this library easily with Qt 2021-02-14 23:24:22 +01:00
49d78d1837 Silenced warning 2021-02-09 18:32:44 +01:00
a32ff4f07e esp-idf fixes 2021-02-09 17:46:44 +01:00
3be6b76d70 Added library.json 2021-02-09 17:46:44 +01:00
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
14 changed files with 593 additions and 451 deletions

View File

@ -1,248 +1,23 @@
#[===================================================================[
date library by Howard Hinnant
if(DEFINED IDF_TARGET)
idf_component_register(INCLUDE_DIRS include)
set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 23)
target_compile_definitions(${COMPONENT_TARGET} INTERFACE HAS_UNCAUGHT_EXCEPTIONS=1)
else()
add_library(date
include/date/chrono_io.h
include/date/date.h
include/date/ios.h
include/date/islamic.h
include/date/iso_week.h
include/date/julian.h
include/date/ptz.h
include/date/solar_hijri.h
include/date/tz.h
include/date/tz_private.h
src/tz.cpp
)
CMake projects that wish to use this library should consider
something like the following :
include( FetchContent )
FetchContent_Declare( date_src
GIT_REPOSITORY https://github.com/HowardHinnant/date.git
GIT_TAG 2.4.2 # adjust tag/branch/commit as needed
)
FetchContent_MakeAvailable(date_src)
...
target_link_libraries (my_target PRIVATE date::date)
#]===================================================================]
cmake_minimum_required( VERSION 3.7 )
project( date VERSION 2.4.1 )
include( GNUInstallDirs )
get_directory_property( has_parent PARENT_DIRECTORY )
# Override by setting on CMake command line.
set( CMAKE_CXX_STANDARD 17 CACHE STRING "The C++ standard whose features are requested." )
option( USE_SYSTEM_TZ_DB "Use the operating system's timezone database" OFF )
option( MANUAL_TZ_DB "User will set TZ DB manually by invoking set_install in their code" OFF )
option( USE_TZ_DB_IN_DOT "Save the timezone database in the current folder" OFF )
option( BUILD_SHARED_LIBS "Build a shared version of library" OFF )
option( ENABLE_DATE_TESTING "Enable unit tests" OFF )
option( DISABLE_STRING_VIEW "Disable string view" OFF )
option( COMPILE_WITH_C_LOCALE "define ONLY_C_LOCALE=1" OFF )
option( BUILD_TZ_LIB "build/install of TZ library" OFF )
if( ENABLE_DATE_TESTING AND NOT BUILD_TZ_LIB )
message(WARNING "Testing requested, bug BUILD_TZ_LIB not ON - forcing the latter")
set (BUILD_TZ_LIB ON CACHE BOOL "required for testing" FORCE)
endif( )
function( print_option OPT )
if ( NOT DEFINED PRINT_OPTION_CURR_${OPT} OR ( NOT PRINT_OPTION_CURR_${OPT} STREQUAL ${OPT} ) )
set( PRINT_OPTION_CURR_${OPT} ${${OPT}} CACHE BOOL "" )
mark_as_advanced(PRINT_OPTION_CURR_${OPT})
message( "# date: ${OPT} ${${OPT}}" )
endif( )
endfunction( )
print_option( USE_SYSTEM_TZ_DB )
print_option( MANUAL_TZ_DB )
print_option( USE_TZ_DB_IN_DOT )
print_option( BUILD_SHARED_LIBS )
print_option( ENABLE_DATE_TESTING )
print_option( DISABLE_STRING_VIEW )
#[===================================================================[
date (header only) library
#]===================================================================]
add_library( date INTERFACE )
add_library( date::date ALIAS date )
target_include_directories( date INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include> )
# adding header sources just helps IDEs
target_sources( date INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>$<INSTALL_INTERFACE:include>/date/date.h
# the rest of these are not currently part of the public interface of the library:
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include/date/solar_hijri.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include/date/islamic.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include/date/iso_week.h>
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include/date/julian.h>
)
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.15)
# public headers will get installed:
set_target_properties( date PROPERTIES PUBLIC_HEADER include/date/date.h )
endif ()
target_compile_definitions( date INTERFACE
#To workaround libstdc++ issue https://github.com/HowardHinnant/date/issues/388
ONLY_C_LOCALE=$<IF:$<BOOL:${COMPILE_WITH_C_LOCALE}>,1,0>
$<$<BOOL:${DISABLE_STRING_VIEW}>:HAS_STRING_VIEW=0> )
#[===================================================================[
tz (compiled) library
#]===================================================================]
if( BUILD_TZ_LIB )
add_library( tz )
target_sources( tz
PUBLIC
$<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
include/date/tz_private.h
$<$<BOOL:${IOS}>:src/ios.mm>
src/tz.cpp )
add_library( date::tz ALIAS tz )
target_link_libraries( tz PUBLIC date )
target_include_directories( tz PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include> )
target_compile_definitions( tz
PRIVATE
AUTO_DOWNLOAD=$<IF:$<OR:$<BOOL:${USE_SYSTEM_TZ_DB}>,$<BOOL:${MANUAL_TZ_DB}>>,0,1>
HAS_REMOTE_API=$<IF:$<OR:$<BOOL:${USE_SYSTEM_TZ_DB}>,$<BOOL:${MANUAL_TZ_DB}>>,0,1>
$<$<AND:$<BOOL:${WIN32}>,$<BOOL:${BUILD_SHARED_LIBS}>>:DATE_BUILD_DLL=1>
$<$<BOOL:${USE_TZ_DB_IN_DOT}>:INSTALL=.>
PUBLIC
USE_OS_TZDB=$<IF:$<AND:$<BOOL:${USE_SYSTEM_TZ_DB}>,$<NOT:$<BOOL:${WIN32}>>,$<NOT:$<BOOL:${MANUAL_TZ_DB}>>>,1,0>
INTERFACE
$<$<AND:$<BOOL:${WIN32}>,$<BOOL:${BUILD_SHARED_LIBS}>>:DATE_USE_DLL=1> )
set(TZ_HEADERS include/date/tz.h)
if( IOS )
list(APPEND TZ_HEADERS include/date/ios.h)
endif( )
set_target_properties( tz PROPERTIES
POSITION_INDEPENDENT_CODE ON
PUBLIC_HEADER "${TZ_HEADERS}"
VERSION "${PROJECT_VERSION}"
SOVERSION "${PROJECT_VERSION}" )
if( NOT MSVC )
find_package( Threads )
target_link_libraries( tz PUBLIC Threads::Threads )
endif( )
if( NOT USE_SYSTEM_TZ_DB AND NOT MANUAL_TZ_DB )
find_package( CURL REQUIRED )
target_include_directories( tz SYSTEM PRIVATE ${CURL_INCLUDE_DIRS} )
target_link_libraries( tz PRIVATE ${CURL_LIBRARIES} )
endif( )
endif( )
#[===================================================================[
installation
#]===================================================================]
set( version_config "${CMAKE_CURRENT_BINARY_DIR}/dateConfigVersion.cmake" )
include( CMakePackageConfigHelpers )
write_basic_package_version_file( "${version_config}"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion )
install( TARGETS date
EXPORT dateConfig
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date )
export( TARGETS date NAMESPACE date:: FILE dateTargets.cmake )
if (CMAKE_VERSION VERSION_LESS 3.15)
install(
FILES include/date/date.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date )
endif ()
if( BUILD_TZ_LIB )
install( TARGETS tz
EXPORT dateConfig
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) # This is for Windows
export( TARGETS tz NAMESPACE date:: APPEND FILE dateTargets.cmake )
endif( )
if( WIN32 AND NOT CYGWIN)
set( CONFIG_LOC CMake )
else( )
set( CONFIG_LOC "${CMAKE_INSTALL_LIBDIR}/cmake/date" )
endif( )
install( EXPORT dateConfig
FILE dateTargets.cmake
NAMESPACE date::
DESTINATION ${CONFIG_LOC} )
install (
FILES cmake/dateConfig.cmake "${version_config}"
DESTINATION ${CONFIG_LOC})
#[===================================================================[
testing
#]===================================================================]
if( ENABLE_DATE_TESTING )
enable_testing( )
add_custom_target( testit COMMAND ${CMAKE_CTEST_COMMAND} )
add_dependencies( testit tz )
function( add_pass_tests TEST_GLOB TEST_PREFIX )
file( GLOB_RECURSE FILENAMES ${TEST_GLOB} )
foreach( TEST_FILE ${FILENAMES} )
get_filename_component( TEST_NAME ${TEST_FILE} NAME_WE )
get_filename_component( TEST_EXT ${TEST_FILE} EXT )
if( NOT ${TEST_EXT} STREQUAL ".fail.cpp" )
set( PREFIX "${TEST_PREFIX}_pass_${TEST_NAME}" )
set( BIN_NAME ${PREFIX}_bin )
set( TST_NAME ${PREFIX}_test )
add_executable( ${BIN_NAME} EXCLUDE_FROM_ALL ${TEST_FILE} )
add_test( ${TST_NAME} ${BIN_NAME} )
target_link_libraries( ${BIN_NAME} tz )
# HACK: because the test files don't use FQ includes:
target_include_directories( ${BIN_NAME} PRIVATE include/date )
add_dependencies( testit ${BIN_NAME} )
endif( )
endforeach( )
endfunction( )
function( add_fail_tests TEST_GLOB TEST_PREFIX )
file( GLOB_RECURSE FILENAMES ${TEST_GLOB} )
foreach( TEST_FILE ${FILENAMES} )
get_filename_component( TEST_NAME ${TEST_FILE} NAME_WE )
get_filename_component( TEST_EXT ${TEST_FILE} EXT )
set( TEST_TYPE "_fail" )
set( PREFIX "${TEST_PREFIX}_fail_${TEST_NAME}" )
set( BIN_NAME ${PREFIX}_bin )
set( TST_NAME ${PREFIX}_test )
set( TEST_BIN_NAME ${CMAKE_BINARY_DIR}/${BIN_NAME} )
add_custom_target( ${BIN_NAME}
COMMAND
${PROJECT_SOURCE_DIR}/compile_fail.sh
${TEST_BIN_NAME}
${CMAKE_CXX_COMPILER}
-std=c++14
-L${CMAKE_BINARY_DIR}/
-ltz
-I${PROJECT_SOURCE_DIR}/include
-I${PROJECT_SOURCE_DIR}/include/date
-o ${BIN_NAME}
${TEST_FILE}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT ${TST_NAME} )
add_test( ${TST_NAME} "${PROJECT_SOURCE_DIR}/test_fail.sh" ${CMAKE_BINARY_DIR}/${BIN_NAME} WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/" )
#set_tests_properties( ${TST_NAME} PROPERTIES WILL_FAIL TRUE)
add_dependencies( testit ${BIN_NAME} )
endforeach( )
endfunction( )
file( GLOB children RELATIVE "${PROJECT_SOURCE_DIR}/test" "${PROJECT_SOURCE_DIR}/test/*" )
foreach( child ${children} )
if( IS_DIRECTORY "${PROJECT_SOURCE_DIR}/test/${child}" )
set( CUR_FOLDER "${PROJECT_SOURCE_DIR}/test/${child}" )
add_pass_tests( "${CUR_FOLDER}/*.cpp" ${child} )
if( NOT WIN32 )
add_fail_tests( "${CUR_FOLDER}/*.fail.cpp" ${child} )
endif( )
endif( )
endforeach( )
endif( )
target_include_directories(date PUBLIC
include/
)
endif()

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
@ -43,6 +43,14 @@ Slightly modified versions of `"date.h"` and `"tz.h"` were voted into the C++20
## 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:
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://routinghub.com
* 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.

View File

@ -1,8 +1,8 @@
include( CMakeFindDependencyMacro )
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)
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" )
find_dependency( CURL )
endif( )

1
date.pri Normal file
View File

@ -0,0 +1 @@
QMAKE_CXXFLAGS += -isystem $$PWD/include

View File

@ -45,9 +45,7 @@
#include <cctype>
#include <chrono>
#include <climits>
#if !(__cplusplus >= 201402)
# include <cmath>
#endif
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
@ -71,7 +69,7 @@
#ifdef __GNUC__
# 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"
# endif
# if __GNUC__ < 5
@ -1166,7 +1164,11 @@ private:
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 d2 = R2::den / gcd_d1_d2;
#ifdef __cpp_constexpr
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>
struct mul // overflow == false
@ -1354,6 +1356,47 @@ using std::chrono::abs;
#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
template <class To, class Clock, class FromDuration>
CONSTCD11
@ -3681,11 +3724,12 @@ struct undocumented {explicit undocumented() = default;};
// Example: width<4>::value == 2
// Example: width<10>::value == 1
// Example: width<1000>::value == 3
template <std::uint64_t n, std::uint64_t d = 10, unsigned w = 0,
bool should_continue = !(n < 2) && d != 0 && (w < 19)>
template <std::uint64_t n, std::uint64_t d, unsigned w = 0,
bool should_continue = n%d != 0 && (w < 19)>
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>
@ -3714,9 +3758,10 @@ class decimal_format_seconds
{
using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
using rep = typename CT::rep;
static unsigned CONSTDATA trial_width =
detail::width<CT::period::num, CT::period::den>::value;
public:
static unsigned constexpr width = detail::width<CT::period::den>::value < 19 ?
detail::width<CT::period::den>::value : 6u;
static unsigned CONSTDATA width = trial_width < 19 ? trial_width : 6u;
using precision = std::chrono::duration<rep,
std::ratio<1, static_pow10<width>::value>>;
@ -3732,8 +3777,7 @@ public:
CONSTCD11 explicit decimal_format_seconds(const Duration& d) NOEXCEPT
: s_(std::chrono::duration_cast<std::chrono::seconds>(d))
, sub_s_(std::chrono::treat_as_floating_point<rep>::value ? d - s_ :
std::chrono::duration_cast<precision>(d - s_))
, sub_s_(std::chrono::duration_cast<precision>(d - 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)
template <class CharT,
class = std::enable_if_t<std::is_same<CharT, char>{} ||
std::is_same<CharT, wchar_t>{} ||
std::is_same<CharT, char16_t>{} ||
std::is_same<CharT, char32_t>{}>>
class = std::enable_if_t<std::is_same<CharT, char>::value ||
std::is_same<CharT, wchar_t>::value ||
std::is_same<CharT, char16_t>::value ||
std::is_same<CharT, char32_t>::value>>
CONSTCD14
inline
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)
{
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(
std::use_facet<std::numpunct<CharT>>(is.getloc()).decimal_point());
std::string buf;
#endif
while (true)
{
auto ic = is.peek();
@ -6133,18 +6184,25 @@ read_long_double(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned
break;
if (Traits::eq_int_type(ic, decimal_point))
{
buf += '.';
decimal_point = Traits::eof();
is.get();
parsing_fraction = true;
}
else
{
auto c = static_cast<char>(Traits::to_char_type(ic));
if (!('0' <= c && c <= '9'))
break;
buf += c;
(void)is.get();
if (!parsing_fraction)
{
i = 10*i + static_cast<unsigned>(c - '0');
}
else
{
f = 10*f + static_cast<unsigned>(c - '0');
++fcount;
}
}
(void)is.get();
if (++count == M)
break;
}
@ -6153,7 +6211,7 @@ read_long_double(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned
is.setstate(std::ios::failbit);
return 0;
}
return std::stold(buf);
return i + f/std::pow(10.L, fcount);
}
struct rs
@ -6310,6 +6368,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
using std::chrono::seconds;
using std::chrono::minutes;
using std::chrono::hours;
using detail::round_i;
typename std::basic_istream<CharT, Traits>::sentry ok{is, true};
if (ok)
{
@ -6325,7 +6384,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
auto modified = CharT{};
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_century = not_a_year / 100;
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});
checked_set(H, tH, not_a_hour, 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);
ws(is);
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});
checked_set(H, tH, not_a_hour, 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);
#endif
}
@ -6919,7 +6978,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
#else
auto nm = detail::ampm_names();
auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;
tp = i;
tp = static_cast<decltype(tp)>(i);
#endif
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});
checked_set(I, tI, not_a_hour_12_value, 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);
ws(is);
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;
long double S;
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);
}
#if !ONLY_C_LOCALE
@ -7048,7 +7107,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
CharT{':'}, rld{S, 1, w});
checked_set(H, tH, not_a_hour, 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);
}
else
@ -7751,6 +7810,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
std::chrono::minutes* offset = nullptr)
{
using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
using detail::round_i;
std::chrono::minutes offset_local{};
auto offptr = offset ? offset : &offset_local;
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())
is.setstate(std::ios::failbit);
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;
}
@ -7770,13 +7830,14 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
std::chrono::minutes* offset = nullptr)
{
using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
using detail::round_i;
fields<CT> fds{};
fds.has_tod = true;
from_stream(is, fmt, fds, abbrev, offset);
if (!fds.ymd.ok() || !fds.tod.in_conventional_range())
is.setstate(std::ios::failbit);
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;
}

View File

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

View File

@ -36,6 +36,9 @@
// Posix::time_zone tz{"EST5EDT,M3.2.0,M11.1.0"};
// 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:
// 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_signed_time(const string_t& s, unsigned i, std::chrono::seconds& t);
unsigned read_unsigned_time(const string_t& s, unsigned i, std::chrono::seconds& t);
unsigned read_unsigned(const string_t& s, unsigned i, unsigned limit, unsigned& u);
unsigned read_unsigned(const string_t& s, unsigned i, unsigned limit, unsigned& u,
const string_t& message = string_t{});
class rule
{
@ -87,11 +91,38 @@ public:
bool ok() const {return mode_ != off;}
date::local_seconds operator()(date::year y) const;
std::string to_string() const;
friend std::ostream& operator<<(std::ostream& os, const 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
date::local_seconds
rule::operator()(date::year y) const
@ -119,6 +150,62 @@ rule::operator()(date::year y) const
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
std::ostream&
operator<<(std::ostream& os, const rule& r)
@ -178,6 +265,10 @@ public:
friend std::ostream& operator<<(std::ostream& os, const time_zone& z);
const time_zone* operator->() const {return this;}
std::string name() const;
friend bool operator==(const time_zone& x, const time_zone& y);
};
inline
@ -195,7 +286,10 @@ time_zone::time_zone(const detail::string_t& s)
if (i != s.size())
{
if (s[i] != ',')
{
i = read_signed_time(s, i, save_);
save_ = -save_ - offset_;
}
if (i != s.size())
{
if (s[i] != ',')
@ -416,6 +510,72 @@ operator<<(std::ostream& os, const time_zone& z)
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
{
@ -428,7 +588,7 @@ throw_invalid(const string_t& s, unsigned i, const string_t& message)
std::string(s) + '\n' +
"\x1b[1;32m" +
std::string(i, '~') + '^' +
std::string(s.size()-i-1, '~') +
std::string(i < s.size() ? s.size()-i-1 : 0, '~') +
"\x1b[0m");
}
@ -444,7 +604,7 @@ read_date(const string_t& s, unsigned i, rule& r)
{
++i;
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.n_ = n;
}
@ -452,17 +612,17 @@ read_date(const string_t& s, unsigned i, rule& r)
{
++i;
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] != '.')
throw_invalid(s, i, "Expected '.' after month");
++i;
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] != '.')
throw_invalid(s, i, "Expected '.' after weekday index");
++i;
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.m_ = month{m};
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())
throw_invalid(s, i, "Expected to read unsigned time, but found end of string");
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};
if (i != s.size() && s[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};
if (i != s.size() && s[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};
}
}
@ -571,10 +731,11 @@ read_unsigned_time(const string_t& s, unsigned i, std::chrono::seconds& t)
inline
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]))
throw_invalid(s, i, "Expected to find a decimal digit");
throw_invalid(s, i, message);
u = static_cast<unsigned>(s[i] - '0');
unsigned count = 1;
for (++i; count < limit && i != s.size() && std::isdigit(s[i]); ++i, ++count)

View File

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

View File

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

View File

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

11
library.json Normal file
View File

@ -0,0 +1,11 @@
{
"name": "date",
"version": "1.0.0",
"build": {
"includeDir": "include",
"srcFilter":
[
"+<->"
]
}
}

View File

@ -89,6 +89,7 @@
# include "date/ios.h"
#else
# define TARGET_OS_IPHONE 0
# define TARGET_OS_SIMULATOR 0
#endif
#if USE_OS_TZDB
@ -140,7 +141,7 @@
# endif // HAS_REMOTE_API
#else // !_WIN32
# include <unistd.h>
# if !USE_OS_TZDB
# if !USE_OS_TZDB && !defined(INSTALL)
# include <wordexp.h>
# endif
# include <limits.h>
@ -361,7 +362,11 @@ discover_tz_dir()
throw runtime_error("discover_tz_dir failed to find zoneinfo\n");
# else // __APPLE__
# if TARGET_OS_IPHONE
# if TARGET_OS_SIMULATOR
return "/usr/share/zoneinfo";
# else
return "/var/db/timezone/zoneinfo";
# endif
# else
CONSTDATA auto timezone = "/etc/localtime";
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)}
{
}
void
tzdb_list::push_front(tzdb* tzdb) noexcept
tzdb_list::push_front(tzdb* tzdb) NOEXCEPT
{
tzdb->next = head_;
head_ = tzdb;
}
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;
p.p_->next = p.p_->next->next;
@ -438,7 +443,7 @@ tzdb_list::erase_after(const_iterator p) noexcept
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);
}
@ -460,6 +465,32 @@ get_tzdb_list()
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
#ifdef _WIN32
@ -674,18 +705,6 @@ load_timezone_mappings_from_xml_file(const std::string& input_path)
// 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
unsigned
parse_dow(std::istream& in)
@ -699,20 +718,6 @@ parse_dow(std::istream& in)
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
std::chrono::seconds
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;
assert(!transitions_.empty());
assert(i != transitions_.begin());
sys_info r;
r.begin = i[-1].timepoint;
r.end = i != transitions_.end() ? i->timepoint :
sys_seconds(sys_days(year::max()/max_day));
r.offset = i[-1].info->offset;
r.save = i[-1].info->is_dst ? minutes{1} : minutes{0};
r.abbrev = i[-1].info->abbrev;
if (i != transitions_.begin())
{
r.begin = i[-1].timepoint;
r.end = i != transitions_.end() ? i->timepoint :
sys_seconds(sys_days(year::max()/max_day));
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;
}
@ -2162,7 +2178,7 @@ time_zone::get_info_impl(local_seconds tp) const
{
i.second = load_sys_info(--tr);
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;
std::swap(i.first, i.second);
@ -2205,15 +2221,11 @@ operator<<(std::ostream& os, const time_zone& z)
return os;
}
#if !MISSING_LEAP_SECONDS
leap_second::leap_second(const sys_seconds& s, detail::undocumented)
: date_(s)
{
}
#endif // !MISSING_LEAP_SECONDS
#else // !USE_OS_TZDB
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
#if !MISSING_LEAP_SECONDS
std::ostream&
operator<<(std::ostream& os, const leap_second& x)
{
@ -2619,11 +2629,8 @@ operator<<(std::ostream& os, const leap_second& x)
return os << x.date_ << " +";
}
#endif // !MISSING_LEAP_SECONDS
#if USE_OS_TZDB
# ifdef __APPLE__
static
std::string
get_version()
@ -2632,12 +2639,99 @@ get_version()
auto path = get_tz_dir() + string("/+VERSION");
ifstream in{path};
string version;
in >> version;
if (in.fail())
throw std::runtime_error("Unable to get Timezone database version from " + path);
return version;
if (in)
{
in >> 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
std::unique_ptr<tzdb>
@ -2666,6 +2760,7 @@ init_tzdb()
strcmp(d->d_name, "iso3166.tab") == 0 ||
strcmp(d->d_name, "right") == 0 ||
strcmp(d->d_name, "+VERSION") == 0 ||
strcmp(d->d_name, "version") == 0 ||
strcmp(d->d_name, "zone.tab") == 0 ||
strcmp(d->d_name, "zone1970.tab") == 0 ||
strcmp(d->d_name, "tzdata.zi") == 0 ||
@ -2693,28 +2788,8 @@ init_tzdb()
}
db->zones.shrink_to_fit();
std::sort(db->zones.begin(), db->zones.end());
# if !MISSING_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->leap_seconds = find_read_and_leap_seconds();
db->version = get_version();
# endif
return db;
}
@ -3289,8 +3364,8 @@ remote_download(const std::string& version, char* error_buffer)
{
auto mapping_file = get_download_mapping_file(version);
result = download_to_file(
"https://raw.githubusercontent.com/unicode-org/cldr/master/"
"common/supplemental/windowsZones.xml",
"https://raw.githubusercontent.com/unicode-org/cldr/master/"
"common/supplemental/windowsZones.xml",
mapping_file, download_file_options::text, error_buffer);
}
# endif // _WIN32
@ -3564,11 +3639,9 @@ operator<<(std::ostream& os, const tzdb& db)
os << "Version: " << db.version << "\n\n";
for (const auto& x : db.zones)
os << x << '\n';
#if !MISSING_LEAP_SECONDS
os << '\n';
for (const auto& x : db.leap_seconds)
os << x << '\n';
#endif // !MISSING_LEAP_SECONDS
return os;
}

View File

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