Topic: Converting file_time_type to string.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Wed, 7 Jun 2017 14:42:58 -0700 (PDT)
Raw View
------=_Part_2615_1182574075.1496871778412
Content-Type: multipart/alternative;
 boundary="----=_Part_2616_488633602.1496871778412"

------=_Part_2616_488633602.1496871778412
Content-Type: text/plain; charset="UTF-8"

Sometimes, such as when presenting a directory listing, there is a need to
convert a file time to a string.

This is ridiculously complicated when using the std::filesystem library,
and in fact, it seems to be sheer luck that this even compiles:

             auto time = last_write_time(iter->path());

             time_t tt = decltype(time)::clock::to_time_t(time);  *// Note:
to_time_t not guaranteed to exist.*

             tm tmt;

             localtime_s(&tmt, &tt);



             cout << std::put_time<wchar_t>(&tmt, L"%F %T") << std::endl;


So the most pressing issue is that (at least according to cppreference.com)
the *std::filesystem::file_time_type::clock* type only has to satisfy the
TrivialClock concept, which does not imply that it has a *to_time_t* method
at all (i.e. it doesn't have to be the system_clock). Is this an oversight,
an error in cppreference.com's description or am I missing some other way
to convert the filesystem::file_time_type object to a printable type? The
code above is fairly similar to what replyers come up with on stack
overflow: (
https://stackoverflow.com/questions/12835577/how-to-convert-stdchronotime-point-to-calendar-datetime-string-with-fraction)
so it seems that there is no more straight forward way.


Apart from this specification problem I think that there should be a pure
C++ way of formatting time_points that does not involve ancient C functions
and multiple steps (getting higher precision than a second makes my code
even more complicated).


One way would be to provide an overload of put_time that takes a
system_clock::time_point and a similar function that returns the formatted
string. A way to get sub-second fractions should be available as (%f is
actually free according to strftime documentation at cppreference.com). As
put_time is dependant on the locale facet imbued on the stream a string
conversion function would probably need to have a locale parameter which
defaults to the global locale of the process.


A similar shortcut without C middlemen would be appropriate for scanning
time values, I presume.


In C++17 we got the new type timespec and the function to get the current
time, timespec_get(). However there does not seem to be a link from this C
struct (?) to any of the chrono functionality or filesystem times. Also
there does not seem to exist a formatting function which handles formatting
including the fractions (see the example here:
http://en.cppreference.com/w/cpp/chrono/c/timespec_get).



--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/6c14fbc4-6627-4e48-ad52-db7f2ecea7ad%40isocpp.org.

------=_Part_2616_488633602.1496871778412
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Sometimes, such as when presenting a directory listing, th=
ere is a need to convert a file time to a string.<div><br></div><div>This i=
s ridiculously complicated when using the std::filesystem library, and in f=
act, it seems to be sheer luck that this even compiles:</div><div><br></div=
><div><p class=3D"MsoNormal">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0auto time =3D last_write_time(iter-&gt;path());<o:p></o:p></p>
<p class=3D"MsoNormal">=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 time_t tt =3D decltype(time)::clock::to_time_t(time);=
 =C2=A0<b>// Note: to_time_t not guaranteed to exist.</b><o:p></o:p></p>
<p class=3D"MsoNormal">=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 tm tmt;<o:p></o:p></p>
<p class=3D"MsoNormal">=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 localtime_s(&amp;tmt, &amp;tt);<o:p></o:p></p>
<p class=3D"MsoNormal"><o:p>=C2=A0</o:p></p>
<p class=3D"MsoNormal">=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 cout &lt;&lt;=20
std::put_time&lt;wchar_t&gt;(&amp;tmt, L&quot;%F %T&quot;) &lt;&lt; std::en=
dl;</p><p class=3D"MsoNormal"><br></p><p class=3D"MsoNormal">So the most pr=
essing issue is that (at least according to cppreference.com) the <b>std::f=
ilesystem::file_time_type::clock</b> type only has to satisfy the TrivialCl=
ock concept, which does not imply that it has a <b>to_time_t</b> method at =
all (i.e. it doesn&#39;t have to be the system_clock). Is this an oversight=
, an error in cppreference.com&#39;s description or am I missing some other=
 way to convert the filesystem::file_time_type object to a printable type? =
The code above is fairly similar to what replyers come up with on stack ove=
rflow: (<a href=3D"https://stackoverflow.com/questions/12835577/how-to-conv=
ert-stdchronotime-point-to-calendar-datetime-string-with-fraction">https://=
stackoverflow.com/questions/12835577/how-to-convert-stdchronotime-point-to-=
calendar-datetime-string-with-fraction</a>) so it seems that there is no mo=
re straight forward way.</p><p class=3D"MsoNormal"><br></p><p class=3D"MsoN=
ormal">Apart from this specification problem I think that there should be a=
 pure C++ way of formatting time_points that does not involve ancient C fun=
ctions and multiple steps (getting higher precision than a second makes my =
code even more complicated).</p><p class=3D"MsoNormal"><br></p><p class=3D"=
MsoNormal">One way would be to provide an overload of put_time that takes a=
 system_clock::time_point and a similar function that returns the formatted=
 string. A way to get sub-second fractions should be available as (%f is ac=
tually free according to strftime documentation at cppreference.com). As pu=
t_time is dependant on the locale facet imbued on the stream a string conve=
rsion function would probably need to have a locale parameter which default=
s to the global locale of the process.</p><p class=3D"MsoNormal"><br></p><p=
 class=3D"MsoNormal">A similar shortcut without C middlemen would be approp=
riate for scanning time values, I presume.</p><p class=3D"MsoNormal"><br></=
p><p class=3D"MsoNormal">In C++17 we got the new type timespec and the func=
tion to get the current time, timespec_get(). However there does not seem t=
o be a link from this C struct (?) to any of the chrono functionality or fi=
lesystem times. Also there does not seem to exist a formatting function whi=
ch handles formatting including the fractions (see the example here:=C2=A0<=
a href=3D"http://en.cppreference.com/w/cpp/chrono/c/timespec_get">http://en=
..cppreference.com/w/cpp/chrono/c/timespec_get</a>).</p><p class=3D"MsoNorma=
l"><br></p><p class=3D"MsoNormal"><br></p></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/6c14fbc4-6627-4e48-ad52-db7f2ecea7ad%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/6c14fbc4-6627-4e48-ad52-db7f2ecea7ad=
%40isocpp.org</a>.<br />

------=_Part_2616_488633602.1496871778412--

------=_Part_2615_1182574075.1496871778412--

.


Author: "T. C." <rs2740@gmail.com>
Date: Wed, 7 Jun 2017 15:30:15 -0700 (PDT)
Raw View
------=_Part_53_1992918977.1496874615531
Content-Type: multipart/alternative;
 boundary="----=_Part_54_506396496.1496874615531"

------=_Part_54_506396496.1496874615531
Content-Type: text/plain; charset="UTF-8"

On Wednesday, June 7, 2017 at 5:42:58 PM UTC-4, Bengt Gustafsson wrote:
>
> an error in cppreference.com's description
>

At cppreference we try pretty hard not to make stuff up. For this
particular case, see [fs.filesystem.syn]/1.

More generally, shouldn't you try to confirm whether the standard says X
yourself before making a big post about how X is a bad idea on a mailing
list about the standard?

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/99366508-3379-4151-92ae-df6b7bdf2227%40isocpp.org.

------=_Part_54_506396496.1496874615531
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Wednesday, June 7, 2017 at 5:42:58 PM UTC-4, Bengt Gust=
afsson wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-le=
ft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">=
<p class=3D"MsoNormal">an error in <a href=3D"http://cppreference.com" targ=
et=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D&#39;http://www.g=
oogle.com/url?q\x3dhttp%3A%2F%2Fcppreference.com\x26sa\x3dD\x26sntz\x3d1\x2=
6usg\x3dAFQjCNFfMEVsriPdiSLWG49XWK9zX_c5Ug&#39;;return true;" onclick=3D"th=
is.href=3D&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fcppreference.com=
\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFfMEVsriPdiSLWG49XWK9zX_c5Ug&#39;;=
return true;">cppreference.com</a>&#39;s description=C2=A0</p></div></block=
quote><div><br></div><div>At cppreference we try pretty hard not to make st=
uff up. For this particular case, see [fs.filesystem.syn]/1.</div><div><br>=
</div><div>More generally, shouldn&#39;t you try to confirm whether the sta=
ndard says X yourself before making a big post about how X is a bad idea on=
 a mailing list about the standard?</div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/99366508-3379-4151-92ae-df6b7bdf2227%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/99366508-3379-4151-92ae-df6b7bdf2227=
%40isocpp.org</a>.<br />

------=_Part_54_506396496.1496874615531--

------=_Part_53_1992918977.1496874615531--

.


Author: Howard Hinnant <howard.hinnant@gmail.com>
Date: Wed, 7 Jun 2017 20:57:07 -0400
Raw View
--Apple-Mail=_96CC8C8A-9653-47A2-8625-1DCE75FD0E28
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset="UTF-8"

On Jun 7, 2017, at 5:42 PM, Bengt Gustafsson <bengt.gustafsson@beamways.com=
> wrote:
>=20
> Sometimes, such as when presenting a directory listing, there is a need t=
o convert a file time to a string.
>=20
> This is ridiculously complicated when using the std::filesystem library, =
and in fact, it seems to be sheer luck that this even compiles:
>=20
>              auto time =3D last_write_time(iter->path());
>=20
>              time_t tt =3D decltype(time)::clock::to_time_t(time);  // No=
te: to_time_t not guaranteed to exist.
>=20
>              tm tmt;
>=20
>              localtime_s(&tmt, &tt);
>=20
>=20
>=20
>              cout << std::put_time<wchar_t>(&tmt, L"%F %T") << std::endl;


It is sheer luck.  std::filesystem::file_time_type::clock is not specified =
to have the member function to_time_t.

>=20
>=20
>=20
> So the most pressing issue is that (at least according to cppreference.co=
m) the std::filesystem::file_time_type::clock type only has to satisfy the =
TrivialClock concept, which does not imply that it has a to_time_t method a=
t all (i.e. it doesn't have to be the system_clock). Is this an oversight, =
an error in cppreference.com's description or am I missing some other way t=
o convert the filesystem::file_time_type object to a printable type? The co=
de above is fairly similar to what replyers come up with on stack overflow:=
 (https://stackoverflow.com/questions/12835577/how-to-convert-stdchronotime=
-point-to-calendar-datetime-string-with-fraction) so it seems that there is=
 no more straight forward way.
>=20
>=20
>=20
> Apart from this specification problem I think that there should be a pure=
 C++ way of formatting time_points that does not involve ancient C function=
s and multiple steps (getting higher precision than a second makes my code =
even more complicated).

I=E2=80=99ve been working on a proposal to format and parse time_point<syst=
em_clock, Duration>.  Your post has inspired me to include I/O for file_tim=
e_type as well.

> One way would be to provide an overload of put_time that takes a system_c=
lock::time_point and a similar function that returns the formatted string. =
A way to get sub-second fractions should be available as (%f is actually fr=
ee according to strftime documentation at cppreference.com). As put_time is=
 dependant on the locale facet imbued on the stream a string conversion fun=
ction would probably need to have a locale parameter which defaults to the =
global locale of the process.

One of the things I dislike about put_time is that it uses a std::tm to hol=
d the time to be formatted.  This inherently limits the precision of the ou=
tput to seconds.  I see almost daily a desire to parse and format at precis=
ions finer than a second.  And many modern file systems support subsecond r=
esolution for their file timestamps.

> A similar shortcut without C middlemen would be appropriate for scanning =
time values, I presume.

Absolutely.

> In C++17 we got the new type timespec and the function to get the current=
 time, timespec_get(). However there does not seem to be a link from this C=
 struct (?) to any of the chrono functionality or filesystem times. Also th=
ere does not seem to exist a formatting function which handles formatting i=
ncluding the fractions (see the example here: http://en.cppreference.com/w/=
cpp/chrono/c/timespec_get).

timespec is simply imported from C.  Imho it is born flawed as one doesn=E2=
=80=99t know whether a timespec is a time point or a time duration, and the=
 C API uses it both ways.  I would not encourage the C community to embrace=
 it for that reason alone.

I have been working on this library for a few years now:

https://github.com/HowardHinnant/date

It is fully documented, open-source, and has a small but growing community =
supporting it.  It does not replace <chrono>, and it does not build somethi=
ng in addition to <chrono>.  It builds on top of <chrono>, fully embracing =
it, and extending it into the realm of calendars.  It contains formatting a=
nd parsing for all reasonable precisions of time_point<sytem_clock, Duratio=
n>, as well as simple and efficient conversions between these time_points a=
nd calendar types such as year_month_day (a {year, month, day} struct).

Use of it can be as simple as this:

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

    int
    main()
    {
        using namespace std::chrono;
        using namespace date;
        std::cout << system_clock::now() << '\n';
    }

which just output for me:

    2017-06-08 00:34:40.718556

On my platform, system_clock::time_point has microseconds precision.  If on=
 your platform it has nanoseconds precision, that is the precision you=E2=
=80=99ll see by default on streaming.

I believe I can easily do the same for file_time_type.

If you want custom formatting, that is easy too:

    std::cout << format("%a, %b %d, %Y at %I:%M %p", system_clock::now()) <=
< '\n=E2=80=99;

    Thu, Jun 08, 2017 at 12:34 AM

This library supports a superset of the strftime formatting flags, includin=
g the ability to control the precision of the output:

    std::cout << format("%F %T", floor<milliseconds>(system_clock::now())) =
<< '\n=E2=80=99;

    2017-06-08 00:34:40.718

And yes, there=E2=80=99s parsing too:

    #include "date.h"
    #include <cassert>
    #include <iostream>
    #include <sstream>

    int
    main()
    {
        using namespace std::chrono;
        using namespace date;
        std::istringstream ss{"2017-06-08 00:34:40.718556"};
        system_clock::time_point tp;
        ss >> parse("%F %T", tp);
        assert(tp =3D=3D sys_days{2017_y/jun/8} + 34min + 40s + 718556us);
    }

And as you can see above in the assert, it is easy to build system_clock::t=
ime_points out of field information (year, month, day, hour, etc).

I see two ways to go on file_time_type:

1.  Provide bidirectional conversions to time_point<system_clock, D>, and t=
hen do all of the I/O and calendar stuff with system_clock.

2.  Provide I/O and calendar interoperability on file_time_type directly, j=
ust like I=E2=80=99ve done for time_point<system_clock, D>.

1 would be easier for the implementor and proposer (me).  But I think 2 mig=
ht be the higher quality solution.  I will give this more thought.  The lat=
ter will introduce more types, such as file_time_days, adding more work for=
 calendar authors (the civil calendar isn=E2=80=99t the only one).  Hmm=E2=
=80=A6

3.  Provide only I/O for file_time_type, and not calendar interoperability.=
  This would mean you could not easily create a file_time_type for a specif=
ic year/month/day hh:mm:ss, nor could you easily extract such fields from a=
 file_time_type, though you could observe them by printing them out.

Howard

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/3877A441-CFCF-46AD-963C-F4E3A6040F94%40gmail.com=
..

--Apple-Mail=_96CC8C8A-9653-47A2-8625-1DCE75FD0E28
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename=signature.asc
Content-Type: application/pgp-signature;
 name=signature.asc
Content-Description: Message signed with OpenPGP

-----BEGIN PGP SIGNATURE-----

iQIcBAEBCAAGBQJZOKDkAAoJEGbcHCxKqhWCXSAP/jTh2zYAM+42HIlbPzosFI+H
bATk19kXy+Pw63Il1VwNmfZostUJkDHoGs8UdqYiXxPJcZYaXYtPajAXXzzreH0J
SHARq7Lgvad70e/LaqvAnMsYT1Msw+5yni8tVY3Eoog4ALfb48ydM8sktB4j7byS
Ag2edgVBd4oASzLeo03MB1b76ppnGtFO2ixq98hScauEv2A8mmQvRvOBFS1Ak9SB
yIqFiCfogM//i5whOfr4e5z5J5iswB7kD0jhBFUzWzv3ZN1hsNclFX4KIb2WU7ha
+KeEl7/UPTfpW804h+Jp7Q5+q8nGNX+233OYwnNif8YHbfHShbU2x27NQxkh+1kW
jPLpJ5EXjIlUQP1qmWpDeDbDWLqkkCJXoUSAv3ZLyOyQGksARybuXW24niptxEF4
HIFHDXcd8P1OjQqwJxvnJUs1cvMXzqV5XFIItY6ffF+mpEf4HQWZhjDZ1XL3AUod
cnWdxScoGk9BgPKoCjRkyvv48C77xs2ExqLILuduuzBdTi67CDhho+fWuLmu7q+C
A8QIK/E2dAzwbeUbOvrYz6UQrA7eIbcck12AE/i4rj0JHgV4MEBA5McL5Xuj7Jiw
vy9iEotikq+/kVr4g1moFixUNuLjtkT/DzVeP8UuHc4vPWZG98plh5AHMRStobZr
DWvg3xaBauNSoICrgMHF
=iIoZ
-----END PGP SIGNATURE-----

--Apple-Mail=_96CC8C8A-9653-47A2-8625-1DCE75FD0E28--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Thu, 8 Jun 2017 11:14:10 -0700 (PDT)
Raw View
------=_Part_580_550950037.1496945650739
Content-Type: multipart/alternative;
 boundary="----=_Part_581_1697720126.1496945650739"

------=_Part_581_1697720126.1496945650739
Content-Type: text/plain; charset="UTF-8"

I'm sorry if this came through as belitteling cppreference.com. I rely on
it every day and I have never found an error. However, given the rather
catastrophic result of not having a standardized way to get from a
file_time_type to a string representation so lets say I was rather more
hoping that you would be wrong for once...

Den torsdag 8 juni 2017 kl. 00:30:15 UTC+2 skrev T. C.:
>
> On Wednesday, June 7, 2017 at 5:42:58 PM UTC-4, Bengt Gustafsson wrote:
>>
>> an error in cppreference.com's description
>>
>
> At cppreference we try pretty hard not to make stuff up. For this
> particular case, see [fs.filesystem.syn]/1.
>
> More generally, shouldn't you try to confirm whether the standard says X
> yourself before making a big post about how X is a bad idea on a mailing
> list about the standard?
>

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/187d2a1f-d9b1-445a-b0cd-61ea0e7e65ae%40isocpp.org.

------=_Part_581_1697720126.1496945650739
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">I&#39;m sorry if this came through as belitteling cpprefer=
ence.com. I rely on it every day and I have never found an error. However, =
given the rather catastrophic result of not having a standardized way to ge=
t from a file_time_type to a string representation so lets say I was rather=
 more hoping that you would be wrong for once...<br><br>Den torsdag 8 juni =
2017 kl. 00:30:15 UTC+2 skrev T. C.:<blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;"><div dir=3D"ltr">On Wednesday, June 7, 2017 at 5:42:58 PM UTC-4, Beng=
t Gustafsson wrote:<blockquote class=3D"gmail_quote" style=3D"margin:0;marg=
in-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir=3D"ltr"=
><p class=3D"MsoNormal">an error in <a href=3D"http://cppreference.com" rel=
=3D"nofollow" target=3D"_blank" onmousedown=3D"this.href=3D&#39;http://www.=
google.com/url?q\x3dhttp%3A%2F%2Fcppreference.com\x26sa\x3dD\x26sntz\x3d1\x=
26usg\x3dAFQjCNFfMEVsriPdiSLWG49XWK9zX_c5Ug&#39;;return true;" onclick=3D"t=
his.href=3D&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fcppreference.co=
m\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFfMEVsriPdiSLWG49XWK9zX_c5Ug&#39;=
;return true;">cppreference.com</a>&#39;s description=C2=A0</p></div></bloc=
kquote><div><br></div><div>At cppreference we try pretty hard not to make s=
tuff up. For this particular case, see [fs.filesystem.syn]/1.</div><div><br=
></div><div>More generally, shouldn&#39;t you try to confirm whether the st=
andard says X yourself before making a big post about how X is a bad idea o=
n a mailing list about the standard?</div></div></blockquote></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/187d2a1f-d9b1-445a-b0cd-61ea0e7e65ae%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/187d2a1f-d9b1-445a-b0cd-61ea0e7e65ae=
%40isocpp.org</a>.<br />

------=_Part_581_1697720126.1496945650739--

------=_Part_580_550950037.1496945650739--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Thu, 8 Jun 2017 14:54:42 -0700 (PDT)
Raw View
------=_Part_786_1440572918.1496958882661
Content-Type: multipart/alternative;
 boundary="----=_Part_787_1853863326.1496958882662"

------=_Part_787_1853863326.1496958882662
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Howard,

it is very good that you have this type of functionality in the wings. I=20
don't see how you can make this work for file_time_type if it does not=20
specify a way to convert to wall clock time. Maybe some part of the chrono=
=20
interface is still eluding me... I understand that you can get a duration=
=20
from the epoch of the file_time_type::clock to the time point, but I don't=
=20
see a way to know what the epoch of an unspecified clock actually is. In=20
reality I guess this is not a problem, but specificationwise it may be.=20
However, if the date library gets standardized as part of C++ this would of=
=20
course be relatively easy to fix in the process.


Here are some comments when reading the date library documentation at:=20
https://howardhinnant.github.io/date/date.html, mostly motivated by its=20
route towards standardization. Admittedly I haven't read the P0355r2=20
proposal, comments are solely related to the documentation mentioned here.

- It seems that the procedure for creating year_month_day may be a little=
=20
overworked, involving several other data types with overloaded / operators=
=20
and user defined literals. Also, if you don't "use" the date namespace and=
=20
this gets standardized all those types will have long names like=20
std::date::year, or maybe std::chrono::year if this functionality is=20
integrated with chrono. As these names are the same as the usual names you=
=20
would prefer to use for your variables it can get messy, and with a using=
=20
statement it downright clashes and you have to give your variables cryptic=
=20
names.

void MyFunction(int year, int month, int day)
{
    auto dt =3D std::date::year(year) / month / day;
}

also the use of the slash operator is not that obvious as many parts of the=
=20
world (and ISO8601) are more at ease with using - between the parts. Using=
=20
an overloaded operator when the operation is not consistent with the usual=
=20
meaning of the operator is also generally discouraged (No, I don't like=20
path / path either). Maybe use + as it is neutral between different=20
notations of dates and actually seems to be consistent: You are actually=20
adding years, days and months to make a complete date. On the other hand=20
doing this without first casting all the ints to their corresponding year,=
=20
day and month types seems strange if you view it as addition.

A library which is more complicated than its task warrants risks not being=
=20
used as the benefit may not outweigh the learning curve. I would more favor=
=20
one user defined literal _date which takes a string in ISO-6801 format and=
=20
returns a date_time object. As you point out we already have one of those=
=20
in system_clock::time_point. However, this is what you define as a=20
serial-based representation, so why not have a field-based representation=
=20
of the complete time_point, and ways to convert between the two. Having to=
=20
do a floor operation, a subtraction and two conversions from serial to=20
field based types seems to be to ask too much of the user.

- The *_last types also seem a bit unnecessary, while a way to inquiry the=
=20
number of days of a given month is a must. I don't understand how to do=20
that easily with this library. That's part of the learning curve I wrote=20
about above -- simple things should be simple.

- I fail also (sorry) to see the importance of the year_month_weekday type,=
=20
although it is important to be able to ask what weekday a certain date is.=
=20
Well, maybe sometimes you may want to get the date of the third sunday of=
=20
March of 2017 but it is not so easy to find a plausible use case. With this=
=20
library asking what weekday a date is does not seem particularly simple as=
=20
each field-based type can only report the fields it has. Here is what I=20
think would be needed:

date::year_month_day date =3D date::year(2017)/2/4;
date::year_month_weekday wdate =3D date::sys_days(date);
return wdate.weekday();

In wxWidgets, by contrast, you can do:

wxDate date(2, 4, 2017);
return date.GetDayOfWeek();

This level of simplicity is what we should strive for. Maybe the gist of=20
what I'm trying to say here is that while the internal representation of a=
=20
datetime may be configurable for optimal performance of certain operations,=
=20
it would be good if the API of the classes was the same. This could be=20
viewed as fully specialized instances of a template class with an enum=20
template parameter:

enum class datetime_representation {
    linear,
    year_month_day.
    year_month_weekday,
    year_week_day
};

template<datetime_representation =3D linear> class datetime {
    // Lots of methods to set and get the different parts, with equal=20
behaviour but different performance.
    // Implementations of methods exist only in specializations
};


Now back to more nitpicking:

- The definition of months (the duration) is a bit scary as it relates to=
=20
an "average month length" which means that it will not accurately represent=
=20
the current month when used as a duration from a year's start. Is it really=
=20
needed? I guess the same can be said for years, which tries to subsume the=
=20
concept of leap years but where presumably the number of years since the=20
start of another year can be off by one on Jan 1 or Dec 31.

- I'm undecided on whether to prefer your to_stream() idea or an overload=
=20
of the put_time() manipulator. I think both may well be outflanked by a=20
general format() function (see below).

- It seems strange to me that the 12/24 hour format is part of the=20
time_of_day object. Shouldn't this be a formatting issue when converting to=
=20
a string rather than a member of the object?

- In general I don't like the idea of having different specializations with=
=20
different API (such as time_of_day<minutes> having a minutes() function=20
while time_of_day<hours> has not). Maybe minutes() could always exist but=
=20
return 0 for a hour-only specialization? I understand it as your idea being=
=20
to save implementation bits when not needed.

- format() should take its fmt parameter as a basic_string_view. [this is=
=20
likely fixed in the standardization proposal]

- Maybe it would be better if format's char types for the returned string=
=20
and for the fmt parameter were decoupled. I write maybe as this decoupling=
=20
would require callers to explicitly name the char type they want for the=20
returned string. A name convention as used for basic_string itself could=20
solve this, possibly.

- The name format() could be a bit too generic, especially if the=20
format("{}, is a nice {}", ...) proposal gets standardized. Instead I would=
=20
suggest integrating the functionality intended here into a general format()=
=20
method so that the formatting parameters are "strftime like" if the=20
corresponding argument is of a date/time related type as proposed here.=20
This would also work nicely with string translation, so that locale=20
specific formats can be used if needed (without involving a locale=20
parameter).

- A problem with parsing dates entered by users is that persons tend to not=
=20
type dates in a coherent way. A remedy I have used is to allow multiple=20
format strings which are tried in succession. This could fall outside a=20
standard library but as the standard allows for two distinct output formats=
=20
per locale it does not seem too far fetched to allow at least two on input.=
=20
One possible way to define this would be to reserve one character, such as=
=20
| as a separator in format strings when used for input, with the meaning=20
that each | separated part is one complete format to be tried in order.=20
Obviously it would be up to the programmer to place the formats in a=20
suitable order to avoid ambiguities.






Den torsdag 8 juni 2017 kl. 02:57:11 UTC+2 skrev Howard Hinnant:
>
> On Jun 7, 2017, at 5:42 PM, Bengt Gustafsson <bengt.gu...@beamways.com=20
> <javascript:>> wrote:=20
> >=20
> > Sometimes, such as when presenting a directory listing, there is a need=
=20
> to convert a file time to a string.=20
> >=20
> > This is ridiculously complicated when using the std::filesystem library=
,=20
> and in fact, it seems to be sheer luck that this even compiles:=20
> >=20
> >              auto time =3D last_write_time(iter->path());=20
> >=20
> >              time_t tt =3D decltype(time)::clock::to_time_t(time);  //=
=20
> Note: to_time_t not guaranteed to exist.=20
> >=20
> >              tm tmt;=20
> >=20
> >              localtime_s(&tmt, &tt);=20
> >=20
> >=20
> >=20
> >              cout << std::put_time<wchar_t>(&tmt, L"%F %T") <<=20
> std::endl;=20
>
>
> It is sheer luck.  std::filesystem::file_time_type::clock is not specifie=
d=20
> to have the member function to_time_t.=20
>
> >=20
> >=20
> >=20
> > So the most pressing issue is that (at least according to=20
> cppreference.com) the std::filesystem::file_time_type::clock type only=20
> has to satisfy the TrivialClock concept, which does not imply that it has=
 a=20
> to_time_t method at all (i.e. it doesn't have to be the system_clock). Is=
=20
> this an oversight, an error in cppreference.com's description or am I=20
> missing some other way to convert the filesystem::file_time_type object t=
o=20
> a printable type? The code above is fairly similar to what replyers come =
up=20
> with on stack overflow: (
> https://stackoverflow.com/questions/12835577/how-to-convert-stdchronotime=
-point-to-calendar-datetime-string-with-fraction)=20
> so it seems that there is no more straight forward way.=20
> >=20
> >=20
> >=20
> > Apart from this specification problem I think that there should be a=20
> pure C++ way of formatting time_points that does not involve ancient C=20
> functions and multiple steps (getting higher precision than a second make=
s=20
> my code even more complicated).=20
>
> I=E2=80=99ve been working on a proposal to format and parse=20
> time_point<system_clock, Duration>.  Your post has inspired me to include=
=20
> I/O for file_time_type as well.=20
>
> > One way would be to provide an overload of put_time that takes a=20
> system_clock::time_point and a similar function that returns the formatte=
d=20
> string. A way to get sub-second fractions should be available as (%f is=
=20
> actually free according to strftime documentation at cppreference.com).=
=20
> As put_time is dependant on the locale facet imbued on the stream a strin=
g=20
> conversion function would probably need to have a locale parameter which=
=20
> defaults to the global locale of the process.=20
>
> One of the things I dislike about put_time is that it uses a std::tm to=
=20
> hold the time to be formatted.  This inherently limits the precision of t=
he=20
> output to seconds.  I see almost daily a desire to parse and format at=20
> precisions finer than a second.  And many modern file systems support=20
> subsecond resolution for their file timestamps.=20
>
> > A similar shortcut without C middlemen would be appropriate for scannin=
g=20
> time values, I presume.=20
>
> Absolutely.=20
>
> > In C++17 we got the new type timespec and the function to get the=20
> current time, timespec_get(). However there does not seem to be a link fr=
om=20
> this C struct (?) to any of the chrono functionality or filesystem times.=
=20
> Also there does not seem to exist a formatting function which handles=20
> formatting including the fractions (see the example here:=20
> http://en.cppreference.com/w/cpp/chrono/c/timespec_get).=20
>
> timespec is simply imported from C.  Imho it is born flawed as one doesn=
=E2=80=99t=20
> know whether a timespec is a time point or a time duration, and the C API=
=20
> uses it both ways.  I would not encourage the C community to embrace it f=
or=20
> that reason alone.=20
>
> I have been working on this library for a few years now:=20
>
> https://github.com/HowardHinnant/date=20
>
> It is fully documented, open-source, and has a small but growing communit=
y=20
> supporting it.  It does not replace <chrono>, and it does not build=20
> something in addition to <chrono>.  It builds on top of <chrono>, fully=
=20
> embracing it, and extending it into the realm of calendars.  It contains=
=20
> formatting and parsing for all reasonable precisions of=20
> time_point<sytem_clock, Duration>, as well as simple and efficient=20
> conversions between these time_points and calendar types such as=20
> year_month_day (a {year, month, day} struct).=20
>
> Use of it can be as simple as this:=20
>
>     #include "date.h"=20
>     #include <iostream>=20
>
>     int=20
>     main()=20
>     {=20
>         using namespace std::chrono;=20
>         using namespace date;=20
>         std::cout << system_clock::now() << '\n';=20
>     }=20
>
> which just output for me:=20
>
>     2017-06-08 00:34:40.718556=20
>
> On my platform, system_clock::time_point has microseconds precision.  If=
=20
> on your platform it has nanoseconds precision, that is the precision you=
=E2=80=99ll=20
> see by default on streaming.=20
>
> I believe I can easily do the same for file_time_type.=20
>
> If you want custom formatting, that is easy too:=20
>
>     std::cout << format("%a, %b %d, %Y at %I:%M %p", system_clock::now())=
=20
> << '\n=E2=80=99;=20
>
>     Thu, Jun 08, 2017 at 12:34 AM=20
>
> This library supports a superset of the strftime formatting flags,=20
> including the ability to control the precision of the output:=20
>
>     std::cout << format("%F %T", floor<milliseconds>(system_clock::now())=
)=20
> << '\n=E2=80=99;=20
>
>     2017-06-08 00:34:40.718=20
>
> And yes, there=E2=80=99s parsing too:=20
>
>     #include "date.h"=20
>     #include <cassert>=20
>     #include <iostream>=20
>     #include <sstream>=20
>
>     int=20
>     main()=20
>     {=20
>         using namespace std::chrono;=20
>         using namespace date;=20
>         std::istringstream ss{"2017-06-08 00:34:40.718556"};=20
>         system_clock::time_point tp;=20
>         ss >> parse("%F %T", tp);=20
>         assert(tp =3D=3D sys_days{2017_y/jun/8} + 34min + 40s + 718556us)=
;=20
>     }=20
>
> And as you can see above in the assert, it is easy to build=20
> system_clock::time_points out of field information (year, month, day, hou=
r,=20
> etc).=20
>
> I see two ways to go on file_time_type:=20
>
> 1.  Provide bidirectional conversions to time_point<system_clock, D>, and=
=20
> then do all of the I/O and calendar stuff with system_clock.=20
>
> 2.  Provide I/O and calendar interoperability on file_time_type directly,=
=20
> just like I=E2=80=99ve done for time_point<system_clock, D>.=20
>
> 1 would be easier for the implementor and proposer (me).  But I think 2=
=20
> might be the higher quality solution.  I will give this more thought.  Th=
e=20
> latter will introduce more types, such as file_time_days, adding more wor=
k=20
> for calendar authors (the civil calendar isn=E2=80=99t the only one).  Hm=
m=E2=80=A6=20
>
> 3.  Provide only I/O for file_time_type, and not calendar=20
> interoperability.  This would mean you could not easily create a=20
> file_time_type for a specific year/month/day hh:mm:ss, nor could you easi=
ly=20
> extract such fields from a file_time_type, though you could observe them =
by=20
> printing them out.=20
>
> Howard=20
>
>

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/b075080f-87f4-42f8-bc37-9747615966c7%40isocpp.or=
g.

------=_Part_787_1853863326.1496958882662
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Howard,<div><br></div><div>it is very good that you have t=
his type of functionality in the wings. I don&#39;t see how you can make th=
is work for file_time_type if it does not specify a way to convert to wall =
clock time. Maybe some part of the chrono interface is still eluding me... =
I understand that you can get a duration from the epoch of the file_time_ty=
pe::clock to the time point, but I don&#39;t see a way to know what the epo=
ch of an unspecified clock actually is. In reality I guess this is not a pr=
oblem, but specificationwise it may be. However, if the date library gets s=
tandardized as part of C++ this would of course be relatively easy to fix i=
n the process.</div><div><br></div><div><br></div><div>Here are some commen=
ts when reading the date library documentation at:=C2=A0<a href=3D"https://=
howardhinnant.github.io/date/date.html">https://howardhinnant.github.io/dat=
e/date.html</a>, mostly motivated by its route towards standardization. Adm=
ittedly I haven&#39;t read the P0355r2 proposal, comments are solely relate=
d to the documentation mentioned here.</div><div><br></div><div>- It seems =
that the procedure for creating year_month_day may be a little overworked, =
involving several other data types with overloaded / operators and user def=
ined literals. Also, if you don&#39;t &quot;use&quot; the date namespace an=
d this gets standardized all those types will have long names like std::dat=
e::year, or maybe std::chrono::year if this functionality is integrated wit=
h chrono. As these names are the same as the usual names you would prefer t=
o use for your variables it can get messy, and with a using statement it do=
wnright clashes and you have to give your variables cryptic names.</div><di=
v><br></div><div>void MyFunction(int year, int month, int day)</div><div>{<=
/div><div>=C2=A0 =C2=A0 auto dt =3D std::date::year(year) / month / day;</d=
iv><div>}</div><div><br></div><div>also the use of the slash operator is no=
t that obvious as many parts of the world (and ISO8601) are more at ease wi=
th using - between the parts. Using an overloaded operator when the operati=
on is not consistent with the usual meaning of the operator is also general=
ly discouraged (No, I don&#39;t like path / path either). Maybe use + as it=
 is neutral between different notations of dates and actually seems to be c=
onsistent: You are actually adding years, days and months to make a complet=
e date. On the other hand doing this without first casting all the ints to =
their corresponding year, day and month types seems strange if you view it =
as addition.</div><div><br></div><div>A library which is more complicated t=
han its task warrants risks not being used as the benefit may not outweigh =
the learning curve. I would more favor one user defined literal _date which=
 takes a string in ISO-6801 format and returns a date_time object. As you p=
oint out we already have one of those in system_clock::time_point. However,=
 this is what you define as a serial-based representation, so why not have =
a field-based representation of the complete time_point, and ways to conver=
t between the two. Having to do a floor operation, a subtraction and two co=
nversions from serial to field based types seems to be to ask too much of t=
he user.</div><div><br></div><div>- The *_last types also seem a bit unnece=
ssary, while a way to inquiry the number of days of a given month is a must=
.. I don&#39;t understand how to do that easily with this library. That&#39;=
s part of the learning curve I wrote about above -- simple things should be=
 simple.</div><div><br></div><div>- I fail also (sorry) to see the importan=
ce of the year_month_weekday type, although it is important to be able to a=
sk what weekday a certain date is. Well, maybe sometimes you may want to ge=
t the date of the third sunday of March of 2017 but it is not so easy to fi=
nd a plausible use case. With this library asking what weekday a date is do=
es not seem particularly simple as each field-based type can only report th=
e fields it has. Here is what I think would be needed:</div><div><br></div>=
<div>date::year_month_day date =3D date::year(2017)/2/4;</div><div>date::ye=
ar_month_weekday wdate =3D date::sys_days(date);</div><div>return wdate.wee=
kday();</div><div><br></div><div>In wxWidgets, by contrast, you can do:</di=
v><div><br></div><div>wxDate date(2, 4, 2017);</div><div>return date.GetDay=
OfWeek();</div><div><br></div><div>This level of simplicity is what we shou=
ld strive for. Maybe the gist of what I&#39;m trying to say here is that wh=
ile the internal representation of a datetime may be configurable for optim=
al performance of certain operations, it would be good if the API of the cl=
asses was the same. This could be viewed as fully specialized instances of =
a template class with an enum template parameter:</div><div><br></div><div>=
enum class datetime_representation {</div><div>=C2=A0 =C2=A0 linear,</div><=
div>=C2=A0 =C2=A0 year_month_day.</div><div>=C2=A0 =C2=A0 year_month_weekda=
y,</div><div>=C2=A0 =C2=A0 year_week_day</div><div>};</div><div><br></div><=
div>template&lt;datetime_representation =3D linear&gt; class datetime {</di=
v><div>=C2=A0 =C2=A0 // Lots of methods to set and get the different parts,=
 with equal behaviour but different performance.</div><div>=C2=A0 =C2=A0 //=
 Implementations of methods exist only in specializations</div><div>};</div=
><div><br></div><div><br></div><div>Now back to more nitpicking:</div><div>=
<br></div><div>- The definition of months (the duration) is a bit scary as =
it relates to an &quot;average month length&quot; which means that it will =
not accurately represent the current month when used as a duration from a y=
ear&#39;s start. Is it really needed? I guess the same can be said for year=
s, which tries to subsume the concept of leap years but where presumably th=
e number of years since the start of another year can be off by one on Jan =
1 or Dec 31.<br></div><div><br></div><div>- I&#39;m undecided on whether to=
 prefer your to_stream() idea or an overload of the put_time() manipulator.=
 I think both may well be outflanked by a general format() function (see be=
low).<br></div><div><br></div><div>- It seems strange to me that the 12/24 =
hour format is part of the time_of_day object. Shouldn&#39;t this be a form=
atting issue when converting to a string rather than a member of the object=
?</div><div><br></div><div>- In general I don&#39;t like the idea of having=
 different specializations with different API (such as time_of_day&lt;minut=
es&gt; having a minutes() function while time_of_day&lt;hours&gt; has not).=
 Maybe minutes() could always exist but return 0 for a hour-only specializa=
tion? I understand it as your idea being to save implementation bits when n=
ot needed.</div><div><br></div><div>- format() should take its fmt paramete=
r as a basic_string_view. [this is likely fixed in the standardization prop=
osal]</div><div><br></div><div>- Maybe it would be better if format&#39;s c=
har types for the returned string and for the fmt parameter were decoupled.=
 I write maybe as this decoupling would require callers to explicitly name =
the char type they want for the returned string. A name convention as used =
for basic_string itself could solve this, possibly.</div><div><br></div><di=
v>- The name format() could be a bit too generic, especially if the format(=
&quot;{}, is a nice {}&quot;, ...) proposal gets standardized. Instead I wo=
uld suggest integrating the functionality intended here into a general form=
at() method so that the formatting parameters are &quot;strftime like&quot;=
 if the corresponding argument is of a date/time related type as proposed h=
ere. This would also work nicely with string translation, so that locale sp=
ecific formats can be used if needed (without involving a locale parameter)=
..</div><div><br></div><div>- A problem with parsing dates entered by users =
is that persons tend to not type dates in a coherent way. A remedy I have u=
sed is to allow multiple format strings which are tried in succession. This=
 could fall outside a standard library but as the standard allows for two d=
istinct output formats per locale it does not seem too far fetched to allow=
 at least two on input. One possible way to define this would be to reserve=
 one character, such as | as a separator in format strings when used for in=
put, with the meaning that each | separated part is one complete format to =
be tried in order. Obviously it would be up to the programmer to place the =
formats in a suitable order to avoid ambiguities.</div><div><br></div><div>=
<br></div><div><br></div><div><br></div><div><br><br>Den torsdag 8 juni 201=
7 kl. 02:57:11 UTC+2 skrev Howard Hinnant:<blockquote class=3D"gmail_quote"=
 style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-=
left: 1ex;">On Jun 7, 2017, at 5:42 PM, Bengt Gustafsson &lt;<a href=3D"jav=
ascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"HgdpXYYOAQAJ" rel=3D"n=
ofollow" onmousedown=3D"this.href=3D&#39;javascript:&#39;;return true;" onc=
lick=3D"this.href=3D&#39;javascript:&#39;;return true;">bengt.gu...@beamway=
s.com</a><wbr>&gt; wrote:
<br>&gt;=20
<br>&gt; Sometimes, such as when presenting a directory listing, there is a=
 need to convert a file time to a string.
<br>&gt;=20
<br>&gt; This is ridiculously complicated when using the std::filesystem li=
brary, and in fact, it seems to be sheer luck that this even compiles:
<br>&gt;=20
<br>&gt; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0auto time =3D last=
_write_time(iter-&gt;path());
<br>&gt;=20
<br>&gt; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0time_t tt =3D decl=
type(time)::clock::to_<wbr>time_t(time); =C2=A0// Note: to_time_t not guara=
nteed to exist.
<br>&gt;=20
<br>&gt; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0tm tmt;
<br>&gt;=20
<br>&gt; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0localtime_s(&amp;t=
mt, &amp;tt);
<br>&gt;=20
<br>&gt;=20
<br>&gt;=20
<br>&gt; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0cout &lt;&lt; std:=
:put_time&lt;wchar_t&gt;(&amp;tmt, L&quot;%F %T&quot;) &lt;&lt; std::endl;
<br>
<br>
<br>It is sheer luck. =C2=A0std::filesystem::file_time_<wbr>type::clock is =
not specified to have the member function to_time_t.
<br>
<br>&gt;=20
<br>&gt;=20
<br>&gt;=20
<br>&gt; So the most pressing issue is that (at least according to <a href=
=3D"http://cppreference.com" target=3D"_blank" rel=3D"nofollow" onmousedown=
=3D"this.href=3D&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fcppreferen=
ce.com\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFfMEVsriPdiSLWG49XWK9zX_c5Ug=
&#39;;return true;" onclick=3D"this.href=3D&#39;http://www.google.com/url?q=
\x3dhttp%3A%2F%2Fcppreference.com\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNF=
fMEVsriPdiSLWG49XWK9zX_c5Ug&#39;;return true;">cppreference.com</a>) the st=
d::filesystem::file_time_<wbr>type::clock type only has to satisfy the Triv=
ialClock concept, which does not imply that it has a to_time_t method at al=
l (i.e. it doesn&#39;t have to be the system_clock). Is this an oversight, =
an error in <a href=3D"http://cppreference.com" target=3D"_blank" rel=3D"no=
follow" onmousedown=3D"this.href=3D&#39;http://www.google.com/url?q\x3dhttp=
%3A%2F%2Fcppreference.com\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFfMEVsriP=
diSLWG49XWK9zX_c5Ug&#39;;return true;" onclick=3D"this.href=3D&#39;http://w=
ww.google.com/url?q\x3dhttp%3A%2F%2Fcppreference.com\x26sa\x3dD\x26sntz\x3d=
1\x26usg\x3dAFQjCNFfMEVsriPdiSLWG49XWK9zX_c5Ug&#39;;return true;">cpprefere=
nce.com</a>&#39;s description or am I missing some other way to convert the=
 filesystem::file_time_type object to a printable type? The code above is f=
airly similar to what replyers come up with on stack overflow: (<a href=3D"=
https://stackoverflow.com/questions/12835577/how-to-convert-stdchronotime-p=
oint-to-calendar-datetime-string-with-fraction" target=3D"_blank" rel=3D"no=
follow" onmousedown=3D"this.href=3D&#39;https://www.google.com/url?q\x3dhtt=
ps%3A%2F%2Fstackoverflow.com%2Fquestions%2F12835577%2Fhow-to-convert-stdchr=
onotime-point-to-calendar-datetime-string-with-fraction\x26sa\x3dD\x26sntz\=
x3d1\x26usg\x3dAFQjCNHVLRsAzMvBENXLpG_4c-D_1cmdSQ&#39;;return true;" onclic=
k=3D"this.href=3D&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fstackov=
erflow.com%2Fquestions%2F12835577%2Fhow-to-convert-stdchronotime-point-to-c=
alendar-datetime-string-with-fraction\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQ=
jCNHVLRsAzMvBENXLpG_4c-D_1cmdSQ&#39;;return true;">https://stackoverflow.co=
m/<wbr>questions/12835577/how-to-<wbr>convert-stdchronotime-point-<wbr>to-c=
alendar-datetime-string-<wbr>with-fraction</a>) so it seems that there is n=
o more straight forward way.
<br>&gt;=20
<br>&gt;=20
<br>&gt;=20
<br>&gt; Apart from this specification problem I think that there should be=
 a pure C++ way of formatting time_points that does not involve ancient C f=
unctions and multiple steps (getting higher precision than a second makes m=
y code even more complicated).
<br>
<br>I=E2=80=99ve been working on a proposal to format and parse time_point&=
lt;system_clock, Duration&gt;. =C2=A0Your post has inspired me to include I=
/O for file_time_type as well.
<br>
<br>&gt; One way would be to provide an overload of put_time that takes a s=
ystem_clock::time_point and a similar function that returns the formatted s=
tring. A way to get sub-second fractions should be available as (%f is actu=
ally free according to strftime documentation at <a href=3D"http://cpprefer=
ence.com" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.href=3D&#3=
9;http://www.google.com/url?q\x3dhttp%3A%2F%2Fcppreference.com\x26sa\x3dD\x=
26sntz\x3d1\x26usg\x3dAFQjCNFfMEVsriPdiSLWG49XWK9zX_c5Ug&#39;;return true;"=
 onclick=3D"this.href=3D&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fcp=
preference.com\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFfMEVsriPdiSLWG49XWK=
9zX_c5Ug&#39;;return true;">cppreference.com</a>). As put_time is dependant=
 on the locale facet imbued on the stream a string conversion function woul=
d probably need to have a locale parameter which defaults to the global loc=
ale of the process.
<br>
<br>One of the things I dislike about put_time is that it uses a std::tm to=
 hold the time to be formatted. =C2=A0This inherently limits the precision =
of the output to seconds. =C2=A0I see almost daily a desire to parse and fo=
rmat at precisions finer than a second. =C2=A0And many modern file systems =
support subsecond resolution for their file timestamps.
<br>
<br>&gt; A similar shortcut without C middlemen would be appropriate for sc=
anning time values, I presume.
<br>
<br>Absolutely.
<br>
<br>&gt; In C++17 we got the new type timespec and the function to get the =
current time, timespec_get(). However there does not seem to be a link from=
 this C struct (?) to any of the chrono functionality or filesystem times. =
Also there does not seem to exist a formatting function which handles forma=
tting including the fractions (see the example here: <a href=3D"http://en.c=
ppreference.com/w/cpp/chrono/c/timespec_get" target=3D"_blank" rel=3D"nofol=
low" onmousedown=3D"this.href=3D&#39;http://www.google.com/url?q\x3dhttp%3A=
%2F%2Fen.cppreference.com%2Fw%2Fcpp%2Fchrono%2Fc%2Ftimespec_get\x26sa\x3dD\=
x26sntz\x3d1\x26usg\x3dAFQjCNG_rdqnw4e9h_-gmv3O3rxugrV6bg&#39;;return true;=
" onclick=3D"this.href=3D&#39;http://www.google.com/url?q\x3dhttp%3A%2F%2Fe=
n.cppreference.com%2Fw%2Fcpp%2Fchrono%2Fc%2Ftimespec_get\x26sa\x3dD\x26sntz=
\x3d1\x26usg\x3dAFQjCNG_rdqnw4e9h_-gmv3O3rxugrV6bg&#39;;return true;">http:=
//en.cppreference.com/w/<wbr>cpp/chrono/c/timespec_get</a>).
<br>
<br>timespec is simply imported from C. =C2=A0Imho it is born flawed as one=
 doesn=E2=80=99t know whether a timespec is a time point or a time duration=
, and the C API uses it both ways. =C2=A0I would not encourage the C commun=
ity to embrace it for that reason alone.
<br>
<br>I have been working on this library for a few years now:
<br>
<br><a href=3D"https://github.com/HowardHinnant/date" target=3D"_blank" rel=
=3D"nofollow" onmousedown=3D"this.href=3D&#39;https://www.google.com/url?q\=
x3dhttps%3A%2F%2Fgithub.com%2FHowardHinnant%2Fdate\x26sa\x3dD\x26sntz\x3d1\=
x26usg\x3dAFQjCNHEHQzEBOwPYMsGqdYMBTeo_IQuwA&#39;;return true;" onclick=3D"=
this.href=3D&#39;https://www.google.com/url?q\x3dhttps%3A%2F%2Fgithub.com%2=
FHowardHinnant%2Fdate\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNHEHQzEBOwPYMs=
GqdYMBTeo_IQuwA&#39;;return true;">https://github.com/<wbr>HowardHinnant/da=
te</a>
<br>
<br>It is fully documented, open-source, and has a small but growing commun=
ity supporting it. =C2=A0It does not replace &lt;chrono&gt;, and it does no=
t build something in addition to &lt;chrono&gt;. =C2=A0It builds on top of =
&lt;chrono&gt;, fully embracing it, and extending it into the realm of cale=
ndars. =C2=A0It contains formatting and parsing for all reasonable precisio=
ns of time_point&lt;sytem_clock, Duration&gt;, as well as simple and effici=
ent conversions between these time_points and calendar types such as year_m=
onth_day (a {year, month, day} struct).
<br>
<br>Use of it can be as simple as this:
<br>
<br>=C2=A0 =C2=A0 #include &quot;date.h&quot;
<br>=C2=A0 =C2=A0 #include &lt;iostream&gt;
<br>
<br>=C2=A0 =C2=A0 int
<br>=C2=A0 =C2=A0 main()
<br>=C2=A0 =C2=A0 {
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 using namespace std::chrono;
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 using namespace date;
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 std::cout &lt;&lt; system_clock::now() &lt;=
&lt; &#39;\n&#39;;
<br>=C2=A0 =C2=A0 }
<br>
<br>which just output for me:
<br>
<br>=C2=A0 =C2=A0 2017-06-08 00:34:40.718556
<br>
<br>On my platform, system_clock::time_point has microseconds precision. =
=C2=A0If on your platform it has nanoseconds precision, that is the precisi=
on you=E2=80=99ll see by default on streaming.
<br>
<br>I believe I can easily do the same for file_time_type.
<br>
<br>If you want custom formatting, that is easy too:
<br>
<br>=C2=A0 =C2=A0 std::cout &lt;&lt; format(&quot;%a, %b %d, %Y at %I:%M %p=
&quot;, system_clock::now()) &lt;&lt; &#39;\n=E2=80=99;
<br>
<br>=C2=A0 =C2=A0 Thu, Jun 08, 2017 at 12:34 AM
<br>
<br>This library supports a superset of the strftime formatting flags, incl=
uding the ability to control the precision of the output:
<br>
<br>=C2=A0 =C2=A0 std::cout &lt;&lt; format(&quot;%F %T&quot;, floor&lt;mil=
liseconds&gt;(system_<wbr>clock::now())) &lt;&lt; &#39;\n=E2=80=99;
<br>
<br>=C2=A0 =C2=A0 2017-06-08 00:34:40.718
<br>
<br>And yes, there=E2=80=99s parsing too:
<br>
<br>=C2=A0 =C2=A0 #include &quot;date.h&quot;
<br>=C2=A0 =C2=A0 #include &lt;cassert&gt;
<br>=C2=A0 =C2=A0 #include &lt;iostream&gt;
<br>=C2=A0 =C2=A0 #include &lt;sstream&gt;
<br>
<br>=C2=A0 =C2=A0 int
<br>=C2=A0 =C2=A0 main()
<br>=C2=A0 =C2=A0 {
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 using namespace std::chrono;
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 using namespace date;
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 std::istringstream ss{&quot;2017-06-08 00:3=
4:40.718556&quot;};
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 system_clock::time_point tp;
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 ss &gt;&gt; parse(&quot;%F %T&quot;, tp);
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 assert(tp =3D=3D sys_days{2017_y/jun/8} + 3=
4min + 40s + 718556us);
<br>=C2=A0 =C2=A0 }
<br>
<br>And as you can see above in the assert, it is easy to build system_cloc=
k::time_points out of field information (year, month, day, hour, etc).
<br>
<br>I see two ways to go on file_time_type:
<br>
<br>1. =C2=A0Provide bidirectional conversions to time_point&lt;system_cloc=
k, D&gt;, and then do all of the I/O and calendar stuff with system_clock.
<br>
<br>2. =C2=A0Provide I/O and calendar interoperability on file_time_type di=
rectly, just like I=E2=80=99ve done for time_point&lt;system_clock, D&gt;.
<br>
<br>1 would be easier for the implementor and proposer (me). =C2=A0But I th=
ink 2 might be the higher quality solution. =C2=A0I will give this more tho=
ught. =C2=A0The latter will introduce more types, such as file_time_days, a=
dding more work for calendar authors (the civil calendar isn=E2=80=99t the =
only one). =C2=A0Hmm=E2=80=A6
<br>
<br>3. =C2=A0Provide only I/O for file_time_type, and not calendar interope=
rability. =C2=A0This would mean you could not easily create a file_time_typ=
e for a specific year/month/day hh:mm:ss, nor could you easily extract such=
 fields from a file_time_type, though you could observe them by printing th=
em out.
<br>
<br>Howard
<br>
<br></blockquote></div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/b075080f-87f4-42f8-bc37-9747615966c7%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/b075080f-87f4-42f8-bc37-9747615966c7=
%40isocpp.org</a>.<br />

------=_Part_787_1853863326.1496958882662--

------=_Part_786_1440572918.1496958882661--

.


Author: Howard Hinnant <howard.hinnant@gmail.com>
Date: Thu, 8 Jun 2017 21:05:38 -0400
Raw View
--Apple-Mail=_B7DE5083-26D7-48E7-A1F9-C96D513177F8
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset="UTF-8"

Hi Bengt,

Thanks for your feedback.  Just a few clarifications below:

On Jun 8, 2017, at 5:54 PM, Bengt Gustafsson <bengt.gustafsson@beamways.com=
> wrote:

> - It seems that the procedure for creating year_month_day may be a little=
 overworked, involving several other data types with overloaded / operators=
 and user defined literals. Also, if you don't "use" the date namespace and=
 this gets standardized all those types will have long names like std::date=
::year, or maybe std::chrono::year if this functionality is integrated with=
 chrono. As these names are the same as the usual names you would prefer to=
 use for your variables it can get messy, and with a using statement it dow=
nright clashes and you have to give your variables cryptic names.
>=20
> void MyFunction(int year, int month, int day)
> {
>     auto dt =3D std::date::year(year) / month / day;
> }


The current proposal is to put these into namespace chrono.  And my current=
 C++11/14/17 usage of chrono almost always resorts to =E2=80=9Cusing namesp=
ace std::chrono=E2=80=9D at function scope as I=E2=80=99m already frustrate=
d with:

    auto min =3D std::chrono::time_point_cast<std::chrono::minutes>(std::ch=
rono::system_clock::now());

I write instead:

    using namespace std::chrono;
    auto min =3D time_point_cast<minutes>(system_clock::now());

With just one component needing qualification as in your example, I might n=
ot bother with the using declaration.  But by the time I have to qualify tw=
o components, I am so done with that.

You can also write MyFunction like this:

    void MyFunction(int y, int m, int d)
    {
        using namespace std::chrono;
        auto dt =3D year_month_day{year{year}, month{m}, day{d}};
    }

The overall picture, as with <chrono>, is to reduce to a minimum the conver=
sions you do between an untyped system (i.e. int) and a typed system where =
unit mixups are compile-time errors instead of run time errors:

    void MyFunction(std::chrono::year y, std::chrono::month m, std::chrono:=
:day d)
    {
        auto dt =3D y/m/d;
    }

Those conversion points, like reinterpret_cast, are the error-prone parts o=
f large code bases, for example:

    void AnotherFunction(int y, int m, int d, int h, int M, int s)
    {
         ...
         g(y, M, d, h, m, s);  // real easy to accidentally rearrange your =
units: run time error
         ...
    }

vs

    void AnotherFunction(year y, month m, day d, hours h, minutes M, second=
s s)
    {
         ...
         g(y, M, d, h, m, s);  // compile-time error
         ...
    }

Like <chrono> my lib continues the tradition of strong type safety to catch=
 as many errors as possible at compile-time.  We force people into such dan=
gerous conversion points today mostly with I/O, and so I=E2=80=99m trying t=
o alleviate that with good I/O support.


> also the use of the slash operator is not that obvious as many parts of t=
he world (and ISO8601) are more at ease with using - between the parts. Usi=
ng an overloaded operator when the operation is not consistent with the usu=
al meaning of the operator is also generally discouraged (No, I don't like =
path / path either). Maybe use + as it is neutral between different notatio=
ns of dates and actually seems to be consistent: You are actually adding ye=
ars, days and months to make a complete date. On the other hand doing this =
without first casting all the ints to their corresponding year, day and mon=
th types seems strange if you view it as addition.

+ and - have the wrong precedence:

    2017_y+jan - 2015_y+sep

vs

    2017_y/jan - 2015_y/sep =3D=3D months{16}

and can easily lead to confusing expressions like this:

    2015_y+sep+months{16}

vs

    2015_y/sep + months{16} =3D=3D 2017_y/jan

But if you really just don=E2=80=99t like the =E2=80=99/=E2=80=98 syntax, y=
ou=E2=80=99re not alone.  Others feel the same way.  Feel free to use the c=
onstructor syntax instead:

    year_month{2017_y, jan} - year_month{2015_y, sep} =3D=3D months{16}

or:

    year_month{year{2017}, month{1}} - year_month{year{2015}, month{9}} =3D=
=3D months{16}

instead of:

    2017_y/jan - 2015_y/sep =3D=3D months{16}

Just don=E2=80=99t tell everyone else that they _have_ to use the construct=
or syntax instead of the =E2=80=98/=E2=80=98 syntax (unless you want to enf=
orce that as a coding guideline on a project you=E2=80=99re in charge of). =
 Because there=E2=80=99s lots of people who really like the =E2=80=98/=E2=
=80=98 syntax.  This lib provides both, with no performance, functionality =
or type-safety penalties for using either.

> A library which is more complicated than its task warrants risks not bein=
g used as the benefit may not outweigh the learning curve.

True, that=E2=80=99s why I=E2=80=99ve been field testing this lib for a cou=
ple of years now.  The field testing is actually going pretty well.  This l=
ibrary strives for a simple, self-consistent API.  But simple doesn=E2=80=
=99t always mean =E2=80=9Cdo it the way it has always been done in the past=
=E2=80=9D, or even =E2=80=9Cdon=E2=80=99t have too many types.=E2=80=9D  My=
 experience from <chrono> is that many people said simple means =E2=80=9Cdo=
n=E2=80=99t use templates.=E2=80=9D.  And indeed, reading the <chrono> head=
er is a good way to get terrified of that library.  But the code people usu=
ally write with <chrono> is simple, readable and type-safe.  Ditto with thi=
s library that extends <chrono> to calendars.

I=E2=80=99m leaning heavily on modern features like auto and user-defined l=
iterals which reduce the need to remember so many type names:

    auto today    =3D 8_d/jun/2017;     // has type year_month_day
    auto tomorrow =3D fri[2]/jun/2017;  // has type year_month_weekday

Similarly, auto is of great help with <chrono> itself, in deducing the resu=
ltant type of =E2=80=9Cmixed-mode=E2=80=9D arithmetic across time_points an=
d durations of varying precisions.

> date::year_month_day date =3D date::year(2017)/2/4;
> date::year_month_weekday wdate =3D date::sys_days(date);
> return wdate.weekday();
>=20
> In wxWidgets, by contrast, you can do:
>=20
> wxDate date(2, 4, 2017);
> return date.GetDayOfWeek();

This will do it;

    using namespace date::literals;
    return date::weekday{feb/4/2017};  // or did you mean 2_d/apr/2017? so =
hard to tell when your only tool is int

> This level of simplicity is what we should strive for.

The wxWidgets code is actually unreadable to me.  I can not read that and k=
now what date you mean without breaking out the wxWidgets documentation.  S=
uch ambiguity is not possible in my date lib.  Ambiguity is a compile-time =
error.

> Maybe the gist of what I'm trying to say here is that while the internal =
representation of a datetime may be configurable for optimal performance of=
 certain operations, it would be good if the API of the classes was the sam=
e. This could be viewed as fully specialized instances of a template class =
with an enum template parameter:
>=20
> enum class datetime_representation {
>     linear,
>     year_month_day.
>     year_month_weekday,
>     year_week_day
> };
>=20
> template<datetime_representation =3D linear> class datetime {
>     // Lots of methods to set and get the different parts, with equal beh=
aviour but different performance.
>     // Implementations of methods exist only in specializations
> };

I feel pretty strongly that this library should build on <chrono>.  The cen=
tral theme of this library is that time_point<system_clock, Duration> _is_ =
the =E2=80=9Clinear=E2=80=9D datetime representation.  Choose any precision=
 you want, it is already in your <chrono> header.  Everything else is just =
helpers for converting to and from calendars.  And that very design decisio=
n is what will make I/O on file_time_type so convenient, functional and eas=
y.

>=20
>=20
> Now back to more nitpicking:
>=20
> - The definition of months (the duration) is a bit scary as it relates to=
 an "average month length" which means that it will not accurately represen=
t the current month when used as a duration from a year's start. Is it real=
ly needed? I guess the same can be said for years, which tries to subsume t=
he concept of leap years but where presumably the number of years since the=
 start of another year can be off by one on Jan 1 or Dec 31.

months can be used both as a chrono::duration (when used with a chrono time=
_point), getting what you describe above.  This is useful for doing chronol=
ogical computations on physical processes that don=E2=80=99t respect human =
calendars (e.g. changing weather patterns or mammalian gestation periods). =
 For example:

    auto t =3D system_clock::now() + months{18};  // about 18 months from n=
ow

months can also be used as a calendrical duration when used with calendrica=
l types and subtypes such as year_month_day and year_month.  This is useful=
 for doing calendrical computations when you require days of the month to m=
atch up, for example:

    static_assert(2017_y/jan/3 + months{18} =3D=3D jul/3/2018);

Both chronological and calendrical use cases have value, and are easy to do=
..

> - It seems strange to me that the 12/24 hour format is part of the time_o=
f_day object. Shouldn't this be a formatting issue when converting to a str=
ing rather than a member of the object?

This may well disappear.  time_of_day was born as a formatting aid, and pre=
dates the more generalized format function.

>=20
> - In general I don't like the idea of having different specializations wi=
th different API (such as time_of_day<minutes> having a minutes() function =
while time_of_day<hours> has not). Maybe minutes() could always exist but r=
eturn 0 for a hour-only specialization? I understand it as your idea being =
to save implementation bits when not needed.

The different types have come in useful in the same manner that different t=
ypes are useful for durations, instead of just say timespec.  But the major=
 client of time_of_day has in practice been format/parse, and so time_of_da=
y may not need to be part of the API.  That being said, some clients like t=
o do their own formatting/parsing and time_of_day is useful for them.

>=20
> - format() should take its fmt parameter as a basic_string_view. [this is=
 likely fixed in the standardization proposal]

Agreed.  I haven=E2=80=99t done so in the lib as I get a fair number of req=
uests to support older compilers.  I have a small but growing list of such =
details that should change for the proposal (the next revision of which I n=
eed to finish within a week and a half).

>=20
> - Maybe it would be better if format's char types for the returned string=
 and for the fmt parameter were decoupled. I write maybe as this decoupling=
 would require callers to explicitly name the char type they want for the r=
eturned string. A name convention as used for basic_string itself could sol=
ve this, possibly.

Nope.  That design has already irritated me enough when trying to write gen=
eric code with to_string/to_wstring.

>=20
> - The name format() could be a bit too generic, especially if the format(=
"{}, is a nice {}", ...) proposal gets standardized.

Agreed, though overloading with the type-safe arguments may also address th=
is issue.

> Instead I would suggest integrating the functionality intended here into =
a general format() method so that the formatting parameters are "strftime l=
ike" if the corresponding argument is of a date/time related type as propos=
ed here. This would also work nicely with string translation, so that local=
e specific formats can be used if needed (without involving a locale parame=
ter).

I anticipate a cooperative integration of these two libraries if they both =
find their way into the standardization process.  I think there could be a =
strong synergy there.

>=20
> - A problem with parsing dates entered by users is that persons tend to n=
ot type dates in a coherent way. A remedy I have used is to allow multiple =
format strings which are tried in succession. This could fall outside a sta=
ndard library but as the standard allows for two distinct output formats pe=
r locale it does not seem too far fetched to allow at least two on input. O=
ne possible way to define this would be to reserve one character, such as |=
 as a separator in format strings when used for input, with the meaning tha=
t each | separated part is one complete format to be tried in order. Obviou=
sly it would be up to the programmer to place the formats in a suitable ord=
er to avoid ambiguities.

I can=E2=80=99t reserve =E2=80=9C|=E2=80=9D, but I could reserve =E2=80=9C%=
|=E2=80=9D.  Or perhaps multiple parse fmt string arguments?  Would not be =
difficult to write as an add-on.  Here=E2=80=99s how I did this with two pa=
rsing formats:

https://stackoverflow.com/a/38839725/576911

Interesting idea, thanks.

Howard


--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/9FA3C088-B730-43A1-834D-19933FDE2BE6%40gmail.com=
..

--Apple-Mail=_B7DE5083-26D7-48E7-A1F9-C96D513177F8
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename=signature.asc
Content-Type: application/pgp-signature;
 name=signature.asc
Content-Description: Message signed with OpenPGP

-----BEGIN PGP SIGNATURE-----

iQIcBAEBCAAGBQJZOfRjAAoJEGbcHCxKqhWCgoMP/RqhIPstay84sw1XeKvOLK8x
hioZpNQSop8JEBm1Mt7Vq6zY1nfGFbN10Xf+V4VdrU3YKLldJ+gN+oxRO7f/X2d8
VVJocglEoY4ozP/3bezZCvKeeCq+B3JyvP4xbpUrCSwGM2vQA99spYRoIgT/XlJz
QjkmELVN0HnJp1pjJIIOrwxYTlSM6zjRz03b09+bk2kmceYzzPjK31pmhtMnjUah
yQBi1YZhGiCQ3Xsuc+4VA9O6a01y856ctHFRJLjOQjSK0P5dx0H4vpb+chsq3sAI
AzwwJTj7Vt/aP4T+0v85Cs3zUXzoAe4e7oRQ/RTczgym95pseYJrbVq0OjFIWw55
IzFAipRmjzlZYBt83kUbluGAv6U3ojcFNr3dwA2gj+W3PEdCKfwil0T1SZmvKwGS
S07Mz2WXQtAiDcos/T+oJPMmYrQJx5oFlxnpb2hVe0YxSLMIj0b3SQ25YRJhu5Gh
2EWCBPEYrsVj46ZBhqPiMSurrUHOyNZMi97oWLY+IrdOAoM9anLG5QB9Tp2XQKjh
1wCHajrnCShxHYpGkXxfAAXJkoEDPspwaWwh35a8MjUamoe1yeXfwQn2yr7YsfRQ
BlZRkXOkJTAcM2PSyRdh/BxW6jzAkbPh1hIFMDtPTGeSkZrd2jijOinLr2/uG5LM
oTgeAFDFsdyzHM6Roo4B
=9qyB
-----END PGP SIGNATURE-----

--Apple-Mail=_B7DE5083-26D7-48E7-A1F9-C96D513177F8--

.


Author: Bengt Gustafsson <bengt.gustafsson@beamways.com>
Date: Sat, 10 Jun 2017 14:58:51 -0700 (PDT)
Raw View
------=_Part_183_395913651.1497131932065
Content-Type: multipart/alternative;
 boundary="----=_Part_184_465116176.1497131932066"

------=_Part_184_465116176.1497131932066
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable


>
> > - It seems that the procedure for creating year_month_day may be a=20
> little overworked, involving several other data types with overloaded /=
=20
> operators and user defined literals. Also, if you don't "use" the date=20
> namespace and this gets standardized all those types will have long names=
=20
> like std::date::year, or maybe std::chrono::year if this functionality is=
=20
> integrated with chrono. As these names are the same as the usual names yo=
u=20
> would prefer to use for your variables it can get messy, and with a using=
=20
> statement it downright clashes and you have to give your variables crypti=
c=20
> names.
>

I think we may have to disagree on this. For me <chrono> seems very much=20
too complicated for what it actually offers most users. I can see that to=
=20
cater for every usage in the universe with utmost storage space efficiency=
=20
you may have to make everything a template like this, but for a vast=20
majority of uses using double for both time_point and duration would have=
=20
sufficed. The precision is microseconds in a century which must be well=20
beyond most needs. Alternatively a 64 bit integer representation similar to=
=20
timespec with suitable functions and operators. As 64 bits gives nanosecond=
=20
precision for 580 years there seems to be little need for anything else=20
outside very specific physics areas.

While you with your intimate knowledge of <chrono> may find it easy to use=
=20
as you have the whole history of developing it to fall back on, it surely=
=20
is not easy to grasp when you start to use it. I think it was Bjarne who=20
stated it so aptly: "Let's not confuse familiarity with simplicity".=20
Everything can't be expected to be done in simple ways, but getting the=20
current time can.

Much of the problem seems to be that the standard does not define: a) a way=
=20
to know the resolution of a clock object, b) the epoch of a clock object as=
=20
a date. Without this information it is very hard
to get a wall clock time out of a clock object and know what precision I=20
have. Surely, I can do a duration cast to nanoseconds, but I don't know=20
what precision I actually get. As for the epoch it seems that the only way=
=20
is to retrieve the time_t (only available on system_clock) which is defined=
=20
to be relative to 1970-01-01. So to get the number of seconds since this=20
epoch with decimals the minimum is to do:

double GetCurrentTime() {
    system_clock::time_point n =3D system_clock::now();
    time_t st =3D system_clock::to_time_t(n);
    int nanoseconds =3D duration_cast<nanoseconds>(n) -=20
duration_cast<nanoseconds>(seconds(st));
    return st + double(nanoseconds) * 0.000000001;
}

I still fail to call this simple. It took me 15 minutes to figure it out (I=
=20
have not compiled and tested) and I now have 12 browser history entries (on=
=20
cppreference.com) of where I have looked around to get this done. Then I=20
have done very similar things before so I'm not a complete newbie to=20
chrono. Still a few pain points: a) The result is of undefined precision,=
=20
it may not contain any decimals at all for instance. b) I don't feel=20
certain that the number of bits will be enough to convert all the seconds=
=20
from the epoch to nanoseconds before subtracting them to get only the=20
fraction of the last second. c) I still have to go to an age-old C type to=
=20
get the time anchored to the wall clock time.

That's why I would much more like <chrono> to get some more convenience=20
functions along the lines of GetCurrentTime() above than to *only *extend=
=20
it with even more stuff akin to its current features.

=20

> >=20
> > void MyFunction(int year, int month, int day)=20
> > {=20
> >     auto dt =3D std::date::year(year) / month / day;=20
> > }=20
>
>
> The current proposal is to put these into namespace chrono.  And my=20
> current C++11/14/17 usage of chrono almost always resorts to =E2=80=9Cusi=
ng=20
> namespace std::chrono=E2=80=9D at function scope as I=E2=80=99m already f=
rustrated with:=20
>
>     auto min =3D=20
> std::chrono::time_point_cast<std::chrono::minutes>(std::chrono::system_cl=
ock::now());=20
>
>
> I write instead:=20
>
>     using namespace std::chrono;=20
>     auto min =3D time_point_cast<minutes>(system_clock::now());
>

Sure you can use the namespace but  then you end up with "using" most of=20
the names you would want to use as identifiers in the context of working=20
with wall clock time, such as months, year, seconds etc.


> With just one component needing qualification as in your example, I might=
=20
> not bother with the using declaration.  But by the time I have to qualify=
=20
> two components, I am so done with that.=20
>
> You can also write MyFunction like this:=20
>
>     void MyFunction(int y, int m, int d)=20
>     {=20
>         using namespace std::chrono;=20
>         auto dt =3D year_month_day{year{year}, month{m}, day{d}};=20
>     }=20
>
> The overall picture, as with <chrono>, is to reduce to a minimum the=20
> conversions you do between an untyped system (i.e. int) and a typed syste=
m=20
> where unit mixups are compile-time errors instead of run time errors:=20
>
>     void MyFunction(std::chrono::year y, std::chrono::month m,=20
> std::chrono::day d)=20
>     {=20
>         auto dt =3D y/m/d;=20
>     }
>

Ok, I see your point here. I was a bit thrown off track by your examples=20
which only involved _literal_ integers rather than variables.


> Like <chrono> my lib continues the tradition of strong type safety to=20
> catch as many errors as possible at compile-time.=20


As I made obvious above the problem with chrono _today_ is not so much that=
=20
it has too many types but that too many things are left unspecified, which=
=20
makes it hard to relate to reality. What you find yourself
searching for are non-existant methods to ask for epochs, resolutions etc.=
=20
It is a well eastblished fact that you can waste a lot of time searching=20
for things that don't exist... which I think is a major reason chrono is=20
viewed as so hard to use. One typical example is that the file_time_type=20
type is unrelated to everything else, except that it is on _some_=20
TrivialClock which in itself is potentially unrelated to time_t, which as=
=20
of yet is the only way I have found to relate to a _known_ epoch.

=20

>  We force people into such dangerous conversion points today mostly with=
=20
> I/O, and so I=E2=80=99m trying to alleviate that with good I/O support.
>

I also dislike untyped data in general, so I will play along here.
=20

>
>
> > also the use of the slash operator is not that obvious as many parts of=
=20
> the world (and ISO8601) are more at ease with using - between the parts.=
=20
> Using an overloaded operator when the operation is not consistent with th=
e=20
> usual meaning of the operator is also generally discouraged (No, I don't=
=20
> like path / path either). Maybe use + as it is neutral between different=
=20
> notations of dates and actually seems to be consistent: You are actually=
=20
> adding years, days and months to make a complete date. On the other hand=
=20
> doing this without first casting all the ints to their corresponding year=
,=20
> day and month types seems strange if you view it as addition.=20
>
> + and - have the wrong precedence:=20
>

I see that now.=20


>     2017_y+jan - 2015_y+sep=20
>
> vs=20
>
>     2017_y/jan - 2015_y/sep =3D=3D months{16}=20
>
> and can easily lead to confusing expressions like this:=20
>
>     2015_y+sep+months{16}=20
>
> vs=20
>
>     2015_y/sep + months{16} =3D=3D 2017_y/jan=20
>
> But if you really just don=E2=80=99t like the =E2=80=99/=E2=80=98 syntax,=
 you=E2=80=99re not alone.=20
>  Others feel the same way.  Feel free to use the constructor syntax=20
> instead:=20
>
>     year_month{2017_y, jan} - year_month{2015_y, sep} =3D=3D months{16}=
=20
>
> or:=20
>
>     year_month{year{2017}, month{1}} - year_month{year{2015}, month{9}} =
=3D=3D=20
> months{16}=20
>
> instead of:=20
>
>     2017_y/jan - 2015_y/sep =3D=3D months{16}=20
>
> Just don=E2=80=99t tell everyone else that they _have_ to use the constru=
ctor=20
> syntax instead of the =E2=80=98/=E2=80=98 syntax (unless you want to enfo=
rce that as a=20
> coding guideline on a project you=E2=80=99re in charge of).  Because ther=
e=E2=80=99s lots=20
> of people who really like the =E2=80=98/=E2=80=98 syntax.  This lib provi=
des both, with no=20
> performance, functionality or type-safety penalties for using either. =20


> > A library which is more complicated than its task warrants risks not=20
> being used as the benefit may not outweigh the learning curve.=20
>
> True, that=E2=80=99s why I=E2=80=99ve been field testing this lib for a c=
ouple of years=20
> now.  The field testing is actually going pretty well.  This library=20
> strives for a simple, self-consistent API.  But simple doesn=E2=80=99t al=
ways mean=20
> =E2=80=9Cdo it the way it has always been done in the past=E2=80=9D, or e=
ven =E2=80=9Cdon=E2=80=99t have=20
> too many types.=E2=80=9D  My experience from <chrono> is that many people=
 said=20
> simple means =E2=80=9Cdon=E2=80=99t use templates.=E2=80=9D.  And indeed,=
 reading the <chrono>=20
> header is a good way to get terrified of that library.  But the code peop=
le=20
> usually write with <chrono> is simple, readable and type-safe. =20


Not for all important use cases, as shown above.
=20

> Ditto with this library that extends <chrono> to calendars.=20
>
> I=E2=80=99m leaning heavily on modern features like auto and user-defined=
 literals=20
> which reduce the need to remember so many type names:=20
>
>     auto today    =3D 8_d/jun/2017;     // has type year_month_day=20
>     auto tomorrow =3D fri[2]/jun/2017;  // has type year_month_weekday=20


> Similarly, auto is of great help with <chrono> itself, in deducing the=20
> resultant type of =E2=80=9Cmixed-mode=E2=80=9D arithmetic across time_poi=
nts and durations=20
> of varying precisions.=20
>
> > date::year_month_day date =3D date::year(2017)/2/4;=20
> > date::year_month_weekday wdate =3D date::sys_days(date);=20
> > return wdate.weekday();=20
> >=20
> > In wxWidgets, by contrast, you can do:=20
> >=20
> > wxDate date(2, 4, 2017);=20
> > return date.GetDayOfWeek();=20
>
> This will do it;=20
>
>     using namespace date::literals;=20
>     return date::weekday{feb/4/2017};  // or did you mean 2_d/apr/2017? s=
o=20
> hard to tell when your only tool is int
>

Ok, I was unaware that you can construct a weekday, (and I assume  day,=20
month, etc [upon reading date.h it seems I was assuming wrongly: only=20
weekday has this type of constructor]) a complete date and it will=20
"extract" the relevant information. That seems like a nice feature.

Can you also do:

    auto wd =3D date::day{system_clock::now()};  // Day in month right now

If not, why?



> > This level of simplicity is what we should strive for.=20
>
> The wxWidgets code is actually unreadable to me.  I can not read that and=
=20
> know what date you mean without breaking out the wxWidgets documentation.=
=20
>  Such ambiguity is not possible in my date lib.  Ambiguity is a=20
> compile-time error.
>

Unless you want to play hide and seek with the compiler you would still=20
need to open the documentation if you are not already a pro. With=20
wxDateTime you have all functionality related to dates and times in one=20
class and thus the documentation is similarly close by when you need it. Or=
=20
type a dot in the IDE if you forgot the exact method name and it will be=20
shown in a dropdown list, most likely. (No 12 history entries in your=20
browser).


>
> I feel pretty strongly that this library should build on <chrono>.  The=
=20
> central theme of this library is that time_point<system_clock, Duration>=
=20
> _is_ the =E2=80=9Clinear=E2=80=9D datetime representation.  Choose any pr=
ecision you want,=20
> it is already in your <chrono> header.  Everything else is just helpers f=
or=20
> converting to and from calendars.  And that very design decision is what=
=20
> will make I/O on file_time_type so convenient, functional and easy.
>
Lets hope for that.=20

>
> >=20
> >=20
> > Now back to more nitpicking:=20
> >=20
> > - The definition of months (the duration) is a bit scary as it relates=
=20
> to an "average month length" which means that it will not accurately=20
> represent the current month when used as a duration from a year's start. =
Is=20
> it really needed? I guess the same can be said for years, which tries to=
=20
> subsume the concept of leap years but where presumably the number of year=
s=20
> since the start of another year can be off by one on Jan 1 or Dec 31.=20
>
> months can be used both as a chrono::duration (when used with a chrono=20
> time_point), getting what you describe above.  This is useful for doing=
=20
> chronological computations on physical processes that don=E2=80=99t respe=
ct human=20
> calendars (e.g. changing weather patterns or mammalian gestation periods)=
..=20
>  For example:=20
>
>     auto t =3D system_clock::now() + months{18};  // about 18 months from=
=20
> now=20
>
> months can also be used as a calendrical duration when used with=20
> calendrical types and subtypes such as year_month_day and year_month.  Th=
is=20
> is useful for doing calendrical computations when you require days of the=
=20
> month to match up, for example:=20
>
>     static_assert(2017_y/jan/3 + months{18} =3D=3D jul/3/2018);=20
>

Are you saying that this assert will not fail for any date pairs? Surely=20
2017_y/feb/1 + month(1) will not be march/1/2017 as february is so short?


> Both chronological and calendrical use cases have value, and are easy to=
=20
> do.=20
>
> > - It seems strange to me that the 12/24 hour format is part of the=20
> time_of_day object. Shouldn't this be a formatting issue when converting =
to=20
> a string rather than a member of the object?=20
>
> This may well disappear.  time_of_day was born as a formatting aid, and=
=20
> predates the more generalized format function.
>
=20
Why the conceptual difference between:

year
year_month
year_month_day

vs

hour
time_of_day

If this is historical reasons it seems that it should be unified. Adding=20
hour_minute and hour_minute_second does not seem to be too much of an=20
addition to the already large type menagerie.

I still also think that there needs to be a datetime thing with fields=20
based representation as you want to be able to pass around complete=20
"time-points" in fields based representation. Maybe a template type like so=
:

template<class D, class T> class date_time {
    D date_part;
    T time_part;
    date_time(system_clock::time_point);
};

Obviously the D part has to be complete, but you had three such variants,=
=20
right? For the T part you could have any of the types including hours, as=
=20
it is ok to loose precision on the right, but not in the middle. However,=
=20
that could maybe be ignored, allowing any type in this position.=20

Is it possible to construct a complete date from year + week number + day=
=20
within week? If so, what type do I get?


> >=20
> > - In general I don't like the idea of having different specializations=
=20
> with different API (such as time_of_day<minutes> having a minutes()=20
> function while time_of_day<hours> has not). Maybe minutes() could always=
=20
> exist but return 0 for a hour-only specialization? I understand it as you=
r=20
> idea being to save implementation bits when not needed.=20
>
> The different types have come in useful in the same manner that different=
=20
> types are useful for durations, instead of just say timespec.  But the=20
> major client of time_of_day has in practice been format/parse, and so=20
> time_of_day may not need to be part of the API.  That being said, some=20
> clients like to do their own formatting/parsing and time_of_day is useful=
=20
> for them.
>

I still think that classes with different APIs should have different names.=
=20
You seem to adhere to this for dates, why not for times?


> >=20
> > - format() should take its fmt parameter as a basic_string_view. [this=
=20
> is likely fixed in the standardization proposal]=20
>
> Agreed.  I haven=E2=80=99t done so in the lib as I get a fair number of r=
equests=20
> to support older compilers.  I have a small but growing list of such=20
> details that should change for the proposal (the next revision of which I=
=20
> need to finish within a week and a half).=20
>
ok=20

>
> >=20
> > - Maybe it would be better if format's char types for the returned=20
> string and for the fmt parameter were decoupled. I write maybe as this=20
> decoupling would require callers to explicitly name the char type they wa=
nt=20
> for the returned string. A name convention as used for basic_string itsel=
f=20
> could solve this, possibly.=20
>
> Nope.  That design has already irritated me enough when trying to write=
=20
> generic code with to_string/to_wstring.
>

Ok, that's fine then, at least as long as you have a string literal as=20
formatting parameter you can use the L to control whether to get a string=
=20
or wstring. It is less nice with an incoming basic_string_view though, but=
=20
on the other hand most programs do tend to use one string width or the=20
other more or less throughout.

>
> >=20
> > - The name format() could be a bit too generic, especially if the=20
> format("{}, is a nice {}", ...) proposal gets standardized.=20
>
> Agreed, though overloading with the type-safe arguments may also address=
=20
> this issue.=20
>
> > Instead I would suggest integrating the functionality intended here int=
o=20
> a general format() method so that the formatting parameters are "strftime=
=20
> like" if the corresponding argument is of a date/time related type as=20
> proposed here. This would also work nicely with string translation, so th=
at=20
> locale specific formats can be used if needed (without involving a locale=
=20
> parameter).=20
>
> I anticipate a cooperative integration of these two libraries if they bot=
h=20
> find their way into the standardization process.  I think there could be =
a=20
> strong synergy there.=20
>
Yes, just let it not be forgotten as the dreaded is_const_t thing, where=20
template alias and type_info were both introduced in C++11 and the _t still=
=20
ended up on the alias because of proposal timing vissues (or so I suppose=
=20
at least). I guess that's one drawback with the process where proposals are=
=20
considered mostly one by one.

In the case of the date library there is also a possible prospect of a=20
general units library showing up, which would make it a hard call where to=
=20
put some of the types, such as hour and year. Maybe the wisest thing in=20
that regard is to use type aliasing to make the same types available in two=
=20
namespaces (assuming there will be a new units namespace).


> >=20
> > - A problem with parsing dates entered by users is that persons tend to=
=20
> not type dates in a coherent way. A remedy I have used is to allow multip=
le=20
> format strings which are tried in succession. This could fall outside a=
=20
> standard library but as the standard allows for two distinct output forma=
ts=20
> per locale it does not seem too far fetched to allow at least two on inpu=
t.=20
> One possible way to define this would be to reserve one character, such a=
s=20
> | as a separator in format strings when used for input, with the meaning=
=20
> that each | separated part is one complete format to be tried in order.=
=20
> Obviously it would be up to the programmer to place the formats in a=20
> suitable order to avoid ambiguities.=20
>
> I can=E2=80=99t reserve =E2=80=9C|=E2=80=9D, but I could reserve =E2=80=
=9C%|=E2=80=9D.  Or perhaps multiple parse=20
> fmt string arguments?  Would not be difficult to write as an add-on.=20
>  Here=E2=80=99s how I did this with two parsing formats:

I think you can reserve | by applying the rule that || or possibly %| means=
=20
one vertical bar. Or am I missing something?

A typical format() call would be something like this, from a dir listing=20
function:

format("File: {}, last written: {:%Y %H:%M}", fileName, fileTime)

The leading : before the datetime formatting is the delimiter between the=
=20
identifier (empty) and the format. So any characters except } would be=20
allowed in the fornat string itself.

Question: I assume that this formatting would work regardless of the type=
=20
of fileTime, i.e. time_point, year_month_day or year_month_weekday would=20
work. If so, i.e. if a field representation can be converted implicitly to=
=20
another field representation (possibly via a time_point or time_t type=20
representation) is all of this field representation only for performance,=
=20
and only when you manually match the type to the required fields. Or is it=
=20
just for type safety when assembling a date or time from its fields. If so=
=20
why have more than one representation of a complete date? Indeed, why have=
=20
any at all beyond system_clock::time_point?

=20

>
>
> https://stackoverflow.com/a/38839725/576911=20
>
The length of this function sort of proves the value of having this feature=
=20
built in.

>
> Interesting idea, thanks.=20
>
> Howard=20
>
>
>

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/9584f00e-a51e-4eed-bd03-3f3d92c3cee0%40isocpp.or=
g.

------=_Part_184_465116176.1497131932066
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">&gt; - It see=
ms that the procedure for creating year_month_day may be a little overworke=
d, involving several other data types with overloaded / operators and user =
defined literals. Also, if you don&#39;t &quot;use&quot; the date namespace=
 and this gets standardized all those types will have long names like std::=
date::year, or maybe std::chrono::year if this functionality is integrated =
with chrono. As these names are the same as the usual names you would prefe=
r to use for your variables it can get messy, and with a using statement it=
 downright clashes and you have to give your variables cryptic names.<br></=
blockquote><div><br></div><div>I think we may have to disagree on this. For=
 me &lt;chrono&gt; seems very much too complicated for what it actually off=
ers most users. I can see that to cater for every usage in the universe wit=
h utmost storage space efficiency you may have to make everything a templat=
e like this, but for a vast majority of uses using double for both time_poi=
nt and duration would have sufficed. The precision is microseconds in a cen=
tury which must be well beyond most needs. Alternatively a 64 bit integer r=
epresentation similar to timespec with suitable functions and operators. As=
 64 bits gives nanosecond precision for 580 years there seems to be little =
need for anything else outside very specific physics areas.</div><div><br><=
/div><div>While you with your intimate knowledge of &lt;chrono&gt; may find=
 it easy to use as you have the whole history of developing it to fall back=
 on, it surely is not easy to grasp when you start to use it. I think it wa=
s Bjarne who stated it so aptly: &quot;Let&#39;s not confuse familiarity wi=
th simplicity&quot;. Everything can&#39;t be expected to be done in simple =
ways, but getting the current time can.</div><div><br></div><div>Much of th=
e problem seems to be that the standard does not define: a) a way to know t=
he resolution of a clock object, b) the epoch of a clock object as a date. =
Without this information it is very hard</div><div>to get a wall clock time=
 out of a clock object and know what precision I have. Surely, I can do a d=
uration cast to nanoseconds, but I don&#39;t know what precision I actually=
 get. As for the epoch it seems that the only way is to retrieve the time_t=
 (only available on system_clock) which is defined to be relative to 1970-0=
1-01. So to get the number of seconds since this epoch with decimals the mi=
nimum is to do:</div><div><br></div><div>double GetCurrentTime() {</div><di=
v>=C2=A0 =C2=A0 system_clock::time_point n =3D system_clock::now();</div><d=
iv>=C2=A0 =C2=A0 time_t st =3D system_clock::to_time_t(n);</div><div>=C2=A0=
 =C2=A0 int nanoseconds =3D duration_cast&lt;nanoseconds&gt;(n) - duration_=
cast&lt;nanoseconds&gt;(seconds(st));</div><div>=C2=A0 =C2=A0 return st + d=
ouble(nanoseconds) * 0.000000001;</div><div>}</div><div><br></div><div>I st=
ill fail to call this simple. It took me 15 minutes to figure it out (I hav=
e not compiled and tested) and I now have 12 browser history entries (on cp=
preference.com) of where I have looked around to get this done. Then I have=
 done very similar things before so I&#39;m not a complete newbie to chrono=
.. Still a few pain points: a) The result is of undefined precision, it may =
not contain any decimals at all for instance. b) I don&#39;t feel certain t=
hat the number of bits will be enough to convert all the seconds from the e=
poch to nanoseconds before subtracting them to get only the fraction of the=
 last second. c) I still have to go to an age-old C type to get the time an=
chored to the wall clock time.</div><div><br></div><div>That&#39;s why I wo=
uld much more like &lt;chrono&gt; to get some more convenience functions al=
ong the lines of GetCurrentTime() above than to <i>only=C2=A0</i>extend it =
with even more stuff akin to its current features.</div><div><br></div><div=
>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-le=
ft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">&gt;=20
<br>&gt; void MyFunction(int year, int month, int day)
<br>&gt; {
<br>&gt; =C2=A0 =C2=A0 auto dt =3D std::date::year(year) / month / day;
<br>&gt; }
<br>
<br>
<br>The current proposal is to put these into namespace chrono. =C2=A0And m=
y current C++11/14/17 usage of chrono almost always resorts to =E2=80=9Cusi=
ng namespace std::chrono=E2=80=9D at function scope as I=E2=80=99m already =
frustrated with:
<br>
<br>=C2=A0 =C2=A0 auto min =3D std::chrono::time_point_cast&lt;<wbr>std::ch=
rono::minutes&gt;(std::<wbr>chrono::system_clock::now());
<br>
<br>I write instead:
<br>
<br>=C2=A0 =C2=A0 using namespace std::chrono;
<br>=C2=A0 =C2=A0 auto min =3D time_point_cast&lt;minutes&gt;(<wbr>system_c=
lock::now());<br></blockquote><div><br></div><div>Sure you can use the name=
space but =C2=A0then you end up with &quot;using&quot; most of the names yo=
u would want to use as identifiers in the context of working with wall cloc=
k time, such as months, year, seconds etc.</div><div><br></div><blockquote =
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1p=
x #ccc solid;padding-left: 1ex;">
<br>With just one component needing qualification as in your example, I mig=
ht not bother with the using declaration. =C2=A0But by the time I have to q=
ualify two components, I am so done with that.
<br>
<br>You can also write MyFunction like this:
<br>
<br>=C2=A0 =C2=A0 void MyFunction(int y, int m, int d)
<br>=C2=A0 =C2=A0 {
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 using namespace std::chrono;
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 auto dt =3D year_month_day{year{year}, mont=
h{m}, day{d}};
<br>=C2=A0 =C2=A0 }
<br>
<br>The overall picture, as with &lt;chrono&gt;, is to reduce to a minimum =
the conversions you do between an untyped system (i.e. int) and a typed sys=
tem where unit mixups are compile-time errors instead of run time errors:
<br>
<br>=C2=A0 =C2=A0 void MyFunction(std::chrono::year y, std::chrono::month m=
, std::chrono::day d)
<br>=C2=A0 =C2=A0 {
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 auto dt =3D y/m/d;
<br>=C2=A0 =C2=A0 }<br></blockquote><div><br></div><div>Ok, I see your poin=
t here. I was a bit thrown off track by your examples which only involved _=
literal_ integers rather than variables.</div><div><br></div><blockquote cl=
ass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px =
#ccc solid;padding-left: 1ex;"><br>Like &lt;chrono&gt; my lib continues the=
 tradition of strong type safety to catch as many errors as possible at com=
pile-time. </blockquote><div><br></div><div>As I made obvious above the pro=
blem with chrono _today_ is not so much that it has too many types but that=
 too many things are left unspecified, which makes it hard to relate to rea=
lity. What you find yourself</div><div>searching for are non-existant metho=
ds to ask for epochs, resolutions etc. It is a well eastblished fact that y=
ou can waste a lot of time searching for things that don&#39;t exist... whi=
ch I think is a major reason chrono is viewed as so hard to use. One typica=
l example is that the file_time_type type is unrelated to everything else, =
except that it is on _some_ TrivialClock which in itself is potentially unr=
elated to time_t, which as of yet is the only way I have found to relate to=
 a _known_ epoch.</div><div><br></div><div>=C2=A0</div><blockquote class=3D=
"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc s=
olid;padding-left: 1ex;">=C2=A0We force people into such dangerous conversi=
on points today mostly with I/O, and so I=E2=80=99m trying to alleviate tha=
t with good I/O support.<br></blockquote><div><br></div><div>I also dislike=
 untyped data in general, so I will play along here.</div><div>=C2=A0</div>=
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bor=
der-left: 1px #ccc solid;padding-left: 1ex;">
<br>
<br>&gt; also the use of the slash operator is not that obvious as many par=
ts of the world (and ISO8601) are more at ease with using - between the par=
ts. Using an overloaded operator when the operation is not consistent with =
the usual meaning of the operator is also generally discouraged (No, I don&=
#39;t like path / path either). Maybe use + as it is neutral between differ=
ent notations of dates and actually seems to be consistent: You are actuall=
y adding years, days and months to make a complete date. On the other hand =
doing this without first casting all the ints to their corresponding year, =
day and month types seems strange if you view it as addition.
<br>
<br>+ and - have the wrong precedence:
<br></blockquote><div><br></div><div>I see that now.=C2=A0</div><div><br></=
div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex=
;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>=C2=A0 =C2=A0 2017_y+jan - 2015_y+sep
<br>
<br>vs
<br>
<br>=C2=A0 =C2=A0 2017_y/jan - 2015_y/sep =3D=3D months{16}
<br>
<br>and can easily lead to confusing expressions like this:
<br>
<br>=C2=A0 =C2=A0 2015_y+sep+months{16}
<br>
<br>vs
<br>
<br>=C2=A0 =C2=A0 2015_y/sep + months{16} =3D=3D 2017_y/jan
<br>
<br>But if you really just don=E2=80=99t like the =E2=80=99/=E2=80=98 synta=
x, you=E2=80=99re not alone. =C2=A0Others feel the same way. =C2=A0Feel fre=
e to use the constructor syntax instead:
<br>
<br>=C2=A0 =C2=A0 year_month{2017_y, jan} - year_month{2015_y, sep} =3D=3D =
months{16}
<br>
<br>or:
<br>
<br>=C2=A0 =C2=A0 year_month{year{2017}, month{1}} - year_month{year{2015},=
 month{9}} =3D=3D months{16}
<br>
<br>instead of:
<br>
<br>=C2=A0 =C2=A0 2017_y/jan - 2015_y/sep =3D=3D months{16}
<br>
<br>Just don=E2=80=99t tell everyone else that they _have_ to use the const=
ructor syntax instead of the =E2=80=98/=E2=80=98 syntax (unless you want to=
 enforce that as a coding guideline on a project you=E2=80=99re in charge o=
f). =C2=A0Because there=E2=80=99s lots of people who really like the =E2=80=
=98/=E2=80=98 syntax. =C2=A0This lib provides both, with no performance, fu=
nctionality or type-safety penalties for using either. =C2=A0</blockquote><=
blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bord=
er-left: 1px #ccc solid;padding-left: 1ex;">
<br>&gt; A library which is more complicated than its task warrants risks n=
ot being used as the benefit may not outweigh the learning curve.
<br>
<br>True, that=E2=80=99s why I=E2=80=99ve been field testing this lib for a=
 couple of years now. =C2=A0The field testing is actually going pretty well=
.. =C2=A0This library strives for a simple, self-consistent API. =C2=A0But s=
imple doesn=E2=80=99t always mean =E2=80=9Cdo it the way it has always been=
 done in the past=E2=80=9D, or even =E2=80=9Cdon=E2=80=99t have too many ty=
pes.=E2=80=9D =C2=A0My experience from &lt;chrono&gt; is that many people s=
aid simple means =E2=80=9Cdon=E2=80=99t use templates.=E2=80=9D. =C2=A0And =
indeed, reading the &lt;chrono&gt; header is a good way to get terrified of=
 that library. =C2=A0But the code people usually write with &lt;chrono&gt; =
is simple, readable and type-safe. =C2=A0</blockquote><div><br></div><div>N=
ot for all important use cases, as shown above.</div><div>=C2=A0</div><bloc=
kquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-l=
eft: 1px #ccc solid;padding-left: 1ex;">Ditto with this library that extend=
s &lt;chrono&gt; to calendars.
<br>
<br>I=E2=80=99m leaning heavily on modern features like auto and user-defin=
ed literals which reduce the need to remember so many type names:
<br>
<br>=C2=A0 =C2=A0 auto today =C2=A0 =C2=A0=3D 8_d/jun/2017; =C2=A0 =C2=A0 /=
/ has type year_month_day
<br>=C2=A0 =C2=A0 auto tomorrow =3D fri[2]/jun/2017; =C2=A0// has type year=
_month_weekday=C2=A0</blockquote><blockquote class=3D"gmail_quote" style=3D=
"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex=
;">
<br>Similarly, auto is of great help with &lt;chrono&gt; itself, in deducin=
g the resultant type of =E2=80=9Cmixed-mode=E2=80=9D arithmetic across time=
_points and durations of varying precisions.
<br>
<br>&gt; date::year_month_day date =3D date::year(2017)/2/4;
<br>&gt; date::year_month_weekday wdate =3D date::sys_days(date);
<br>&gt; return wdate.weekday();
<br>&gt;=20
<br>&gt; In wxWidgets, by contrast, you can do:
<br>&gt;=20
<br>&gt; wxDate date(2, 4, 2017);
<br>&gt; return date.GetDayOfWeek();
<br>
<br>This will do it;
<br>
<br>=C2=A0 =C2=A0 using namespace date::literals;
<br>=C2=A0 =C2=A0 return date::weekday{feb/4/2017}; =C2=A0// or did you mea=
n 2_d/apr/2017? so hard to tell when your only tool is int<br></blockquote>=
<div><br></div><div>Ok, I was unaware that you can construct a weekday, (an=
d I assume =C2=A0day, month, etc [upon reading date.h it seems I was assumi=
ng wrongly: only weekday has this type of constructor]) a complete date and=
 it will &quot;extract&quot; the relevant information. That seems like a ni=
ce feature.</div><div><br></div><div>Can you also do:</div><div><br></div><=
div>=C2=A0 =C2=A0 auto wd =3D date::day{system_clock::now()}; =C2=A0// Day =
in month right now</div><div><br></div><div>If not, why?</div><div><br></di=
v><div><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>&gt; This level of simplicity is what we should strive for.
<br>
<br>The wxWidgets code is actually unreadable to me. =C2=A0I can not read t=
hat and know what date you mean without breaking out the wxWidgets document=
ation. =C2=A0Such ambiguity is not possible in my date lib. =C2=A0Ambiguity=
 is a compile-time error.<br></blockquote><div><br></div><div>Unless you wa=
nt to play hide and seek with the compiler you would still need to open the=
 documentation if you are not already a pro. With wxDateTime you have all f=
unctionality related to dates and times in one class and thus the documenta=
tion is similarly close by when you need it. Or type a dot in the IDE if yo=
u forgot the exact method name and it will be shown in a dropdown list, mos=
t likely. (No 12 history entries in your browser).</div><div><br></div><blo=
ckquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-=
left: 1px #ccc solid;padding-left: 1ex;"><br></blockquote><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;">
<br>I feel pretty strongly that this library should build on &lt;chrono&gt;=
.. =C2=A0The central theme of this library is that time_point&lt;system_cloc=
k, Duration&gt; _is_ the =E2=80=9Clinear=E2=80=9D datetime representation. =
=C2=A0Choose any precision you want, it is already in your &lt;chrono&gt; h=
eader. =C2=A0Everything else is just helpers for converting to and from cal=
endars. =C2=A0And that very design decision is what will make I/O on file_t=
ime_type so convenient, functional and easy.<br></blockquote><div>Lets hope=
 for that.=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;=
margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>&gt;=20
<br>&gt;=20
<br>&gt; Now back to more nitpicking:
<br>&gt;=20
<br>&gt; - The definition of months (the duration) is a bit scary as it rel=
ates to an &quot;average month length&quot; which means that it will not ac=
curately represent the current month when used as a duration from a year&#3=
9;s start. Is it really needed? I guess the same can be said for years, whi=
ch tries to subsume the concept of leap years but where presumably the numb=
er of years since the start of another year can be off by one on Jan 1 or D=
ec 31.
<br>
<br>months can be used both as a chrono::duration (when used with a chrono =
time_point), getting what you describe above. =C2=A0This is useful for doin=
g chronological computations on physical processes that don=E2=80=99t respe=
ct human calendars (e.g. changing weather patterns or mammalian gestation p=
eriods). =C2=A0For example:
<br>
<br>=C2=A0 =C2=A0 auto t =3D system_clock::now() + months{18}; =C2=A0// abo=
ut 18 months from now
<br>
<br>months can also be used as a calendrical duration when used with calend=
rical types and subtypes such as year_month_day and year_month. =C2=A0This =
is useful for doing calendrical computations when you require days of the m=
onth to match up, for example:
<br>
<br>=C2=A0 =C2=A0 static_assert(2017_y/jan/3 + months{18} =3D=3D jul/3/2018=
);
<br></blockquote><div><br></div><div>Are you saying that this assert will n=
ot fail for any date pairs? Surely 2017_y/feb/1 + month(1) will not be marc=
h/1/2017 as february is so short?</div><div><br></div><blockquote class=3D"=
gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc so=
lid;padding-left: 1ex;">
<br>Both chronological and calendrical use cases have value, and are easy t=
o do.
<br>
<br>&gt; - It seems strange to me that the 12/24 hour format is part of the=
 time_of_day object. Shouldn&#39;t this be a formatting issue when converti=
ng to a string rather than a member of the object?
<br>
<br>This may well disappear. =C2=A0time_of_day was born as a formatting aid=
, and predates the more generalized format function.<br></blockquote><div>=
=C2=A0</div><div>Why the conceptual difference between:</div><div><br></div=
><div>year</div><div>year_month</div><div>year_month_day</div><div><br></di=
v><div>vs</div><div><br></div><div>hour</div><div>time_of_day</div><div><br=
></div><div>If this is historical reasons it seems that it should be unifie=
d. Adding hour_minute and hour_minute_second does not seem to be too much o=
f an addition to the already large type menagerie.</div><div><br></div><div=
>I still also think that there needs to be a datetime thing with fields bas=
ed representation as you want to be able to pass around complete &quot;time=
-points&quot; in fields based representation. Maybe a template type like so=
:</div><div><br></div><div>template&lt;class D, class T&gt; class date_time=
 {</div><div>=C2=A0 =C2=A0 D date_part;</div><div>=C2=A0 =C2=A0 T time_part=
;</div><div>=C2=A0 =C2=A0 date_time(system_clock::time_point);</div><div>};=
</div><div><br></div><div>Obviously the D part has to be complete, but you =
had three such variants, right? For the T part you could have any of the ty=
pes including hours, as it is ok to loose precision on the right, but not i=
n the middle. However, that could maybe be ignored, allowing any type in th=
is position.=C2=A0</div><div><br></div><div>Is it possible to construct a c=
omplete date from year + week number + day within week? If so, what type do=
 I get?</div><div><br></div><blockquote class=3D"gmail_quote" style=3D"marg=
in: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>&gt;=20
<br>&gt; - In general I don&#39;t like the idea of having different special=
izations with different API (such as time_of_day&lt;minutes&gt; having a mi=
nutes() function while time_of_day&lt;hours&gt; has not). Maybe minutes() c=
ould always exist but return 0 for a hour-only specialization? I understand=
 it as your idea being to save implementation bits when not needed.
<br>
<br>The different types have come in useful in the same manner that differe=
nt types are useful for durations, instead of just say timespec. =C2=A0But =
the major client of time_of_day has in practice been format/parse, and so t=
ime_of_day may not need to be part of the API. =C2=A0That being said, some =
clients like to do their own formatting/parsing and time_of_day is useful f=
or them.<br></blockquote><div><br></div><div>I still think that classes wit=
h different APIs should have different names. You seem to adhere to this fo=
r dates, why not for times?</div><div><br></div><blockquote class=3D"gmail_=
quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pa=
dding-left: 1ex;">
<br>&gt;=20
<br>&gt; - format() should take its fmt parameter as a basic_string_view. [=
this is likely fixed in the standardization proposal]
<br>
<br>Agreed. =C2=A0I haven=E2=80=99t done so in the lib as I get a fair numb=
er of requests to support older compilers. =C2=A0I have a small but growing=
 list of such details that should change for the proposal (the next revisio=
n of which I need to finish within a week and a half).
<br></blockquote><div>ok=C2=A0</div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;">
<br>&gt;=20
<br>&gt; - Maybe it would be better if format&#39;s char types for the retu=
rned string and for the fmt parameter were decoupled. I write maybe as this=
 decoupling would require callers to explicitly name the char type they wan=
t for the returned string. A name convention as used for basic_string itsel=
f could solve this, possibly.
<br>
<br>Nope. =C2=A0That design has already irritated me enough when trying to =
write generic code with to_string/to_wstring.<br></blockquote><div><br></di=
v><div>Ok, that&#39;s fine then, at least as long as you have a string lite=
ral as formatting parameter you can use the L to control whether to get a s=
tring or wstring. It is less nice with an incoming basic_string_view though=
, but on the other hand most programs do tend to use one string width or th=
e other more or less throughout.</div><blockquote class=3D"gmail_quote" sty=
le=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left=
: 1ex;">
<br>&gt;=20
<br>&gt; - The name format() could be a bit too generic, especially if the =
format(&quot;{}, is a nice {}&quot;, ...) proposal gets standardized.
<br>
<br>Agreed, though overloading with the type-safe arguments may also addres=
s this issue.
<br>
<br>&gt; Instead I would suggest integrating the functionality intended her=
e into a general format() method so that the formatting parameters are &quo=
t;strftime like&quot; if the corresponding argument is of a date/time relat=
ed type as proposed here. This would also work nicely with string translati=
on, so that locale specific formats can be used if needed (without involvin=
g a locale parameter).
<br>
<br>I anticipate a cooperative integration of these two libraries if they b=
oth find their way into the standardization process. =C2=A0I think there co=
uld be a strong synergy there.
<br></blockquote><div>Yes, just let it not be forgotten as the dreaded is_c=
onst_t thing, where template alias and type_info were both introduced in C+=
+11 and the _t still ended up on the alias because of proposal timing vissu=
es (or so I suppose at least). I guess that&#39;s one drawback with the pro=
cess where proposals are considered mostly one by one.</div><div><br></div>=
<div>In the case of the date library there is also a possible prospect of a=
 general units library showing up, which would make it a hard call where to=
 put some of the types, such as hour and year. Maybe the wisest thing in th=
at regard is to use type aliasing to make the same types available in two n=
amespaces (assuming there will be a new units namespace).</div><div><br></d=
iv><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;">
<br>&gt;=20
<br>&gt; - A problem with parsing dates entered by users is that persons te=
nd to not type dates in a coherent way. A remedy I have used is to allow mu=
ltiple format strings which are tried in succession. This could fall outsid=
e a standard library but as the standard allows for two distinct output for=
mats per locale it does not seem too far fetched to allow at least two on i=
nput. One possible way to define this would be to reserve one character, su=
ch as | as a separator in format strings when used for input, with the mean=
ing that each | separated part is one complete format to be tried in order.=
 Obviously it would be up to the programmer to place the formats in a suita=
ble order to avoid ambiguities.
<br>
<br>I can=E2=80=99t reserve =E2=80=9C|=E2=80=9D, but I could reserve =E2=80=
=9C%|=E2=80=9D. =C2=A0Or perhaps multiple parse fmt string arguments? =C2=
=A0Would not be difficult to write as an add-on. =C2=A0Here=E2=80=99s how I=
 did this with two parsing formats:</blockquote><div>I think you can reserv=
e | by applying the rule that || or possibly %| means one vertical bar. Or =
am I missing something?</div><div><br></div><div>A typical format() call wo=
uld be something like this, from a dir listing function:</div><div><br></di=
v><div>format(&quot;File: {}, last written: {:%Y %H:%M}&quot;, fileName, fi=
leTime)</div><div><br></div><div>The leading : before the datetime formatti=
ng is the delimiter between the identifier (empty) and the format. So any c=
haracters except } would be allowed in the fornat string itself.</div><div>=
<br></div><div>Question: I assume that this formatting would work regardles=
s of the type of fileTime, i.e. time_point, year_month_day or year_month_we=
ekday would work. If so, i.e. if a field representation can be converted im=
plicitly to another field representation (possibly via a time_point or time=
_t type representation) is all of this field representation only for perfor=
mance, and only when you manually match the type to the required fields. Or=
 is it just for type safety when assembling a date or time from its fields.=
 If so why have more than one representation of a complete date? Indeed, wh=
y have any at all beyond system_clock::time_point?</div><div><br></div><div=
>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-le=
ft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">
<br>
<br><a href=3D"https://stackoverflow.com/a/38839725/576911" target=3D"_blan=
k" rel=3D"nofollow" onmousedown=3D"this.href=3D&#39;https://www.google.com/=
url?q\x3dhttps%3A%2F%2Fstackoverflow.com%2Fa%2F38839725%2F576911\x26sa\x3dD=
\x26sntz\x3d1\x26usg\x3dAFQjCNFIs2ysUZYMPyPX1DesbQgQb8raXg&#39;;return true=
;" onclick=3D"this.href=3D&#39;https://www.google.com/url?q\x3dhttps%3A%2F%=
2Fstackoverflow.com%2Fa%2F38839725%2F576911\x26sa\x3dD\x26sntz\x3d1\x26usg\=
x3dAFQjCNFIs2ysUZYMPyPX1DesbQgQb8raXg&#39;;return true;">https://stackoverf=
low.com/a/<wbr>38839725/576911</a>
<br></blockquote><div>The length of this function sort of proves the value =
of having this feature built in.</div><blockquote class=3D"gmail_quote" sty=
le=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left=
: 1ex;">
<br>Interesting idea, thanks.
<br>
<br>Howard
<br>
<br>
<br></blockquote></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/9584f00e-a51e-4eed-bd03-3f3d92c3cee0%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/9584f00e-a51e-4eed-bd03-3f3d92c3cee0=
%40isocpp.org</a>.<br />

------=_Part_184_465116176.1497131932066--

------=_Part_183_395913651.1497131932065--

.


Author: "T. C." <rs2740@gmail.com>
Date: Sat, 10 Jun 2017 15:41:37 -0700 (PDT)
Raw View
------=_Part_2164_116841074.1497134497850
Content-Type: multipart/alternative;
 boundary="----=_Part_2165_1328448456.1497134497851"

------=_Part_2165_1328448456.1497134497851
Content-Type: text/plain; charset="UTF-8"



On Saturday, June 10, 2017 at 5:58:52 PM UTC-4, Bengt Gustafsson wrote:

double GetCurrentTime() {
>     system_clock::time_point n = system_clock::now();
>     time_t st = system_clock::to_time_t(n);
>     int nanoseconds = duration_cast<nanoseconds>(n) -
> duration_cast<nanoseconds>(seconds(st));
>     return st + double(nanoseconds) * 0.000000001;
> }
>

system_clock de facto has the same epoch as time_t. If you are willing to
rely on that:

double GetCurrentTime(){
    return duration<double>(system_clock::now().time_since_epoch()).count();
}


Otherwise,

double GetCurrentTime(){
    return duration<double>(system_clock::now() - system_clock::from_time_t(
0)).count();
}

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/de34f799-c7d2-4bf2-af15-d0786629c83c%40isocpp.org.

------=_Part_2165_1328448456.1497134497851
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>On Saturday, June 10, 2017 at 5:58:52 PM UTC-4, Be=
ngt Gustafsson wrote:<div><br><blockquote class=3D"gmail_quote" style=3D"ma=
rgin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">=
<div dir=3D"ltr"><div>double GetCurrentTime() {</div><div>=C2=A0 =C2=A0 sys=
tem_clock::time_point n =3D system_clock::now();</div><div>=C2=A0 =C2=A0 ti=
me_t st =3D system_clock::to_time_t(n);</div><div>=C2=A0 =C2=A0 int nanosec=
onds =3D duration_cast&lt;nanoseconds&gt;(n) - duration_cast&lt;nanoseconds=
&gt;(<wbr>seconds(st));</div><div>=C2=A0 =C2=A0 return st + double(nanoseco=
nds) * 0.000000001;</div><div>}</div></div></blockquote><div><br></div><div=
>system_clock de facto has the same epoch as time_t. If you are willing to =
rely on that:</div></div><div><br></div><div class=3D"prettyprint" style=3D=
"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187); bo=
rder-style: solid; border-width: 1px; word-wrap: break-word;"><code class=
=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;"=
 class=3D"styled-by-prettify">double</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> </span><span style=3D"color: #606;" class=3D"sty=
led-by-prettify">GetCurrentTime</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">(){</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">return</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> duration</span><span style=3D"color: #080;" class=3D"s=
tyled-by-prettify">&lt;double&gt;</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">system_clock</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify">now</span><span style=3D"color: #660;" class=3D"styled-by-prettify=
">().</span><span style=3D"color: #000;" class=3D"styled-by-prettify">time_=
since_epoch</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>()).</span><span style=3D"color: #000;" class=3D"styled-by-prettify">count=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">();</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">}</span></div></code></=
div><div><br></div><div><br></div><div>Otherwise,</div><div><br></div><div>=
<div class=3D"prettyprint" style=3D"border-width: 1px; border-style: solid;=
 border-color: rgb(187, 187, 187); background-color: rgb(250, 250, 250); wo=
