From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from b-painless.mh.aa.net.uk ([81.187.30.52]) by ewsd; Wed Apr 8 02:48:44 EDT 2020 Received: from 132.198.187.81.in-addr.arpa ([81.187.198.132] helo=quintile.net) by b-painless.mh.aa.net.uk with esmtp (Exim 4.92) (envelope-from ) id 1jM4VZ-0002Jq-Cc for 9front@9front.org; Wed, 08 Apr 2020 07:48:21 +0100 Received: from [192.168.1.37] ([81.187.198.132]) by quintile.net; Wed Apr 8 07:48:19 BST 2020 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable From: Steve Simon Mime-Version: 1.0 (1.0) Subject: Re: [9front] Date and time handling. Date: Wed, 8 Apr 2020 07:48:18 +0100 Message-Id: <43B494B5-78E6-4967-ACE5-289ADD02CD2F@quintile.net> References: <09D185393BD8E86D37288FC967E7EA69@eigenstate.org> In-Reply-To: <09D185393BD8E86D37288FC967E7EA69@eigenstate.org> To: 9front@9front.org X-Mailer: iPhone Mail (17E255) List-ID: <9front.9front.org> List-Help: X-Glyph: ➈ X-Bullshit: property enhancement extension backend well done! i tried to do this years ago whilst writing an ical parser - and gave up in h= orror. -Steve > On 8 Apr 2020, at 5:57 am, ori@eigenstate.org wrote: >=20 > =EF=BB=BFHi, >=20 > Date handling on 9front is almost adequate today if you don't > have to parse dates or deal with timezones, and don't do > multithreading. Otherwise, it's difficult to get right, and > we often don't. >=20 > We've got a crappy home-rolled date parser in seconds(1), > a few in the upas source tree to deal with mail formats, > and git9 has a few hacks around this as well. >=20 > Out of tree, joe9 has been trying to write code that takes > stock information in one timezone and moves them to another, > and our APIs there are completely inadequate. >=20 > So, I tried to write a library that is adequate, without > being complicated. >=20 > It allows working with times in multiple timezones at the > same time. It is thread safe, including timezone loading. > It allows parsing and formatting arbitrary formats. It lets > you adjust the day and figure out the timeshift-shift > adjusted time. >=20 > Eventually, when it's ready (not yet), I'd like to put this > into libc. The API additions are small, and all of our curent > time APIs can be implemented trivially in terms of this api. > At worst, I'd like to add the field additions from struct tmd > to it. >=20 > There are a few known bugs -- not all fields of the time struct > are filled in yet, for example. >=20 > The code is here: >=20 > https://git.eigenstate.org/ori/date.git >=20 > The formatted draft of the manpage is below, for comments and > thoughts: >=20 > TMDATE(2) TMDATE(2) >=20 > NAME > tmnow, tmtime, tmstime, tmshiftzone, tmparse, tmfmt, tmnorm, > - convert date and time >=20 > SYNOPSIS > #include > #include >=20 > typedef struct Tmd Tmd; > struct { > vlong abs; /* milliseconds since Jan 1 1970, GMT */ > int sec; /* seconds (range 0..59) */ > int min; /* minutes (0..59) */ > int hour; /* hours (0..23) */ > int mday; /* day of the month (1..31) */ > int mon; /* month of the year (0..11) */ > int year; /* year A.D. - 1900 */ > int wday; /* day of week (0..6, Sunday =3D 0) */ > int yday; /* day of year (0..365) */ > char zone[]; /* time zone name */ > int tzoff; /* time zone delta from GMT */ > }; >=20 > Tm *tmnow(Tm *tm, char *tz); > Tm *tmtime(Tm *tm, vlong abs, char *tz); > Tm *tmstime(Tm *tm, vlong sec, char *tz); > Tm *tmshiftzone(Tm *dst, Tm *src, char *tz); > Tm *tmparse(Tm *dst, char *fmt, char *tm); > int tmfmt(char *buf, usize nbuf, char *fmt, Tm *tm); > void tmnorm(Tm *tm); > void tmfmtinstall(char *fmt); >=20 > DESCRIPTION > This family of functions handles simple date and time manpu- > lation. Times are represented as an absolute instant in > time, combined with a time zone. >=20 > Time zones are represented as strings. They can be provided > as the abbreviated timezone name, the full timezone name, > the path to a timezone file, or an absolute offset in the > HHMM form. >=20 > When given as a timezone name, any instant-dependent adjust- > ments such as leap seconds and daylight savings time will be > applied to the derived fields of struct tm, but will not > affect the absolute time. The time zone name local always > refers to the time in /env/timezone. >=20 > Tmnow gets the current time of day in the requested time > zone. >=20 > Tmtime converts the millisecond-resolution timestamp 'abs' > into a Tm struct in the requested timezone. >=20 > Tmstime is identical to tmtime, but accepts the time in sec- > onds. >=20 > Tmshiftzone moves a time from one timezone to another, doing > the appropriate conversions. >=20 > Tmparse parses a time from a string according to the format > argument. The format argument takes the form of a special > date string, with the following components: >=20 > 1,Jan,January > Represents the month in numeric, short, or long form, > respectively. >=20 > 2 The day of month. >=20 > 3,Mon,Monday > The day of week in numeric, short, or long form, > respectively. >=20 > 3,15 The hour in 12 or 24 hour time, respectively. >=20 > 4 The minute. >=20 > 5 The second. >=20 > 6,2006 > The year in 2 and 4 digit forms, respectively. >=20 > 7,MST > The time zone offset in numeric or abbreviated form. > As a special case, 7:00 will fill in both the hour and > minutes in the timezone. >=20 > _ Pads the following field with spaces. 0 Pads the fol- > lowing field with zeroes. >=20 > If the format argument is nil, it makes an attempt to parse > common human readable date formats. These formats include > ISO-8601,RFC-3339 and RFC-2822 dates. >=20 > Tmfmt formats a Tm struct according to the format fmt. If > fmt is nil, we format as in ctime(2). At most nbuf-1 char- > actters are written into buf, which is nul-terminated. >=20 > Tmrecalc takes a manually adjusted Tm structure, and recal- > culates the absolute time from it. This recalculation > respects the time zone stored in struct tm. It also takes > out of range values and wraps them around, simplifying cal- > culations >=20 > Tmfmtinstall installs a time format specifier %T. The time > format behaves as in tmfmt >=20 > Examples > All examples assume tmfmtinstall has been called. >=20 > Get the current date in the local timezone, GMT, and > US_Pacific time. Print it using the default format. >=20 > Tm t; > print("local: %T0, tmnow(&t, "local")); > print"gmt: %T0, tmnow(&t, "GMT")); > print("eastern: %T0, tmnow(&t, "US_Pacific")); >=20 > Compare if two times are the same, regardless of timezone. >=20 > Tm a, b; >=20 > tmparse(&a, nil, "Tue Dec 10 12:36:00 PST 2019"); > tmparse(&b, nil, "Tue Dec 10 15:36:00 EST 2019"); > if(a.abs =3D=3D b.abs) > print("same0); > else > print("different0); >=20 > Add a day to two times. Because we picked daylight savings > time to adjust over, only 23 hours are added. >=20 > Tm t; > tmparse(&t, nil, "Sun Nov 2 13:11:11 PST 2019"); > tm.day++; > tmrecalc(&t); > print("%T", &t); /* Mon Nov 3 13:11:11 PST 2019 */