Giter Site home page Giter Site logo

howardhinnant / date Goto Github PK

View Code? Open in Web Editor NEW
3.0K 126.0 659.0 3.24 MB

A date and time library based on the C++11/14/17 <chrono> header

License: Other

C++ 97.53% Shell 0.49% Objective-C++ 0.94% C 0.12% CMake 0.92%
date datetime timezone calendar time iana-database timezone-library

date's Introduction

Date

Build Status Join the chat at https://gitter.im/HowardHinnant/date


Try it out on wandbox!

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.

  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.

  3. "iso_week.h" is a header-only library built on top of the "date.h" library which implements the ISO week date calendar.

  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.

  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.

Standardization

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:

Build & Test

The recommended way to use any of these libraries besides "tz.h" is to just include it. These are header-only libraries (except "tz.h").

To use "tz.h", there is a single source file (src/tz.cpp) that needs to be compiled. Here are the recommended directions: https://howardhinnant.github.io/date/tz.html#Installation.

One can run tests by cd'ing into the test subdirectory and running testit. There are known failures on all platforms except for macOS. And even on macOS if C++11 is used. If any of these failures present problems for you, there exist workarounds.

Additionally there is unsupported support for vcpkg and CMake. I don't personally use or maintain these systems as for me they cause more problems than they solve (for this small project). If you would like to contribute to these build systems please feel free to file a PR.

You can download and install Date using the vcpkg 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 on the vcpkg repository.

You can optionally build using CMake. Here is a guide of how to build and test using the CMake Makefile generator.

mkdir build
cd build
cmake -DENABLE_DATE_TESTING=ON -DBUILD_TZ_LIB=ON ../
cmake --build . --target testit # Consider '-- -j4' for multithreading

Projects using this library

If you would like your project (or product) on this list, just let me know.

date's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

date's Issues

zone.pass.cpp fails test with GCC v3.2.1 and clang++ v3.7.0 on Linux

./testit
passed 1 tests in /home/galik/dev/date/test
passed 63 tests in /home/galik/dev/date/test/date_test
passed 16 tests in /home/galik/dev/date/test/iso_week
zone.pass.cpp:14:5: error: static_assert failed ""
    static_assert( is_nothrow_move_assignable<Zone>{}, "");
    ^              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
/home/galik/dev/date/test/tz_test/zone.pass.cpp failed to compile
Compile line was: clang++ -std=c++14 -I/home/galik/dev/date -Wall zone.pass.cpp
failed 1 tests in /home/galik/dev/date/test/tz_test
****************************************************
Results for /home/galik/dev/date/test:
using clang version 3.7.0 (tags/RELEASE_370/final)
Target: x86_64-redhat-linux-gnu
Thread model: posix
with -std=c++14  -I/home/galik/dev/date -Wall  
----------------------------------------------------
sections without tests   : 0
sections with failures   : 1
sections without failures: 3
                       +   ----
total number of sections : 4
----------------------------------------------------
number of tests failed   : 1
number of tests passed   : 80
                       +   ----
total number of tests    : 81
****************************************************

`make_time` fails to compile when fed with durations having non-trivial ratios as period

Severity: high (does not compile)
Probability of users hitting this one: low I mean, look, not everyone attempts to use the date library for the temporal dimension of a FFF library

Description: make_time will fail to compile when fed with duration<R, std::ratio<Den, Num>> having both Den and Num greater than 1 (non-trivial ratios).

Config: g++ v 5.4.1 (20160904) on Ubuntu 14.04

Scenario: snippet of code to demonstrate:

  using namespace date;

  // this is Ok, num is 1
  auto alpha=std::chrono::duration<std::uintmax_t, std::ratio<1,5>>{1};
  auto alphaTod=make_time(alpha);

  // this is Ok, den is one
  auto beta=std::chrono::duration<std::uintmax_t, std::ratio<5,1>>{1};
  auto betaTod=make_time(beta);

  // this is Ok, num is 1 after reducing
  auto gamma=std::chrono::duration<std::uintmax_t, std::ratio<3,9>>{1};
  auto gammaTod=make_time(gamma);

  // this fails to compile
  auto delta=std::chrono::duration<std::uintmax_t, std::ratio<2,3>>{1};
  auto deltaTod=make_time(delta); // <<<< compilation failure here

  // this fails to compile
  auto eta=std::chrono::duration<std::uintmax_t, std::ratio<355,113>>{1};
  auto etaTod=make_time(eta); // <<<< compilation failure here


Analysis: to be more precise, the bug description should sound like

The detail::classify::subsecond specialization of the time_of_day_storage template will fail to compile when the Period template parameter is represented by a std::ratio which does not divide a second by an integral number