rd-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprettypr=
int"><span style=3D"color: #008;" class=3D"styled-by-prettify">double</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=3D"color: #606;" class=3D"styled-by-prettify">GetCurrentTime</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">(){</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><sp=
an style=3D"color: #008;" class=3D"styled-by-prettify">return</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> duration</span><span st=
yle=3D"color: #080;" class=3D"styled-by-prettify">&lt;double&gt;</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">system_clock</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify">now</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">()</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">-</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> system_clock</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y">from_time_t</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">(</span><span style=3D"color: #066;" class=3D"styled-by-prettify">0</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">).</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify">count</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">();</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">}</span></div><div><span class=3D"styled-by-prett=
ify" style=3D"color: rgb(102, 102, 0);"><br></span></div></code></div></div=
></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/de34f799-c7d2-4bf2-af15-d0786629c83c%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/de34f799-c7d2-4bf2-af15-d0786629c83c=
%40isocpp.org</a>.<br />

------=_Part_2165_1328448456.1497134497851--

------=_Part_2164_116841074.1497134497850--

.


Author: Nicol Bolas <jmckesson@gmail.com>
Date: Sat, 10 Jun 2017 19:08:12 -0700 (PDT)
Raw View
------=_Part_2232_1413275546.1497146892269
Content-Type: multipart/alternative;
 boundary="----=_Part_2233_696891864.1497146892270"

