169 Commits

Author SHA1 Message Date
4c1968b8f0 Fix constexpr overflow problems on gcc-7-9 2020-03-08 21:58:56 -04:00
9cc3a7bca1 Adding Persian/Jalali/Solar-Hijri calendar 2020-03-08 20:18:45 -04:00
9a0ee25428 Do a runtime test for realpath vs readlink
* Ubuntu needs to use readlink under current_zone
  and most everyone else needs realpath.  Attempting
  to make everyone happy with this commit.
2020-01-25 10:05:26 -05:00
c8d311f6f1 fixes #534 (#535) 2020-01-16 18:16:58 -05:00
fe63f0bb5f Add MANUAL_TZ_DB configure option: (#527)
* Add MANUAL_TZ_DB configure option:

FIXES: #458

* [fold] address review feedback
2020-01-15 22:08:15 -05:00
9502bc27a3 Update Date.h (#529)
* Remove arithmetic overflow: 

Using operator '-' on a 4 byte value and then casting the result to a 8 byte value. Casting the value to the wider type before calling operator '-' to avoid overflow.
2020-01-11 15:24:10 -05:00
66a5aa482e Add constexpr for clock_cast. 2020-01-11 14:44:06 -05:00
b9cd9c3fde Fixed a typo in CMakeLists.txt: USE_AUTOLOAD => AUTO_DOWNLOAD (#523)
USE_AUTOLOAD wasn't used anywhere else in date's sources. AUTO_DOWNLOAD
is used in .cpp/.h files while never mentioned in CMakeLists.txt.
Must have been a typo.
2020-01-03 20:15:29 -05:00
a184309786 Fix unwanted localization of integral grouping
* Fixes #525
2020-01-01 11:12:14 -05:00
fc4cf092f9 Fix cmake install for 3.14 or earlier (3.7 min) (#522)
* Fix cmake install for 3.14 or earlier (3.7 min)

Fixes: #504, #505

* Add find_dependency to config file

FIXES: #514
2019-12-29 14:51:04 -05:00
48433b9892 Update date.h (#518)
using decltype in day constructor to be consistent with month and year
2019-12-05 14:00:16 -05:00
4c95165298 Constrain make_zoned for icc16
Build fails with Intel Compiler v16:

<source>(1698): error: expression must have a constant value
  std::is_class<typename std::decay<decltype(*std::declval<TimeZonePtr&>())>::type>{}
                                                                                    ^
2019-11-29 19:45:59 -05:00
940f4a5ceb Support Curl Error Buffer
Allow user to get error message when download fails
2019-11-29 19:38:40 -05:00
018a50bcd0 Work around for a NVCC compiler bug
The NVCC compiler fails to compile the date library due
to a compiler bug which causes it to emit an error when
directly using std::ratio_{multiply,divide} in the template
instantiations for std::duration. This PR works around the
issue by introducing custom ratio_{multiply,divide} which
delegate to the standard library templates
2019-11-29 19:27:36 -05:00
3e376be2e9 Rename link to time_zone_link
* At the request of LEWG
2019-11-08 19:36:09 +00:00
224c71a899 Rename leap to leap_second and leaps to leap_seconds
* At the request of LEWG
2019-11-08 19:24:03 +00:00
67e272a54e change the order in hh_mm_ss::to_duration() to have correct result on Windows for cases when h is 2147483647 hours and m and s are all 0 (#501) 2019-10-24 09:57:36 -04:00
d399e10cba Bump zoned_time fixes for MSVC from 1900 to 1916 2019-10-22 13:28:48 -04:00
96ffe23f72 Replace INTMAX_MAX with numeric_limits 2019-10-21 22:22:50 -04:00
48f1455cd2 CMake refactor for easier subdirectory inclusion 2019-10-18 14:59:37 -04:00
e3186e36c2 typo (#498) 2019-10-18 14:47:38 -04:00
3f0f9b3cbe Search for '/' after "zoneinfo" in current_zone() 2019-10-14 15:54:32 -04:00
23fa1bb86d Add vcpkg installation instructions (#495) 2019-09-27 09:46:58 -04:00
4481c75192 Improve current_zone().
Fixes #454
2019-09-23 22:09:13 -04:00
e6d2c08159 Honor symbol visibility settings (#464) 2019-09-23 22:08:07 -04:00
a5c4b4ebf8 Protect is_am and make12 from ADL 2019-09-17 15:48:15 -04:00
44344000f0 Fix MSVC C++ version detection 2019-09-12 19:58:05 -04:00
6d5ff9b958 Point travis badge to upstream master 2019-09-11 14:00:11 -04:00
375579eac1 Remove point release verison from descriptions 2019-09-11 14:00:11 -04:00
2ced83ceff Add clang 6 and clang 7 builds 2019-09-11 14:00:11 -04:00
718cbe3f9b Add gcc 8 build for bionic 2019-09-11 14:00:11 -04:00
961bf06c32 Add nice names to build matrix 2019-09-11 14:00:11 -04:00
fe491eff1c Add travis ci configuration file 2019-09-10 09:36:13 -04:00
c56f915cc3 fixed shared library support 2019-09-09 11:47:47 -04:00
5e57a19abe renamed targets to date and tz 2019-09-09 11:47:47 -04:00
9454aeda2b set library version to 2.4.1
Update CMakeLists.txt to set library version to 2.4.1
2019-09-06 17:32:15 -04:00
3a343adf6a Improve main CMake file
Rename target date_interface to interface and tz to timezone.
Export targets date::interface and date::timezone from cmake.
2019-09-06 10:29:30 -04:00
d21333f636 Fixes #484 2019-09-03 23:17:43 -04:00
cb4bf26fc7 Fix compilation error with GCC 5
GCC 5 complains that `operator-=` and `operator+=` are not constexpr.  The `-` and `+` operator appear seem to be fine.
2019-09-03 22:59:04 -04:00
b87eb970c1 Implemented test for checking addition with classes converible to years/months
To work this specific test require current implementation
strategy (template with unspecified argument).
2019-09-03 22:52:31 -04:00
5a0057587d Correct behavior for classes for which only lvalue is convertible to string_view.
Added OnlyLValueString test case that shows the problem with
current impl. Implemented the change, that accept TimeZonePtrOrName
by forwarding reference (to preserve value category), and
merged time_zone selection into one trait.
2019-09-01 14:43:50 -04:00
5345d135b7 Implemented custom time zone deduction test.
Implemented test for deduction from the custom time zone ptr.
Used OffsetZone extracted for that purpose.
2019-09-01 14:43:50 -04:00
7c020642fb Fixed deduction guides for GCC 8.
The GCC 8 was correctly preffering the deduction guide
syntezied from the std::string_view constructor which is more
specialized than deduction guide. Changed the constructor
so the Duration cannot be deduced from it.
2019-09-01 14:43:50 -04:00
1d721d9afd Implemented set of basic deduction test.
Implemented test for deduction from string, string_view,
time_zone ptr and other zoned_time.
2019-09-01 14:43:50 -04:00
141ba85614 Fix space-matches 0 spaces at end of format string 2019-08-23 15:51:18 -04:00
dca8ddc659 Replace computed value with standard macro 2019-07-21 23:43:29 -04:00
1f5c192f4a Resolve GCC 9.1.0 noexcept warning 2019-07-21 23:31:29 -04:00
46ccd69c9c Resolve GCC 9.1.0 unused-function warning 2019-07-21 23:18:54 -04:00
c0e7b4e2f7 Make date.h compatible with g++-4.7 2019-07-21 21:48:51 -04:00
09d90a8b5e Fix operator<< for years with non C locale
Fix the issue https://github.com/HowardHinnant/date/issues/392
2019-07-21 21:20:49 -04:00
6f0b645df1 #388 add comment on unit test failure (#442) 2019-07-21 20:47:33 -04:00
7ef1a55143 tz.cpp: Cast conversions to/from size_t
These cause warnings with -Wsign-conversion.
2019-07-21 20:46:01 -04:00
27d1e1e54e Removed undefined behavioir from year_mont_day_last::day (#456)
This is done to make the result of calling day() on
year_month_day_last object that is !ok() unspecified.
Checked only months, are there are needed to avoid UB.
2019-05-28 09:01:14 -04:00
7817ebf45a Update date.h (#451)
endf -> endif
2019-05-20 09:44:20 -04:00
a029f1105d Conditionally set _SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING 2019-05-19 22:46:35 -04:00
44215f6781 Eschew using directives in headers, even at function scope.
* There is still an impact on user code, though I'm not sure
  if by specification or compiler bug.
* Prefer using declarations instead.
2019-05-19 21:53:29 -04:00
ed0368fc75 The URL for windowsZones.xml changed to (#447)
https://raw.githubusercontent.com/unicode-org/cldr/master/common/supplemental/windowsZones.xml
2019-05-15 12:08:24 -04:00
429d9ba739 Add User-Agent curl option in download_to_string function. [#438] 2019-04-19 09:07:03 -04:00
081e9af55b Migrate ptz.h from jan to January 2019-04-05 22:36:21 -04:00
8a563041fa Adjust HAS_STRING_VIEW for VS
Fixes #330
2019-04-05 09:19:54 -04:00
9dc96fd9b5 Silence warning
Fixes #337
2019-03-26 18:13:39 -04:00
8b69087d35 Fix up constexpr of changed weekday_from_days 2019-03-21 12:23:38 -04:00
d5e96f0991 Suppress VS-15 warning about concerning conditional expression is constant
Thanks to https://github.com/ujos for the report.
2019-03-20 21:24:01 -04:00
5ba1c1ad85 HAS_UNCAUGHT_EXCEPTIONS definition.
Added some flexibility for usage of std::uncaught_exceptions().
Xcode 10 uses clang and perfectly compiles C++17, but
std::uncaught_exceptions() is available only on iOS 10+ devices. When
application supports iOS 9 devices and uses C++17 there is no way to
build it, except drop iOS 9 support or remove C++17 code. Using this
define we could configure should date.h use std::uncaught_exceptions()
or not.
2019-03-20 20:43:43 -04:00
10ab6ae9e5 Fix warnings from Clang (#421)
Clang 9 (in Visual Studio) complains about a mixed signed-unsigned comparison and an unused function.
Replace the naked `int` constant -1 by `std::size_t(-1)` with the same codegen as before (no curlies to avoid narrowing).
Guard the definition of `get_download_folder()` by the same condition as its call-site.

Signed-off-by: Daniela Engert <dani@ngrt.de>
2019-03-19 20:25:59 -04:00
e31daf8093 Unit tests for !year_month::ok() arithmetic. (#425) 2019-03-19 20:22:23 -04:00
cb7ca96f68 Protect weekday_from_days from signed overflow
Found by static analyzer.
This change makes weekday_from_days slightly more efficient.
2019-03-19 19:51:32 -04:00
b5d025ea2f Align time_of_day with hh_mm_ss
Per committee review
2019-03-19 19:50:30 -04:00
f782ae98f0 Fix type-o again 2019-02-20 15:27:44 -10:00
d6c5d02068 Fix type-o in get_leap_second_info_t 2019-02-20 15:25:50 -10:00
16077472af Rename is_leap_second to get_leap_second_info 2019-02-20 15:19:54 -10:00
5a62c405e0 Remove unneeded make_precision 2019-02-03 23:21:36 -05:00
09a19a09f4 Further consolidate time_of_day logic
Adjust how it works for floating point durations.
2019-02-03 16:14:56 -05:00
9cb0013aef Update time_of_day to be more consistent ...
the needs of formatting.
2019-02-02 14:06:12 -05:00
f1326968af Make compatible with const-only string.data() spec 2019-01-31 19:23:17 -05:00
61c3d35634 Fix problem with wchar_t* to std::string conversion. (#419)
VS2019 correctly points out that a conversion from a wide NTCS to std::string requires narrowing. This may result in an undesired string value. Implement the string conversion properly.

Signed-off-by: Daniela Engert <dani@ngrt.de>
2019-01-27 17:08:01 -05:00
4e7e76b981 add c_encoding and iso_encoding weekday functions (#380)
- c_encoding satisfies ctime wday encoding: days since Sunday, range
  [0,6]
- iso_encoding satisfies ISO 8601 weekday:
  a digit d from 1 through 7, beginning with Monday and ending with Sunday
2019-01-19 14:46:21 -05:00
90d0440884 Introduce %q and %Q to_stream formatting flags
* These flags format a duration.
* %Q specifies the duration's numeric value.
* %q specifies the duration's SI abbreviation.
* Example: format("%Q %q", 45ms) == "45 ms"
2019-01-19 14:30:19 -05:00
2cb4c34009 Ignore tzdata.zi and leapseconds tzdb files on Linux when loading time zones (#411) 2018-12-18 12:15:00 -05:00
7231a182a4 Revert 5f34c40 and 23b1f00 in preparation of a better solution.
Signed-off-by: Daniela Engert <dani@ngrt.de>
2018-12-16 15:29:17 -05:00
0e85704e47 Don't write to ~/Downloads if not installing there 2018-12-14 20:12:55 -05:00
5f34c40523 More patches for VS-2017 compatiblity 2018-11-25 17:04:27 -05:00
23b1f007fe Patch for VS-2017 compatiblity 2018-11-25 14:38:54 -05:00
a22125ca40 Remove constexpr from islamic::year::isleap for C++11 2018-11-20 09:00:12 -05:00
8f91ef27ed Revert "Model the TAI-UTC difference between 1961 and 1972"
This reverts commit 1eed461d06.
2018-11-08 13:56:23 -08:00
4b46deb4f9 Update README.md
Add  Valhalla (Open Source Routing Library/Service)
2018-11-01 15:19:35 -04:00
54e8516af2 Update README with more accurate CMake info 2018-10-23 11:12:05 -04:00
1eed461d06 Model the TAI-UTC difference between 1961 and 1972 2018-10-03 17:51:55 -04:00
591f572b67 Allow %j to parse and format durations 2018-09-26 14:35:03 -07:00
F
69e9cd612f Prefer using std::string that using namespace std and unqualified string (#386)
'using namespace std;' in header files can conflict with custom
namespace names. For example 'string' is used without 'std::'
qualification. If tz.h is included in a file where string is a
namespace, it cannot be compiled anymore. The same happens with date.h
if ONLY_C_LOCALE=1.
2018-09-26 17:31:56 -04:00
6b51ca8271 Add routinghub to README 2018-09-12 20:42:25 -04:00
3e82a52d66 Add ViewTouch to list of project using this library 2018-08-27 19:33:16 -04:00
6a4d93a0bd Silence more shadow warnings 2018-07-01 23:00:33 -04:00
39d6730665 Silence shadow warnings 2018-07-01 22:37:25 -04:00
de6a03d337 Set _SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING for VS 2018-06-27 09:21:19 -04:00
e86edc3820 Added missing license to unit test files (#356) 2018-06-23 10:39:00 -04:00
1b32e316db Workaround MSVC 19.14.26431 parsing bug (#355) 2018-06-21 10:08:59 -04:00
f46885e632 Suffix d for days duration (#354) 2018-06-20 11:39:48 -04:00
2d282e35fa Use string_literal for C++11 when possible 2018-06-19 19:37:02 -04:00
d50970b32a Some backwards compatibility fixes for VS-2013 2018-06-12 18:13:24 -04:00
af2b2b70b3 Remove usage of octal literals in tests (#350)
* Remove usage of octal literals

* Fixed July
2018-06-12 13:18:18 -04:00
3933a0122d Add option to disable string_view
Also add -fPIC flag when compiling the shared version of the library.
2018-06-11 17:01:51 -04:00
07876e4433 Character classification functions (isspace, isalnum) are undefined for signed chars
Convert them to int using char_traits or static_cast to unsigned char
2018-06-11 17:00:45 -04:00
0197889505 Update to Sunday constants 2018-06-11 15:14:44 -04:00
b86def339e Test for utc during leap second insertion 2018-06-11 10:45:41 -04:00
aa0494b980 custom clock and noncastable tests 2018-06-11 10:45:41 -04:00
df31560701 Moved test to clock_cast_test dir 2018-06-11 10:45:41 -04:00
4b687f4c04 Test is now C++11 compatible 2018-06-11 10:45:41 -04:00
db60c5eb8e Unit test and typo fix 2018-06-11 10:45:41 -04:00
9f1c4b0110 Implemented clock_cast for local_time.
Implemented clock_time_conversion<D, local_t> calling D::from_local
and clock_time_conversion<locat_t, S> calling S::to_local.

To avoid ambiguities addes:
* clock_time_conversion<local_t, local_t> - idenitity
* clock_time_conversion<local_t, utc_clock> - same as default (utc_clock::to_local)
* clock_time_conversion<utc_clock, local_t> - same as default (utc_clock::from_local)

In addition, as std::chrono::system_clock cannot be edited, added:
* clock_time_conversion<local_t, std::chrono::system_clock> - assumes same epoch
* clock_time_conversion<std::chrono::system_clock, local_t> - assumes same epoch
They will be required to resolve amibiguity anyway.
2018-06-11 10:45:41 -04:00
da15227f6c Implemented to/from_local functions for utc/tai/gps.
Implemented to_local and from_local functions for utc_clock,
tai_clock and gps_clock. For the tai/gps clock used this function
for defining the io - we delegate to serializing/parsing local
time.

The drwaback is that the local_time cannot properly represent
leap second in the UTC time, so separate serialization is needed.
2018-06-11 10:45:41 -04:00
d4fb7eb76d Put unspecified_month_disambiguator in namespace detail 2018-06-10 16:22:21 -04:00
0e3e84fd56 Used suggested Tim Song implementation 2018-06-10 16:22:21 -04:00
3eac2d376e Revert "Fixed addition of multi-year duration to year_month."
This reverts commit 328cecaa56.
2018-06-10 16:22:21 -04:00
f5f4d76936 Replace save_stream with save_ostream
* In islamic.h and julian.h
2018-06-10 15:44:43 -04:00
c7b69d949a Change the encoding for an invalid weekday from 7 to 8 2018-06-08 09:50:40 -04:00
48baa942fc Use uncaught_exceptions in C++17 2018-06-06 13:52:23 -04:00
af415701ba Update wandbox link 2018-06-06 13:31:03 -04:00
be2ec2310b Emphasize Sunday over sun in the implementation
*  Keep the three letter lower case spellings for backwards
   compatibility purposes.
2018-06-03 13:55:00 -04:00
40b83654b6 [API BREAKING] Remove conversion from weekday to unsigned
* There has been a great deal of anguish over the encoding of
  weekdays:  whether [0, 6] maps to [Sunday, Saturday] or
  [1, 7] maps to [Monday, Sunday].  This commit attempts
  to address that issue, but will break a small amount of
  code at compile-time.  See below on how to fix that.

* The weekday constructor used to accept [0, 6] to represent
  [Sunday, Saturday].  It now accepts [0, 7] to represent
  [Sunday, Saturday] with both 0 and 7 mapping to Sunday.

* The conversion from weekday to unsigned has been removed.

* To convert a weekday to unsigned replace:

      auto u = unsigned{wd};

  with:

      auto u = (wd - Sunday).count();

  This maps [Sunday, Saturday] to [0, 6], which is the
  C/POSIX mapping.  If you prefer the ISO mapping
  ([Monday, Sunday] -> [1, 7]), then do:

      auto u = (wd - Monday).count() + 1;
2018-06-02 22:56:10 -04:00
6c4d333026 fixed build in WinRT mode, where some API are not available 2018-06-02 16:14:18 -04:00
1fdda81a30 fixed build with latest VS2017 v15.7.1; toolset MSVC 14.14 2018-06-02 16:14:18 -04:00
apo
f33e179936 Eliminate use of uninitialized offset. 2018-05-25 09:56:34 -04:00
328cecaa56 Fixed addition of multi-year duration to year_month.
* Added new overloads for operator+/- between year_month and duration
  that is convertible to years, so it is better candidate for operands
  that are convertible to both years and months. To preserve
  functionality, this operator is conditionally noexcept.

* Reworked year_month_day, year_month_day_last, year_month_weekday,
  and year_month_weekday_last.

* Added tests for this new functionality.
2018-05-12 18:21:24 -04:00
5d15157bbb Fix bug for parsing negative offsets of less than 1h 2018-05-05 12:01:56 -04:00
a91ceefb4e Allow %H %M and %S to deal with negative durations 2018-04-23 20:31:28 -04:00
88c661e9f3 Fix zoned_time deduction guides 2018-04-23 20:30:58 -04:00
c665992a6e Allow heterogeneous zoned_time constructors
taking {string_view, zoned_time}
2018-04-21 17:45:52 -04:00
9d0bcdb63f Fix deduction error in parse where only offset is requested 2018-04-18 21:56:11 -04:00
973bd393bc Respect and minimize tie/flush in from/to_stream
* Save/restore tie, setting it to nullptr during the operation
* On construction tie_->flush()
* For ostreams only, flush if unitbuf
2018-04-18 21:47:15 -04:00
d53db7a1cb And yet more fixes to allow duplicate flags on parse 2018-04-15 15:32:24 -04:00
e5c69d84ab Fix constexpr issue for VS2015 2018-04-09 11:01:58 -04:00
b48a18a1d9 More fixes to allow duplicate parsing 2018-04-08 15:49:06 -04:00
cdb4b276d9 Allow duplicate parsing into the same fields
* as long as all duplicates produce consistent results.
2018-04-07 21:42:00 -04:00
1d9e49ea21 to_stream sets failbit if unable to format
*  If a formatting flag requests data that is not available in
   the Streamable object, or if the Streamable object answers !ok(),
   failbit is set.
2018-04-06 11:19:44 -04:00
0125d330ab Correct to_stream/from_stream handling of stream data
* to_stream and from_stream now reset the stream formatting state to
  default settings on entry, and restore the stream state on exit.

* to_stream and from_stream now correctly handle mis-modified flags.

* Fix %h to be equivalent to %b instead of %B.

* This addresses issues 319, 320 and 321.
2018-03-31 13:06:57 -04:00
e7e1482087 Remove BUILD_TZ_STATIC and replace with BUILD_SHARED_LIBS
* This is more standard CMake
* See https://cmake.org/cmake/help/v3.1/command/add_library.html
2018-03-19 18:04:34 +00:00
d6b95dc301 Remove TZ_CXX_STANDARD and instead use CMAKE_CXX_STANDARD
* See https://cmake.org/cmake/help/v3.1/variable/CMAKE_CXX_STANDARD.html?highlight=cmake_cxx_standard
2018-03-19 17:59:36 +00:00
700489e475 Introduced full weekday and month names
* The standardized version of this library has std::chrono::January
  and std::chrono::Sunday in place of std::chrono_literals::jan and
  std::chrono_literals::sun.  Compatible names added to namespace
  date to ease transition from this lib to std::chrono.  The old
  names are retained for backwards compatibility.
2018-03-18 18:27:04 -04:00
e6941697eb Validate TZdata failed with OS TZdata 2018-03-18 18:17:27 -04:00
c311db2f1a Clean up tz_test README 2018-03-18 18:14:40 -04:00
fffa52ac0e Cleanup and add to README.md 2018-03-18 18:14:40 -04:00
f105595f04 Use proper lib directory when installing on UNIX
Linux distributions use lib, lib32, and lib64 directories for library files,
symlinking them where needed. Let's follow distirbution rules by
utilising CMake module GNUInstallDirs.
2018-03-18 17:55:08 -04:00
20f0595b32 Update standardization progress 2018-03-17 10:57:45 -04:00
674a9e6953 Update README.md 2018-03-16 15:42:13 -04:00
bc8cf368e5 Update readme link to d0355r6 2018-03-14 22:50:18 -04:00
1e8ab50f82 Test modifications for standardization 2018-03-14 22:49:04 -04:00
38c5ca38bb Typo fixes in comment text 2018-03-04 18:26:07 -05:00
0bde4ba8c8 Make the parsing of minutes optional under the flag %z 2018-03-03 11:57:03 -05:00
afe61df277 Fix case of generated dateConfig so it will work on a case sensitive filesystem 2018-03-02 16:37:32 -05:00
43d8a4eab0 Range check minutes under parse 2018-03-02 09:03:41 -05:00
mwu
ca4036a4b0 Explicitly qualify std::string. Having a global scope string type shall not break the compilation anymore. 2018-02-23 21:17:26 -05:00
a1ceec19fe Workaround for MSVC 2018-02-20 11:51:28 -05:00
5524dd1ae8 Update README.md 2018-02-15 18:49:37 -05:00
4ada98d247 Enable testing in CMakeLists.txt
* Per instructions by @SlavSlavov in https://github.com/HowardHinnant/date/pull/278
2018-01-29 08:39:58 -05:00
040eed838b Augment path to ios.h 2018-01-26 19:53:51 -05:00
2acf403bcd Dont include ios.h unconditionally.
The include in tz.cpp was changed to only include the ios.h header
when compiling on apple platforms, as the documentation states that
only the four files date.h, tz.h, tz_private.h, and tz.cpp should be
required to use the time zone library.

Additionally, the ios.mm file was moved to src/ since it contains
C++ source code.
2018-01-24 20:24:10 -05:00
637e5d8007 Use target_compile_definitions
It's generally preferred to use [`target_compile_definitions`](https://floooh.github.io/2016/01/12/cmake-dependency-juggling.html) over `add_definitions`.
2018-01-21 12:33:42 -05:00
362cd8f27e Account for WIN32 2018-01-21 12:29:13 -05:00
a4ce4bc2d3 Use correct target
Also, fix the formatting in the generator expressions. For some reason, the previous
formatting caused this error:

  Target "date_interface" INTERFACE_INCLUDE_DIRECTORIES property contains
  path:

  ...

  which is prefixed in the source directory.
2018-01-21 12:29:13 -05:00
3e5a57467a Export a CMake config file
This will allow users to import the project via CMake methods, i.e `find_package` rather than doing it manually.
2018-01-21 12:29:13 -05:00
3b8372f4fa Avoid use of undeclared to_utc_time.
* Fixes https://github.com/HowardHinnant/date/issues/289
2018-01-18 15:55:58 -05:00
6941691de4 implement current_zone() for iOS using native API from iOSUtils 2018-01-12 14:59:01 -05:00
09b78ba92c bump msvc define to fix compile issue on MSVC 15.6 2018-01-12 10:51:05 -05:00
28c1c61ac2 Advertise that this works in C++17 2018-01-08 09:54:42 -05:00
55289f0d73 Make tz_dir a function-local static
* This solves initialization order issues detailed
  in https://github.com/HowardHinnant/date/issues/275
2018-01-05 19:26:44 -05:00
b7e58e193f Set standard or default to C++17
Changed cmake to default to c++17 unless TZ_CXX_STANDARD is set(e.g. to 11,14 or 17)
2018-01-05 18:45:29 -05:00
2b6ee6378c minutes fix 2018-01-05 18:42:48 -05:00
7d80d89a44 Allow specifying cxx standard to target
Not everyone can use C++17 even with compilers that support it
2017-12-31 16:42:29 -05:00
45 changed files with 8557 additions and 3179 deletions

147
.travis.yml Normal file
View File

@ -0,0 +1,147 @@
language: cpp
env:
global:
- CMAKE_EXTRA_CONF="-DCOMPILE_WITH_C_LOCALE=ON"
- CTEST_OUTPUT_ON_FAILURE=1
matrix:
include:
- name: "Ubuntu 16.04 LTS (Xenial Xerus) GCC 7"
os: linux
dist: xenial
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-7
env:
- MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
- name: "Ubuntu 16.04 LTS (Xenial Xerus) GCC 8"
os: linux
dist: xenial
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
env:
- MATRIX_EVAL="CC=gcc-8 && CXX=g++-8"
- name: "Ubuntu 16.04 LTS (Xenial Xerus) GCC 9"
os: linux
dist: xenial
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-9
env:
- MATRIX_EVAL="CC=gcc-9 && CXX=g++-9"
- name: "Ubuntu 18.04 LTS (Bionic Beaver) GCC 7"
os: linux
dist: bionic
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-7
env:
- MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
- name: "Ubuntu 18.04 LTS (Bionic Beaver) GCC 8"
os: linux
dist: bionic
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
env:
- MATRIX_EVAL="CC=gcc-8 && CXX=g++-8"
- name: "Ubuntu 18.04 LTS (Bionic Beaver) Clang 6"
os: linux
dist: bionic
addons:
apt:
sources:
- llvm-toolchain-bionic-6.0
packages:
- clang-6.0
env:
- MATRIX_EVAL="CC=clang-6.0 && CXX=clang++-6.0"
- name: "Ubuntu 18.04 LTS (Bionic Beaver) Clang 7"
os: linux
dist: bionic
addons:
apt:
sources:
- llvm-toolchain-bionic-7
packages:
- clang-7
env:
- MATRIX_EVAL="CC=clang-7 && CXX=clang++-7"
- name: "Ubuntu 18.04 LTS (Bionic Beaver) Clang 8"
os: linux
dist: bionic
addons:
apt:
sources:
- llvm-toolchain-bionic-8
packages:
- clang-8
env:
- MATRIX_EVAL="CC=clang-8 && CXX=clang++-8"
- &macos
name: xcode10
os: osx
osx_image: xcode10.2
env:
- CMAKE_EXTRA_CONF=""
addons:
homebrew:
packages:
- bash
- ninja
- <<: *macos
name: xcode9
# xcode 9 only works if we tell it to use c++14 explicitly
env:
- CMAKE_EXTRA_CONF="-DCMAKE_CXX_STANDARD=14"
osx_image: xcode9.4
- <<: *macos
osx_image: xcode11
name: xcode11
before_install:
- eval "${MATRIX_EVAL}"
- ci/install_cmake.sh 3.15.2
- export OPENSSL_ROOT=$(brew --prefix openssl@1.1)
- if [ "$(uname)" = "Darwin" ] ; then export PATH="$HOME/cmake/CMake.app/Contents/bin:${PATH}"; fi
- if [ "$(uname)" = "Linux" ] ; then export PATH="$HOME/cmake/bin:${PATH}"; fi
cache:
directories:
- $HOME/cmake
script:
- mkdir -p build
- cd build
- eval cmake -DENABLE_DATE_TESTING=ON -DBUILD_SHARED_LIBS=ON ${CMAKE_EXTRA_CONF} ..
- cmake --build . --parallel
- cmake --build . --parallel --target testit

View File

@ -1,161 +1,248 @@
cmake_minimum_required( VERSION 3.0.2 )
#[===================================================================[
date library by Howard Hinnant
project( date_prj )
CMake projects that wish to use this library should consider
something like the following :
find_package( Threads REQUIRED )
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)
enable_testing( )
#]===================================================================]
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_TZ_STATIC "Build a static version of library" ON )
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( )
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_TZ_STATIC )
print_option( BUILD_SHARED_LIBS )
print_option( ENABLE_DATE_TESTING )
print_option( DISABLE_STRING_VIEW )
if( USE_SYSTEM_TZ_DB )
add_definitions( -DUSE_AUTOLOAD=0 )
add_definitions( -DHAS_REMOTE_API=0 )
# cannot set USE_OS_TZDB to 1 on Windows
if( NOT WIN32 )
add_definitions( -DUSE_OS_TZDB=1 )
endif( )
else( )
add_definitions( -DUSE_AUTOLOAD=1 )
add_definitions( -DHAS_REMOTE_API=1 )
add_definitions( -DUSE_OS_TZDB=0 )
find_package( CURL REQUIRED )
include_directories( SYSTEM ${CURL_INCLUDE_DIRS} )
set( OPTIONAL_LIBRARIES ${CURL_LIBRARIES} )
endif( )
if( USE_TZ_DB_IN_DOT )
add_definitions( -DINSTALL=. )
endif( )
set( HEADER_FOLDER "include" )
set( SOURCE_FOLDER "src" )
set( TEST_FOLDER "test" )
# This is needed so IDE's live MSVC show header files
set( HEADER_FILES
${HEADER_FOLDER}/date/chrono_io.h
${HEADER_FOLDER}/date/date.h
${HEADER_FOLDER}/date/ios.h
${HEADER_FOLDER}/date/islamic.h
${HEADER_FOLDER}/date/iso_week.h
${HEADER_FOLDER}/date/julian.h
${HEADER_FOLDER}/date/tz.h
${HEADER_FOLDER}/date/tz_private.h
#[===================================================================[
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> )
if( BUILD_TZ_STATIC )
add_library( tz STATIC ${HEADER_FILES} ${SOURCE_FOLDER}/tz.cpp )
else( )
add_library( tz SHARED ${HEADER_FILES} ${SOURCE_FOLDER}/tz.cpp )
#[===================================================================[
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( )
if ( ${CMAKE_MINOR_VERSION} GREATER 7 )
set( TZ_CXX_STANDARD 17 )
else( )
set( TZ_CXX_STANDARD 14 )
#[===================================================================[
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( )
set_property(TARGET tz PROPERTY CXX_STANDARD ${TZ_CXX_STANDARD})
target_link_libraries( tz ${CMAKE_THREAD_LIBS_INIT} ${OPTIONAL_LIBRARIES} )
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})
# add include folders to the library and targets that consume it
target_include_directories(tz PUBLIC
$<BUILD_INTERFACE:
${CMAKE_CURRENT_SOURCE_DIR}/${HEADER_FOLDER}
>
$<INSTALL_INTERFACE:
include
>
)
#[===================================================================[
testing
#]===================================================================]
if( ENABLE_DATE_TESTING )
enable_testing( )
add_library(date_interface INTERFACE) # an interface (not a library), to enable automatic include_directory (for when just date.h, but not "tz.h and its lib" are needed)
add_custom_target( testit COMMAND ${CMAKE_CTEST_COMMAND} )
add_dependencies( testit tz )
# add include folders to the INTERFACE and targets that consume it
target_include_directories(date_interface INTERFACE
$<BUILD_INTERFACE:
${CMAKE_CURRENT_SOURCE_DIR}/${HEADER_FOLDER}
>
$<INSTALL_INTERFACE:
include
>
)
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( )
install( TARGETS tz DESTINATION lib )
install( DIRECTORY ${HEADER_FOLDER}/ DESTINATION include/ )
function( add_fail_tests TEST_GLOB TEST_PREFIX )
file( GLOB_RECURSE FILENAMES ${TEST_GLOB} )
add_custom_target( testit COMMAND ${CMAKE_CTEST_COMMAND} )
foreach( TEST_FILE ${FILENAMES} )
get_filename_component( TEST_NAME ${TEST_FILE} NAME_WE )
get_filename_component( TEST_EXT ${TEST_FILE} EXT )
add_dependencies( testit tz )
function( add_pass_tests TEST_GLOB TEST_PREFIX )
file( GLOB_RECURSE FILENAMES ${TEST_GLOB} )
include_directories( "${HEADER_FOLDER}/date" )
set( TEST_TYPE "_fail" )
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} )
set_property(TARGET ${BIN_NAME} PROPERTY CXX_STANDARD ${TZ_CXX_STANDARD})
add_test( ${TST_NAME} ${BIN_NAME} )
target_link_libraries( ${BIN_NAME} tz )
add_dependencies( testit ${BIN_NAME} )
endif( )
endforeach( )
endfunction( )
set( PREFIX "${TEST_PREFIX}_fail_${TEST_NAME}" )
set( BIN_NAME ${PREFIX}_bin )
set( TST_NAME ${PREFIX}_test )
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 )
#target_compile_definitions( ${BIN_NAME} PRIVATE ${TST_NAME} )
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}/${HEADER_FOLDER}/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_FOLDER}" "${PROJECT_SOURCE_DIR}/${TEST_FOLDER}/*" )
foreach( child ${children} )
if( IS_DIRECTORY "${PROJECT_SOURCE_DIR}/${TEST_FOLDER}/${child}" )
set( CUR_FOLDER "${PROJECT_SOURCE_DIR}/${TEST_FOLDER}/${child}" )
add_pass_tests( "${CUR_FOLDER}/*.cpp" ${child} )
if( NOT WIN32 )
add_fail_tests( "${CUR_FOLDER}/*.fail.cpp" ${child} )
endif( )
endif( )
endforeach( )
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( )

View File

@ -1,43 +1,72 @@
# Date
[![Build Status](https://travis-ci.org/HowardHinnant/date.svg?branch=master)](https://travis-ci.org/HowardHinnant/date)
[![Join the chat at https://gitter.im/HowardHinnant/date](https://badges.gitter.im/HowardHinnant/date.svg)](https://gitter.im/HowardHinnant/date?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<hr/>
**[Try it out on wandbox!](https://wandbox.org/permlink/vqwMyTphHJv5iXX7)**
---
This is actually several separate C++11/C++14 libraries:
**[Try it out on wandbox!](https://wandbox.org/permlink/L8MwjzSSC3fXXrMd)**
1. `"date.h"` is a header-only library which builds upon `<chrono>`. It adds some new `duration` types, and new `time_point` types. It also adds "field" types such as `year_month_day` which is a struct `{year, month, day}`. And it provides convenient means to convert between the "field" types and the `time_point` types.
## Summary
This is actually several separate C++11/C++14/C++17 libraries:
1. `"date.h"` is a header-only library which builds upon `<chrono>`. It adds some new `duration` types, and new `time_point` types. It also adds "field" types such as `year_month_day` which is a struct `{year, month, day}`. And it provides convenient means to convert between the "field" types and the `time_point` types.
* Documentation: http://howardhinnant.github.io/date/date.html
* Video: https://www.youtube.com/watch?v=tzyGjOm8AKo
* Slides: http://schd.ws/hosted_files/cppcon2015/43/hinnant_dates.pdf
2. `"tz.h"` / `"tz.cpp"` are a timezone library built on top of the `"date.h"` library. This timezone library is a complete parser of the IANA timezone database. It provides for an easy way to access all of the data in this database, using the types from `"date.h"` and `<chrono>`. The IANA database also includes data on leap seconds, and this library provides utilities to compute with that information as well.
1. `"tz.h"` / `"tz.cpp"` are a timezone library built on top of the `"date.h"` library. This timezone library is a complete parser of the IANA timezone database. It provides for an easy way to access all of the data in this database, using the types from `"date.h"` and `<chrono>`. The IANA database also includes data on leap seconds, and this library provides utilities to compute with that information as well.
* Documentation: http://howardhinnant.github.io/date/tz.html
* Video: https://www.youtube.com/watch?v=Vwd3pduVGKY
* Slides: http://schd.ws/hosted_files/cppcon2016/0f/Welcome%20To%20The%20Time%20Zone%20-%20Howard%20Hinnant%20-%20CppCon%202016.pdf
3. `"iso_week.h"` is a header-only library built on top of the `"date.h"` library which implements the ISO week date calendar.
1. `"iso_week.h"` is a header-only library built on top of the `"date.h"` library which implements the ISO week date calendar.
* Documentation: http://howardhinnant.github.io/date/iso_week.html
4. `"julian.h"` is a header-only library built on top of the `"date.h"` library which implements a proleptic Julian calendar which is fully interoperable with everything above.
1. `"julian.h"` is a header-only library built on top of the `"date.h"` library which implements a proleptic Julian calendar which is fully interoperable with everything above.
* Documentation: http://howardhinnant.github.io/date/julian.html
5. `"islamic.h"` is a header-only library built on top of the `"date.h"` library which implements a proleptic Islamic calendar which is fully interoperable with everything above.
1. `"islamic.h"` is a header-only library built on top of the `"date.h"` library which implements a proleptic Islamic calendar which is fully interoperable with everything above.
* Documentation: http://howardhinnant.github.io/date/islamic.html
`"date.h"` and `"tz.h"` are now being proposed for standardization:
## Standardization
* Current proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0355r4.html
* Draft revision: http://howardhinnant.github.io/date/d0355r5.html
* Status: The proposal was approved by LEWG and forwarded to LWG with the recommendation of targeting C++20 at the Albuquerque, NM meeting in Nov. 2017.
Slightly modified versions of `"date.h"` and `"tz.h"` were voted into the C++20 working draft at the Jacksonville FL meeting on 2018-03-17:
List of projects using this library:
* http://howardhinnant.github.io/date/d0355r7.html
* www.safe.com
* www.webtoolkit.eu/wt
## Build & Test
You can download and install Date using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
vcpkg install date
The Date port in vcpkg is updated by Microsoft team members and community contributors. If the version falls behind, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
You can optionally build using [CMake](https://cmake.org/). Here is a guide of how to build and test using the CMake Makefile generator.
```bash
mkdir build
cd build
cmake ../
cmake --build . --target testit # Consider '-- -j4' for multithreading
```
## Projects using this library
* www.safe.com
* www.webtoolkit.eu/wt
* https://github.com/ViewTouch/viewtouch
* https://routinghub.com
* https://github.com/valhalla
If you would like your project (or product) on this list, just let me know.

34
ci/install_cmake.sh Executable file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env bash
set -e
IFS=. read cm_maj cm_min cm_rel <<<"$1"
: ${cm_rel:-0}
CMAKE_ROOT=${2:-"${HOME}/cmake"}
function cmake_version ()
{
if [[ -d ${CMAKE_ROOT} ]] ; then
local perms=$(test $(uname) = "Linux" && echo "/111" || echo "+111")
local installed=$(find ${CMAKE_ROOT} -perm ${perms} -type f -name cmake)
if [[ "${installed}" != "" ]] ; then
echo "$(${installed} --version | head -1)"
fi
fi
}
installed=$(cmake_version)
if [[ "${installed}" != "" && ${installed} =~ ${cm_maj}.${cm_min}.${cm_rel} ]] ; then
echo "cmake already installed: ${installed}"
exit
fi
pkgname="cmake-${cm_maj}.${cm_min}.${cm_rel}-$(uname)-x86_64.tar.gz"
tmppkg="/tmp/cmake.tar.gz"
wget --quiet https://cmake.org/files/v${cm_maj}.${cm_min}/${pkgname} -O ${tmppkg}
mkdir -p ${CMAKE_ROOT}
cd ${CMAKE_ROOT}
tar --strip-components 1 -xf ${tmppkg}
rm -f ${tmppkg}
echo "installed: $(cmake_version)"

11
cmake/dateConfig.cmake Normal file
View File

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

File diff suppressed because it is too large Load Diff

View File

@ -38,6 +38,7 @@
{
std::string get_tzdata_path();
std::string get_current_timezone();
} // namespace iOSUtils
} // namespace date

View File

@ -39,10 +39,10 @@ using days = date::days;
using weeks = date::weeks;
using years = std::chrono::duration
<int, std::ratio_multiply<std::ratio<10631, 30>, days::period>>;
<int, date::detail::ratio_multiply<std::ratio<10631, 30>, days::period>>;
using months = std::chrono::duration
<int, std::ratio_divide<years::period, std::ratio<12>>>;
<int, date::detail::ratio_divide<years::period, std::ratio<12>>>;
// time_point
@ -253,7 +253,7 @@ public:
CONSTCD14 year& operator+=(const years& y) NOEXCEPT;
CONSTCD14 year& operator-=(const years& y) NOEXCEPT;
CONSTCD11 bool is_leap() const NOEXCEPT;
CONSTCD14 bool is_leap() const NOEXCEPT;
CONSTCD11 explicit operator int() const NOEXCEPT;
CONSTCD11 bool ok() const NOEXCEPT;
@ -866,7 +866,7 @@ inline
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const day& d)
{
date::detail::save_stream<CharT, Traits> _(os);
date::detail::save_ostream<CharT, Traits> _(os);
os.fill('0');
os.flags(std::ios::dec | std::ios::right);
os.width(2);
@ -1046,7 +1046,7 @@ CONSTCD14 inline year year::operator--(int) NOEXCEPT {auto tmp(*this); --(*this)
CONSTCD14 inline year& year::operator+=(const years& y) NOEXCEPT {*this = *this + y; return *this;}
CONSTCD14 inline year& year::operator-=(const years& y) NOEXCEPT {*this = *this - y; return *this;}
CONSTCD11
CONSTCD14
inline
bool
year::is_leap() const NOEXCEPT
@ -1177,7 +1177,7 @@ inline
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const year& y)
{
date::detail::save_stream<CharT, Traits> _(os);
date::detail::save_ostream<CharT, Traits> _(os);
os.fill('0');
os.flags(std::ios::dec | std::ios::internal);
os.width(4 + (y < year{0}));
@ -2236,7 +2236,7 @@ inline
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day& ymd)
{
date::detail::save_stream<CharT, Traits> _(os);
date::detail::save_ostream<CharT, Traits> _(os);
os.fill('0');
os.flags(std::ios::dec | std::ios::right);
os << ymd.year() << '-';

View File

@ -451,7 +451,7 @@ weekday::weekday(unsigned wd) NOEXCEPT
CONSTCD11
inline
weekday::weekday(date::weekday wd) NOEXCEPT
: wd_(to_iso_encoding(static_cast<unsigned>(wd)))
: wd_(wd.iso_encoding())
{}
CONSTCD11
@ -607,7 +607,10 @@ inline
year
year::min() NOEXCEPT
{
using namespace std::chrono;
using std::chrono::seconds;
using std::chrono::minutes;
using std::chrono::hours;
using std::chrono::duration_cast;
static_assert(sizeof(seconds)*CHAR_BIT >= 41, "seconds may overflow");
static_assert(sizeof(hours)*CHAR_BIT >= 30, "hours may overflow");
return sizeof(minutes)*CHAR_BIT < 34 ?
@ -620,7 +623,10 @@ inline
year
year::max() NOEXCEPT
{
using namespace std::chrono;
using std::chrono::seconds;
using std::chrono::minutes;
using std::chrono::hours;
using std::chrono::duration_cast;
static_assert(sizeof(seconds)*CHAR_BIT >= 41, "seconds may overflow");
static_assert(sizeof(hours)*CHAR_BIT >= 30, "hours may overflow");
return sizeof(minutes)*CHAR_BIT < 34 ?
@ -713,7 +719,7 @@ inline
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const year& y)
{
date::detail::save_stream<CharT, Traits> _(os);
date::detail::save_ostream<CharT, Traits> _(os);
os.fill('0');
os.flags(std::ios::dec | std::ios::internal);
os.width(4 + (y < year{0}));
@ -875,7 +881,7 @@ inline
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const weeknum& wn)
{
date::detail::save_stream<CharT, Traits> _(os);
date::detail::save_ostream<CharT, Traits> _(os);
os << 'W';
os.fill('0');
os.flags(std::ios::dec | std::ios::right);

View File

@ -39,10 +39,10 @@ using days = date::days;
using weeks = date::weeks;
using years = std::chrono::duration
<int, std::ratio_multiply<std::ratio<1461, 4>, days::period>>;
<int, date::detail::ratio_multiply<std::ratio<1461, 4>, days::period>>;
using months = std::chrono::duration
<int, std::ratio_divide<years::period, std::ratio<12>>>;
<int, date::detail::ratio_divide<years::period, std::ratio<12>>>;
// time_point
@ -879,7 +879,7 @@ inline
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const day& d)
{
date::detail::save_stream<CharT, Traits> _(os);
date::detail::save_ostream<CharT, Traits> _(os);
os.fill('0');
os.flags(std::ios::dec | std::ios::right);
os.width(2);
@ -1171,7 +1171,7 @@ inline
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const year& y)
{
date::detail::save_stream<CharT, Traits> _(os);
date::detail::save_ostream<CharT, Traits> _(os);
os.fill('0');
os.flags(std::ios::dec | std::ios::internal);
os.width(4 + (y < year{0}));
@ -2250,7 +2250,7 @@ inline
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day& ymd)
{
date::detail::save_stream<CharT, Traits> _(os);
date::detail::save_ostream<CharT, Traits> _(os);
os.fill('0');
os.flags(std::ios::dec | std::ios::right);
os << ymd.year() << '-';

View File

@ -96,19 +96,22 @@ inline
date::local_seconds
rule::operator()(date::year y) const
{
using namespace date;
using date::local_days;
using date::January;
using date::days;
using date::last;
using sec = std::chrono::seconds;
date::local_seconds t;
switch (mode_)
{
case J:
t = local_days{y/jan/0} + days{n_ + (y.is_leap() && n_ > 59)} + sec{time_};
t = local_days{y/January/0} + days{n_ + (y.is_leap() && n_ > 59)} + sec{time_};
break;
case M:
t = (n_ == 5 ? local_days{y/m_/wd_[last]} : local_days{y/m_/wd_[n_]}) + sec{time_};
break;
case N:
t = local_days{y/jan/1} + days{n_} + sec{time_};
t = local_days{y/January/1} + days{n_} + sec{time_};
break;
default:
assert(!"rule called with bad mode");
@ -180,7 +183,9 @@ public:
inline
time_zone::time_zone(const detail::string_t& s)
{
using namespace detail;
using detail::read_name;
using detail::read_signed_time;
using detail::throw_invalid;
auto i = read_name(s, 0, std_abbrev_);
i = read_signed_time(s, i, offset_);
offset_ = -offset_;
@ -212,8 +217,19 @@ template <class Duration>
date::sys_info
time_zone::get_info(date::sys_time<Duration> st) const
{
using namespace date;
using namespace std::chrono;
using date::sys_info;
using date::year_month_day;
using date::sys_seconds;
using date::sys_days;
using date::floor;
using date::ceil;
using date::days;
using date::years;
using date::year;
using date::January;
using date::December;
using date::last;
using std::chrono::minutes;
sys_info r{};
r.offset = offset_;
if (start_rule_.ok())
@ -245,8 +261,8 @@ time_zone::get_info(date::sys_time<Duration> st) const
}
else // constant offset
{
r.begin = sys_days{year::min()/jan/1};
r.end = sys_days{year::max()/dec/last};
r.begin = sys_days{year::min()/January/1};
r.end = sys_days{year::max()/December/last};
r.abbrev = std_abbrev_;
}
return r;
@ -256,9 +272,21 @@ template <class Duration>
date::local_info
time_zone::get_info(date::local_time<Duration> tp) const
{
using namespace date;
using namespace std::chrono;
using date::local_info;
using date::year_month_day;
using date::days;
using date::sys_days;
using date::sys_seconds;
using date::years;
using date::year;
using date::ceil;
using date::January;
using date::December;
using date::last;
using std::chrono::seconds;
using std::chrono::minutes;
local_info r{};
using date::floor;
if (start_rule_.ok())
{
auto y = year_month_day{floor<days>(tp)}.year();
@ -323,8 +351,8 @@ time_zone::get_info(date::local_time<Duration> tp) const
}
else // constant offset
{
r.first.begin = sys_days{year::min()/jan/1};
r.first.end = sys_days{year::max()/dec/last};
r.first.begin = sys_days{year::min()/January/1};
r.first.end = sys_days{year::max()/December/last};
r.first.abbrev = std_abbrev_;
r.first.offset = offset_;
}
@ -335,7 +363,9 @@ template <class Duration>
date::sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
time_zone::to_sys(date::local_time<Duration> tp) const
{
using namespace date;
using date::local_info;
using date::sys_time;
using date::ambiguous_local_time;
auto i = get_info(tp);
if (i.result == local_info::nonexistent)
throw nonexistent_local_time(tp, i);
@ -348,7 +378,9 @@ template <class Duration>
date::sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
time_zone::to_sys(date::local_time<Duration> tp, date::choose z) const
{
using namespace date;
using date::local_info;
using date::sys_time;
using date::choose;
auto i = get_info(tp);
if (i.result == local_info::nonexistent)
{
@ -366,8 +398,8 @@ template <class Duration>
date::local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
time_zone::to_local(date::sys_time<Duration> tp) const
{
using namespace date;
using namespace std::chrono;
using date::local_time;
using std::chrono::seconds;
using LT = local_time<typename std::common_type<Duration, seconds>::type>;
auto i = get_info(tp);
return LT{(tp + i.offset).time_since_epoch()};
@ -393,7 +425,7 @@ throw_invalid(const string_t& s, unsigned i, const string_t& message)
{
throw std::runtime_error(std::string("Invalid time_zone initializer.\n") +
std::string(message) + ":\n" +
s + '\n' +
std::string(s) + '\n' +
"\x1b[1;32m" +
std::string(i, '~') + '^' +
std::string(s.size()-i-1, '~') +
@ -404,7 +436,8 @@ inline
unsigned
read_date(const string_t& s, unsigned i, rule& r)
{
using namespace date;
using date::month;
using date::weekday;
if (i == s.size())
throw_invalid(s, i, "Expected rule but found end of string");
if (s[i] == 'J')
@ -513,7 +546,9 @@ inline
unsigned
read_unsigned_time(const string_t& s, unsigned i, std::chrono::seconds& t)
{
using namespace std::chrono;
using std::chrono::seconds;
using std::chrono::minutes;
using std::chrono::hours;
if (i == s.size())
throw_invalid(s, i, "Expected to read unsigned time, but found end of string");
unsigned x;

3143
include/date/solar_hijri.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -95,9 +95,9 @@ private:
U& operator=(const pair& x);
} u;
std::chrono::hours h_{0};
std::chrono::minutes m_{0};
std::chrono::seconds s_{0};
std::chrono::hours h_{};
std::chrono::minutes m_{};
std::chrono::seconds s_{};
tz zone_{tz::local};
public:
@ -289,11 +289,9 @@ struct transition
std::ostream&
operator<<(std::ostream& os, const transition& t)
{
using namespace date;
using namespace std::chrono;
using date::operator<<;
os << t.timepoint << "Z ";
if (t.info->offset >= seconds{0})
if (t.info->offset >= std::chrono::seconds{0})
os << '+';
os << make_time(t.info->offset);
if (t.info->is_dst > 0)

View File

@ -22,7 +22,7 @@
// SOFTWARE.
//
#include "ios.h"
#include "date/ios.h"
#if TARGET_OS_IPHONE

View File

@ -84,10 +84,11 @@
#endif // _WIN32
#include "date/tz_private.h"
#include "date/ios.h"
#ifndef __APPLE__
# define TARGET_OS_IPHONE 0
#ifdef __APPLE__
# include "date/ios.h"
#else
# define TARGET_OS_IPHONE 0
#endif
#if USE_OS_TZDB
@ -97,6 +98,7 @@
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <cwchar>
#include <exception>
#include <fstream>
#include <iostream>
@ -116,6 +118,14 @@
// gcc/mingw supports unistd.h on Win32 but MSVC does not.
#ifdef _WIN32
# ifdef WINAPI_FAMILY
# include <winapifamily.h>
# if WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP
# define WINRT
# define INSTALL .
# endif
# endif
# include <io.h> // _unlink etc.
# if defined(__clang__)
@ -148,7 +158,7 @@
#if HAS_REMOTE_API
// Note curl includes windows.h so we must include curl AFTER definitions of things
// that effect windows.h such as NOMINMAX.
// that affect windows.h such as NOMINMAX.
#if defined(_MSC_VER) && defined(SHORTENED_CURL_INCLUDE)
// For rmt_curl nuget package
# include <curl.h>
@ -172,6 +182,7 @@ static CONSTDATA char folder_delimiter = '/';
#if !USE_OS_TZDB
# ifdef _WIN32
# ifndef WINRT
namespace
{
@ -198,11 +209,20 @@ get_known_folder(const GUID& folderid)
if (SUCCEEDED(hr))
{
co_task_mem_ptr folder_ptr(pfolder);
folder = std::string(folder_ptr.get(), folder_ptr.get() + wcslen(folder_ptr.get()));
const wchar_t* fptr = folder_ptr.get();
auto state = std::mbstate_t();
const auto required = std::wcsrtombs(nullptr, &fptr, 0, &state);
if (required != 0 && required != std::size_t(-1))
{
folder.resize(required);
std::wcsrtombs(&folder[0], &fptr, folder.size(), &state);
}
}
return folder;
}
# ifndef INSTALL
// Usually something like "c:\Users\username\Downloads".
static
std::string
@ -211,9 +231,12 @@ get_download_folder()
return get_known_folder(FOLDERID_Downloads);
}
# endif // !INSTALL
# endif // WINRT
# else // !_WIN32
# if !defined(INSTALL) || HAS_REMOTE_API
# if !defined(INSTALL)
static
std::string
@ -239,7 +262,7 @@ get_download_folder()
return expand_path("~/Downloads");
}
# endif // !defined(INSTALL) || HAS_REMOTE_API
# endif // !defined(INSTALL)
# endif // !_WIN32
@ -308,8 +331,8 @@ get_download_gz_file(const std::string& version)
CONSTDATA auto min_year = date::year::min();
CONSTDATA auto max_year = date::year::max();
CONSTDATA auto min_day = date::jan/1;
CONSTDATA auto max_day = date::dec/31;
CONSTDATA auto min_day = date::January/1;
CONSTDATA auto max_day = date::December/31;
#if USE_OS_TZDB
@ -360,7 +383,13 @@ discover_tz_dir()
# endif // __APPLE__
}
static const std::string tz_dir = discover_tz_dir();
static
const std::string&
get_tz_dir()
{
static const std::string tz_dir = discover_tz_dir();
return tz_dir;
}
#endif
@ -368,11 +397,6 @@ static const std::string tz_dir = discover_tz_dir();
// | End Configuration |
// +-------------------+
namespace detail
{
struct undocumented {explicit undocumented() = default;};
}
#ifndef _MSC_VER
static_assert(min_year <= max_year, "Configuration error");
#endif
@ -492,7 +516,7 @@ native_to_standard_timezone_name(const std::string& native_tz_name,
}
// Parse this XML file:
// http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml
// https://raw.githubusercontent.com/unicode-org/cldr/master/common/supplemental/windowsZones.xml
// The parsing method is designed to be simple and quick. It is not overly
// forgiving of change but it should diagnose basic format issues.
// See timezone_mapping structure for more info.
@ -609,7 +633,7 @@ load_timezone_mappings_from_xml_file(const std::string& input_path)
// NOTE: We could extract the version info that follows the opening
// mapTimezones tag and compare that to the version of other data we have.
// I would have expected them to be kept in synch but testing has shown
// it is typically does not match anyway. So what's the point?
// it typically does not match anyway. So what's the point?
while (!mapTimezonesCloseTagFound)
{
std::ws(is);
@ -1217,7 +1241,7 @@ detail::operator<<(std::ostream& os, const Rule& r)
{
using namespace date;
using namespace std::chrono;
detail::save_stream<char> _(os);
detail::save_ostream<char> _(os);
os.fill(' ');
os.flags(std::ios::dec | std::ios::left);
os.width(15);
@ -1900,13 +1924,13 @@ load_abbreviations(std::istream& inf, std::int32_t tzh_charcnt)
template <class TimeType>
static
std::vector<leap>
std::vector<leap_second>
load_leaps(std::istream& inf, std::int32_t tzh_leapcnt)
{
// Read tzh_leapcnt pairs
using namespace std::chrono;
std::vector<leap> leap_seconds;
leap_seconds.reserve(tzh_leapcnt);
std::vector<leap_second> leap_seconds;
leap_seconds.reserve(static_cast<std::size_t>(tzh_leapcnt));
for (std::int32_t i = 0; i < tzh_leapcnt; ++i)
{
TimeType t0;
@ -1923,17 +1947,18 @@ load_leaps(std::istream& inf, std::int32_t tzh_leapcnt)
template <class TimeType>
static
std::vector<leap>
std::vector<leap_second>
load_leap_data(std::istream& inf,
std::int32_t tzh_leapcnt, std::int32_t tzh_timecnt,
std::int32_t tzh_typecnt, std::int32_t tzh_charcnt)
{
inf.ignore(tzh_timecnt*sizeof(TimeType) + tzh_timecnt + tzh_typecnt*6 + tzh_charcnt);
inf.ignore(tzh_timecnt*static_cast<std::int32_t>(sizeof(TimeType)) + tzh_timecnt +
tzh_typecnt*6 + tzh_charcnt);
return load_leaps<TimeType>(inf, tzh_leapcnt);
}
static
std::vector<leap>
std::vector<leap_second>
load_just_leaps(std::istream& inf)
{
// Read tzh_leapcnt pairs
@ -1979,7 +2004,7 @@ time_zone::load_data(std::istream& inf,
auto infos = load_ttinfo(inf, tzh_typecnt);
auto abbrev = load_abbreviations(inf, tzh_charcnt);
#if !MISSING_LEAP_SECONDS
auto& leap_seconds = get_tzdb_list().front().leaps;
auto& leap_seconds = get_tzdb_list().front().leap_seconds;
if (leap_seconds.empty() && tzh_leapcnt > 0)
leap_seconds = load_leaps<TimeType>(inf, tzh_leapcnt);
#endif
@ -2011,7 +2036,7 @@ time_zone::init_impl()
{
using namespace std;
using namespace std::chrono;
auto name = tz_dir + ('/' + name_);
auto name = get_tz_dir() + ('/' + name_);
std::ifstream inf(name);
if (!inf.is_open())
throw std::runtime_error{"Unable to open " + name};
@ -2047,7 +2072,7 @@ time_zone::init_impl()
#if !MISSING_LEAP_SECONDS
if (tzh_leapcnt > 0)
{
auto& leap_seconds = get_tzdb_list().front().leaps;
auto& leap_seconds = get_tzdb_list().front().leap_seconds;
auto itr = leap_seconds.begin();
auto l = itr->date();
seconds leap_count{0};
@ -2182,7 +2207,7 @@ operator<<(std::ostream& os, const time_zone& z)
#if !MISSING_LEAP_SECONDS
leap::leap(const sys_seconds& s, detail::undocumented)
leap_second::leap_second(const sys_seconds& s, detail::undocumented)
: date_(s)
{
}
@ -2534,7 +2559,7 @@ operator<<(std::ostream& os, const time_zone& z)
{
using namespace date;
using namespace std::chrono;
detail::save_stream<char> _(os);
detail::save_ostream<char> _(os);
os.fill(' ');
os.flags(std::ios::dec | std::ios::left);
std::call_once(*z.adjusted_,
@ -2588,7 +2613,7 @@ operator<<(std::ostream& os, const time_zone& z)
#if !MISSING_LEAP_SECONDS
std::ostream&
operator<<(std::ostream& os, const leap& x)
operator<<(std::ostream& os, const leap_second& x)
{
using namespace date;
return os << x.date_ << " +";
@ -2604,7 +2629,7 @@ std::string
get_version()
{
using namespace std;
auto path = tz_dir + string("/+VERSION");
auto path = get_tz_dir() + string("/+VERSION");
ifstream in{path};
string version;
in >> version;
@ -2622,7 +2647,7 @@ init_tzdb()
//Iterate through folders
std::queue<std::string> subfolders;
subfolders.emplace(tz_dir);
subfolders.emplace(get_tz_dir());
struct dirent* d;
struct stat s;
while (!subfolders.empty())
@ -2643,6 +2668,8 @@ init_tzdb()
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 ||
strcmp(d->d_name, "leapseconds") == 0 ||
strcmp(d->d_name, "leap-seconds.list") == 0 )
continue;
auto subname = dirname + folder_delimiter + d->d_name;
@ -2657,7 +2684,7 @@ init_tzdb()
}
else
{
db->zones.emplace_back(subname.substr(tz_dir.size()+1),
db->zones.emplace_back(subname.substr(get_tz_dir().size()+1),
detail::undocumented{});
}
}
@ -2667,21 +2694,22 @@ init_tzdb()
db->zones.shrink_to_fit();
std::sort(db->zones.begin(), db->zones.end());
# if !MISSING_LEAP_SECONDS
std::ifstream in(tz_dir + std::string(1, folder_delimiter) + "right/UTC",
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->leaps = load_just_leaps(in);
db->leap_seconds = load_just_leaps(in);
}
else
{
in.clear();
in.open(tz_dir + std::string(1, folder_delimiter) + "UTC", std::ios_base::binary);
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->leaps = load_just_leaps(in);
db->leap_seconds = load_just_leaps(in);
}
# endif // !MISSING_LEAP_SECONDS
# ifdef __APPLE__
@ -2692,9 +2720,9 @@ init_tzdb()
#else // !USE_OS_TZDB
// link
// time_zone_link
link::link(const std::string& s)
time_zone_link::time_zone_link(const std::string& s)
{
using namespace date;
std::istringstream in(s);
@ -2704,19 +2732,19 @@ link::link(const std::string& s)
}
std::ostream&
operator<<(std::ostream& os, const link& x)
operator<<(std::ostream& os, const time_zone_link& x)
{
using namespace date;
detail::save_stream<char> _(os);
detail::save_ostream<char> _(os);
os.fill(' ');
os.flags(std::ios::dec | std::ios::left);
os.width(35);
return os << x.name_ << " --> " << x.target_;
}
// leap
// leap_second
leap::leap(const std::string& s, detail::undocumented)
leap_second::leap_second(const std::string& s, detail::undocumented)
{
using namespace date;
std::istringstream in(s);
@ -2783,6 +2811,7 @@ download_to_string(const std::string& url, std::string& str)
if (!curl)
return false;
std::string version;
curl_easy_setopt(curl.get(), CURLOPT_USERAGENT, "curl");
curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str());
curl_write_callback write_cb = [](char* contents, std::size_t size, std::size_t nmemb,
void* userp) -> std::size_t
@ -2807,13 +2836,15 @@ namespace
static
bool
download_to_file(const std::string& url, const std::string& local_filename,
download_file_options opts)
download_file_options opts, char* error_buffer)
{
auto curl = curl_init();
if (!curl)
return false;
curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str());
curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, false);
if (error_buffer)
curl_easy_setopt(curl.get(), CURLOPT_ERRORBUFFER, error_buffer);
curl_write_callback write_cb = [](char* contents, std::size_t size, std::size_t nmemb,
void* userp) -> std::size_t
{
@ -2956,7 +2987,7 @@ make_directory(const std::string& folder)
# endif // !USE_SHELL_API
# else // !_WIN32
# if USE_SHELL_API
return std::system(("mkdir " + folder).c_str()) == EXIT_SUCCESS;
return std::system(("mkdir -p " + folder).c_str()) == EXIT_SUCCESS;
# else // !USE_SHELL_API
return mkdir(folder.c_str(), 0777) == 0;
# endif // !USE_SHELL_API
@ -3233,7 +3264,7 @@ extract_gz_file(const std::string&, const std::string& gz_file, const std::strin
# endif // !_WIN32
bool
remote_download(const std::string& version)
remote_download(const std::string& version, char* error_buffer)
{
assert(!version.empty());
@ -3241,24 +3272,26 @@ remote_download(const std::string& version)
// Download folder should be always available for Windows
# else // !_WIN32
// Create download folder if it does not exist on UNIX system
auto download_folder = get_download_folder();
auto download_folder = get_install();
if (!file_exists(download_folder))
{
make_directory(download_folder);
if (!make_directory(download_folder))
return false;
}
# endif // _WIN32
auto url = "https://data.iana.org/time-zones/releases/tzdata" + version +
".tar.gz";
bool result = download_to_file(url, get_download_gz_file(version),
download_file_options::binary);
download_file_options::binary, error_buffer);
# ifdef _WIN32
if (result)
{
auto mapping_file = get_download_mapping_file(version);
result = download_to_file("http://unicode.org/repos/cldr/trunk/common/"
"supplemental/windowsZones.xml",
mapping_file, download_file_options::text);
result = download_to_file(
"https://raw.githubusercontent.com/unicode-org/cldr/master/"
"common/supplemental/windowsZones.xml",
mapping_file, download_file_options::text, error_buffer);
}
# endif // _WIN32
return result;
@ -3407,12 +3440,12 @@ init_tzdb()
}
else if (word == "Link")
{
db->links.push_back(link(line));
db->links.push_back(time_zone_link(line));
continue_zone = false;
}
else if (word == "Leap")
{
db->leaps.push_back(leap(line, detail::undocumented{}));
db->leap_seconds.push_back(leap_second(line, detail::undocumented{}));
continue_zone = false;
}
else if (word == "Zone")
@ -3437,8 +3470,8 @@ init_tzdb()
db->zones.shrink_to_fit();
std::sort(db->links.begin(), db->links.end());
db->links.shrink_to_fit();
std::sort(db->leaps.begin(), db->leaps.end());
db->leaps.shrink_to_fit();
std::sort(db->leap_seconds.begin(), db->leap_seconds.end());
db->leap_seconds.shrink_to_fit();
#ifdef _WIN32
std::string mapping_file = get_install() + folder_delimiter + "windowsZones.xml";
@ -3490,9 +3523,9 @@ tzdb::locate_zone(const std::string& tz_name) const
#if !USE_OS_TZDB
auto li = std::lower_bound(links.begin(), links.end(), tz_name,
#if HAS_STRING_VIEW
[](const link& z, const std::string_view& nm)
[](const time_zone_link& z, const std::string_view& nm)
#else
[](const link& z, const std::string& nm)
[](const time_zone_link& z, const std::string& nm)
#endif
{
return z.name() < nm;
@ -3533,7 +3566,7 @@ operator<<(std::ostream& os, const tzdb& db)
os << x << '\n';
#if !MISSING_LEAP_SECONDS
os << '\n';
for (const auto& x : db.leaps)
for (const auto& x : db.leap_seconds)
os << x << '\n';
#endif // !MISSING_LEAP_SECONDS
return os;
@ -3593,7 +3626,7 @@ operator<<(std::ostream& os, const tzdb& db)
"---------------------------------------------------------"
"--------------------------------------------------------\n");
os << title;
for (const auto& x : db.leaps)
for (const auto& x : db.leap_seconds)
os << x << '\n';
return os;
}
@ -3640,6 +3673,56 @@ tzdb::current_zone() const
#else // !_WIN32
#if HAS_STRING_VIEW
static
std::string_view
extract_tz_name(char const* rp)
{
using namespace std;
string_view result = rp;
CONSTDATA string_view zoneinfo = "zoneinfo";
size_t pos = result.rfind(zoneinfo);
if (pos == result.npos)
throw runtime_error(
"current_zone() failed to find \"zoneinfo\" in " + string(result));
pos = result.find('/', pos);
result.remove_prefix(pos + 1);
return result;
}
#else // !HAS_STRING_VIEW
static
std::string
extract_tz_name(char const* rp)
{
using namespace std;
string result = rp;
CONSTDATA char zoneinfo[] = "zoneinfo";
size_t pos = result.rfind(zoneinfo);
if (pos == result.npos)
throw runtime_error(
"current_zone() failed to find \"zoneinfo\" in " + result);
pos = result.find('/', pos);
result.erase(0, pos + 1);
return result;
}
#endif // HAS_STRING_VIEW
static
bool
sniff_realpath(const char* timezone)
{
using namespace std;
char rp[PATH_MAX+1] = {};
if (realpath(timezone, rp) == nullptr)
throw system_error(errno, system_category(), "realpath() failed");
auto result = extract_tz_name(rp);
return result != "posixrules";
}
const time_zone*
tzdb::current_zone() const
{
@ -3651,7 +3734,7 @@ tzdb::current_zone() const
// "/usr/share/zoneinfo/America/Los_Angeles"
// If it does, we try to determine the current
// timezone from the remainder of the path by removing the prefix
// and hoping the rest resolves to valid timezone.
// and hoping the rest resolves to a valid timezone.
// It may not always work though. If it doesn't then an
// exception will be thrown by local_timezone.
// The path may also take a relative form:
@ -3659,19 +3742,22 @@ tzdb::current_zone() const
{
struct stat sb;
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)
{
using namespace std;
string result;
static const bool use_realpath = sniff_realpath(timezone);
char rp[PATH_MAX+1] = {};
if (readlink(timezone, rp, sizeof(rp)-1) > 0)
result = string(rp);
if (use_realpath)
{
if (realpath(timezone, rp) == nullptr)
throw system_error(errno, system_category(), "realpath() failed");
}
else
throw system_error(errno, system_category(), "readlink() failed");
const size_t pos = result.find(tz_dir);
if (pos != result.npos)
result.erase(0, tz_dir.size() + 1 + pos);
return locate_zone(result);
{
if (readlink(timezone, rp, sizeof(rp)-1) <= 0)
throw system_error(errno, system_category(), "readlink() failed");
}
return locate_zone(extract_tz_name(rp));
}
}
// On embedded systems e.g. buildroot with uclibc the timezone is linked
@ -3696,9 +3782,9 @@ tzdb::current_zone() const
else
throw system_error(errno, system_category(), "readlink() failed");
const size_t pos = result.find(tz_dir);
const size_t pos = result.find(get_tz_dir());
if (pos != result.npos)
result.erase(0, tz_dir.size() + 1 + pos);
result.erase(0, get_tz_dir().size() + 1 + pos);
return locate_zone(result);
}
}
@ -3731,6 +3817,18 @@ tzdb::current_zone() const
// Fall through to try other means.
}
{
// On some versions of some bsd distro's (e.g. iOS),
// it is not possible to use file based approach,
// we switch to system API, calling functions in
// CoreFoundation framework.
#if TARGET_OS_IPHONE
std::string result = date::iOSUtils::get_current_timezone();
if (!result.empty())
return locate_zone(result);
#endif
// Fall through to try other means.
}
{
// On some versions of some linux distro's (e.g. Red Hat),
// the current timezone might be in the first line of
// the /etc/sysconfig/clock file as:

View File

@ -0,0 +1,75 @@
// The MIT License (MIT)
//
// Copyright (c) 2019 nanoric
//
// 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 <cassert>
#include <type_traits>
struct const_clock {
using duration =
typename std::common_type<std::chrono::system_clock::duration,
date::days>::type;
using rep = duration::rep;
using period = duration::period;
using time_point = std::chrono::time_point<const_clock, duration>;
static constexpr date::sys_days epoch { date::days { 1000 } };
template <typename Duration>
static std::chrono::time_point<std::chrono::system_clock,
typename std::common_type<Duration, date::days>::type>
CONSTCD11 to_sys(std::chrono::time_point<const_clock, Duration> const& tp)
{
return epoch + tp.time_since_epoch();
}
template <typename Duration>
static std::chrono::time_point<const_clock,
typename std::common_type<Duration, date::days>::type>
CONSTCD11 from_sys(
std::chrono::time_point<std::chrono::system_clock, Duration> const&
tp)
{
using res = std::chrono::time_point<const_clock,
typename std::common_type<Duration, date::days>::type>;
return res(tp - epoch);
}
};
int main()
{
using namespace date;
using namespace std::chrono;
using const_days = time_point<const_clock, days>;
CONSTCD14 sys_days sys { days { 1024 } };
static_assert(sys.time_since_epoch().count() == 1024, "");
CONSTCD14 const_days c {clock_cast<const_clock>(sys)};
CONSTCD14 sys_days sys2 {clock_cast<system_clock>(c)};
CONSTCD14 sys_days sys3 { clock_cast<system_clock>(const_days(days(48))) };
#if __cplusplus >= 201402L
static_assert(c.time_since_epoch().count() == 24, "");
static_assert(sys2.time_since_epoch().count() == 1024, "");
static_assert(sys3.time_since_epoch().count() == 1048, "");
#endif
}

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2017 Tomasz Kamiński
// Copyright (c) 2017, 2018 Tomasz Kamiński
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -30,16 +30,16 @@ int conversions = 0;
//to/from impl
struct mil_clock
{
using duration = std::common_type_t<std::chrono::system_clock::duration, date::days>;
using duration = typename std::common_type<std::chrono::system_clock::duration, date::days>::type;
using rep = duration::rep;
using period = duration::period;
using time_point = std::chrono::time_point<mil_clock, duration>;
static constexpr date::sys_days epoch = date::year{2000}/date::month{0}/date::day{1};
static constexpr date::sys_days epoch{date::days{1000}};
template<typename Duration>
static
std::chrono::time_point<std::chrono::system_clock, std::common_type_t<Duration, date::days>>
std::chrono::time_point<std::chrono::system_clock, typename std::common_type<Duration, date::days>::type>
to_sys(std::chrono::time_point<mil_clock, Duration> const& tp)
{
++conversions;
@ -48,14 +48,31 @@ struct mil_clock
template<typename Duration>
static
std::chrono::time_point<mil_clock, std::common_type_t<Duration, date::days>>
std::chrono::time_point<mil_clock, typename std::common_type<Duration, date::days>::type>
from_sys(std::chrono::time_point<std::chrono::system_clock, Duration> const& tp)
{
++conversions;
using res = std::chrono::time_point<mil_clock, std::common_type_t<Duration, date::days>>;
using res = std::chrono::time_point<mil_clock, typename std::common_type<Duration, date::days>::type>;
return res(tp - epoch);
}
template<typename Duration>
static
std::chrono::time_point<date::local_t, typename std::common_type<Duration, date::days>::type>
to_local(std::chrono::time_point<mil_clock, Duration> const& tp)
{
return date::clock_cast<date::local_t>(to_sys(tp));
}
template<typename Duration>
static
std::chrono::time_point<mil_clock, typename std::common_type<Duration, date::days>::type>
from_local(std::chrono::time_point<date::local_t, Duration> const& tp)
{
return from_sys(date::clock_cast<std::chrono::system_clock>(tp));
}
static time_point now()
{
return from_sys(std::chrono::system_clock::now());
@ -103,11 +120,11 @@ namespace date
struct clock_time_conversion<mil_clock, s2s_clock>
{
template<typename Duration>
std::chrono::time_point<mil_clock, std::common_type_t<Duration, date::days>>
std::chrono::time_point<mil_clock, typename std::common_type<Duration, date::days>::type>
operator()(std::chrono::time_point<s2s_clock, Duration> const& tp)
{
++conversions;
using res = std::chrono::time_point<mil_clock, std::common_type_t<Duration, date::days>>;
using res = std::chrono::time_point<mil_clock, typename std::common_type<Duration, date::days>::type>;
return res(tp.time_since_epoch() - mil_clock::epoch.time_since_epoch());
}
};
@ -127,6 +144,15 @@ main()
assert(clock_cast<mil_clock>(mt) == mt);
}
// mil <-> local
{
local_days lt(1997_y/dec/12);
auto mt = mil_clock::from_local(lt);
assert(clock_cast<mil_clock>(lt) == mt);
assert(clock_cast<local_t>(mt) == lt);
}
// mil <-> sys
{
sys_days st(1997_y/dec/12);

View File

@ -0,0 +1,132 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Tomasz Kamiński
//
// 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 <chrono>
#include "date/tz.h"
int
main()
{
using namespace date;
using namespace std::chrono;
// self
{
auto ls = local_days{1970_y/January/1_d};
assert(clock_cast<local_t>(ls) == ls);
}
/// sys epoch
{
auto ls = local_days{1970_y/January/1_d};
auto st = clock_cast<system_clock>(ls);
assert(clock_cast<local_t>(st) == ls);
assert(st.time_since_epoch() == seconds(0));
}
/// sys 2000 case
{
auto ls = local_days{2000_y/January/1_d};
auto st = clock_cast<system_clock>(ls);
assert(clock_cast<local_t>(st) == ls);
assert(st.time_since_epoch() == seconds(946684800));
}
/// utc epoch
{
auto lu = local_days{1970_y/January/1_d};
auto ut = clock_cast<utc_clock>(lu);
assert(clock_cast<local_t>(ut) == lu);
assert(ut.time_since_epoch() == seconds(0));
}
// utc leap second
{
auto lu = local_days{2015_y/July/1_d} - milliseconds(1);
auto ut = clock_cast<utc_clock>(lu) + milliseconds(50); //into leap second
assert(clock_cast<local_t>(ut) == lu);
}
/// utc paper example
{
auto lu = local_days{2000_y/January/1_d};
auto ut = clock_cast<utc_clock>(lu);
assert(clock_cast<local_t>(ut) == lu);
assert(ut.time_since_epoch() == seconds(946684822));
}
/// tai epoch
{
auto lt = local_days{1958_y/January/1_d};
auto tt = clock_cast<tai_clock>(lt);
assert(clock_cast<local_t>(tt) == lt);
assert(tt.time_since_epoch() == seconds(0));
auto lu = local_days{1958_y/January/1_d} - seconds(10);
auto ut = clock_cast<utc_clock>(lu);
assert(clock_cast<tai_clock>(ut) == tt);
}
// tai paper example
{
auto lt = local_days{2000_y/January/1_d} + seconds(32);
auto tt = clock_cast<tai_clock>(lt);
assert(clock_cast<local_t>(tt) == lt);
auto lu = local_days{2000_y/January/1_d};
auto ut = clock_cast<utc_clock>(lu);
assert(clock_cast<tai_clock>(ut) == tt);
}
/// gps epoch
{
auto lg = local_days{1980_y/January/Sunday[1]};
auto gt = clock_cast<gps_clock>(lg);
assert(clock_cast<local_t>(gt) == lg);
assert(gt.time_since_epoch() == seconds(0));
auto lu = local_days{1980_y/January/Sunday[1]};
auto ut = clock_cast<utc_clock>(lu);
assert(clock_cast<gps_clock>(ut) == gt);
auto lt = local_days{1980_y/January/Sunday[1]} + seconds(19);
auto tt = clock_cast<tai_clock>(lt);
assert(clock_cast<gps_clock>(tt) == gt);
}
// gps 2000 example
{
auto lg = local_days{2000_y/January/1_d};
auto gt = clock_cast<gps_clock>(lg);
assert(clock_cast<local_t>(gt) == lg);
auto lu = local_days{2000_y/January/1_d} - seconds(13);
auto ut = clock_cast<utc_clock>(lu);
assert(clock_cast<gps_clock>(ut) == gt);
auto lt = local_days{2000_y/January/1_d} + seconds(19);
auto tt = clock_cast<tai_clock>(lt);
assert(clock_cast<gps_clock>(tt) == gt);
}
}

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2017 Tomasz Kamiński
// Copyright (c) 2017, 2018 Tomasz Kamiński
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -194,6 +194,8 @@ main()
//steady_clock (must be different that sys_clock)
static_assert(is_clock_castable<steady_clock, steady_clock>::value, "steady_clock -> steady_clock");
static_assert(!is_clock_castable<steady_clock, local_t>::value, "steady_clock -> local_t");
static_assert(!is_clock_castable<local_t, steady_clock>::value, "local_t -> steady_clock");
static_assert(!is_clock_castable<steady_clock, sys_clock>::value, "steady_clock -> sys_clock");
static_assert(!is_clock_castable<sys_clock, steady_clock>::value, "sys_clock -> steady_clock");
static_assert(!is_clock_castable<steady_clock, utc_clock>::value, "steady_clock -> utc_clock");
@ -203,6 +205,8 @@ main()
//steady_based_clock (unrelated to sys_clock and utc_clocks)
static_assert(is_clock_castable<steady_based_clock, steady_based_clock>::value, "steady_based_clock -> steady_based_clock");
static_assert(!is_clock_castable<steady_based_clock, local_t>::value, "steady_based_clock -> local_t");
static_assert(!is_clock_castable<local_t, steady_based_clock>::value, "local_t -> steady_based_clock");
static_assert(!is_clock_castable<steady_based_clock, sys_clock>::value, "steady_based_clock -> sys_clock");
static_assert(!is_clock_castable<sys_clock, steady_based_clock>::value, "sys_clock -> steady_based_clock");
static_assert(!is_clock_castable<steady_based_clock, utc_clock>::value, "steady_based_clock -> utc_clock");

View File

@ -1,6 +1,6 @@
// The MIT License (MIT)
//
// Copyright (c) 2017 Tomasz Kamiński
// Copyright (c) 2017, 2018 Tomasz Kamiński
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -34,7 +34,7 @@ struct bad_clock
date::utc_time<Duration>
to_sys(std::chrono::time_point<bad_clock, Duration> const& tp)
{
return utc_time<Duration>(tp.time_since_epoch());
return date::utc_time<Duration>(tp.time_since_epoch());
}
};

View File

@ -20,16 +20,16 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// template <class Duration,
// unsigned w = width<std::common_type<
// Duration,
// std::chrono::seconds>::type::period::den>::value>
// template <class Duration>
// class decimal_format_seconds
// {
// using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
// using rep = typename CT::rep;
// public:
// using precision = typename make_precision<w>::type;
// static auto constexpr width = make_precision<w>::width;
//
// static unsigned constexpr width = detail::width<CT::period::den>::value < 19 ?
// detail::width<CT::period::den>::value : 6u;
// using precision = std::chrono::duration<rep,
// std::ratio<1, static_pow10<width>::value>>;
// private:
// std::chrono::seconds s_;
// precision sub_s_;
@ -55,12 +55,12 @@
#include <type_traits>
using fortnights = std::chrono::duration<date::weeks::rep,
std::ratio_multiply<std::ratio<2>,
date::weeks::period>>;
date::detail::ratio_multiply<std::ratio<2>,
date::weeks::period>>;
using microfortnights = std::chrono::duration<std::int64_t,
std::ratio_multiply<fortnights::period,
std::micro>>;
date::detail::ratio_multiply<fortnights::period,
std::micro>>;
int
main()
@ -94,7 +94,6 @@ main()
{
using D = decimal_format_seconds<milliseconds>;
static_assert(D::width == 3, "");
static_assert(is_same<D::precision, make_precision<D::rep, D::width>::type>{}, "");
D dfs{seconds{3}};
assert(dfs.seconds() == seconds{3});
assert(dfs.to_duration() == seconds{3});
@ -106,7 +105,6 @@ main()
{
using D = decimal_format_seconds<milliseconds>;
static_assert(D::width == 3, "");
static_assert(is_same<D::precision, make_precision<D::rep, D::width>::type>{}, "");
D dfs{milliseconds{3}};
assert(dfs.seconds() == seconds{0});
assert(dfs.to_duration() == milliseconds{3});
@ -118,9 +116,8 @@ main()
{
using D = decimal_format_seconds<microfortnights>;
static_assert(D::width == 4, "");
using S = make_precision<D::rep, D::width>::type;
static_assert(is_same<D::precision, S>{}, "");
D dfs{microfortnights{3}};
using S = D::precision;
assert(dfs.seconds() == seconds{3});
assert(dfs.to_duration() == S{36288});
assert(dfs.subseconds() == S{6288});
@ -132,9 +129,8 @@ main()
using CT = common_type<seconds, microfortnights>::type;
using D = decimal_format_seconds<CT>;
static_assert(D::width == 4, "");
using S = make_precision<D::rep, D::width>::type;
static_assert(is_same<D::precision, S>{}, "");
D dfs{microfortnights{3}};
using S = D::precision;
assert(dfs.seconds() == seconds{3});
assert(dfs.to_duration() == S{36288});
assert(dfs.subseconds() == S{6288});

View File

@ -1,63 +0,0 @@
// The MIT License (MIT)
//
// Copyright (c) 2017 Howard Hinnant
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// template <unsigned w>
// struct make_precision
// {
// using type = std::chrono::duration<std::int64_t,
// std::ratio<1, static_pow10<w>::value>>;
// static constexpr unsigned width = w;
// };
#include "date.h"
#include <cstdint>
#include <type_traits>
int
main()
{
using namespace date::detail;
using namespace std;
using namespace std::chrono;
static_assert(make_precision<int64_t, 0>::width == 0, "");
static_assert(is_same<make_precision<int64_t, 0>::type, duration<int64_t, ratio<1, 1>>>{}, "");
static_assert(make_precision<int64_t, 1>::width == 1, "");
static_assert(is_same<make_precision<int64_t, 1>::type, duration<int64_t, ratio<1, 10>>>{}, "");
static_assert(make_precision<int64_t, 2>::width == 2, "");
static_assert(is_same<make_precision<int64_t, 2>::type, duration<int64_t, ratio<1, 100>>>{}, "");
static_assert(make_precision<int64_t, 3>::width == 3, "");
static_assert(is_same<make_precision<int64_t, 3>::type, duration<int64_t, ratio<1, 1000>>>{}, "");
static_assert(make_precision<int64_t, 18>::width == 18, "");
static_assert(is_same<make_precision<int64_t, 18>::type, duration<int64_t, ratio<1, 1000000000000000000>>>{}, "");
static_assert(make_precision<int64_t, 19>::width == 6, "");
static_assert(is_same<make_precision<int64_t, 19>::type, microseconds>{}, "");
static_assert(make_precision<int64_t, 20>::width == 6, "");
static_assert(is_same<make_precision<int64_t, 20>::type, microseconds>{}, "");
}

View File

@ -0,0 +1,328 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Tomasz Kamiński
//
// 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 "date.h"
#include <cassert>
#include <sstream>
void test_SI()
{
using namespace std::chrono;
using namespace date;
std::ostringstream os;
// atto
{
duration<int, std::atto> d(13);
os << d;
assert(os.str() == "13as");
os.str("");
}
// femto
{
duration<int, std::femto> d(13);
os << d;
assert(os.str() == "13fs");
os.str("");
}
// pico
{
duration<int, std::pico> d(13);
os << d;
assert(os.str() == "13ps");
os.str("");
}
// nano
{
duration<int, std::nano> d(13);
os << d;
assert(os.str() == "13ns");
os.str("");
}
// mikro
{
duration<int, std::micro> d(13);
os << d;
assert(os.str() == "13\xC2\xB5s");
os.str("");
}
// milli
{
duration<int, std::milli> d(13);
os << d;
assert(os.str() == "13ms");
os.str("");
}
// centi
{
duration<int, std::centi> d(13);
os << d;
assert(os.str() == "13cs");
os.str("");
}
// deci
{
duration<int, std::deci> d(13);
os << d;
assert(os.str() == "13ds");
os.str("");
}
// seconds
{
duration<int> d(13);
os << d;
assert(os.str() == "13s");
os.str("");
}
// deca
{
duration<int, std::deca> d(13);
os << d;
assert(os.str() == "13das");
os.str("");
}
// hecto
{
duration<int, std::hecto> d(13);
os << d;
assert(os.str() == "13hs");
os.str("");
}
// kilo
{
duration<int, std::kilo> d(13);
os << d;
assert(os.str() == "13ks");
os.str("");
}
// mega
{
duration<int, std::mega> d(13);
os << d;
assert(os.str() == "13Ms");
os.str("");
}
// giga
{
duration<int, std::giga> d(13);
os << d;
assert(os.str() == "13Gs");
os.str("");
}
// tera
{
duration<int, std::tera> d(13);
os << d;
assert(os.str() == "13Ts");
os.str("");
}
// peta
{
duration<int, std::peta> d(13);
os << d;
assert(os.str() == "13Ps");
os.str("");
}
// femto
{
duration<int, std::exa> d(13);
os << d;
assert(os.str() == "13Es");
os.str("");
}
}
void test_calendar()
{
using namespace std::chrono;
using namespace date;
std::ostringstream os;
// minutes
{
minutes d(13);
os << d;
assert(os.str() == "13min");
os.str("");
}
// hours
{
hours d(13);
os << d;
assert(os.str() == "13h");
os.str("");
}
// days
{
days d(13);
os << d;
assert(os.str() == "13d");
os.str("");
}
}
void test_integral_scale()
{
using namespace std::chrono;
using namespace date;
std::ostringstream os;
// ratio 123 / 1
{
duration<int, std::ratio<123, 1>> d(13);
os << d;
assert(os.str() == "13[123]s");
os.str("");
}
// ratio 100 / 4 = ratio 25 / 1
{
duration<int, std::ratio<25, 1>> d(13);
os << d;
assert(os.str() == "13[25]s");
os.str("");
}
// weeks = ratio 7 * 24 * 60 * 60 / 1 = ratio 604800 / 1
{
weeks d(13);
os << d;
assert(os.str() == "13[604800]s");
os.str("");
}
// years = 146097/400 days = ratio 146097/400 * 24 * 60 * 60 = ratio 31556952 / 1
{
years d(13);
os << d;
assert(os.str() == "13[31556952]s");
os.str("");
}
// months = 1/12 years = ratio 1/12 * 31556952 = ratio 2629746 / 1
{
months d(13);
os << d;
assert(os.str() == "13[2629746]s");
os.str("");
}
}
void test_ratio_scale()
{
using namespace std::chrono;
using namespace date;
std::ostringstream os;
// ratio 1 / 2
{
duration<int, std::ratio<1, 2>> d(13);
os << d;
assert(os.str() == "13[1/2]s");
os.str("");
}
// ratio 100 / 3
{
duration<int, std::ratio<100, 3>> d(13);
os << d;
assert(os.str() == "13[100/3]s");
os.str("");
}
// ratio 100 / 6 = ratio 50 / 3
{
duration<int, std::ratio<100, 6>> d(13);
os << d;
assert(os.str() == "13[50/3]s");
os.str("");
}
}
void test_constexpr()
{
using date::detail::get_units;
CONSTCD11 auto as = get_units<char>(std::atto{});
CONSTCD11 auto fs = get_units<char>(std::femto{});
CONSTCD11 auto ps = get_units<char>(std::pico{});
CONSTCD11 auto ns = get_units<char>(std::nano{});
CONSTCD11 auto us = get_units<char>(std::micro{});
CONSTCD11 auto usw = get_units<wchar_t>(std::micro{});
CONSTCD11 auto ms = get_units<char>(std::milli{});
CONSTCD11 auto cs = get_units<char>(std::centi{});
CONSTCD11 auto ds = get_units<char>(std::deci{});
CONSTCD11 auto s = get_units<char>(std::ratio<1>{});
CONSTCD11 auto das = get_units<char>(std::deca{});
CONSTCD11 auto hs = get_units<char>(std::hecto{});
CONSTCD11 auto ks = get_units<char>(std::kilo{});
CONSTCD11 auto Ms = get_units<char>(std::mega{});
CONSTCD11 auto Gs = get_units<char>(std::giga{});
CONSTCD11 auto Ts = get_units<char>(std::tera{});
CONSTCD11 auto Ps = get_units<char>(std::peta{});
CONSTCD11 auto Es = get_units<char>(std::exa{});
(void)as, (void)fs, (void)ps, (void)ns, (void)usw, (void)us,
(void)ms, (void)cs, (void)ds, (void)s, (void)das, (void)hs,
(void)ks, (void)Ms, (void)Gs, (void)Ts, (void)Ps, (void)Es;
CONSTCD11 auto min = get_units<char>(std::ratio<60>{});
CONSTCD11 auto h = get_units<char>(std::ratio<3600>{});
CONSTCD11 auto d = get_units<char>(std::ratio<86400>{});
(void)min, (void)h, (void)d;
CONSTCD14 auto integer = get_units<char>(std::ratio<123>{});
CONSTCD14 auto ratio = get_units<char>(std::ratio<123, 3>{});
(void)integer, (void)ratio;
}
int
main()
{
test_SI();
test_calendar();
test_integral_scale();
test_ratio_scale();
}

View File

@ -27,12 +27,12 @@
#include <type_traits>
using fortnights = std::chrono::duration<date::weeks::rep,
std::ratio_multiply<std::ratio<2>,
date::weeks::period>>;
date::detail::ratio_multiply<std::ratio<2>,
date::weeks::period>>;
using microfortnights = std::chrono::duration<std::int64_t,
std::ratio_multiply<fortnights::period,
std::micro>>;
date::detail::ratio_multiply<fortnights::period,
std::micro>>;
int
main()
@ -69,10 +69,10 @@ main()
assert(os.str() == "32767-12-31 00:00:01.2096");
os.str("");
os << format("%F %T", jan/1/year::min());
assert(os.str() == "-32767-01-01 00:00:00");
os << format("%F", jan/1/year::min());
assert(os.str() == "-32767-01-01");
os.str("");
os << format("%F %T", dec/last/year::max());
assert(os.str() == "32767-12-31 00:00:00");
os << format("%F", dec/last/year::max());
assert(os.str() == "32767-12-31");
os.str("");
}

View File

@ -27,27 +27,6 @@
// time_of_day<std::chrono::duration<Rep, Period>>
// make_time(std::chrono::duration<Rep, Period> d) noexcept;
// constexpr
// time_of_day<std::chrono::hours>
// make_time(std::chrono::hours h, unsigned md) noexcept;
// constexpr
// time_of_day<std::chrono::minutes>
// make_time(std::chrono::hours h, std::chrono::minutes m, unsigned md) noexcept;
// constexpr
// time_of_day<std::chrono::seconds>
// make_time(std::chrono::hours h, std::chrono::minutes m, std::chrono::seconds s,
// unsigned md) noexcept;
// template <class Rep, class Period,
// class = typename std::enable_if<std::ratio_less<Period,
// std::ratio<1>>::value>::type>
// constexpr
// time_of_day<std::chrono::duration<Rep, Period>>
// make_time(std::chrono::hours h, std::chrono::minutes m, std::chrono::seconds s,
// std::chrono::duration<Rep, Period> sub_s, unsigned md) noexcept;
#include "date.h"
#include <cassert>
@ -68,7 +47,6 @@ main()
assert(tod.minutes() == minutes{7});
assert(tod.seconds() == seconds{9});
assert(tod.subseconds() == nanoseconds{22});
assert(tod.mode() == 0);
}
{
static_assert(is_same<decltype(make_time(microseconds{18429000022})),
@ -78,7 +56,6 @@ main()
assert(tod.minutes() == minutes{7});
assert(tod.seconds() == seconds{9});
assert(tod.subseconds() == microseconds{22});
assert(tod.mode() == 0);
}
{
static_assert(is_same<decltype(make_time(seconds{18429})),
@ -87,7 +64,6 @@ main()
assert(tod.hours() == hours{5});
assert(tod.minutes() == minutes{7});
assert(tod.seconds() == seconds{9});
assert(tod.mode() == 0);
}
{
static_assert(is_same<decltype(make_time(minutes{307})),
@ -95,70 +71,11 @@ main()
auto tod = make_time(minutes{307});
assert(tod.hours() == hours{5});
assert(tod.minutes() == minutes{7});
assert(tod.mode() == 0);
}
{
static_assert(is_same<decltype(make_time(hours{5})),
time_of_day<hours>>{}, "");
auto tod = make_time(hours{5});
assert(tod.hours() == hours{5});
assert(tod.mode() == 0);
}
{
static_assert(is_same<decltype(make_time(hours{5}, minutes{7}, seconds{9},
nanoseconds{22}, pm)),
time_of_day<nanoseconds>>{}, "");
auto tod = make_time(hours{5}, minutes{7}, seconds{9}, nanoseconds{22}, pm);
assert(tod.hours() == hours{5});
assert(tod.minutes() == minutes{7});
assert(tod.seconds() == seconds{9});
assert(tod.subseconds() == nanoseconds{22});
assert(tod.mode() == pm);
}
{
static_assert(is_same<decltype(make_time(hours{5}, minutes{7}, seconds{9},
microseconds{22}, 0)),
time_of_day<microseconds>>{}, "");
auto tod = make_time(hours{5}, minutes{7}, seconds{9}, microseconds{22}, 0);
assert(tod.hours() == hours{5});
assert(tod.minutes() == minutes{7});
assert(tod.seconds() == seconds{9});
assert(tod.subseconds() == microseconds{22});
assert(tod.mode() == 0);
}
{
static_assert(is_same<decltype(make_time(hours{5}, minutes{7}, seconds{9},
milliseconds{22}, am)),
time_of_day<milliseconds>>{}, "");
auto tod = make_time(hours{5}, minutes{7}, seconds{9}, milliseconds{22}, am);
assert(tod.hours() == hours{5});
assert(tod.minutes() == minutes{7});
assert(tod.seconds() == seconds{9});
assert(tod.subseconds() == milliseconds{22});
assert(tod.mode() == am);
}
{
static_assert(is_same<decltype(make_time(hours{5}, minutes{7}, seconds{9}, am)),
time_of_day<seconds>>{}, "");
auto tod = make_time(hours{5}, minutes{7}, seconds{9}, am);
assert(tod.hours() == hours{5});
assert(tod.minutes() == minutes{7});
assert(tod.seconds() == seconds{9});
assert(tod.mode() == am);
}
{
static_assert(is_same<decltype(make_time(hours{5}, minutes{7}, pm)),
time_of_day<minutes>>{}, "");
auto tod = make_time(hours{5}, minutes{7}, pm);
assert(tod.hours() == hours{5});
assert(tod.minutes() == minutes{7});
assert(tod.mode() == pm);
}
{
static_assert(is_same<decltype(make_time(hours{5}, 0)),
time_of_day<hours>>{}, "");
auto tod = make_time(hours{5}, 0);
assert(tod.hours() == hours{5});
assert(tod.mode() == 0);
}
}

View File

@ -0,0 +1,487 @@
// The MIT License (MIT)
//
// Copyright (c) 2018 Tomasz Kamiński
//
// 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 "date.h"
#include <chrono>
#include <cassert>
#include <type_traits>
#define CPP11_ASSERT(...) static_assert(__VA_ARGS__, "")
#if __cplusplus >= 201402
// C++14
# define CPP14_ASSERT(...) static_assert(__VA_ARGS__, "")
#else
// C++11
# define CPP14_ASSERT(...) assert(__VA_ARGS__)
#endif
#define NOEXCEPT_ASSERT(...) static_assert(noexcept(__VA_ARGS__), "")
//Invocation involves a conversion between duration that is currently
//not marked as noexcept.
#define NOEXCEPT_CONVERSION(...)
template<typename T>
constexpr T copy(T const& t) noexcept { return t; }
struct ConvertibleToYears
{
CONSTCD11 operator date::years() const NOEXCEPT
{ return date::years{1}; };
};
struct ConvertibleToMonths
{
CONSTCD11 operator date::months() const NOEXCEPT
{ return date::months{1}; };
};
struct ConvertibleToYearsAndMonths
{
CONSTCD11 operator date::years() const NOEXCEPT
{ return date::years{1}; };
CONSTCD11 operator date::months() const NOEXCEPT
{ return date::months{1}; };
};
int
main()
{
using namespace date;
using namespace std::chrono;
using decades = duration<int, date::detail::ratio_multiply<std::ratio<10>, years::period>>;
using decamonths = duration<int, date::detail::ratio_multiply<std::ratio<10>, months::period>>;
constexpr months one_month{1};
constexpr years one_year{1};
constexpr decades one_decade{1};
constexpr decamonths one_decamonth{1};
constexpr ConvertibleToMonths custom_month;
constexpr ConvertibleToYears custom_year;
constexpr ConvertibleToYearsAndMonths prefer_year;
{
constexpr year_month ym = 2001_y/feb;
CPP14_ASSERT(ym + one_month == 2001_y/mar);
NOEXCEPT_ASSERT(ym + one_month);
CPP14_ASSERT(one_month + ym == 2001_y/mar);
NOEXCEPT_ASSERT(one_month + ym);
CPP14_ASSERT(ym - one_month == 2001_y/jan);
NOEXCEPT_ASSERT(ym - one_month);
CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar);
NOEXCEPT_ASSERT(copy(ym) += one_month);
CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan);
NOEXCEPT_ASSERT(copy(ym) -= one_month);
CPP11_ASSERT(ym + one_year == 2002_y/feb);
NOEXCEPT_ASSERT(ym + one_year);
CPP11_ASSERT(one_year + ym == 2002_y/feb);
NOEXCEPT_ASSERT(one_year + ym);
CPP11_ASSERT(ym - one_year == 2000_y/feb);
NOEXCEPT_ASSERT(ym - one_year);
CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb);
NOEXCEPT_ASSERT(copy(ym) += one_year);
CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb);
NOEXCEPT_ASSERT(copy(ym) -= one_year);
CPP11_ASSERT(ym + one_decade == 2011_y/feb);
NOEXCEPT_CONVERSION(ym + one_decade);
CPP11_ASSERT(one_decade + ym == 2011_y/feb);
NOEXCEPT_CONVERSION(one_decade + ym);
CPP11_ASSERT(ym - one_decade == 1991_y/feb);
NOEXCEPT_CONVERSION(ym - one_decade);
CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb);
NOEXCEPT_CONVERSION(copy(ym) += one_decade);
CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb);
NOEXCEPT_CONVERSION(copy(ym) -= one_decade);
CPP14_ASSERT(ym + one_decamonth == 2001_y/dec);
NOEXCEPT_CONVERSION(ym + one_decamonth);
CPP14_ASSERT(one_decamonth + ym == 2001_y/dec);
NOEXCEPT_CONVERSION(one_decamonth + ym);
CPP14_ASSERT(ym - one_decamonth == 2000_y/apr);
NOEXCEPT_CONVERSION(ym - one_decamonth);
CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec);
NOEXCEPT_CONVERSION(copy(ym) += one_decamonth);
CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr);
NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth);
CPP14_ASSERT(ym + custom_month == 2001_y/mar);
NOEXCEPT_ASSERT(ym + custom_month);
CPP14_ASSERT(custom_month + ym == 2001_y/mar);
NOEXCEPT_ASSERT(custom_month + ym);
CPP14_ASSERT(ym - custom_month == 2001_y/jan);
NOEXCEPT_ASSERT(ym - custom_month);
CPP14_ASSERT((copy(ym) += custom_month) == 2001_y/mar);
NOEXCEPT_ASSERT(copy(ym) += custom_month);
CPP14_ASSERT((copy(ym) -= custom_month) == 2001_y/jan);
NOEXCEPT_ASSERT(copy(ym) -= custom_month);
CPP11_ASSERT(ym + custom_year == 2002_y/feb);
NOEXCEPT_ASSERT(ym + custom_year);
CPP11_ASSERT(custom_year + ym == 2002_y/feb);
NOEXCEPT_ASSERT(custom_year + ym);
CPP11_ASSERT(ym - custom_year == 2000_y/feb);
NOEXCEPT_ASSERT(ym - custom_year);
CPP14_ASSERT((copy(ym) += custom_year) == 2002_y/feb);
NOEXCEPT_ASSERT(copy(ym) += custom_year);
CPP14_ASSERT((copy(ym) -= custom_year) == 2000_y/feb);
NOEXCEPT_ASSERT(copy(ym) -= custom_year);
CPP11_ASSERT(ym + prefer_year == 2002_y/feb);
NOEXCEPT_ASSERT(ym + prefer_year);
CPP11_ASSERT(prefer_year + ym == 2002_y/feb);
NOEXCEPT_ASSERT(prefer_year + ym);
CPP11_ASSERT(ym - prefer_year == 2000_y/feb);
NOEXCEPT_ASSERT(ym - prefer_year);
CPP14_ASSERT((copy(ym) += prefer_year) == 2002_y/feb);
NOEXCEPT_ASSERT(copy(ym) += prefer_year);
CPP14_ASSERT((copy(ym) -= prefer_year) == 2000_y/feb);
NOEXCEPT_ASSERT(copy(ym) -= prefer_year);
}
{
constexpr year_month_day ym = 2001_y/feb/10;
CPP14_ASSERT(ym + one_month == 2001_y/mar/10);
NOEXCEPT_ASSERT(ym + one_month);
CPP14_ASSERT(one_month + ym == 2001_y/mar/10);
NOEXCEPT_ASSERT(one_month + ym);
CPP14_ASSERT(ym - one_month == 2001_y/jan/10);
NOEXCEPT_ASSERT(ym - one_month);
CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar/10);
NOEXCEPT_ASSERT(copy(ym) += one_month);
CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan/10);
NOEXCEPT_ASSERT(copy(ym) -= one_month);
CPP11_ASSERT(ym + one_year == 2002_y/feb/10);
NOEXCEPT_ASSERT(ym + one_year);
CPP11_ASSERT(one_year + ym == 2002_y/feb/10);
NOEXCEPT_ASSERT(one_year + ym);
CPP11_ASSERT(ym - one_year == 2000_y/feb/10);
NOEXCEPT_ASSERT(ym - one_year);
CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb/10);
NOEXCEPT_ASSERT(copy(ym) += one_year);
CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb/10);
NOEXCEPT_ASSERT(copy(ym) -= one_year);
CPP11_ASSERT(ym + one_decade == 2011_y/feb/10);
NOEXCEPT_CONVERSION(ym + one_decade);
CPP11_ASSERT(one_decade + ym == 2011_y/feb/10);
NOEXCEPT_CONVERSION(one_decade + ym);
CPP11_ASSERT(ym - one_decade == 1991_y/feb/10);
NOEXCEPT_CONVERSION(ym - one_decade);
CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb/10);
NOEXCEPT_CONVERSION(copy(ym) += one_decade);
CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb/10);
NOEXCEPT_CONVERSION(copy(ym) -= one_decade);
CPP14_ASSERT(ym + one_decamonth == 2001_y/dec/10);
NOEXCEPT_CONVERSION(ym + one_decamonth);
CPP14_ASSERT(one_decamonth + ym == 2001_y/dec/10);
NOEXCEPT_CONVERSION(one_decamonth + ym);
CPP14_ASSERT(ym - one_decamonth == 2000_y/apr/10);
NOEXCEPT_CONVERSION(ym - one_decamonth);
CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec/10);
NOEXCEPT_CONVERSION(copy(ym) += one_decamonth);
CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr/10);
NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth);
CPP14_ASSERT(ym + custom_month == 2001_y/mar/10);
NOEXCEPT_ASSERT(ym + custom_month);
CPP14_ASSERT(custom_month + ym == 2001_y/mar/10);
NOEXCEPT_ASSERT(custom_month + ym);
CPP14_ASSERT(ym - custom_month == 2001_y/jan/10);
NOEXCEPT_ASSERT(ym - custom_month);
CPP14_ASSERT((copy(ym) += custom_month) == 2001_y/mar/10);
NOEXCEPT_ASSERT(copy(ym) += custom_month);
CPP14_ASSERT((copy(ym) -= custom_month) == 2001_y/jan/10);
NOEXCEPT_ASSERT(copy(ym) -= custom_month);
CPP11_ASSERT(ym + custom_year == 2002_y/feb/10);
NOEXCEPT_ASSERT(ym + custom_year);
CPP11_ASSERT(custom_year + ym == 2002_y/feb/10);
NOEXCEPT_ASSERT(custom_year + ym);
CPP11_ASSERT(ym - custom_year == 2000_y/feb/10);
NOEXCEPT_ASSERT(ym - custom_year);
CPP14_ASSERT((copy(ym) += custom_year) == 2002_y/feb/10);
NOEXCEPT_ASSERT(copy(ym) += custom_year);
CPP14_ASSERT((copy(ym) -= custom_year) == 2000_y/feb/10);
NOEXCEPT_ASSERT(copy(ym) -= custom_year);
CPP11_ASSERT(ym + prefer_year == 2002_y/feb/10);
NOEXCEPT_ASSERT(ym + prefer_year);
CPP11_ASSERT(prefer_year + ym == 2002_y/feb/10);
NOEXCEPT_ASSERT(prefer_year + ym);
CPP11_ASSERT(ym - prefer_year == 2000_y/feb/10);
NOEXCEPT_ASSERT(ym - prefer_year);
CPP14_ASSERT((copy(ym) += prefer_year) == 2002_y/feb/10);
NOEXCEPT_ASSERT(copy(ym) += prefer_year);
CPP14_ASSERT((copy(ym) -= prefer_year) == 2000_y/feb/10);
NOEXCEPT_ASSERT(copy(ym) -= prefer_year);
}
{
constexpr year_month_day_last ym = 2001_y/feb/last;
CPP14_ASSERT(ym + one_month == 2001_y/mar/last);
NOEXCEPT_ASSERT(ym + one_month);
CPP14_ASSERT(one_month + ym == 2001_y/mar/last);
NOEXCEPT_ASSERT(one_month + ym);
CPP14_ASSERT(ym - one_month == 2001_y/jan/last);
NOEXCEPT_ASSERT(ym - one_month);
CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar/last);
NOEXCEPT_ASSERT(copy(ym) += one_month);
CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan/last);
NOEXCEPT_ASSERT(copy(ym) -= one_month);
CPP11_ASSERT(ym + one_year == 2002_y/feb/last);
NOEXCEPT_ASSERT(ym + one_year);
CPP11_ASSERT(one_year + ym == 2002_y/feb/last);
NOEXCEPT_ASSERT(one_year + ym);
CPP11_ASSERT(ym - one_year == 2000_y/feb/last);
NOEXCEPT_ASSERT(ym - one_year);
CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb/last);
NOEXCEPT_ASSERT(copy(ym) += one_year);
CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb/last);
NOEXCEPT_ASSERT(copy(ym) -= one_year);
CPP11_ASSERT(ym + one_decade == 2011_y/feb/last);
NOEXCEPT_CONVERSION(ym + one_decade);
CPP11_ASSERT(one_decade + ym == 2011_y/feb/last);
NOEXCEPT_CONVERSION(one_decade + ym);
CPP11_ASSERT(ym - one_decade == 1991_y/feb/last);
NOEXCEPT_CONVERSION(ym - one_decade);
CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb/last);
NOEXCEPT_CONVERSION(copy(ym) += one_decade);
CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb/last);
NOEXCEPT_CONVERSION(copy(ym) -= one_decade);
CPP14_ASSERT(ym + one_decamonth == 2001_y/dec/last);
NOEXCEPT_CONVERSION(ym + one_decamonth);
CPP14_ASSERT(one_decamonth + ym == 2001_y/dec/last);
NOEXCEPT_CONVERSION(one_decamonth + ym);
CPP14_ASSERT(ym - one_decamonth == 2000_y/apr/last);
NOEXCEPT_CONVERSION(ym - one_decamonth);
CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec/last);
NOEXCEPT_CONVERSION(copy(ym) += one_decamonth);
CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr/last);
NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth);
CPP14_ASSERT(ym + custom_month == 2001_y/mar/last);
NOEXCEPT_ASSERT(ym + custom_month);
CPP14_ASSERT(custom_month + ym == 2001_y/mar/last);
NOEXCEPT_ASSERT(custom_month + ym);
CPP14_ASSERT(ym - custom_month == 2001_y/jan/last);
NOEXCEPT_ASSERT(ym - custom_month);
CPP14_ASSERT((copy(ym) += custom_month) == 2001_y/mar/last);
NOEXCEPT_ASSERT(copy(ym) += custom_month);
CPP14_ASSERT((copy(ym) -= custom_month) == 2001_y/jan/last);
NOEXCEPT_ASSERT(copy(ym) -= custom_month);
CPP11_ASSERT(ym + custom_year == 2002_y/feb/last);
NOEXCEPT_ASSERT(ym + custom_year);
CPP11_ASSERT(custom_year + ym == 2002_y/feb/last);
NOEXCEPT_ASSERT(custom_year + ym);
CPP11_ASSERT(ym - custom_year == 2000_y/feb/last);
NOEXCEPT_ASSERT(ym - custom_year);
CPP14_ASSERT((copy(ym) += custom_year) == 2002_y/feb/last);
NOEXCEPT_ASSERT(copy(ym) += custom_year);
CPP14_ASSERT((copy(ym) -= custom_year) == 2000_y/feb/last);
NOEXCEPT_ASSERT(copy(ym) -= custom_year);
CPP11_ASSERT(ym + prefer_year == 2002_y/feb/last);
NOEXCEPT_ASSERT(ym + prefer_year);
CPP11_ASSERT(prefer_year + ym == 2002_y/feb/last);
NOEXCEPT_ASSERT(prefer_year + ym);
CPP11_ASSERT(ym - prefer_year == 2000_y/feb/last);
NOEXCEPT_ASSERT(ym - prefer_year);
CPP14_ASSERT((copy(ym) += prefer_year) == 2002_y/feb/last);
NOEXCEPT_ASSERT(copy(ym) += prefer_year);
CPP14_ASSERT((copy(ym) -= prefer_year) == 2000_y/feb/last);
NOEXCEPT_ASSERT(copy(ym) -= prefer_year);
}
{
constexpr year_month_weekday ym = 2001_y/feb/fri[4];
CPP14_ASSERT(ym + one_month == 2001_y/mar/fri[4]);
NOEXCEPT_ASSERT(ym + one_month);
CPP14_ASSERT(one_month + ym == 2001_y/mar/fri[4]);
NOEXCEPT_ASSERT(one_month + ym);
CPP14_ASSERT(ym - one_month == 2001_y/jan/fri[4]);
NOEXCEPT_ASSERT(ym - one_month);
CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar/fri[4]);
NOEXCEPT_ASSERT(copy(ym) += one_month);
CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan/fri[4]);
NOEXCEPT_ASSERT(copy(ym) -= one_month);
CPP11_ASSERT(ym + one_year == 2002_y/feb/fri[4]);
NOEXCEPT_ASSERT(ym + one_year);
CPP11_ASSERT(one_year + ym == 2002_y/feb/fri[4]);
NOEXCEPT_ASSERT(one_year + ym);
CPP11_ASSERT(ym - one_year == 2000_y/feb/fri[4]);
NOEXCEPT_ASSERT(ym - one_year);
CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb/fri[4]);
NOEXCEPT_ASSERT(copy(ym) += one_year);
CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb/fri[4]);
NOEXCEPT_ASSERT(copy(ym) -= one_year);
CPP11_ASSERT(ym + one_decade == 2011_y/feb/fri[4]);
NOEXCEPT_CONVERSION(ym + one_decade);
CPP11_ASSERT(one_decade + ym == 2011_y/feb/fri[4]);
NOEXCEPT_CONVERSION(one_decade + ym);
CPP11_ASSERT(ym - one_decade == 1991_y/feb/fri[4]);
NOEXCEPT_CONVERSION(ym - one_decade);
CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb/fri[4]);
NOEXCEPT_CONVERSION(copy(ym) += one_decade);
CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb/fri[4]);
NOEXCEPT_CONVERSION(copy(ym) -= one_decade);
CPP14_ASSERT(ym + one_decamonth == 2001_y/dec/fri[4]);
NOEXCEPT_CONVERSION(ym + one_decamonth);
CPP14_ASSERT(one_decamonth + ym == 2001_y/dec/fri[4]);
NOEXCEPT_CONVERSION(one_decamonth + ym);
CPP14_ASSERT(ym - one_decamonth == 2000_y/apr/fri[4]);
NOEXCEPT_CONVERSION(ym - one_decamonth);
CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec/fri[4]);
NOEXCEPT_CONVERSION(copy(ym) += one_decamonth);
CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr/fri[4]);
NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth);
CPP14_ASSERT(ym + custom_month == 2001_y/mar/fri[4]);
NOEXCEPT_ASSERT(ym + custom_month);
CPP14_ASSERT(custom_month + ym == 2001_y/mar/fri[4]);
NOEXCEPT_ASSERT(custom_month + ym);
CPP14_ASSERT(ym - custom_month == 2001_y/jan/fri[4]);
NOEXCEPT_ASSERT(ym - custom_month);
CPP14_ASSERT((copy(ym) += custom_month) == 2001_y/mar/fri[4]);
NOEXCEPT_ASSERT(copy(ym) += custom_month);
CPP14_ASSERT((copy(ym) -= custom_month) == 2001_y/jan/fri[4]);
NOEXCEPT_ASSERT(copy(ym) -= custom_month);
CPP11_ASSERT(ym + custom_year == 2002_y/feb/fri[4]);
NOEXCEPT_ASSERT(ym + custom_year);
CPP11_ASSERT(custom_year + ym == 2002_y/feb/fri[4]);
NOEXCEPT_ASSERT(custom_year + ym);
CPP11_ASSERT(ym - custom_year == 2000_y/feb/fri[4]);
NOEXCEPT_ASSERT(ym - custom_year);
CPP14_ASSERT((copy(ym) += custom_year) == 2002_y/feb/fri[4]);
NOEXCEPT_ASSERT(copy(ym) += custom_year);
CPP14_ASSERT((copy(ym) -= custom_year) == 2000_y/feb/fri[4]);
NOEXCEPT_ASSERT(copy(ym) -= custom_year);
CPP11_ASSERT(ym + prefer_year == 2002_y/feb/fri[4]);
NOEXCEPT_ASSERT(ym + prefer_year);
CPP11_ASSERT(prefer_year + ym == 2002_y/feb/fri[4]);
NOEXCEPT_ASSERT(prefer_year + ym);
CPP11_ASSERT(ym - prefer_year == 2000_y/feb/fri[4]);
NOEXCEPT_ASSERT(ym - prefer_year);
CPP14_ASSERT((copy(ym) += prefer_year) == 2002_y/feb/fri[4]);
NOEXCEPT_ASSERT(copy(ym) += prefer_year);
CPP14_ASSERT((copy(ym) -= prefer_year) == 2000_y/feb/fri[4]);
NOEXCEPT_ASSERT(copy(ym) -= prefer_year);
}
{
constexpr year_month_weekday_last ym = 2001_y/feb/fri[last];
CPP14_ASSERT(ym + one_month == 2001_y/mar/fri[last]);
NOEXCEPT_ASSERT(ym + one_month);
CPP14_ASSERT(one_month + ym == 2001_y/mar/fri[last]);
NOEXCEPT_ASSERT(one_month + ym);
CPP14_ASSERT(ym - one_month == 2001_y/jan/fri[last]);
NOEXCEPT_ASSERT(ym - one_month);
CPP14_ASSERT((copy(ym) += one_month) == 2001_y/mar/fri[last]);
NOEXCEPT_ASSERT(copy(ym) += one_month);
CPP14_ASSERT((copy(ym) -= one_month) == 2001_y/jan/fri[last]);
NOEXCEPT_ASSERT(copy(ym) -= one_month);
CPP11_ASSERT(ym + one_year == 2002_y/feb/fri[last]);
NOEXCEPT_ASSERT(ym + one_year);
CPP11_ASSERT(one_year + ym == 2002_y/feb/fri[last]);
NOEXCEPT_ASSERT(one_year + ym);
CPP11_ASSERT(ym - one_year == 2000_y/feb/fri[last]);
NOEXCEPT_ASSERT(ym - one_year);
CPP14_ASSERT((copy(ym) += one_year) == 2002_y/feb/fri[last]);
NOEXCEPT_ASSERT(copy(ym) += one_year);
CPP14_ASSERT((copy(ym) -= one_year) == 2000_y/feb/fri[last]);
NOEXCEPT_ASSERT(copy(ym) -= one_year);
CPP11_ASSERT(ym + one_decade == 2011_y/feb/fri[last]);
NOEXCEPT_CONVERSION(ym + one_decade);
CPP11_ASSERT(one_decade + ym == 2011_y/feb/fri[last]);
NOEXCEPT_CONVERSION(one_decade + ym);
CPP11_ASSERT(ym - one_decade == 1991_y/feb/fri[last]);
NOEXCEPT_CONVERSION(ym - one_decade);
CPP14_ASSERT((copy(ym) += one_decade) == 2011_y/feb/fri[last]);
NOEXCEPT_CONVERSION(copy(ym) += one_decade);
CPP14_ASSERT((copy(ym) -= one_decade) == 1991_y/feb/fri[last]);
NOEXCEPT_CONVERSION(copy(ym) -= one_decade);
CPP14_ASSERT(ym + one_decamonth == 2001_y/dec/fri[last]);
NOEXCEPT_CONVERSION(ym + one_decamonth);
CPP14_ASSERT(one_decamonth + ym == 2001_y/dec/fri[last]);
NOEXCEPT_CONVERSION(one_decamonth + ym);
CPP14_ASSERT(ym - one_decamonth == 2000_y/apr/fri[last]);
NOEXCEPT_CONVERSION(ym - one_decamonth);
CPP14_ASSERT((copy(ym) += one_decamonth) == 2001_y/dec/fri[last]);
NOEXCEPT_CONVERSION(copy(ym) += one_decamonth);
CPP14_ASSERT((copy(ym) -= one_decamonth) == 2000_y/apr/fri[last]);
NOEXCEPT_CONVERSION(copy(ym) -= one_decamonth);
CPP14_ASSERT(ym + custom_month == 2001_y/mar/fri[last]);
NOEXCEPT_ASSERT(ym + custom_month);
CPP14_ASSERT(custom_month + ym == 2001_y/mar/fri[last]);
NOEXCEPT_ASSERT(custom_month + ym);
CPP14_ASSERT(ym - custom_month == 2001_y/jan/fri[last]);
NOEXCEPT_ASSERT(ym - custom_month);
CPP14_ASSERT((copy(ym) += custom_month) == 2001_y/mar/fri[last]);
NOEXCEPT_ASSERT(copy(ym) += custom_month);
CPP14_ASSERT((copy(ym) -= custom_month) == 2001_y/jan/fri[last]);
NOEXCEPT_ASSERT(copy(ym) -= custom_month);
CPP11_ASSERT(ym + custom_year == 2002_y/feb/fri[last]);
NOEXCEPT_ASSERT(ym + custom_year);
CPP11_ASSERT(custom_year + ym == 2002_y/feb/fri[last]);
NOEXCEPT_ASSERT(custom_year + ym);
CPP11_ASSERT(ym - custom_year == 2000_y/feb/fri[last]);
NOEXCEPT_ASSERT(ym - custom_year);
CPP14_ASSERT((copy(ym) += custom_year) == 2002_y/feb/fri[last]);
NOEXCEPT_ASSERT(copy(ym) += custom_year);
CPP14_ASSERT((copy(ym) -= custom_year) == 2000_y/feb/fri[last]);
NOEXCEPT_ASSERT(copy(ym) -= custom_year);
CPP11_ASSERT(ym + prefer_year == 2002_y/feb/fri[last]);
NOEXCEPT_ASSERT(ym + prefer_year);
CPP11_ASSERT(prefer_year + ym == 2002_y/feb/fri[last]);
NOEXCEPT_ASSERT(prefer_year + ym);
CPP11_ASSERT(ym - prefer_year == 2000_y/feb/fri[last]);
NOEXCEPT_ASSERT(ym - prefer_year);
CPP14_ASSERT((copy(ym) += prefer_year) == 2002_y/feb/fri[last]);
NOEXCEPT_ASSERT(copy(ym) += prefer_year);
CPP14_ASSERT((copy(ym) -= prefer_year) == 2000_y/feb/fri[last]);
NOEXCEPT_ASSERT(copy(ym) -= prefer_year);
}
}

View File

@ -45,6 +45,8 @@ test_a()
std::istringstream in{"Sun 2016-12-11"};
sys_days tp;
in >> parse("%A %F", tp);
// this may fail with libstdc++, see https://github.com/HowardHinnant/date/issues/388
// possible workaround: compile date.h with -DONLY_C_LOCALE=1
assert(!in.fail());
assert(!in.bad());
assert(!in.eof());
@ -360,6 +362,12 @@ test_d()
assert(!in.bad());
assert(tp == 2016_y/12/9);
}
{
std::istringstream in{"2016 31 11"};
sys_days tp;
in >> parse("%Y %e %m", tp);
assert(in.fail());
}
}
void
@ -413,6 +421,12 @@ test_H()
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + hours{15});
}
{
std::istringstream in{"2016-12-11 24"};
sys_time<hours> tp;
in >> parse("%F %H", tp);
assert(in.fail());
}
}
void
@ -436,6 +450,12 @@ test_Ip()
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + hours{1});
}
{
std::istringstream in{"2016-12-11 13 am"};
sys_time<hours> tp;
in >> parse("%F %I %p", tp);
assert(in.fail());
}
}
void
@ -474,6 +494,12 @@ test_m()
assert(!in.bad());
assert(tp == 2016_y/9/12);
}
{
std::istringstream in{"2016 12 13"};
sys_days tp;
in >> parse("%Y %d %m", tp);
assert(in.fail());
}
}
void
@ -489,6 +515,12 @@ test_M()
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + minutes{15});
}
{
std::istringstream in{"2016-12-11 65"};
sys_time<minutes> tp;
in >> parse("%F %M", tp);
assert(in.fail());
}
}
void
@ -512,6 +544,12 @@ test_S()
assert(!in.bad());
assert(tp == sys_days{2016_y/12/11} + seconds{15} + milliseconds{1});
}
{
std::istringstream in{"2016-12-11 60"};
sys_seconds tp;
in >> parse("%F %S", tp);
assert(in.fail());
}
}
void
@ -552,6 +590,24 @@ test_T()
assert(!in.bad());
assert(d == hours{15} + minutes{43} + seconds{22} + milliseconds{1});
}
{
std::istringstream in{"2016-12-11 24:43:22"};
sys_seconds tp;
in >> parse("%F %T", tp);
assert(in.fail());
}
{
std::istringstream in{"2016-12-11 15:60:22"};
sys_seconds tp;
in >> parse("%F %T", tp);
assert(in.fail());
}
{
std::istringstream in{"2016-12-11 15:43:60"};
sys_seconds tp;
in >> parse("%F %T", tp);
assert(in.fail());
}
}
void

View File

@ -57,7 +57,7 @@ main()
using tod = time_of_day<hours>;
static_assert(is_same<tod::precision::period, hours::period>{}, "");
static_assert(is_same<tod::precision::period, seconds::period>{}, "");
static_assert( is_trivially_destructible<tod>{}, "");
static_assert( is_default_constructible<tod>{}, "");
@ -74,7 +74,6 @@ main()
constexpr tod t1 = tod{hours{13}};
static_assert(t1.hours() == hours{13}, "");
static_assert(t1.mode() == 0, "");
#if __cplusplus >= 201402
static_assert(static_cast<tod::precision>(t1) == hours{13}, "");
static_assert(t1.to_duration() == hours{13}, "");
@ -82,23 +81,14 @@ main()
auto t2 = t1;
assert(t2.hours() == t1.hours());
assert(t2.mode() == t1.mode());
assert(t2.to_duration() == t1.to_duration());
ostringstream os;
os << t2;
assert(os.str() == "1300");
t2.make12();
assert(os.str() == "13:00:00");
auto h = make12(t2.hours());
os.str("");
assert(t2.hours() == hours{1});
assert(t2.mode() == pm);
assert(h == hours{1});
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "1pm");
t2.make24();
os.str("");
assert(t2.hours() == hours{13});
assert(t2.mode() == 0);
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "1300");
assert(!is_am(t2.hours()));
assert(is_pm(t2.hours()));
}

View File

@ -57,12 +57,12 @@
#include <type_traits>
using fortnights = std::chrono::duration<date::weeks::rep,
std::ratio_multiply<std::ratio<2>,
date::weeks::period>>;
date::detail::ratio_multiply<std::ratio<2>,
date::weeks::period>>;
using microfortnights = std::chrono::duration<std::int64_t,
std::ratio_multiply<fortnights::period,
std::micro>>;
date::detail::ratio_multiply<fortnights::period,
std::micro>>;
int
main()
@ -108,12 +108,4 @@ main()
ostringstream os;
os << t2;
assert(os.str() == "13:07:06.0480");
t2.make12();
os.str("");
os << t2;
assert(os.str() == "1:07:06.0480pm");
t2.make24();
os.str("");
os << t2;
assert(os.str() == "13:07:06.0480");
}

View File

@ -85,7 +85,6 @@ main()
static_assert(t1.minutes() == minutes{7}, "");
static_assert(t1.seconds() == seconds{5}, "");
static_assert(t1.subseconds() == milliseconds{22}, "");
static_assert(t1.mode() == 0, "");
#if __cplusplus >= 201402
static_assert(static_cast<tod::precision>(t1) == hours{13} + minutes{7}
+ seconds{5} + milliseconds{22}, "");
@ -98,29 +97,8 @@ main()
assert(t2.minutes() == t1.minutes());
assert(t2.seconds() == t1.seconds());
assert(t2.subseconds() == t1.subseconds());
assert(t2.mode() == t1.mode());
assert(t2.to_duration() == t1.to_duration());
ostringstream os;
os << t2;
assert(os.str() == "13:07:05.022");
t2.make12();
os.str("");
assert(t2.hours() == hours{1});
assert(t2.minutes() == minutes{7});
assert(t2.seconds() == seconds{5});
assert(t2.subseconds() == milliseconds{22});
assert(t2.mode() == pm);
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "1:07:05.022pm");
t2.make24();
os.str("");
assert(t2.hours() == hours{13});
assert(t2.minutes() == minutes{7});
assert(t2.seconds() == seconds{5});
assert(t2.subseconds() == milliseconds{22});
assert(t2.mode() == 0);
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "13:07:05.022");
}

View File

@ -59,7 +59,7 @@ main()
using tod = time_of_day<minutes>;
static_assert(is_same<tod::precision::period, minutes::period>{}, "");
static_assert(is_same<tod::precision::period, seconds::period>{}, "");
static_assert( is_trivially_destructible<tod>{}, "");
static_assert( is_default_constructible<tod>{}, "");
@ -77,7 +77,6 @@ main()
constexpr tod t1 = tod{hours{13} + minutes{7}};
static_assert(t1.hours() == hours{13}, "");
static_assert(t1.minutes() == minutes{7}, "");
static_assert(t1.mode() == 0, "");
#if __cplusplus >= 201402
static_assert(static_cast<tod::precision>(t1) == hours{13} + minutes{7}, "");
static_assert(t1.to_duration() == hours{13} + minutes{7}, "");
@ -86,25 +85,8 @@ main()
auto t2 = t1;
assert(t2.hours() == t1.hours());
assert(t2.minutes() == t1.minutes());
assert(t2.mode() == t1.mode());
assert(t2.to_duration() == t1.to_duration());
ostringstream os;
os << t2;
assert(os.str() == "13:07");
t2.make12();
os.str("");
assert(t2.hours() == hours{1});
assert(t2.minutes() == minutes{7});
assert(t2.mode() == pm);
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "1:07pm");
t2.make24();
os.str("");
assert(t2.hours() == hours{13});
assert(t2.minutes() == minutes{7});
assert(t2.mode() == 0);
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "13:07");
assert(os.str() == "13:07:00");
}

View File

@ -85,7 +85,6 @@ main()
static_assert(t1.minutes() == minutes{7}, "");
static_assert(t1.seconds() == seconds{5}, "");
static_assert(t1.subseconds() == nanoseconds{22}, "");
static_assert(t1.mode() == 0, "");
#if __cplusplus >= 201402
static_assert(static_cast<tod::precision>(t1) == hours{13} + minutes{7}
+ seconds{5} + nanoseconds{22}, "");
@ -98,29 +97,8 @@ main()
assert(t2.minutes() == t1.minutes());
assert(t2.seconds() == t1.seconds());
assert(t2.subseconds() == t1.subseconds());
assert(t2.mode() == t1.mode());
assert(t2.to_duration() == t1.to_duration());
ostringstream os;
os << t2;
assert(os.str() == "13:07:05.000000022");
t2.make12();
os.str("");
assert(t2.hours() == hours{1});
assert(t2.minutes() == minutes{7});
assert(t2.seconds() == seconds{5});
assert(t2.subseconds() == nanoseconds{22});
assert(t2.mode() == pm);
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "1:07:05.000000022pm");
t2.make24();
os.str("");
assert(t2.hours() == hours{13});
assert(t2.minutes() == minutes{7});
assert(t2.seconds() == seconds{5});
assert(t2.subseconds() == nanoseconds{22});
assert(t2.mode() == 0);
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "13:07:05.000000022");
}

View File

@ -79,7 +79,6 @@ main()
static_assert(t1.hours() == hours{13}, "");
static_assert(t1.minutes() == minutes{7}, "");
static_assert(t1.seconds() == seconds{5}, "");
static_assert(t1.mode() == 0, "");
#if __cplusplus >= 201402
static_assert(static_cast<tod::precision>(t1) == hours{13} + minutes{7}
+ seconds{5}, "");
@ -90,27 +89,8 @@ main()
assert(t2.hours() == t1.hours());
assert(t2.minutes() == t1.minutes());
assert(t2.seconds() == t1.seconds());
assert(t2.mode() == t1.mode());
assert(t2.to_duration() == t1.to_duration());
ostringstream os;
os << t2;
assert(os.str() == "13:07:05");
t2.make12();
os.str("");
assert(t2.hours() == hours{1});
assert(t2.minutes() == minutes{7});
assert(t2.seconds() == seconds{5});
assert(t2.mode() == pm);
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "1:07:05pm");
t2.make24();
os.str("");
assert(t2.hours() == hours{13});
assert(t2.minutes() == minutes{7});
assert(t2.seconds() == seconds{5});
assert(t2.mode() == 0);
assert(t2.to_duration() == t1.to_duration());
os << t2;
assert(os.str() == "13:07:05");
}

View File

@ -77,11 +77,9 @@ static_assert( std::is_trivially_move_assignable<date::weekday>{}, "");
static_assert( std::is_nothrow_constructible<date::weekday, unsigned>{}, "");
static_assert( std::is_nothrow_constructible<date::weekday, date::sys_days>{}, "");
static_assert( std::is_nothrow_constructible<unsigned, date::weekday>{}, "");
static_assert(!std::is_convertible<unsigned, date::weekday>{}, "");
static_assert( std::is_convertible<date::sys_days, date::weekday>{}, "");
static_assert(!std::is_convertible<date::weekday, unsigned>{}, "");
static_assert(static_cast<unsigned>(date::weekday{1u}) == 1, "");
static_assert( date::weekday{0u}.ok(), "");
static_assert( date::weekday{1u}.ok(), "");
@ -90,7 +88,8 @@ static_assert( date::weekday{3u}.ok(), "");
static_assert( date::weekday{4u}.ok(), "");
static_assert( date::weekday{5u}.ok(), "");
static_assert( date::weekday{6u}.ok(), "");
static_assert(!date::weekday{7u}.ok(), "");
static_assert( date::weekday{7u}.ok(), "");
static_assert(!date::weekday{8u}.ok(), "");
void
test_weekday_arithmetic()

View File

@ -107,7 +107,7 @@ main()
static_assert(year::max().ok(), "");
#if __cplusplus >= 201402
using int64_t = std::int64_t;
using std::int64_t;
static_assert(sys_days(year::min()/jan/1) - sys_days(1970_y/jan/1)
>= as<int64_t>(days::min()), "");
static_assert(sys_days(year::min()/jan/1) - sys_days(1970_y/jan/1)

View File

@ -109,6 +109,90 @@ test_arithmetic()
}
}
void test_arithemtic_not_ok()
{
using namespace date;
using namespace std::chrono;
year_month ym{2018_y, month{14}};
{
year_month ym2{2019_y, month{2}};
assert(ym + months{0} == ym2);
assert(ym - months{0} == ym2);
assert(ym - ym2 == months{0});
assert(ym2 - ym == months{0});
auto ymc = ym;
ymc += months{0};
assert(ymc.ok());
assert(ymc == ym2);
}
{
year_month ym2{2019_y, month{6}};
assert(ym + months{4} == ym2);
assert(ym2 - ym == months{4});
assert(ym - ym2 == -months{4});
auto ymc = ym;
ymc += months{4};
assert(ymc.ok());
assert(ymc == ym2);
}
{
year_month ym2{2018_y, month{10}};
assert(ym - months{4} == ym2);
assert(ym2 - ym == -months{4});
assert(ym - ym2 == months{4});
auto ymc = ym;
ymc -= months{4};
assert(ymc.ok());
assert(ymc == ym2);
}
{
year_month ym2{2020_y, month{6}};
assert(ym + months{16} == ym2);
assert(ym2 - ym == months{16});
assert(ym - ym2 == -months{16});
auto ymc = ym;
ymc += months{16};
assert(ymc.ok());
assert(ymc == ym2);
}
{
year_month ym2{2017_y, month{10}};
assert(ym - months{16} == ym2);
assert(ym2 - ym == -months{16});
assert(ym - ym2 == months(16));
auto ymc = ym;
ymc -= months{16};
assert(ymc.ok());
assert(ymc == ym2);
}
{
year_month ym2{2018_y, month{25}};
assert(ym2 - ym == months{11});
assert(ym - ym2 == -months{11});
}
{
year_month ym2{2019_y, month{25}};
assert(ym2 - ym == months{23});
assert(ym - ym2 == -months{23});
}
}
int
main()
{
@ -135,6 +219,7 @@ main()
static_assert(ym1 - ym2 == -months{11}, "");
test_arithmetic();
test_arithemtic_not_ok();
std::ostringstream os;
os << ym1;

View File

@ -171,7 +171,7 @@ test_with_date_weekday()
auto constexpr d1 = iso_week::sun;
static_assert(unsigned{d1} == 7, "");
auto constexpr d2 = date::weekday{d1};
static_assert(unsigned{d2} == 0, "");
static_assert(d2 == date::Sunday, "");
auto constexpr d3 = iso_week::weekday{d2};
static_assert(unsigned{d3} == 7, "");
}

View File

@ -0,0 +1,237 @@
// The MIT License (MIT)
//
// Copyright (c) 2020 Asad. Gharighi
// 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 "date.h"
#include "solar_hijri.h"
#include "islamic.h"
#include "tz.h"
#include <cassert>
#include <iostream>
#include <chrono>
#include <math.h>
void
test_a() {
constexpr auto civil = date::year{2020}/date::January/27;
using namespace solar_hijri;
static_assert(year_month_day{civil} == 1398_y/11/07, "");
}
void
test_b() {
using namespace solar_hijri::literals;
static_assert(date::year_month_day{475_y/far/1} == date::year{1096}/03/21, "");
static_assert(date::year_month_weekday{475_y/far/1} ==
date::year{1096}/03/date::Saturday[3], "");
}
void
test_c() {
using namespace solar_hijri;
auto date = solar_hijri::year_month_day{1398_y/bah/6};
for (auto i = 0; i < 24; i++) {
auto weekday = solar_hijri::weekday{date};
assert(date == 1398_y/11/06 + months{i});
assert(date.month() == month{(i+10u)%12 + 1});
assert(weekday == (weekday[1]/date.month()/date.year()).weekday());
auto k = weekday;
for (auto j = 0; j < 14; j++, k++) {
assert(weekday + days{j} == k);
}
date+=solar_hijri::months(1);
}
}
void
test_d() {
auto zt = date::make_zoned(date::current_zone(), std::chrono::system_clock::now());
auto ld = date::floor<date::days>(zt.get_local_time());
solar_hijri::year_month_day ymd{ld};
auto time = date::make_time(zt.get_local_time() - ld);
(void)time;
}
void
test_e() {
auto sd = date::floor<solar_hijri::days>(std::chrono::system_clock::now());
auto today = solar_hijri::year_month_day{sd};
assert(solar_hijri::year_month_weekday{today}.weekday() == solar_hijri::weekday{sd});
}
void
test_f() {
constexpr auto isl = islamic::year{1441}/6/1;
using namespace solar_hijri;
static_assert(year_month_day{isl} == 1398_y/11/07, "");
}
void
test_g() {
date::year_month_day ymdd[] = {
date::year{1583}/date::November/21,
date::year{1583}/date::November/22,
date::year{1583}/date::December/6,
date::year{1591}/date::December/26,
date::year{1616}/date::October/20,
date::year{1619}/date::October/13,
date::year{1627}/date::August/9,
date::year{1649}/date::October/15,
date::year{1657}/date::August/9,
date::year{1682}/date::June/23,
date::year{1691}/date::October/12,
date::year{1712}/date::September/13,
date::year{1718}/date::July/17,
date::year{1747}/date::January/4,
date::year{1756}/date::January/1,
date::year{1770}/date::January/15,
date::year{1798}/date::October/24,
date::year{1809}/date::July/11,
date::year{1834}/date::July/17,
date::year{1850}/date::September/9,
date::year{1865}/date::November/4,
date::year{1902}/date::December/21,
date::year{1926}/date::March/21,
date::year{1926}/date::March/22,
date::year{1957}/date::June/1,
date::year{1977}/date::March/7,
date::year{1982}/date::May/30,
date::year{1992}/date::December/8
};
solar_hijri::year_month_day ymdh[] = {
solar_hijri::year{962}/solar_hijri::Aban/30,
solar_hijri::year{962}/solar_hijri::Azar/1,
solar_hijri::year{962}/solar_hijri::Azar/15,
solar_hijri::year{970}/solar_hijri::Dey/5,
solar_hijri::year{995}/solar_hijri::Mehr/29,
solar_hijri::year{998}/solar_hijri::Mehr/21,
solar_hijri::year{1006}/solar_hijri::Mordad/18,
solar_hijri::year{1028}/solar_hijri::Mehr/24,
solar_hijri::year{1036}/solar_hijri::Mordad/19,
solar_hijri::year{1061}/solar_hijri::Tir/3,
solar_hijri::year{1070}/solar_hijri::Mehr/20,
solar_hijri::year{1091}/solar_hijri::Shahrivar/22,
solar_hijri::year{1097}/solar_hijri::Tir/26,
solar_hijri::year{1125}/solar_hijri::Dey/14,
solar_hijri::year{1134}/solar_hijri::Dey/11,
solar_hijri::year{1148}/solar_hijri::Dey/26,
solar_hijri::year{1177}/solar_hijri::Aban/2,
solar_hijri::year{1188}/solar_hijri::Tir/20,
solar_hijri::year{1213}/solar_hijri::Tir/26,
solar_hijri::year{1229}/solar_hijri::Shahrivar/18,
solar_hijri::year{1244}/solar_hijri::Aban/13,
solar_hijri::year{1281}/solar_hijri::Azar/29,
solar_hijri::year{1304}/solar_hijri::Esfand/30,
solar_hijri::year{1305}/solar_hijri::Farvardin/1,
solar_hijri::year{1336}/solar_hijri::Khordad/11,
solar_hijri::year{1355}/solar_hijri::Esfand/16,
solar_hijri::year{1361}/solar_hijri::Khordad/9,
solar_hijri::year{1371}/solar_hijri::Azar/17
};
solar_hijri::year_month_weekday ymdwd[] = {
solar_hijri::year{962}/solar_hijri::Aban/solar_hijri::Doshanbe[5],
solar_hijri::year{962}/solar_hijri::Azar/solar_hijri::Seshanbe[1],
solar_hijri::year{962}/solar_hijri::Azar/solar_hijri::Seshanbe[3],
solar_hijri::year{970}/solar_hijri::Dey/solar_hijri::Panjshanbe[1],
solar_hijri::year{995}/solar_hijri::Mehr/solar_hijri::Panjshanbe[5],
solar_hijri::year{998}/solar_hijri::Mehr/solar_hijri::Yekshanbe[3],
solar_hijri::year{1006}/solar_hijri::Mordad/solar_hijri::Doshanbe[3],
solar_hijri::year{1028}/solar_hijri::Mehr/solar_hijri::Adine[4],
solar_hijri::year{1036}/solar_hijri::Mordad/solar_hijri::Panjshanbe[3],
solar_hijri::year{1061}/solar_hijri::Tir/solar_hijri::Seshanbe[1],
solar_hijri::year{1070}/solar_hijri::Mehr/solar_hijri::Adine[3],
solar_hijri::year{1091}/solar_hijri::Shahrivar/solar_hijri::Seshanbe[4],
solar_hijri::year{1097}/solar_hijri::Tir/solar_hijri::Yekshanbe[4],
solar_hijri::year{1125}/solar_hijri::Dey/solar_hijri::Chaharshanbe[2],
solar_hijri::year{1134}/solar_hijri::Dey/solar_hijri::Panjshanbe[2],
solar_hijri::year{1148}/solar_hijri::Dey/solar_hijri::Doshanbe[4],
solar_hijri::year{1177}/solar_hijri::Aban/solar_hijri::Chaharshanbe[1],
solar_hijri::year{1188}/solar_hijri::Tir/solar_hijri::Seshanbe[3],
solar_hijri::year{1213}/solar_hijri::Tir/solar_hijri::Panjshanbe[4],
solar_hijri::year{1229}/solar_hijri::Shahrivar/solar_hijri::Doshanbe[3],
solar_hijri::year{1244}/solar_hijri::Aban/solar_hijri::Shanbe[2],
solar_hijri::year{1281}/solar_hijri::Azar/solar_hijri::Yekshanbe[5],
solar_hijri::year{1304}/solar_hijri::Esfand/solar_hijri::Yekshanbe[5],
solar_hijri::year{1305}/solar_hijri::Farvardin/solar_hijri::Doshanbe[1],
solar_hijri::year{1336}/solar_hijri::Khordad/solar_hijri::Shanbe[2],
solar_hijri::year{1355}/solar_hijri::Esfand/solar_hijri::Doshanbe[3],
solar_hijri::year{1361}/solar_hijri::Khordad/solar_hijri::Yekshanbe[2],
solar_hijri::year{1371}/solar_hijri::Azar/solar_hijri::Seshanbe[3]
};
bool leaps[] = {
true,
true,
true,
true,
true,
false,
false,
true,
true,
true,
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
false,
false,
true,
false,
false,
false,
false,
false
};
static_assert(sizeof(ymdd)/sizeof(ymdd[0]) == sizeof(ymdwd)/sizeof(ymdwd[0]), "");
static_assert(sizeof(ymdd)/sizeof(ymdd[0]) == sizeof(ymdh)/sizeof(ymdh[0]), "");
static_assert(sizeof(ymdd)/sizeof(ymdd[0]) == sizeof(leaps)/sizeof(leaps[0]), "");
for (auto i = 0; i < sizeof(ymdd)/sizeof(ymdd[0]); ++i)
{
assert(solar_hijri::year_month_day{ymdd[i]} == ymdh[i]);
assert(ymdd[i] == date::year_month_day{ymdh[i]});
assert(ymdh[i].year().is_leap() == leaps[i]);
assert(solar_hijri::year_month_weekday{ymdd[i]} == ymdwd[i]);
}
}
int
main()
{
test_a();
test_b();
test_c();
test_d();
test_e();
test_f();
test_g();
}

View File

@ -0,0 +1,168 @@
// The MIT License (MIT)
//
// Copyright (c) 2020 Asad. Gharighi
// Copyright (c) 2015, 2016 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.
// class year_month_day
// {
// public:
// constexpr year_month_day(const date::year& y, const date::month& m,
// const date::day& d) noexcept;
// constexpr year_month_day(const year_month_day_last& ymdl) noexcept;
// constexpr year_month_day(const sys_days& dp) noexcept;
//
// year_month_day& operator+=(const months& m) noexcept;
// year_month_day& operator-=(const months& m) noexcept;
// year_month_day& operator+=(const years& y) noexcept;
// year_month_day& operator-=(const years& y) noexcept;
//
// constexpr date::year year() const noexcept;
// constexpr date::month month() const noexcept;
// constexpr date::day day() const noexcept;
//
// constexpr operator sys_days() const noexcept;
// constexpr bool ok() const noexcept;
// };
// constexpr bool operator==(const year_month_day& x, const year_month_day& y) noexcept;
// constexpr bool operator!=(const year_month_day& x, const year_month_day& y) noexcept;
// constexpr bool operator< (const year_month_day& x, const year_month_day& y) noexcept;
// constexpr bool operator> (const year_month_day& x, const year_month_day& y) noexcept;
// constexpr bool operator<=(const year_month_day& x, const year_month_day& y) noexcept;
// constexpr bool operator>=(const year_month_day& x, const year_month_day& y) noexcept;
// constexpr year_month_day operator+(const year_month_day& ymd, const months& dm) noexcept;
// constexpr year_month_day operator+(const months& dm, const year_month_day& ymd) noexcept;
// constexpr year_month_day operator-(const year_month_day& ymd, const months& dm) noexcept;
// constexpr year_month_day operator+(const year_month_day& ymd, const years& dy) noexcept;
// constexpr year_month_day operator+(const years& dy, const year_month_day& ymd) noexcept;
// constexpr year_month_day operator-(const year_month_day& ymd, const years& dy) noexcept;
// std::ostream& operator<<(std::ostream& os, const year_month_day& ymd);
#include "date.h"
#include "solar_hijri.h"
#include <iostream>
#include <cassert>
#include <sstream>
#include <type_traits>
static_assert( std::is_trivially_destructible<solar_hijri::year_month_day>{}, "");
static_assert( std::is_default_constructible<solar_hijri::year_month_day>{}, "");
static_assert( std::is_trivially_copy_constructible<solar_hijri::year_month_day>{}, "");
static_assert( std::is_trivially_copy_assignable<solar_hijri::year_month_day>{}, "");
static_assert( std::is_trivially_move_constructible<solar_hijri::year_month_day>{}, "");
static_assert( std::is_trivially_move_assignable<solar_hijri::year_month_day>{}, "");
static_assert(std::is_nothrow_constructible<solar_hijri::year_month_day, solar_hijri::year,
solar_hijri::month,
solar_hijri::day>{}, "");
static_assert(std::is_nothrow_constructible<solar_hijri::year_month_day,
solar_hijri::year_month_day_last>{}, "");
static_assert(std::is_convertible<solar_hijri::year_month_day_last, solar_hijri::year_month_day>{}, "");
static_assert(std::is_nothrow_constructible<solar_hijri::year_month_day, solar_hijri::sys_days>{}, "");
static_assert(std::is_convertible<solar_hijri::sys_days, solar_hijri::year_month_day>{}, "");
static_assert(std::is_nothrow_constructible<solar_hijri::sys_days, solar_hijri::year_month_day>{}, "");
static_assert(std::is_convertible<solar_hijri::year_month_day, solar_hijri::sys_days>{}, "");
void
test_arithmetic()
{
using namespace solar_hijri;
for (int y1 = 1380; y1 <= 1400; ++y1)
{
for (unsigned m1 = 1; m1 <= 12; ++m1)
{
year_month_day ymd1{year{y1}, month{m1}, 9_d};
year_month_day ymd2 = ymd1 + months(24);
assert((ymd2 == year_month_day{year{y1+2}, ymd1.month(), ymd1.day()}));
ymd2 = ymd1 - months(24);
assert((ymd2 == year_month_day{year{y1-2}, ymd1.month(), ymd1.day()}));
for (int m2 = -24; m2 <= 24; ++m2)
{
months m{m2};
year_month_day ymd3 = ymd1 + m;
months dm = year_month{ymd3.year(), ymd3.month()} -
year_month{ymd2.year(), ymd2.month()};
assert(dm == m + years{2});
assert(ymd3 - m == ymd1);
assert(ymd3 + -m == ymd1);
assert(-m + ymd3 == ymd1);
assert((year_month_day{ymd1} += m) == ymd3);
assert((year_month_day{ymd3} -= m) == ymd1);
}
for (int y2 = -2; y2 <= 5; ++y2)
{
years y{y2};
year_month_day ymd3 = ymd1 + y;
years dy = date::floor<years>(year_month{ymd3.year(), ymd3.month()} -
year_month{ymd2.year(), ymd2.month()});
assert(dy == y + years{2});
assert(ymd3 - y == ymd1);
assert(ymd3 + -y == ymd1);
assert(-y + ymd3 == ymd1);
assert((year_month_day{ymd1} += y) == ymd3);
assert((year_month_day{ymd3} -= y) == ymd1);
}
}
}
}
void
test_day_point_conversion()
{
using namespace solar_hijri;
year y = year{-30000};
year end = 30000_y;
sys_days prev_dp = sys_days(year_month_day{y, far, 1_d}) - days{1};
weekday prev_wd = weekday{prev_dp};
for (; y <= end; ++y)
{
month m = far;
do
{
day last_day = year_month_day_last{y, month_day_last{m}}.day();
for (day d = 1_d; d <= last_day; ++d)
{
year_month_day ymd = {y, m, d};
assert(ymd.ok());
sys_days dp = sys_days(ymd);
assert(dp == prev_dp + days{1});
year_month_day ymd2 = dp;
assert(ymd2 == ymd);
weekday wd = dp;
assert(wd.ok());
assert(wd == prev_wd + days{1});
prev_wd = wd;
prev_dp = dp;
}
} while (++m != far);
}
}
int
main()
{
test_arithmetic();
test_day_point_conversion();
}

73
test/tz_test/OffsetZone.h Normal file
View File

@ -0,0 +1,73 @@
#ifndef OFFSET_ZONE_H
#define OFFSET_ZONE_H
// The MIT License (MIT)
//
// Copyright (c) 2017 Howard Hinnant
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// Test custom time zone support
#include "tz.h"
class OffsetZone
{
std::chrono::minutes offset_;
public:
explicit OffsetZone(std::chrono::minutes offset)
: offset_{offset}
{}
template <class Duration>
auto
to_local(date::sys_time<Duration> tp) const
{
using namespace date;
using namespace std::chrono;
using LT = local_time<std::common_type_t<Duration, minutes>>;
return LT{(tp + offset_).time_since_epoch()};
}
template <class Duration>
auto
to_sys(date::local_time<Duration> tp, date::choose = date::choose::earliest) const
{
using namespace date;
using namespace std::chrono;
using ST = sys_time<std::common_type_t<Duration, minutes>>;
return ST{(tp - offset_).time_since_epoch()};
}
template <class Duration>
date::sys_info
get_info(date::sys_time<Duration> st) const
{
using namespace date;
using namespace std::chrono;
return {sys_seconds::min(), sys_seconds::max(), offset_,
minutes{0}, offset_ >= minutes{0} ? "+" + date::format("%H%M", offset_)
: "-" + date::format("%H%M", -offset_)};
}
const OffsetZone* operator->() const {return this;}
};
#endif // OFFSET_ZONE_H

View File

@ -23,50 +23,7 @@
// Test custom time zone support
#include "tz.h"
class OffsetZone
{
std::chrono::minutes offset_;
public:
explicit OffsetZone(std::chrono::minutes offset)
: offset_{offset}
{}
template <class Duration>
auto
to_local(date::sys_time<Duration> tp) const
{
using namespace date;
using namespace std::chrono;
using LT = local_time<std::common_type_t<Duration, minutes>>;
return LT{(tp + offset_).time_since_epoch()};
}
template <class Duration>
auto
to_sys(date::local_time<Duration> tp) const
{
using namespace date;
using namespace std::chrono;
using ST = sys_time<std::common_type_t<Duration, minutes>>;
return ST{(tp - offset_).time_since_epoch()};
}
template <class Duration>
date::sys_info
get_info(date::sys_time<Duration> st) const
{
using namespace date;
using namespace std::chrono;
return {sys_seconds::min(), sys_seconds::max(), offset_,
minutes{0}, offset_ >= minutes{0} ? "+" + date::format("%H%M", offset_)
: "-" + date::format("%H%M", -offset_)};
}
const OffsetZone* operator->() const {return this;}
};
#include "OffsetZone.h"
#include <cassert>
int

View File

@ -1,21 +1,15 @@
To test: * Install tz.cpp by downloading the IANA timezone database
at: http://www.iana.org/time-zones You only need the data, not the
code.
# TZ Test
* Change the string `install` in tz.cpp to point to your downloaded
IANA database.
## How to Test
* Install tz.cpp by downloading the IANA timezone database at: http://www.iana.org/time-zones You only need the data, not the code.
* Change the string `install` in tz.cpp to point to your downloaded IANA database.
* Compile validate.cpp along with tz.cpp.
* Run the binary and direct the terminal output to a temporary file.
* Unzip the tzdata file that has the version corresponding to the IANA database you downloaded (e.g. tzdata2015f.txt.zip).
* Compare the unzipped txt file with the output of your validate test program. If they are identical, the test passes, else it fails.
* Unzip the tzdata file that has the version corresponding to the IANA
database you downloaded (e.g. tzdata2015f.txt.zip).
* Compare the unzipped txt file with the output of your validate test
program. If they are identical, the test passes, else it fails.
Miscellaneous:
## Miscellaneous
You can also compare one version of the tzdatabase with another using
these uncompressed text files. The text files contain for each
@ -25,4 +19,4 @@ versions change, minor updates to the set of these transitions are
typically made, typically due to changes in government policies.
The tests in this section will run much faster with optimizations
cranked up.
cranked up.

View File

@ -1,3 +1,25 @@
// The MIT License (MIT)
//
// Copyright (c) 2015, 2016 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>

View File

@ -0,0 +1,246 @@
// The MIT License (MIT)
//
// Copyright (c) 2019 Tomasz Kamiński
//
// 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 "OffsetZone.h"
#include <cassert>
#include <type_traits>
#include <string>
#if HAS_DEDUCTION_GUIDES
#include <string_view>
template<typename TimeZonePtr, typename Source>
void testDeductionFrom(Source&& s)
{
using namespace date;
using namespace std::chrono;
// No time point
{
zoned_time zt(std::forward<Source>(s));
static_assert(std::is_same<decltype(zt), zoned_time<seconds, TimeZonePtr>>::value, "");
}
// sys_time
{
sys_days sd(2017_y/feb/20);
zoned_time ztd(std::forward<Source>(s), sd);
static_assert(std::is_same<decltype(ztd), zoned_time<seconds, TimeZonePtr>>::value, "");
sys_time<seconds> ss(sd);
zoned_time zts(std::forward<Source>(s), ss);
static_assert(std::is_same<decltype(zts), zoned_time<seconds, TimeZonePtr>>::value, "");
sys_time<milliseconds> sms(ss);
zoned_time ztms(std::forward<Source>(s), sms);
static_assert(std::is_same<decltype(ztms), zoned_time<milliseconds, TimeZonePtr>>::value, "");
}
// local_time
{
local_days ld(2017_y/feb/20);
zoned_time ztd(std::forward<Source>(s), ld);
static_assert(std::is_same<decltype(ztd), zoned_time<seconds, TimeZonePtr>>::value, "");
local_time<seconds> ls(ld);
zoned_time zts(std::forward<Source>(s), ls);
static_assert(std::is_same<decltype(zts), zoned_time<seconds, TimeZonePtr>>::value, "");
local_time<milliseconds> lms(ls);
zoned_time ztms(std::forward<Source>(s), lms);
static_assert(std::is_same<decltype(ztms), zoned_time<milliseconds, TimeZonePtr>>::value, "");
}
// local_time, choose
{
local_days ld(2017_y/feb/20);
zoned_time ztd(std::forward<Source>(s), ld, choose::earliest);
static_assert(std::is_same<decltype(ztd), zoned_time<seconds, TimeZonePtr>>::value, "");
local_time<seconds> ls(ld);
zoned_time zts(std::forward<Source>(s), ls, choose::earliest);
static_assert(std::is_same<decltype(zts), zoned_time<seconds, TimeZonePtr>>::value, "");
local_time<milliseconds> lms(ls);
zoned_time ztms(std::forward<Source>(s), lms, choose::earliest);
static_assert(std::is_same<decltype(ztms), zoned_time<milliseconds, TimeZonePtr>>::value, "");
}
// zoned_time
{
zoned_time<days> zd(sys_days(2017_y/feb/20));
zoned_time ztd(std::forward<Source>(s), zd);
static_assert(std::is_same<decltype(ztd), zoned_time<seconds, TimeZonePtr>>::value, "");
zoned_time<seconds> zs(zd);
zoned_time zts(std::forward<Source>(s), zs);
static_assert(std::is_same<decltype(zts), zoned_time<seconds, TimeZonePtr>>::value, "");
zoned_time<milliseconds> zms(zs);
zoned_time ztms(std::forward<Source>(s), zms);
static_assert(std::is_same<decltype(ztms), zoned_time<milliseconds, TimeZonePtr>>::value, "");
}
// zoned_time, choose
{
zoned_time<days> zd(sys_days(2017_y/feb/20));
zoned_time ztd(std::forward<Source>(s), zd, choose::earliest);
static_assert(std::is_same<decltype(ztd), zoned_time<seconds, TimeZonePtr>>::value, "");
zoned_time<seconds> zs(zd);
zoned_time zts(std::forward<Source>(s), zs, choose::earliest);
static_assert(std::is_same<decltype(zts), zoned_time<seconds, TimeZonePtr>>::value, "");
zoned_time<milliseconds> zms(zs);
zoned_time ztms(std::forward<Source>(s), zms, choose::earliest);
static_assert(std::is_same<decltype(ztms), zoned_time<milliseconds, TimeZonePtr>>::value, "");
}
}
struct MyString
{
MyString(std::string s) : ms(std::move(s)) {}
operator std::string_view() const { return ms; }
private:
std::string ms;
};
struct OnlyLValueString
{
OnlyLValueString(std::string s) : ms(std::move(s)) {}
operator std::string_view() & { return ms; }
private:
std::string ms;
};
#endif // HAS_DEDUCTION_GUIDES
template<typename T>
T const& to_const(T& t) { return t; }
int
main()
{
using namespace date;
using namespace std::chrono;
#if HAS_DEDUCTION_GUIDES
// no arguments
{
zoned_time zt{};
static_assert(std::is_same<decltype(zt), zoned_time<seconds>>::value, "");
}
// zoned_time
{
zoned_time<days> zd(sys_days(2017_y/feb/20));
zoned_time ztd(zd);
static_assert(std::is_same<decltype(ztd), zoned_time<days>>::value, "");
zoned_time<seconds> zs(zd);
zoned_time zts(zs);
static_assert(std::is_same<decltype(zts), zoned_time<seconds>>::value, "");
zoned_time<milliseconds> zms(zs);
zoned_time ztms(zms);
static_assert(std::is_same<decltype(ztms), zoned_time<milliseconds>>::value, "");
}
// sys_time
{
sys_days sd(2017_y/feb/20);
zoned_time ztd(sd);
static_assert(std::is_same<decltype(ztd), zoned_time<seconds>>::value, "");
sys_time<seconds> ss(sd);
zoned_time zts(ss);
static_assert(std::is_same<decltype(zts), zoned_time<seconds>>::value, "");
sys_time<milliseconds> sms(ss);
zoned_time ztms(sms);
static_assert(std::is_same<decltype(ztms), zoned_time<milliseconds>>::value, "");
}
// time_zone const*
{
time_zone const* tz = current_zone();
testDeductionFrom<time_zone const*>(tz);
testDeductionFrom<time_zone const*>(to_const(tz));
testDeductionFrom<time_zone const*>(std::move(tz));
}
// char const*
{
char const* tz = "Europe/Warsaw";
testDeductionFrom<time_zone const*>(tz);
testDeductionFrom<time_zone const*>(to_const(tz));
testDeductionFrom<time_zone const*>(std::move(tz));
}
// std::string
{
std::string tz = "Europe/Warsaw";
testDeductionFrom<time_zone const*>(tz);
testDeductionFrom<time_zone const*>(to_const(tz));
testDeductionFrom<time_zone const*>(std::move(tz));
}
// std::string_view
{
std::string_view tz = "Europe/Warsaw";
testDeductionFrom<time_zone const*>(tz);
testDeductionFrom<time_zone const*>(to_const(tz));
testDeductionFrom<time_zone const*>(std::move(tz));
}
// MyString
{
MyString tz("Europe/Warsaw");
testDeductionFrom<time_zone const*>(tz);
testDeductionFrom<time_zone const*>(to_const(tz));
testDeductionFrom<time_zone const*>(std::move(tz));
}
// custom time zone
{
OffsetZone tz(minutes(45));
testDeductionFrom<OffsetZone>(tz);
testDeductionFrom<OffsetZone>(to_const(tz));
testDeductionFrom<OffsetZone>(std::move(tz));
}
// OnlyLValue
{
OnlyLValueString tz("Europe/Warsaw");
testDeductionFrom<time_zone const*>(tz);
//testDeductionFrom<time_zone const*>(to_const(tz));
//testDeductionFrom<time_zone const*>(std::move(tz));
}
#endif // HAS_DEDUCTION_GUIDES
}