As such:

  • the beta test case is irrelevant to the problem (because there's no subseconds, thus the will be a time_of_day_storage specialization different from the one tagged detail::classify::subsecond
  • the alpha and gamma test cases are equivalent
  • only the delta(subunitary ratio) and eta (supraunitary ratio) test cases are relevant to the failure

The issue is cause by two factors:

  1. the root cause of the issue lies into the template <class Duration> struct classify_duration, which is meant to determine the minimum required precision to represent a duration of "a single tick of its Period".
    The fault is the failure to note that Periods with supraunitary den will require fractional parts of seconds: because the std::ratio will always be reduced at compile time - see issue #85. If all the multiples of tick-units never show a fractional part, then the ratio::den would be 1. Since it's not, it follows there will be some values that will show fractional seconds - QED.
    Once the struct classify_duration is fixed, the compiler will be able to correctly identify which time_of_day_storage specialization to use - and the next bug manifestations will pop up.
  2. the second factor causing the issue lies in the detail::classify::subsecond specialization of the time_of_day_storage template, namely the implicit assumption that the arithmetic involving sub_s will always be integral-representable in terms of the same period as the Period passed as the template parameter. To illustrate, please verify if there is an integral number of 355 / 133 ticks (almost-π - see footnote++ at the end) then think what this would do to an operation like sub_s = since_midnight - h_ - m_ - s_ when working with this value for your tick-unit.

Proposed fixes:

The root cause

The fix for the root cause is straight-forward:

template <class Duration>
struct classify_duration
{
    static CONSTDATA classify value =
        Duration{1} >= days{1}                 ? classify::not_valid :
        Duration::period::den > 1              ? classify::subsecond : // <<< FIX
        Duration{1} >= std::chrono::hours{1}   ? classify::hour :
        Duration{1} >= std::chrono::minutes{1} ? classify::minute :
        Duration{1} >= std::chrono::seconds{1} ? classify::second :
                                                 classify::subsecond;
};

And I argue this fix is necessary. As a preliminary, let's note that the time_of_day struct is more (exclusively?) about user-code-readability/display capabilities than it is about arithmetic; for the time-arithmetic, the duration<R, Precision> is more appropriate.

With 'for-display-purpose' idea in mind, have a look at the code of

    template<class CharT, class Traits>
    friend
    std::basic_ostream<CharT, Traits>&
    operator<<(std::basic_ostream<CharT, Traits>& os, const time_of_day_storage& t)

around line 3760 of date.h. This code suggests the interpretation of: "Period:den defines the user-required decimal precision for output and, as such, it should be honoured", so the followings will take this interpretation as true

So, for example, if the Period is 478799 / 113 will imply, via that interpretation, that the caller require a precision of milliseconds on output (even if the arithmetic was be done, using the corresponding duration, in ticks a-wee-bit-under-one-hour).
Without the fix, the chosen time_of_day_storage specialization will output an inaccurate time_of_day representation when left-shifted into an ostream
In the 478799 / 113 seconds per tick example, without this fix, the chosen representation will be time_of_day_storage<P, detail::classify::hour>, which will cause the 2 ticks of 478799 / 113 seconds each to be simply displayed as 01 (hours). In fact, under the "Period::den defines precision" interpretation, the millisecond-accurate time-of-day representation would be: 01:59:59.985... or, at its worse precision (of 1h) 02:00:00; but certainly not 01 am.

In conclusion: without this fix, not only that the compiler will baulk at the code using non-trivial ratios for durations (the very cause of me raising the issue), but the classify_duration is incompatible with the user expectation (or, at least, with the expectations one can assume by reading the rest of the date library code)

The fix for the "rational arithmetic of time_of_day when using non-trivial ratio tick units"

This requires a bit more analysis. Of course, something like sub_s_ = round<Precision::period>(since_midnight - h_ - m_ - s_) is a possible and straight-forward solution for the compilation problem (it will satisfy the type constraints immediately and make the compiler happy), but I know for sure that the precision in manipulating (at runtime) time_of_day values expressed in terms of, e.g., almost-π++ tick-units isn't going to be great.

The fault in rationing is subtle (yet simple): the time_of_day_storage in its classify::subsecond chooses to store the hours/mins/secs in something that admits an exact decimal representation of seconds.
And yet the sub_s_ is expressed in terms of the template-arg Period units (see the using precision = std::chrono::duration<Rep, Period>; type alias).
If you still don't get it why it is wrong, think what sub_s_ it is likely to contain if the precision's (non-trivial) ratio is sub-unitary but above 1/2 (testcase delta - ratio of 2/3): any multiple of this tick-unit is going to be captured by the secs_ member, letting the sub_s_ with a value of either 0 or 1 tick count. The matter become worse when the tick-unit becomes supra-unitary (but still non-trivial), like in the testcase eta - huh, the sub_s_ data member will be necessary always-0 (because the secs data member will capture all).

So, what's the solution? Well, the very "Period:den defines the user-required decimal precision" assumption suggest that the sub_s data member be represented not in terms of Period (which may be impossible for supra-unitary periods) but with the finer granularity of ratio<1, Period::den>. True, this will make impossible to honour the <b>precision</b> subseconds() const NOEXCEPT {return sub_s_;} as such, but the precision subseconds() const NOEXCEPT {return round<precision>(sub_s_);}will work (even it will always be zero for supra-unitary Periods).
I argue that the idea of storing sub_s_ in a different (finer than Period) precision is not that unusual, after all we already store the h_, m_ and s_ in a different precision, why sub_s_ should be treated differently?

If we already accept the idea of "internal representation of sub_s_ may be different than the Period template-arg", the next question would be: can we do better at the same price? Well, the purpose being convenience of the representation as time_of_day for the user, storing sub_s_ in units of 1/Period::den is not more advantageous than storing it in decimal units of a certain precision.
So, what decimal representation to choose? Well, no less than 1/Period:den but not unnecessary much finer. so how about
ratio<1, POW10(CEIL_LOG10(Period::den))>?

In short, the proposed fix goes along the idea of:

template <class Rep, class Period>
class time_of_day_storage<std::chrono::duration<Rep, Period>, detail::classify::subsecond>
    : private detail::time_of_day_base
{
public:
    using precision = std::chrono::duration<Rep, Period>;

private:
    // ratio den/num can be signed!!! Who knew?
    static CONSTDATA auto DEN=Period::den>0 ? Period::den : -Period::den;
    static CONSTDATA auto NUM=Period::num>0 ? Period::num : -Period::num;
    static CONSTDATA bool subunit_prec=(NUM<DEN);

    using subs_ratio = std::ratio<1, POW10(CEIL_LOG10(DEN))>;
    using subs_prec = std::chrono::duration<Rep, subs_ratio>;

    using base = detail::time_of_day_base;

    std::chrono::minutes m_;
    std::chrono::seconds s_;
    subs_prec            sub_s_;

public:
    CONSTCD11 explicit time_of_day_storage(precision since_midnight) NOEXCEPT
        : base(std::chrono::duration_cast<std::chrono::hours>(since_midnight), is24hr)
        , m_(std::chrono::duration_cast<std::chrono::minutes>(since_midnight - h_))
        , s_(std::chrono::duration_cast<std::chrono::seconds>(since_midnight - h_ - m_))
        , sub_s_(round<subs_prec>(since_midnight - h_ - m_ - s_))
        {}

     // maybe SFINAE disable this constructor if precision>1 ??! See parameter.
    CONSTCD11 explicit time_of_day_storage(std::chrono::hours h, std::chrono::minutes m,
                                           std::chrono::seconds s,
                                           // maybe disable this constructor if precision>1 ??!
                                           std::enable_if<subunit_prec, precision> sub_s,
                                           unsigned md) NOEXCEPT
        : base(h, md)
        , m_(m)
        , s_(s)
        , sub_s_(sub_s)
        {}
// ...
    CONSTCD11 precision subseconds() const NOEXCEPT {return round<precision>(sub_s_);}
// ...
    CONSTCD14 explicit operator precision() const NOEXCEPT
    {
        return round<precision>(to24hr() + s_ + sub_s_ + m_);
    }
//...

++incidentally, the 355 / 133 ratio is the best 6-digit-accurate rational representation of π that can be obtained using fewer than 5 figures when expressing the num and den. As such, it makes a great workhorse for testing the robustness of rational arithmetic.

Visual Studio 2013 compatibility

Currently, the tz code compiles with Visual Studio 2015 but not with the 2013 version. Is Visual Studio 2013 compatibility something you would accept a PR for?

I have it compiling locally with mostly minor modifications. However, the fact that the std::vector implementation coming with VS 2013 does not support incomplete types as first template argument requires a little bit more surgery for the zonelet class. Let me know if you would accept such a PR in principle. Thanks!

init_tzdb slow in Visual Studio debugger

When I call init_tzdb in the debugger it takes ~ 1 minute and 13 seconds.
2016-09-28 07:30:33.9777017 Init TZDB...
2016-09-28 07:31:46.2048970 Init TZDB done...

The call to Rule::split_overlaps(db.rules); seems to take all the time.

When I run the same code outside of the debugger (CTRL+F5) it takes 1 sec and 47 milliseconds
2016-09-28 07:26:44.1113231 Init TZDB...
2016-09-28 07:26:45.6855314 Init TZDB done...

In release mode it takes just 69 milliseonds
2016-09-28 07:28:25.3329903 Init TZDB...
2016-09-28 07:28:25.4011985 Init TZDB done...

I am using Visual Studio 2013.
Might just be a VS problem..

time_point<system_clock, nanoseconds> may lead to overflow in tz.h

In line 336 of function Zone::to_sys_impl(), when the function argument tp is of type time_point<system_clock, nanoseconds> and get_info() returns the zonelet info i such that i.end achieves max (in year 6052 or something), i.end(second_point = time_point<system_clock, seconds>) is first converted into time_point<system_clock, nanoseconds>, which leads to overflow.

A feasible solution could be casting tp to time_point<system_clock, microseconds> or you might consider to limit the type of tp.

Feature request : default constructor

Is it possible to make the default constructors available for some classes ? For instance, calling date::year_month_day foo; is not possible.
I need this feature for serialization purpose.

The following changes work for my cases:

class year_month_day
{
    date::year  y_{0};
    date::month m_{0};
    date::day   d_{0};

public:
    CONSTCD11 year_month_day() NOEXCEPT = default;
    [etc...]

If there is a good reason to prevent default ctor ? If yes, is there a workaround to achieve what I need ? Thanks!

format and parse functions in tz/date

For a project built with C++11 I'd like to use your date-library. It is very useful and provides a really convenient API. I'm specially interested in the parsing and (string-)formating of time_points.

Unfortunately all of the format(...) and parse(...) functions reside in tz.h which also means that one would have to use and include tz.h. In my case im pretty sure, that i don't need the full timezone support.

After looking at the code in tz.h i asked myself: Wouldn't it be possible to move the format and parse functions regarding local_time to date.h so that users without tz.h could use them? I don't see all the impact but that would be definately useful...

Of course it would be possible using tz.h as well, but that in turn needs the tzdata download which i cannot distribute to our PCs...

It is necessary to amend the tz.h file for compilation under MSVC

210 name_(std::move(src.name_)),
-211 zonelets_(std::move(zonelets_))
+211 zonelets_(std::move(src.zonelets_))

  •       version(std::move(src.version)), 
    

    585 zones(std::move(src.zones)),
    -586 links(std::move(links)),
    +586 links(std::move(src.links)),
    -587 leaps(std::move(leaps)),
    +587 leaps(std::move(leaps)),
    -588 rules(std::move(rules))
    +588 rules(std::move(rules))
    589 #if TIMEZONE_MAPPING
    590 ,
    -591 mappings(std::move(mappings)),
    +591 mappings(std::move(mappings)),
    -592 native_zones(std::move(native_zones))
    +592 native_zones(std::move(native_zones))

  •       version = std::move(src.version)); 
    

    598 zones = std::move(src.zones);
    -599 links = std::move(links);
    +599 links = std::move(src.links);
    -600 leaps = std::move(leaps);
    +600 leaps = std::move(src.leaps);
    -601 rules = std::move(rules);
    +601 rules = std::move(src.rules);
    602 #if TIMEZONE_MAPPING
    -603 mappings = std::move(mappings);
    +603 mappings = std::move(src.mappings);
    -604 native_zones = std::move(native_zones);
    +604 native_zones = std::move(src.native_zones);
    605 #endif

Custom formatted input/output?

Should the date library provide facilities for outputting and parsing date-times in customizable formats? This would be very useful for integrating with a UI, or for transmission over the wire.

For custom output, one could provide a function similar to std::strftime, except that it takes a std::chrono::time_point and outputs to a std::ostream. For example:

namespace date
{
    template <typename C, typename D>
    std::ostream& format( std::ostream& out, const std::string& format, const std::time_point<C,D>& tp );
}

where format would contain specifiers used by std::strftime.

For custom input, we could have:

namespace date
{
    template <typename C, typename D>
    std::istream& parse( std::istream& in, const std::string& format, std::time_point<C,D>& tp );
}

Perhaps it's possible to make use of the POSIX function strptime (where available) to implement the proposed parse function.

We could also draw inspiration from Boost.DateTime Input/Output. Their API seems a lot more complicated than what I propose, which makes me think there are probably many subtleties I am currently ignorant about.

I absolutely loathe C++ locales and would personally prefer a direct way to customize date-time output and parsing.

tz - with invalid (semivalid) format str, date::parse may fail to set istream in fail() condition and may return incorrect timepoints

The documentation lead me to believe the date::parse would accept strftime format strings **, thus is stumbled over this bug trying to use "%FT%T%Z" as one.
My initial surprise was the returned value - doesn't contains what one expected. After reading (far down on the page) the spec for date::parse, I learned the function actually uses time_get-style of format string; a check on the time_get::get() format string spec reveals there's no %F (shortcut for %Y-%m-%d) and then my surprise changed into "Why no sign of failure and a bad result?"

Config: g++ (Ubuntu 5.4.1-2ubuntu1~14.04) 5.4.1 20160904

Code to repro:

#include <iostream>
#include <locale>
#include "date/tz.h"

int main() {
  namespace d=date;
  std::istringstream input;
  std::string toParse, fmt;

  std::cout << std::endl << "date::parse with invalid format (failure expected)" << std::endl;
  toParse="2016-09-09T08:45:05Z+1000";
  fmt="%FT%T%Z";
  input.str(toParse);
  input.clear();
  d::sys_time parsedDate;
  d::parse(input, fmt.c_str(), parsedDate);
  std::cout << "Using input: `" << toParse << "` with a format of `"
            << fmt << "` (failure expected)" << std::endl
  ;
  if(input.fail()) {
    std::cout << "Failed date::parse with input date:`"<< toParse <<"`"
        << "` using format `" <<  fmt << "`"
        << std::endl
    ;
  }
  else {
    std::cout << "Parse success; applying date::make_zoned gets `"
              <<  d::make_zoned("Australia/Melbourne", parsedDate)
              <<  "`" << std::endl;
  }
  // Bug already demonstrated by the code above
  // Below is an attempt to see if my expectations (of having istream.fail()-ing)
  // are unreasonable.
  // So...
  // how does time_get behaves?
  toParse="2016-09-09T08:45:05"; // doh. Of course...
  fmt="%FT%T";                   // ...  there's no timezone
  std::cout << "\n---\nAttempting the behaviour of time_get with invalid format `"
            <<  fmt << "` (expecting failure) " << std::endl
  ;
  input.str(toParse);
  input.clear();
  auto& tget=std::use_facet<std::time_get<char>>(input.getloc());
  struct tm tgetResult;
  std::ios_base::iostate err = std::ios_base::goodbit;
  tget.get(
      std::istreambuf_iterator(input),  std::istreambuf_iterator(),
      input,  err,  &tgetResult,
      fmt.c_str(),  fmt.c_str()+fmt.length()
  );
  input.setstate(err);
  if(input.fail()) {
    std::cout << "Failed time_get parsing of `" << toParse
              << "` using format `" << fmt << "`"
              << std::endl
    ;
  }
  else {
    char buff[256];
    strftime(buff, sizeof(buff), fmt.c_str(), &tgetResult);
    std::cout << "Parse success; applying strftime gets `"
              << buff << "`"
              << std::endl
    ;
  }
  return 0;
}

** May I kindly ask you to adjust the doc on tz so that any reference to strftime is replaced by time_get / time_put? The spec of date::parse is so buried down the page that anyone reading the doc is likely to believe the strftime format string is applicable.

GCC 5.3.1 (Linux x86_64) -pedantic-errors breaks: error: ISO C++ does not support '__int128' for 'type name'

Simply including the header produces the error when compiling with -pedantic-errors flag:

#include "date/date.h"

int main()
{

}

g++ -std=c++14 -pedantic-errors -Wall -Wextra -Wfatal-errors -O0 -g3 -D DEBUG -o bin/testcpp src/testcpp.cpp
In file included from src/testcpp.cpp:1:0:
src/date/date.h:821:26: error: ISO C++ does not support '__int128' for 'type name' [-Wpedantic]
__int128
^
compilation terminated due to -Wfatal-errors.

If I remove the -pedantic-errors flag it compiles

Compile failure with clang-3.6

Hi Howard,

yesterday's changes give me trouble with clang-3.6 and older.

Here

/home/rbock/projects/sqlpp11-connector-sqlite3/../date/date.h:4035:41: error: no matching constructor for initialization of 'local_days' (aka 'std::chrono::time_point<date::local_t,
      std::chrono::duration<int, std::ratio<86400, 1> > >')
    tm.tm_yday = static_cast<int>((ld - local_days{ymd.year()/1/1}).count());
/usr/lib/gcc/x86_64-linux-gnu/5.2.1/../../../../include/c++/5.2.1/chrono:546:14: note: candidate constructor (the implicit move constructor) not viable: no known conversion from
      'date::year_month_day' to 'std::chrono::time_point<date::local_t, std::chrono::duration<int, std::ratio<86400, 1> > > &&' for 1st argument
      struct time_point
...

And here:

/home/rbock/projects/sqlpp11-connector-sqlite3/../date/date.h:4294:38: error: no matching constructor for initialization of 'sys_days' (aka
      'std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::duration<int, std::ratio<86400, 1> > >')
                tp = floor<Duration>(sys_days{year{tm.tm_year + 1900}/
...

clang-3.7.1 works fine, though.

I haven't looked into details, let me know if I can help.

Best,

Roland

Iterating over months

Hi,

I would like to use month as the key-part of a std::map. Since the month class almost meets the Iterator requirements, I assumed the following to work:

month first(1), last(13);
while (first != last) {
    my_map[first] = 0;
    ++first;
}

Unfortuantely, the above results in an infinite loop. This is because of month::operator++ being implemented as:

inline month& month::operator++()  {if (++m_ == 13) m_ = 1; return *this;}

What should I use as the last sentinel? Do I need to write a dedicated iterator type?

Thanks.

Releases?

Dear Howard,

We'd like to use your date library in our company. For this it would be helpful to have a FreeBSD package for the library. We can handle the package maintenance. It would be easier if you had release tags in git, though.

Do you have any plans to add release tags?

Best,

Roland

CMake build

Would be nice to have a CMake based build. If you OK with this I will submit a pull request

test/iso_week tests fails in GCC when using explicit conversion operator { }

The files weekday.pass.cpp, weeknum.pass.cpp and year.pass.cpp have explicit conversions using the braced-init-list (C++11), which gcc does not support. Generating erros like the following:

year.pass.cpp:89:33: error: cannot convert ‘iso_week::year’ to ‘int’ in initialization static_assert(int{year{2015}} == 2015, "");

Changing that to static_cast<T>() resolves the "problem". Like is done in test/date_test/day.pass.cpp:71. Clang accepts the code, that I think is the correct behavior but I am not totaly certain. There is a bug report 51553 on gnu-bugzilla.

Is this change ok? If you let me, I can make a PR... Thank you, the lib is awesome!
Oh.. I am using GCC 5.3 on Mingw64

Nicolas

default ctor for date types ?

Hi,
thanks for the great library.

I noticed that there are no default constructors for the various date types.
The issue comes up with serialization logic for example.

I assume you had a reason for not adding them,
but having for example year_month_date have a default ctor to say 1970/1/1 would be nice to have.

Is this something you might add ?
Thanks
Jiri

Library doesn't compile with GCC 4.8.5 on Ubuntu 14.04 LTS

Ubuntu 14.04 is widely used platform nowadays. Standard compiler on it at the moment is GCC 4.8.5. The library just does not compile with it, which make library useless for many users on this platform. Please consider making library buildable in the non-cutting-edge C++11/C++14 compilers, which still widely used.

Sample output:

ivan@xubuntu1404:/proexp/date$ g++ --version
g++ (Ubuntu 4.8.5-1ubuntu1
14.04) 4.8.5
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ivan@xubuntu1404:/proexp/date$ g++ -c -std=gnu++11 tz.cpp
tz.cpp: In static member function ‘static void date::Rule::split_overlaps(std::vectordate::Rule&)’:
tz.cpp:1176:38: error: no matching function for call to ‘std::vectordate::Rule::erase(__gnu_cxx::__normal_iterator<const date::Rule*, std::vectordate::Rule >&, __gnu_cxx::__normal_iterator<const date::Rule*, std::vectordate::Rule >&)’
rules.erase(first_rule, t);
^
tz.cpp:1176:38: note: candidates are:
In file included from /usr/include/c++/4.8/vector:69:0,
from /usr/include/c++/4.8/bits/random.h:34,
from /usr/include/c++/4.8/random:50,
from /usr/include/c++/4.8/bits/stl_algo.h:65,
from /usr/include/c++/4.8/algorithm:62,
from tz.h:55,
from tz_private.h:26,
from tz.cpp:24:
/usr/include/c++/4.8/bits/vector.tcc:134:5: note: std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::iterator) [with _Tp = date::Rule; _Alloc = std::allocatordate::Rule; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<date::Rule*, std::vectordate::Rule >; typename std::_Vector_base<_Tp, Alloc>::pointer = date::Rule]
vector<_Tp, _Alloc>::
^
/usr/include/c++/4.8/bits/vector.tcc:134:5: note: candidate expects 1 argument, 2 provided
/usr/include/c++/4.8/bits/vector.tcc:146:5: note: std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::iterator, std::vector<_Tp, _Alloc>::iterator) [with _Tp = date::Rule; _Alloc = std::allocatordate::Rule; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::_normal_iterator<date::Rule, std::vectordate::Rule >; typename std::_Vector_base<_Tp, Alloc>::pointer = date::Rule]
vector<_Tp, _Alloc>::
^
/usr/include/c++/4.8/bits/vector.tcc:146:5: note: no known conversion for argument 1 from ‘__gnu_cxx::_normal_iterator<const date::Rule, std::vectordate::Rule >’ to ‘std::vectordate::Rule::iterator {aka __gnu_cxx::__normal_iterator<date::Rule*, std::vectordate::Rule >}’
tz.cpp:1185:37: error: no matching function for call to ‘std::vectordate::Rule::erase(__gnu_cxx::__normal_iterator<const date::Rule*, std::vectordate::Rule >&, __gnu_cxx::__normal_iterator<const date::Rule*, std::vectordate::Rule >&)’
rules.erase(t, last_rule);
^
tz.cpp:1185:37: note: candidates are:
In file included from /usr/include/c++/4.8/vector:69:0,
from /usr/include/c++/4.8/bits/random.h:34,
from /usr/include/c++/4.8/random:50,
from /usr/include/c++/4.8/bits/stl_algo.h:65,
from /usr/include/c++/4.8/algorithm:62,
from tz.h:55,
from tz_private.h:26,
from tz.cpp:24:
/usr/include/c++/4.8/bits/vector.tcc:134:5: note: std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::iterator) [with _Tp = date::Rule; _Alloc = std::allocatordate::Rule; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<date::Rule*, std::vectordate::Rule >; typename std::_Vector_base<_Tp, Alloc>::pointer = date::Rule]
vector<_Tp, _Alloc>::
^
/usr/include/c++/4.8/bits/vector.tcc:134:5: note: candidate expects 1 argument, 2 provided
/usr/include/c++/4.8/bits/vector.tcc:146:5: note: std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::iterator, std::vector<_Tp, _Alloc>::iterator) [with _Tp = date::Rule; _Alloc = std::allocatordate::Rule; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::_normal_iterator<date::Rule, std::vectordate::Rule >; typename std::_Vector_base<_Tp, Alloc>::pointer = date::Rule]
vector<_Tp, _Alloc>::
^
/usr/include/c++/4.8/bits/vector.tcc:146:5: note: no known conversion for argument 1 from ‘__gnu_cxx::_normal_iterator<const date::Rule, std::vectordate::Rule >’ to ‘std::vectordate::Rule::iterator {aka __gnu_cxx::__normal_iterator<date::Rule*, std::vectordate::Rule >}’
ivan@xubuntu1404:
/proexp/date$

Cannot stream out a sys_seconds

Hi,

After obtaining a valid date::sys_seconds as a result of calling date::parse I would like to take advantage of the overloaded operator<< as defined in date.h:

date::sys_seconds tp;
date::parse(sstream, "%Y-%m-%d %H:%M:%S", tp);   
std::cout << tp << std::endl;

Unfortunately, both g++ 6 and clang 3.4 on OS X cannot harness the generic version of operator<<. However, they both succeed in harnessing a hand-made, non-generic version defined as follows:

std::ostream& operator<<(std::ostream& os, date::sys_seconds const& tp) {
    auto const dp = date::floor<date::days>(tp);
    os << date::year_month_day(dp) << ' ' << date::make_time(tp - dp);
    return os;
}

As a matter of fact, the above compiles and behaves as expected. What am I doing wrong?

thanks.

Windows build needs NOMINMAX

The tz.cpp file include Windows.h. I would be good to

define NOMINMAX

before this include to avoid Windows.h defining min and max macros
It would also be faster if

define WIN32_LEAN_AND_MEAN

was defined as well

MinGW support

Unfortunately, the library cannot currently be compiled with MinGW due do the lack of the <codecvt> header support. Could you please add support for this? As far as I am concerned, this is needed only to convert UTF16 to UTF8 and back for filenames and timezone names. I am also intended to try to find a workaround myself. Any feedback or hints from your side would be highly appreciated though.

Feature request: year_month_weekday operator+(days)

I've used your fine library to create a program to find out the date of our next c++ ug meeting.
The problem I've found is that the year_month_weekday has operator+ defined for both month and year, but not day.
You can see the way I've used it on my github page, I'd also love to hear if there is another way to use the library, but as far as I could see, If I wanted the day of month of the day after the third tuesday of the given month; this is the way to do it.
IMHO it would be more consistent if the + days returned a year_month_day object, or in some way was usable.

Should year/month/day have a nested rep typedef?

Should year, month, and day have a nested rep typedef? The integer types used in their APIs are currently "hard-coded" to int and unsigned. By having a nested rep typedef, year, month, and day would be more consistent with their std::chrono::hours, minutes, and seconds analogs.

I understand that hours, minutes, and seconds represent durations, whereas year, month, and day do not, so perhaps my question is not really valid.

tz.cpp should parse the compiled form of the TZDB, not the source

I know you're writing only as an example, but given your notoriety, your source code might actually get used elsewhere.

Please parse the compiled form of the database, after zic is done with it. In doing that, you should also set the default DB path to "/usr/share/zoneinfo", which should work just about anywhere that has a /usr directory.

This should also eliminate the need to set a minimum year to be kept in memory, as the database is already pre-compiled.

Clang sanitizer runtime error

date.hpp:2461:40: runtime error: negation of 9 cannot be represented in type 'unsigned int'
SUMMARY: AddressSanitizer: undefined-behavior

Line concerned is auto const m = mp + (mp < 10 ? 3 : -9u); // [1, 12]

Used with Clang 3.7.1. with -fsanitize=address. If needed I can take time to see what exactly produces this error.

Minor Changes

Had to add a few headers and change a for loop index type to build without errors and warnings in VS2015 Update 2.

--- orig/tz.h   2016-04-07 10:29:17.087771500 +0200
+++ include/tz.h    2016-04-07 10:28:34.009325700 +0200
@@ -62,6 +62,8 @@ Technically any OS may use the mapping p
 #include <cstdint>
 #include <istream>
 #include <locale>
+#include <memory>
+#include <mutex>
 #include <ostream>
 #include <ratio>
 #include <sstream>
@@ -718,7 +720,7 @@ format(const std::locale& loc, std::stri

     using namespace std;
     using namespace std::chrono;
-    for (auto i = 0; i < format.size(); ++i)
+    for (std::size_t i = 0; i < format.size(); ++i)
     {
         if (format[i] == '%' && i < format.size()-1)
         {

Edit: Nevermind, there are other things that are broken in tz.h on Windows. Mostly make_time related.

Q: any reason for which date:format(fmt, local_time,...) methods take 'timepoint' by value?

I looked into the code and, half-heartedly, I saw/accepted the reason of passing the std::string fmt by value.

But why the tp (timepoint) parameter is by value and not by const local_time&?

Assuming one uses local_time vars as data-members of other classes/struct, most of the time a format(fmt, tp) call will originate in cases in which the parent struct is subject to 'stringification' - e.g. operator << (ostream&, const parent_struct& toDump) - in which cases, the parent struct will be passed 'by const reference'.
Yes, of course, one can create a local copy for that local_time data member (with optimisation level high enough, it'll be an operation as cheap as creating and init-ing a long), but it's... I don't know... say, annoyingly opposite with 'output ops traditions'?

Year greater than 2^16

Hi.
I was trying to use this library to output custom durations, e.g. like:

#include <iostream>

namespace std
{
  inline std::ostream& operator << (std::ostream& lhs, __int128_t rhs)
  {
     ...   
  }

  __int128_t abs(__int128_t arg) { return arg < 0 ? -arg : arg; }

} // namespace std


#include <date.h>

namespace std { namespace chrono { using date::operator<<; }}

int main()
{
  time_t tt =  549755813888LL;

  // Control output:
  std::cout << "time_t out: " << tt << std::endl;
  std::cout << "time_t out: " << asctime(gmtime(&tt)) << std::endl;

  std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<__int128_t, std::nano>>
     mtp { std::chrono::duration<__int128_t> { tt } };
  std::cout << "M Time: " << mtp << std::endl;
}

It works perfectly up to tt about 2^40, ( year 2^16 ) and then has trouble with year output.
Is it difficult to adapt library to handle years greater than 2^16?
It would solve all my problems. I want to save all diapason of time_t unix timestamp with nanosecond precision like std::chrono's system_clocks. Or I need to work at least up to 294 441 year.

date::format should implement an ostream version for convenience/performance reasons

Following issue #82, it would be desirable the date::format function gets an overload taking and returning an ostream parameter.

The implementation should keep into account Howard's notes on the problem

The 2nd form also doesn't respect width and adjustfield formatters. And even if I create the 2nd form, it will still have to create ostringstream internally for %z and for %S and %T when the precision is finer than seconds (somewhat nullifying the performance argument).

Docs: time_of_day::subseconds()

Hi,

I believe there is a documentation error for time_of_day:

In time_of_day<std::chrono::duration<Rep, Period>>, instead of

   constexpr std::chrono::precision subseconds() const noexcept;

it should be

   constexpr precision subseconds() const noexcept;

And instead of

constexpr std::chrono::seconds time_of_day<std::chrono::duration<Rep, Period>>::subseconds() const noexcept;

it should be something like

constexpr
std::chrono::duration<Rep, Period>
time_of_day<std::chrono::duration<Rep, Period>>::subseconds() const noexcept;

Best,

Roland

Formating of sub-systemclock-resolution timestamps

I have two platforms with two different timestamp resolutions: Linux, which has system_clock::duration in nanoseconds and Windows, which has 100 nanoseconds. For interoperability i use nanoseconds as a common basis:

using my_time_point = time_point<system_clock, nanoseconds>;

That makes sense to me, since even though Wndows cannot measure this resolution, it could calculate differences between two time_points in nanoseconds anyway. Unfortunately, using the format(..) function (that now resides in date.h 😄 ) fails in this case... The problem lies here:

auto tt = system_clock::to_time_t(sys_time<Duration>{tp.time_since_epoch()});

Duration (in my case) is nanoseconds. On Linux thats fine, since system_clock uses nanoseconds as well. But on Windows the function to_time_t only takes 100 nanoseconds so that one would need to cast.

I think that one should cast the input for to_time_t to at least system_clock::duration or even seconds, since the variable is only used for timestamp down to seconds. All fraction-digits are handled before anyway, and they could be in a finer resolution than system_clock::duration...

I'd provide a Pull Request if you agree..

Consolidate detection of C++17 features like `std::chrono::floor`

Commit 59d9cfa breaks gcc 6+ and clang 3.8+ when --std=c++1z is set because the _cplusplus macro is defined as 201500 and 201406 respectively. In other words not whatever value it will be to indicate C++17 support. That libc++ (I haven't checked) might already offer some of those features should be detected for separately, so the work-arounds in date.h are still provided for gcc and clang that build against libstdc++. (running Linux).

Month value off by one in year_month_day::from_day_point

year_month_day::from_day_point computes the month in the range of [0, 11], at line 2220. However, January is defined as having value 1 at line 1076.

I assume that this is a simple off-by-one error, and that it wasn't intentional to have different value ranges for the month.

test/testit fails under GCC

When running CXX=g++ ./testit getting many errors because GCC doesn't like the brace syntax for casting primitive types.

unsigned{w}; // fails to compile

Changing to parenthesis syntax solves this.

unsigned(w); // compiles fine

Additionally there was one failure because class year does not declare one of its decrement operators constexpr .

This is solved by making it CONSTCD14 year& operator--() NOEXCEPT;

But I assume more than just that operator should be made CONSTCD14?

Including Windows.h before date.h causes compile error

I'm working with VS2015 Update 3 in Visual C++. When I write:

#include <Windows.h>
#include "date.h"

I get an error here:

class year
{
    short y_;

public:
    explicit CONSTCD11 year(int y) NOEXCEPT;

    CONSTCD14 year& operator++()    NOEXCEPT;
    CONSTCD14 year  operator++(int) NOEXCEPT;
    CONSTCD14 year& operator--()    NOEXCEPT;
    CONSTCD14 year  operator--(int) NOEXCEPT;

    CONSTCD14 year& operator+=(const years& y) NOEXCEPT;
    CONSTCD14 year& operator-=(const years& y) NOEXCEPT;

    CONSTCD11 bool is_leap() const NOEXCEPT;

    CONSTCD11 explicit operator int() const NOEXCEPT;
    CONSTCD11 bool ok() const NOEXCEPT;

    static CONSTCD11 year min() NOEXCEPT; // <-------- error is here...
    static CONSTCD11 year max() NOEXCEPT;
};
warning C4003: not enough actual parameters for macro 'min'
date.h(323): error C2059: syntax error: '('
date.h(323): error C2143: syntax error: missing ',' before '?'

I'm not sure whether this is a relevant bug, because similar things also happen with other libraries. Switching the order of the includes solves the problem (date before Windows)

Unit Tests?

Any chance of unit tests being written for this library? Without them, I'm hesitant to use this library in our project. It seems to me there are tons of corner cases to worry about: leap years, months with less than 31 days, etc.

If I had more time, I would contribute such tests, but sadly I can't.

Wiki Page for Recipes and Examples

@HowardHinnant , what do you think of creating a Wiki page for users to share examples and recipes? I already have a couple of (trivial) examples I'd be willing to share. This recipes page could be an incubation area for future algorithms to be added to the library.

The wiki area for this repo already allows GitHub members to make changes (you can change those permissions, BTW). But I thought it would be polite to ask before adding stuff to the wiki.

Problem with zonelet operator= on MS build

Zone::zonelet marks the assignment operator as deleted. Zone has a member variable std::vector zonelets_. The problem is that the standard states that some containers like vector may require and assignment opererator. Sadly unlike the clang and GCC standard libraries the Visual Studio one does actually require one. Personally I think this is a terrible mistake, forcing all classes you may want to stick in a vector to have assignment is horrible for things like thread safety. Anyway I'm not sure the best way to fix this, other than obviously implementing the assignment which in my code I tend to do only on Windows using an #ifdef. This means the Clang build will check that the assignment operator is not being used anywhere else.

Timezone database did not install correctly

I just compiled my application with -lcurl and default options on Linux, which means:

  • INSTALL=~/Downloads
  • HAS_REMOTE_API=1
  • AUTO_DOWNLOAD=1

But for some reason it is unable to automatically install tzdata correctly.

This is the error message I get when I run my application for the first time:

unreachable 0
: No such file or directory
terminate called after throwing an instance of 'std::runtime_error'
  what():  Timezone database version "2016f" did not install correctly to "/home/k_sze/Downloads/tzdata"
Aborted (core dumped)

I can see that the application downloaded tzdata2016f.tar.gz; it also automatically created the ~/Downloads/tzdata/ directory, but the directory is empty:

$ ls -l ~/Downloads/tzdata2016f.tar.gz
-rw-rw-r-- 1 k_sze k_sze 313286 Sep 28 18:12 /home/k_sze /Downloads/tzdata2016f.tar.gz
$ ls -al ~/Downloads/tzdata
total 8
drwxrwxr-x 2 k_sze k_sze 4096 Sep 28 18:12 .
drwxr-xr-x 5 k_sze k_sze 4096 Sep 28 18:12 ..

Should literals be within a separate namespace?

Should the _y and _d literals be within a separate namespace, like the ones for std::chrono? The ones for chrono are in std::literals::chrono_literals.

I think the main motivation for a separate namespace, is that it allows one to make literals directly visible, without having to make the entire library directly visible:

using namespace date::date_literals;
date::year year = 2015_y;

Feature request: Support for platform default wide char ( wchar_t )

First of all thank you Howard for your library - it solved my "calendrical programming hurdles" without a hickup. Nevertheless I think that the library should have intrinsic wchar_t support. In other words in adddition to the ostream overloads e.g

std::ostream& operator<<(std::ostream& os, const day& d);
it should provide
std::wostream& operator<<(std::wostream& os, const day& d);

I was really surprised that simple code like:

auto ymd = 2016_y/feb/29
std::wcout << ymd << '\n'; // BOOM !

blew up on me. I found an (fast'n'ugly) workaround involving ostringstream and a conversion function
char->wide char - but seriously - IMHO that shouldn't happen to your library users.
Especially since you might consider putting it up for Standardization ( ISO C++ ).

Export of time symbols on Visual Studio

Unless some other mechanism is used to generate an exports table some classes and free functions in the time zone code need some Windows __declspec(dllexport)/__declspec(dllimport) stuff added. Note that in principle this could also support making symbols non public on clang/GCC if there are internal implementation functions or classes that should not really be made visible to users of the library.

I am intending to generate a pull request for this shortly.

as is, the `date::format` cannot honour required precision for fractional seconds

Low priority, can get around, but perhaps worth a note in documentation
(anyway, that was a "tasty" one to diagnose)

Scenario exposing the issue: model a wallclock that ticks every quarter of a second++ and list the ticks through date::format with two decimal places.
++ this implies the requirement of between consecutive ticks, just increment the tick-count by one

Code:

using custom_dtype=
      std::chrono::duration<std::uintmax_t, std::ratio<25,100>>
  // --------- picking the precision here, you see? ------^
;

template<class Duration>
void tickTockThroughTheDay(
  date::local_time startOfDay,
  std::uintmax_t tacks
) {
  startOfDay+=Duration{tacks};
  std::cout << date::format("%F %T", startOfDay) << std::endl;
}

int main() {
  std::cout << "-----" << std::endl;
  auto now=std::chrono::system_clock::now();
  auto sodTp=date::floor<date::days>(now);
  date::local_time<custom_dtype> startOfDay{sodTp.time_since_epoch()};
  for(uint i=0; i<4; i++) {
    tickTockThroughTheDay(startOfDay, i);
  }
}

Note the seconds going like this:

  {date} 00:00:00.0  < - oops loss of precision
  {date} 00:00:00.2  < - 
  {date} 00:00:00.5  < - 
  {date} 00:00:00.7  < -

Analysis: the issue was traced in the

    template
    friend
    std::basic_ostream&
    operator<<(std::basic_ostream& os, const time_of_day_storage& t)

operator, more specifically in the part which computes the required width for the decimal part of the seconds - the one making use of ceil_log10/pow10 (currently around lines 2780-2790 of the date.h file). The algorithm is correct, however it is based on the assumption that the duration::period::den is a reliable source for the required precision.
This assumption fails due to the CPP specification for the std::ratio, namely the requirement of

Both numerator and denominator are automatically reduced to the lowest terms.

Honouring the requirement, the compiler (in my case g++ 5.4.1 20160904 on ubuntu 14.04) reduces the custom_dtype to std::chrono::duration&lt;std::uintmax_t, std::ratio<1,4>> - even if the debug info (visible through variable listing while debugging) lists the type as declared - (I needed to insert 'spy writes' capturing the num/dem to understand what's happening).


Possible solutions:

  1. do nothing but insert a note into documentation; and/or
  2. adjust the date::format function to receive somehow the precision required by the user (extra argument or refining the format string to accept the precision for the %S/%T specifiers; Note: other programming languages/libs do provide such refinements); and/or
  3. persuade the C++ standard committee that the use of reducible ratiosmay be improper in some areas (where the reducing operation may cause irrecoverable loss of semantics associated with a ratio). Perhaps a stable ratio or whatever-one-would-like-to-call-such-ratios which the compiler does not reduce may be created for such purposes (purpose of a stable_ratio: carry some user-intended semantics together with the num/den members.)

constexpr support in VS 2015

Currently constexpr support is turned off in VS-2015 due to the lack of ability to forward declare constexpr functions.

This issue is to serve as a reminder to re-check constexpr settings with VS-2015 Update 2 (unsure of the timeline for that release). I have reason to believe we can start turning constexpr on for VS at that time (hopefully at least the C++11 parts).

leap second arithmetic returns wrong result:

The** Flight Example with leap seconds** is returning a wrong result. Seems like it always has as my wrong result matches the one in the manual.

Non leap second arithmetic seems to work properly.


int
main()
{
    using namespace std::chrono;
    using namespace date;

    auto nyc_tz = locate_zone("America/New_York");
    auto teh_tz = locate_zone("Asia/Tehran");
    auto nyc_departure_sys = nyc_tz->to_sys(day_point(dec/31/1978) + hours(12) + minutes(1));
    auto nyc_departure = nyc_tz->to_local(nyc_departure_sys);
    auto nyc_departure_utc = utc_clock::sys_to_utc(nyc_departure_sys);
    auto flight_length = hours(14) + minutes(44);
    auto teh_arrival_utc = nyc_departure_utc + flight_length;
    auto teh_arrival_sys = utc_clock::utc_to_sys(teh_arrival_utc);
    auto teh_arrival = teh_tz->to_local(teh_arrival_sys);
    std::cout << "departure NYC time:  " << nyc_departure.first << ' '
                                         << nyc_departure.second << '\n';
    std::cout << "flight time is " << make_time(flight_length) << '\n';
    std::cout << "arrival Tehran time: " << teh_arrival.first << ' '
                                         << teh_arrival.second << '\n';

    std::cout << "*************************************************\n";



    nyc_tz = locate_zone("America/New_York");
    teh_tz = locate_zone("Asia/Tehran");
    nyc_departure_sys = nyc_tz->to_sys(day_point(feb/25/1978) + hours(12) + minutes(1));
    nyc_departure = nyc_tz->to_local(nyc_departure_sys);
    nyc_departure_utc = utc_clock::sys_to_utc(nyc_departure_sys);
    flight_length = hours(14) + minutes(44);
    teh_arrival_utc = nyc_departure_utc + flight_length;
    teh_arrival_sys = utc_clock::utc_to_sys(teh_arrival_utc);
    teh_arrival = teh_tz->to_local(teh_arrival_sys);
    std::cout << "departure NYC time:  " << nyc_departure.first << ' '
                                         << nyc_departure.second << '\n';
    std::cout << "flight time is " << make_time(flight_length) << '\n';
    std::cout << "arrival Tehran time: " << teh_arrival.first << ' '
                                         << teh_arrival.second << '\n';


}

departure NYC time: 1978-12-31 12:01:00 EST
flight time is 14:44
arrival Tehran time: 1979-01-01 11:14:59 IRST <---------------This should be 11:44:59 IRST

departure NYC time: 1978-02-25 12:01:00 EST
flight time is 14:44
arrival Tehran time: 1978-02-26 11:45:00 IRST <---------------This is OK

Regards.

time difference bug?

I would like to compute the number of days between 1666-09-02 and 2012-08-01.

With GCC 4.9, I get different answers if one of the arguments is a chrono::system_clock::time_point.
Clang works fine. Bug or user error?

const auto d1 = day_point(year(1666)/9/2);
const auto d2 = chrono::system_clock::time_point(day_point(year(2012)/8/1));
const auto d3 = day_point(year(2012)/8/1);

cout << "d2 " << d2 << endl << " d1 " << d1 << endl << " d3 " << d3 << endl;
cout << date::days(ceil<date::days>(d1 - d2)).count() << endl;
cout << date::days(ceil<date::days>(d1 - d3)).count() << endl;

GCC 4.9 gives me

d2 2012-08-01 00:00:00.000000000
d1 1666-09-02
d3 2012-08-01
87162
-126342

LLVM 3.6 gives me

d2 2012-08-01 00:00:00.000000000
d1 1666-09-02
d3 2012-08-01
-126342
-126342

Thanks!

error compiling with VStudio 2015 update 2

The following code:

CONSTCD11
inline
time_of_day<std::chrono::minutes>
make_time(std::chrono::hours h, std::chrono::minutes m, unsigned md) NOEXCEPT
{
    return time_of_day<std::chrono::minutes>(h, m, md);
}

gives me the following error:

no suitable user-defined conversion from "std::chrono::hours" to "date::time_of_daystd::chrono::minutes" exists c:\Users\juan_\Documents\GitHub\date\date.h 3694

year_day?

Hi,

Looking over the code I would like to rewrite with your date library, I wondered if there should be a year_day type, representing the nth day in a year?

Also, looking at https://en.wikipedia.org/wiki/ISO_8601, it might make sense to add

year_week
year_week_day

Best,

Roland

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.