------=_Part_2233_696891864.1497146892270
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Saturday, June 10, 2017 at 5:58:52 PM UTC-4, Bengt Gustafsson wrote:
>
> > - It seems that the procedure for creating year_month_day may be a=20
>> little overworked, involving several other data types with overloaded /=
=20
>> operators and user defined literals. Also, if you don't "use" the date=
=20
>> namespace and this gets standardized all those types will have long name=
s=20
>> like std::date::year, or maybe std::chrono::year if this functionality i=
s=20
>> integrated with chrono. As these names are the same as the usual names y=
ou=20
>> would prefer to use for your variables it can get messy, and with a usin=
g=20
>> statement it downright clashes and you have to give your variables crypt=
ic=20
>> names.
>>
>
> I think we may have to disagree on this. For me <chrono> seems very much=
=20
> too complicated for what it actually offers most users. I can see that to=
=20
> cater for every usage in the universe with utmost storage space efficienc=
y=20
> you may have to make everything a template like this, but for a vast=20
> majority of uses using double for both time_point and duration would have=
=20
> sufficed. The precision is microseconds in a century which must be well=
=20
> beyond most needs. Alternatively a 64 bit integer representation similar =
to=20
> timespec with suitable functions and operators. As 64 bits gives nanoseco=
nd=20
> precision for 580 years there seems to be little need for anything else=
=20
> outside very specific physics areas.
>
> While you with your intimate knowledge of <chrono> may find it easy to us=
e=20
> as you have the whole history of developing it to fall back on, it surely=
=20
> is not easy to grasp when you start to use it. I think it was Bjarne who=
=20
> stated it so aptly: "Let's not confuse familiarity with simplicity".=20
> Everything can't be expected to be done in simple ways, but getting the=
=20
> current time can.
>

The problem is this: what does "getting the current time" actually mean?=20
Chrono is the first time library that actually tells you what the "current=
=20
time" actually *means*. All of the others clock libraries I've seen are=20
based on a bunch of assumptions: time is a floating-point value in units of=
=20
seconds, time is relative to some assumed base value, etc.

Chrono is a lot like the STL parts of the standard library. STL is not=20
simple. But once you are familiar with its concepts, it's quite easy to=20
use. Just like Chrono.

So long as you're not *fighting* the library, so long as you're approaching=
=20
the library on its terms rather than your own, it works quite well.

Much of the problem seems to be that the standard does not define: a) a way=
=20
> to know the resolution of a clock object, b) the epoch of a clock object =
as=20
> a date. Without this information it is very hard
> to get a wall clock time out of a clock object and know what precision I=
=20
> have. Surely, I can do a duration cast to nanoseconds, but I don't know=
=20
> what precision I actually get.
>

The result of `now` is a `time_point`, which contains the `period` typedef,=
=20
which is a `ratio` describing the tick period of the clock. AKA: the=20
clock's precision. Also, the clock itself has a `period` in it.

So yes, you do know what precision you actually get. If you want to get the=
=20
number of ticks, you can use the `period` type to get it from the=20
`time_point`.

I don't know what you mean by the difficulty of getting a "wall clock=20
time". `system_clock::now` returns a wall clock time. If your issue is the=
=20
difficulty in *presenting* that time to the user via text of some sort,=20
well that's something that Howard's Date library handles, as he has=20
described.

At the end of the day, Chrono is not a *complete* solution for all time=20
needs. But it was never *intended* to be; it was always just the first=20
step. The Date library is a much more complete solution, using Chrono as=20
the foundation.

It's also not clear how your suggested `GetCurrentTime` solves these=20
problems. It doesn't provide precision information, which would presumably=
=20
be implementation-specific. Nor does it specify what the epoch is (the=20
documentation might).

As for the epoch it seems that the only way is to retrieve the time_t (only=
=20
> available on system_clock) which is defined to be relative to 1970-01-01.=
=20
> So to get the number of seconds since this epoch with decimals
>

Here's a good question: why do you *want* to do that?

I can imagine things that one might do with such a number. But these would=
=20
be means to an end, steps in some process. `time_point` contains 100% of=20
the information that this floating-point value would contain. So there is=
=20
no reason that the process which would consume the result of=20
`GetCurrentTime` couldn't just consume a `time_point`.

<snip>

Ditto with this library that extends <chrono> to calendars.=20
>>
>> I=E2=80=99m leaning heavily on modern features like auto and user-define=
d=20
>> literals which reduce the need to remember so many type names:=20
>>
>>     auto today    =3D 8_d/jun/2017;     // has type year_month_day=20
>>     auto tomorrow =3D fri[2]/jun/2017;  // has type year_month_weekday=
=20
>
>
>> Similarly, auto is of great help with <chrono> itself, in deducing the=
=20
>> resultant type of =E2=80=9Cmixed-mode=E2=80=9D arithmetic across time_po=
ints and durations=20
>> of varying precisions.=20
>>
>> > date::year_month_day date =3D date::year(2017)/2/4;=20
>> > date::year_month_weekday wdate =3D date::sys_days(date);=20
>> > return wdate.weekday();=20
>> >=20
>> > In wxWidgets, by contrast, you can do:=20
>> >=20
>> > wxDate date(2, 4, 2017);=20
>> > return date.GetDayOfWeek();=20
>>
>> This will do it;=20
>>
>>     using namespace date::literals;=20
>>     return date::weekday{feb/4/2017};  // or did you mean 2_d/apr/2017?=
=20
>> so hard to tell when your only tool is int
>>
>
> Ok, I was unaware that you can construct a weekday, (and I assume  day,=
=20
> month, etc [upon reading date.h it seems I was assuming wrongly: only=20
> weekday has this type of constructor]) a complete date and it will=20
> "extract" the relevant information. That seems like a nice feature.
>
> Can you also do:
>
>     auto wd =3D date::day{system_clock::now()};  // Day in month right no=
w
>
> If not, why?
>

I don't know exactly what the current library will do, but I don't think=20
that code ought to work. The reason being that you could mean a lot of=20
things:

1) Days since epoch.
2) Days since the start of the year.
3) Days since the start of the month.

It would be far better to make that be a compile error and require that the=
=20
user convert the time point explicitly to a date before extracting a day or=
=20
month from it.

> This level of simplicity is what we should strive for.=20
>>
>> The wxWidgets code is actually unreadable to me.  I can not read that an=
d=20
>> know what date you mean without breaking out the wxWidgets documentation=
..=20
>>  Such ambiguity is not possible in my date lib.  Ambiguity is a=20
>> compile-time error.
>>
>
> Unless you want to play hide and seek with the compiler you would still=
=20
> need to open the documentation if you are not already a pro. With=20
> wxDateTime you have all functionality related to dates and times in one=
=20
> class and thus the documentation is similarly close by when you need it. =
Or=20
> type a dot in the IDE if you forgot the exact method name and it will be=
=20
> shown in a dropdown list, most likely. (No 12 history entries in your=20
> browser).
>

The difference is this: With Howard's Date library, you have to look up the=
=20
function signatures. With wxDateTime, you have to look up what the=20
functions *do*. With the former, a cheat-sheet of the various functions is=
=20
sufficient. With the latter, you need not just the signatures, but some=20
added textual information to tell you what those parameters mean.

I feel pretty strongly that this library should build on <chrono>.  The=20
>> central theme of this library is that time_point<system_clock, Duration>=
=20
>> _is_ the =E2=80=9Clinear=E2=80=9D datetime representation.  Choose any p=
recision you want,=20
>> it is already in your <chrono> header.  Everything else is just helpers =
for=20
>> converting to and from calendars.  And that very design decision is what=
=20
>> will make I/O on file_time_type so convenient, functional and easy.
>>
> Lets hope for that.=20
>

Hope? Hope is not a thing you need to use here. This library *exists*. If=
=20
you want to see if it makes things "convenient, functional, and easy", just=
=20
download it and have a go.

>=20
>> >=20
>> > Now back to more nitpicking:=20
>> >=20
>> > - The definition of months (the duration) is a bit scary as it relates=
=20
>> to an "average month length" which means that it will not accurately=20
>> represent the current month when used as a duration from a year's start.=
 Is=20
>> it really needed? I guess the same can be said for years, which tries to=
=20
>> subsume the concept of leap years but where presumably the number of yea=
rs=20
>> since the start of another year can be off by one on Jan 1 or Dec 31.=20
>>
>> months can be used both as a chrono::duration (when used with a chrono=
=20
>> time_point), getting what you describe above.  This is useful for doing=
=20
>> chronological computations on physical processes that don=E2=80=99t resp=
ect human=20
>> calendars (e.g. changing weather patterns or mammalian gestation periods=
).=20
>>  For example:=20
>>
>>     auto t =3D system_clock::now() + months{18};  // about 18 months fro=
m=20
>> now=20
>>
>> months can also be used as a calendrical duration when used with=20
>> calendrical types and subtypes such as year_month_day and year_month.  T=
his=20
>> is useful for doing calendrical computations when you require days of th=
e=20
>> month to match up, for example:=20
>>
>>     static_assert(2017_y/jan/3 + months{18} =3D=3D jul/3/2018);=20
>>
>
> Are you saying that this assert will not fail for any date pairs? Surely=
=20
> 2017_y/feb/1 + month(1) will not be march/1/2017 as february is so short?
>

Yes, that is exactly what he is saying. If you add one month to a date, it=
=20
becomes the same day of the next month. A "month" is not a synonym for 30=
=20
days or something; it is a *month*, a typed quantity. So adding a month to=
=20
a date cause that date to shift forward one month.

Or the closest thing to it. If you're on March 31, and you add a month, you=
=20
either get April 30 or May 1; I forget which. But if you add two months,=20
you always get May 31.

The library is designed to do exactly what you say. If you wanted to add 30=
=20
days, you would add `day(30)`.

Is it possible to construct a complete date from year + week number + day=
=20
> within week? If so, what type do I get?
>

Yes, there's a type for that: `year_weeknum_weekday`=20
<https://howardhinnant.github.io/date/iso_week.html>. It is implicitly=20
convertible to `sys_days`, so it can be explicitly converted to/from the=20
other date types. *Any* other date type. So you can convert from=20
week-numbered dates to the Julian calandar, then back to Year/Month/Day,=20
and any other `sys_days`-compatible type someone wants to create.

>

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/46225b93-8c06-4bb9-8abb-90a3a19b0aa4%40isocpp.or=
g.

------=_Part_2233_696891864.1497146892270
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Saturday, June 10, 2017 at 5:58:52 PM UTC-4, Bengt Gust=
afsson wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-le=
ft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr">=
<blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0.8ex;borde=
r-left:1px #ccc solid;padding-left:1ex">&gt; - It seems that the procedure =
for creating year_month_day may be a little overworked, involving several o=
ther data types with overloaded / operators and user defined literals. Also=
, if you don&#39;t &quot;use&quot; the date namespace and this gets standar=
dized all those types will have long names like std::date::year, or maybe s=
td::chrono::year if this functionality is integrated with chrono. As these =
names are the same as the usual names you would prefer to use for your vari=
ables it can get messy, and with a using statement it downright clashes and=
 you have to give your variables cryptic names.<br></blockquote><div><br></=
div><div>I think we may have to disagree on this. For me &lt;chrono&gt; see=
ms very much too complicated for what it actually offers most users. I can =
see that to cater for every usage in the universe with utmost storage space=
 efficiency you may have to make everything a template like this, but for a=
 vast majority of uses using double for both time_point and duration would =
have sufficed. The precision is microseconds in a century which must be wel=
l beyond most needs. Alternatively a 64 bit integer representation similar =
to timespec with suitable functions and operators. As 64 bits gives nanosec=
ond precision for 580 years there seems to be little need for anything else=
 outside very specific physics areas.</div><div><br></div><div>While you wi=
th your intimate knowledge of &lt;chrono&gt; may find it easy to use as you=
 have the whole history of developing it to fall back on, it surely is not =
easy to grasp when you start to use it. I think it was Bjarne who stated it=
 so aptly: &quot;Let&#39;s not confuse familiarity with simplicity&quot;. E=
verything can&#39;t be expected to be done in simple ways, but getting the =
current time can.</div></div></blockquote><div><br>The problem is this: wha=
t does &quot;getting the current time&quot; actually mean? Chrono is the fi=
rst time library that actually tells you what the &quot;current time&quot; =
actually <i>means</i>. All of the others clock libraries I&#39;ve seen are =
based on a bunch of assumptions: time is a floating-point value in units of=
 seconds, time is relative to some assumed base value, etc.<br><br>Chrono i=
s a lot like the STL parts of the standard library. STL is not simple. But =
once you are familiar with its concepts, it&#39;s quite easy to use. Just l=
ike Chrono.<br><br>So long as you&#39;re not <i>fighting</i> the library, s=
o long as you&#39;re approaching the library on its terms rather than your =
own, it works quite well.<br><br></div><blockquote class=3D"gmail_quote" st=
yle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-lef=
t: 1ex;"><div dir=3D"ltr"><div>Much of the problem seems to be that the sta=
ndard does not define: a) a way to know the resolution of a clock object, b=
) the epoch of a clock object as a date. Without this information it is ver=
y hard</div><div>to get a wall clock time out of a clock object and know wh=
at precision I have. Surely, I can do a duration cast to nanoseconds, but I=
 don&#39;t know what precision I actually get.</div></div></blockquote><div=
><br>The result of `now` is a `time_point`, which contains the `period` typ=
edef, which is a `ratio` describing the tick period of the clock. AKA: the =
clock&#39;s precision. Also, the clock itself has a `period` in it.<br><br>=
So yes, you do know what precision you actually get. If you want to get the=
 number of ticks, you can use the `period` type to get it from the `time_po=
int`.<br><br>I don&#39;t know what you mean by the difficulty of getting a =
&quot;wall clock time&quot;. `system_clock::now` returns a wall clock time.=
 If your issue is the difficulty in <i>presenting</i> that time to the user=
 via text of some sort, well that&#39;s something that Howard&#39;s Date li=
brary handles, as he has described.<br><br>At the end of the day, Chrono is=
 not a <i>complete</i> solution for all time needs. But it was never <i>int=
ended</i> to be; it was always just the first step. The Date library is a m=
uch more complete solution, using Chrono as the foundation.<br><br>It&#39;s=
 also not clear how your suggested `GetCurrentTime` solves these problems. =
It doesn&#39;t provide precision information, which would presumably be imp=
lementation-specific. Nor does it specify what the epoch is (the documentat=
ion might).<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin:=
 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div =
dir=3D"ltr"><div>As for the epoch it seems that the only way is to retrieve=
 the time_t (only available on system_clock) which is defined to be relativ=
e to 1970-01-01. So to get the number of seconds since this epoch with deci=
mals</div></div></blockquote><div><br>Here&#39;s a good question: why do yo=
u <i>want</i> to do that?<br><br>I can imagine things that one might do wit=
h such a number. But these would be means to an end, steps in some process.=
 `time_point` contains 100% of the information that this floating-point val=
ue would contain. So there is no reason that the process which would consum=
e the result of `GetCurrentTime` couldn&#39;t just consume a `time_point`.<=
br><br>&lt;snip&gt;<br><br></div><blockquote class=3D"gmail_quote" style=3D=
"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex=
;"><div dir=3D"ltr"><div></div><div></div><blockquote class=3D"gmail_quote"=
 style=3D"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-lef=
t:1ex">Ditto with this library that extends &lt;chrono&gt; to calendars.
<br>
<br>I=E2=80=99m leaning heavily on modern features like auto and user-defin=
ed literals which reduce the need to remember so many type names:
<br>
<br>=C2=A0 =C2=A0 auto today =C2=A0 =C2=A0=3D 8_d/jun/2017; =C2=A0 =C2=A0 /=
/ has type year_month_day
<br>=C2=A0 =C2=A0 auto tomorrow =3D fri[2]/jun/2017; =C2=A0// has type year=
_month_weekday=C2=A0</blockquote><blockquote class=3D"gmail_quote" style=3D=
"margin:0;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>Similarly, auto is of great help with &lt;chrono&gt; itself, in deducin=
g the resultant type of =E2=80=9Cmixed-mode=E2=80=9D arithmetic across time=
_points and durations of varying precisions.
<br>
<br>&gt; date::year_month_day date =3D date::year(2017)/2/4;
<br>&gt; date::year_month_weekday wdate =3D date::sys_days(date);
<br>&gt; return wdate.weekday();
<br>&gt;=20
<br>&gt; In wxWidgets, by contrast, you can do:
<br>&gt;=20
<br>&gt; wxDate date(2, 4, 2017);
<br>&gt; return date.GetDayOfWeek();
<br>
<br>This will do it;
<br>
<br>=C2=A0 =C2=A0 using namespace date::literals;
<br>=C2=A0 =C2=A0 return date::weekday{feb/4/2017}; =C2=A0// or did you mea=
n 2_d/apr/2017? so hard to tell when your only tool is int<br></blockquote>=
<div><br></div><div>Ok, I was unaware that you can construct a weekday, (an=
d I assume =C2=A0day, month, etc [upon reading date.h it seems I was assumi=
ng wrongly: only weekday has this type of constructor]) a complete date and=
 it will &quot;extract&quot; the relevant information. That seems like a ni=
ce feature.</div><div><br></div><div>Can you also do:</div><div><br></div><=
div>=C2=A0 =C2=A0 auto wd =3D date::day{system_clock::now()}<wbr>; =C2=A0//=
 Day in month right now</div><div><br></div><div>If not, why?</div></div></=
blockquote><div><br>I don&#39;t know exactly what the current library will =
do, but I don&#39;t think that code ought to work. The reason being that yo=
u could mean a lot of things:<br><br>1) Days since epoch.<br>2) Days since =
the start of the year.<br>3) Days since the start of the month.<br><br>It w=
ould be far better to make that be a compile error and require that the use=
r convert the time point explicitly to a date before extracting a day or mo=
nth from it.<br><br></div><blockquote class=3D"gmail_quote" style=3D"margin=
: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div=
 dir=3D"ltr"><div></div><blockquote class=3D"gmail_quote" style=3D"margin:0=
;margin-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex">&gt; This l=
evel of simplicity is what we should strive for.
<br>
<br>The wxWidgets code is actually unreadable to me. =C2=A0I can not read t=
hat and know what date you mean without breaking out the wxWidgets document=
ation. =C2=A0Such ambiguity is not possible in my date lib. =C2=A0Ambiguity=
 is a compile-time error.<br></blockquote><div><br></div><div>Unless you wa=
nt to play hide and seek with the compiler you would still need to open the=
 documentation if you are not already a pro. With wxDateTime you have all f=
unctionality related to dates and times in one class and thus the documenta=
tion is similarly close by when you need it. Or type a dot in the IDE if yo=
u forgot the exact method name and it will be shown in a dropdown list, mos=
t likely. (No 12 history entries in your browser).</div></div></blockquote>=
<div><br>The difference is this: With Howard&#39;s Date library, you have t=
o look up the function signatures. With wxDateTime, you have to look up wha=
t the functions <i>do</i>. With the former, a cheat-sheet of the various fu=
nctions is sufficient. With the latter, you need not just the signatures, b=
ut some added textual information to tell you what those parameters mean.<b=
r><br></div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-lef=
t: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><=
div></div><blockquote class=3D"gmail_quote" style=3D"margin:0;margin-left:0=
..8ex;border-left:1px #ccc solid;padding-left:1ex">
I feel pretty strongly that this library should build on &lt;chrono&gt;. =
=C2=A0The central theme of this library is that time_point&lt;system_clock,=
 Duration&gt; _is_ the =E2=80=9Clinear=E2=80=9D datetime representation. =
=C2=A0Choose any precision you want, it is already in your &lt;chrono&gt; h=
eader. =C2=A0Everything else is just helpers for converting to and from cal=
endars. =C2=A0And that very design decision is what will make I/O on file_t=
ime_type so convenient, functional and easy.<br></blockquote><div>Lets hope=
 for that.=C2=A0</div></div></blockquote><div><br>Hope? Hope is not a thing=
 you need to use here. This library <i>exists</i>. If you want to see if it=
 makes things &quot;convenient, functional, and easy&quot;, just download i=
t and have a go.<br><br></div><blockquote class=3D"gmail_quote" style=3D"ma=
rgin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">=
<div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin:0;margin=
-left:0.8ex;border-left:1px #ccc solid;padding-left:1ex">
&gt;=20
<br>&gt;=20
<br>&gt; Now back to more nitpicking:
<br>&gt;=20
<br>&gt; - The definition of months (the duration) is a bit scary as it rel=
ates to an &quot;average month length&quot; which means that it will not ac=
curately represent the current month when used as a duration from a year&#3=
9;s start. Is it really needed? I guess the same can be said for years, whi=
ch tries to subsume the concept of leap years but where presumably the numb=
er of years since the start of another year can be off by one on Jan 1 or D=
ec 31.
<br>
<br>months can be used both as a chrono::duration (when used with a chrono =
time_point), getting what you describe above. =C2=A0This is useful for doin=
g chronological computations on physical processes that don=E2=80=99t respe=
ct human calendars (e.g. changing weather patterns or mammalian gestation p=
eriods). =C2=A0For example:
<br>
<br>=C2=A0 =C2=A0 auto t =3D system_clock::now() + months{18}; =C2=A0// abo=
ut 18 months from now
<br>
<br>months can also be used as a calendrical duration when used with calend=
rical types and subtypes such as year_month_day and year_month. =C2=A0This =
is useful for doing calendrical computations when you require days of the m=
onth to match up, for example:
<br>
<br>=C2=A0 =C2=A0 static_assert(2017_y/jan/3 + months{18} =3D=3D jul/3/2018=
);
<br></blockquote><div><br></div><div>Are you saying that this assert will n=
ot fail for any date pairs? Surely 2017_y/feb/1 + month(1) will not be marc=
h/1/2017 as february is so short?</div></div></blockquote><div><br>Yes, tha=
t is exactly what he is saying. If you add one month to a date, it becomes =
the same day of the next month. A &quot;month&quot; is not a synonym for 30=
 days or something; it is a <i>month</i>, a typed quantity. So adding a mon=
th to a date cause that date to shift forward one month.<br><br>Or the clos=
est thing to it. If you&#39;re on March 31, and you add a month, you either=
 get April 30 or May 1; I forget which. But if you add two months, you alwa=
ys get May 31.<br><br>The library is designed to do exactly what you say. I=
f you wanted to add 30 days, you would add `day(30)`.<br><br></div><blockqu=
ote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left=
: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div></div><div>Is it=
 possible to construct a complete date from year + week number + day within=
 week? If so, what type do I get?</div></div></blockquote><div><br>Yes, the=
re&#39;s a type for that: <a href=3D"https://howardhinnant.github.io/date/i=
so_week.html">`year_weeknum_weekday`</a>. It is implicitly convertible to `=
sys_days`, so it can be explicitly converted to/from the other date types. =
<i>Any</i> other date type. So you can convert from week-numbered dates to =
the Julian calandar, then back to Year/Month/Day, and any other `sys_days`-=
compatible type someone wants to create.<br></div><blockquote class=3D"gmai=
l_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;=
padding-left: 1ex;"><div dir=3D"ltr"></div></blockquote></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/46225b93-8c06-4bb9-8abb-90a3a19b0aa4%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/46225b93-8c06-4bb9-8abb-90a3a19b0aa4=
%40isocpp.org</a>.<br />

------=_Part_2233_696891864.1497146892270--

------=_Part_2232_1413275546.1497146892269--

.


Author: Howard Hinnant <howard.hinnant@gmail.com>
Date: Sun, 11 Jun 2017 09:19:29 -0400
Raw View
--Apple-Mail=_8CDD7C8D-1773-4A7A-8E0D-062C0846D7DF
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset="UTF-8"

Hopefully helpful resources:

1.  A <chrono> tutorial:  This is a much easier way to learn about the C++1=
1/14/17 <chrono> library than reading its specification:

    https://www.youtube.com/watch?v=3DP32hvk8b13M

2.  An introduction to date.h.  Just a couple of things have changed in the=
 2 years since this video was made:

    A.  day_point has been renamed to sys_days.
    B.  The unofficial announcement by Microsoft in the Q/A period that the=
y will change the epoch of their system_clock has been unofficially reverse=
d:  They will not change their epoch, and thus it continues to be true that=
 the de-facto standard is system_clock measures Unix Time (https://en.wikip=
edia.org/wiki/Unix_time).  I hope to standardize this de facto standard in =
the future, and Microsoft has encouraged me to do so.
    C.  The I/O for types in date.h has been greatly improved with the pars=
e/format functions.

    https://www.youtube.com/watch?v=3DtzyGjOm8AKo

3.  Handling time zones and leap seconds:

    https://www.youtube.com/watch?v=3DVwd3pduVGKY

I recommend watching the videos in this order.  Each talk refers to an inde=
pendent library that builds on top of the previous talk.  The first talk is=
 already in your std::lib.  The second two talks represent a library which =
is being proposed, has been ported to Linux, macOS and Windows, and is free=
ly available as open source here:

    https://github.com/HowardHinnant/date

The link above also includes a few miscellaneous calendars which interopera=
te with the above libraries, but are not being proposed for standardization=
:  iso_week.h, julian.h and islamic.h.  So (for example), you can easily tr=
anslate a local datetime specified in the Julian calendar in the Europe/Mos=
cow timezone from the 1800=E2=80=99s into an equivalent local datetime in t=
he Gregorian calendar in the Europe/Paris timezone.

file_time_type can be handled in exactly the same way the third library han=
dles utc_time, tai_time and gps_time, all of which have I/O via the parse/f=
ormat facilities, and are inter-convertible via the namespace scope to_XXX_=
time free functions.

Howard

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/B422A9C9-CD25-4B65-85E7-B5090B6757C4%40gmail.com=
..

--Apple-Mail=_8CDD7C8D-1773-4A7A-8E0D-062C0846D7DF
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename=signature.asc
Content-Type: application/pgp-signature;
 name=signature.asc
Content-Description: Message signed with OpenPGP

-----BEGIN PGP SIGNATURE-----

iQIcBAEBCAAGBQJZPUNiAAoJEGbcHCxKqhWC7ZAP/jAJ+YhZZ1HlxEawgFUOinJo
XKpge9Q2jc5cC3iLlWFDPfvcr4kNT7mEwd2sNK4JFxPAT1IX92SIP8LcgvzqG7Rn
Kt23Y0++AtJOz0n5qKaBiKIkizgdu60ROcTGqSnaS3uVraNrYmojuANp49C/wnti
Q3Mpj07j9k7ZjWyw+VCTiOYa+mo5feVkfJlq8m2ymCYjPfk0aIfHwdLAMrNuzTNR
8zQV3B8R/pJ9dlm5bDLQdwj7ozjTqm1KrdhlLmGUJeL+kchmHEj4nbpIml7N21nH
ohkOSosdZmnTdv6jwy4bQq2Bzr2HTlX4f7zKP6gYIaldjhCOoLTWfpJnNIt1dE8Q
45gucCg9C+04uIiAosxR8OTKKIgXMGV0QuVg/WXFQpT45sEJrYcqrLceqAr4i+wc
2thFrLxQ0meLgQl7FrPAPUwN01tGUf4/ZsGA8BRyyyO/k96ss1GHerB43t4W83YQ
70wjxMo/AwQ4u6qOGaHYZJqRP2H6AU9Qv6d3WP2JaZOyQ01XXbne8j6EZ4JlMJVl
sjrPbuLEJQ0pQ918zuDTNkR8aClZIMCcnCbZCiTwkArnh6oF/fKyUeFZrx0i1hXc
GvefnGV0AMdhFQc2bJaxFwYUyAwy5frUh+F77S/UaFHKfKUkEgPTZjpo+UX4MIn7
JZ/zHXtg2wgwrsN5GmEt
=k7Wf
-----END PGP SIGNATURE-----

--Apple-Mail=_8CDD7C8D-1773-4A7A-8E0D-062C0846D7DF--

.


Author: Howard Hinnant <howard.hinnant@gmail.com>
Date: Fri, 16 Jun 2017 18:31:16 -0400
Raw View
--Apple-Mail=_C8E7EECC-16A7-48E5-822C-EF66489AD074
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset="UTF-8"

On Jun 11, 2017, at 9:19 AM, Howard Hinnant <howard.hinnant@gmail.com> wrot=
e:
>=20
> Hopefully helpful resources:
>=20
> 1.  A <chrono> tutorial:  This is a much easier way to learn about the C+=
+11/14/17 <chrono> library than reading its specification:
>=20
>    https://www.youtube.com/watch?v=3DP32hvk8b13M
>=20
> 2.  An introduction to date.h.  Just a couple of things have changed in t=
he 2 years since this video was made:
>=20
>    A.  day_point has been renamed to sys_days.
>    B.  The unofficial announcement by Microsoft in the Q/A period that th=
ey will change the epoch of their system_clock has been unofficially revers=
ed:  They will not change their epoch, and thus it continues to be true tha=
t the de-facto standard is system_clock measures Unix Time (https://en.wiki=
pedia.org/wiki/Unix_time).  I hope to standardize this de facto standard in=
 the future, and Microsoft has encouraged me to do so.
>    C.  The I/O for types in date.h has been greatly improved with the par=
se/format functions.
>=20
>    https://www.youtube.com/watch?v=3DtzyGjOm8AKo
>=20
> 3.  Handling time zones and leap seconds:
>=20
>    https://www.youtube.com/watch?v=3DVwd3pduVGKY
>=20
> I recommend watching the videos in this order.  Each talk refers to an in=
dependent library that builds on top of the previous talk.  The first talk =
is already in your std::lib.  The second two talks represent a library whic=
h is being proposed, has been ported to Linux, macOS and Windows, and is fr=
eely available as open source here:
>=20
>    https://github.com/HowardHinnant/date
>=20
> The link above also includes a few miscellaneous calendars which interope=
rate with the above libraries, but are not being proposed for standardizati=
on:  iso_week.h, julian.h and islamic.h.  So (for example), you can easily =
translate a local datetime specified in the Julian calendar in the Europe/M=
oscow timezone from the 1800=E2=80=99s into an equivalent local datetime in=
 the Gregorian calendar in the Europe/Paris timezone.
>=20
> file_time_type can be handled in exactly the same way the third library h=
andles utc_time, tai_time and gps_time, all of which have I/O via the parse=
/format facilities, and are inter-convertible via the namespace scope to_XX=
X_time free functions.

I=E2=80=99ve updated my proposal to include wording for I/O on file_time_ty=
pe:

    https://howardhinnant.github.io/date/d0355r3.html

Comments welcome.

Howard

--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/3D05C42E-DA76-47CC-B4E9-6241AD78B8B8%40gmail.com=
..

--Apple-Mail=_C8E7EECC-16A7-48E5-822C-EF66489AD074
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename=signature.asc
Content-Type: application/pgp-signature;
 name=signature.asc
Content-Description: Message signed with OpenPGP

-----BEGIN PGP SIGNATURE-----

iQIcBAEBCAAGBQJZRFw1AAoJEGbcHCxKqhWCdo4P/1aSZxY3edqQ2joJCEZxCT8m
0I0z4fCLIlds9Y07iw7jDVZ9GBxdeIgzT18YViYS4tq43SpcDiN8rGCUXdPCO82E
GD6SIxl5lmsJQ5vyDJkGcU1fEpqfExpseBOyBfVxwQiu/2fFzv6BkF5i90XqV4t+
btZBf4KS7ssmz/TaMcupdeR03lnb7MsEYcK9gYjRF9JOu93d6xCcV2IGlnivVfB3
boyhD289bo9kHF2n3BXIbziOESYd33JaTLk6Jj2TTbOAiIAmij0Hd9ZkYI4R5ETk
qD7E26V9YJFunCl//y5+NY8k06okuFgCZzwo+Z22J5jFS05kW/VKKsKS/ZzCCXOh
O5eCeVpHyeZl6OmHS5LtBujUSrBMHfNYABo2HQyNBC4dK+yZXzS3rw4ALsHpK9Nn
+miFwUvF/Ub5hv1rxr0lbZ49znAfOM917eEOrs1PRPyXh3Py+TQ2X7KW7Mu58vOL
ebg5xkrVxeNQB89TcaMgbOu7x1/h8zDLFTRSsQ0BIpi1+QyRnUv+ThWKmLyhNrAd
oK0dhUeELW22wNHJzZLKqlsakejS2DZl5ogmklf3lcd5trdju/876Uxk8Lyp202Z
OBG2hDyntZ79JPATqxTecFxFK5wFWbu7TY/G3XFMF9FmbKHeQG48v4VciwOOFxT2
zGAq3Tp25Fnh8rnHkgX4
=3mvu
-----END PGP SIGNATURE-----

--Apple-Mail=_C8E7EECC-16A7-48E5-822C-EF66489AD074--

.