From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from tb-mx0.topicbox.com (localhost.local [127.0.0.1]) by tb-mx0.topicbox.com (Postfix) with ESMTP id D7A7C237016B for <9fans@9fans.net>; Sat, 25 Apr 2020 23:14:20 -0400 (EDT) (envelope-from calvin@fastmailteam.com) Received: from tb-mx0.topicbox.com (localhost [127.0.0.1]) by tb-mx0.topicbox.com (Authentication Milter) with ESMTP id 3F5F7FDF858; Sat, 25 Apr 2020 23:14:20 -0400 ARC-Seal: i=1; a=rsa-sha256; cv=none; d=topicbox.com; s=arcseal; t= 1587870860; b=BbqHVugyxPvoQlXgBqBRVz8rH4SUGa95dOAZSXgscHVJJaodbF dJNxMqwtUAc1wYZa3vd4x331osE4Qx5Ew1ZJczfVOb62kW457k6qAe1eJuCFa/gW zImg3RTJ0TDqvHEixL49JgwBkWiSttNJsma7FK/az6oPHAFeX00gS4F4B+kauTgk UniABnKQTsSOzIKcHQ+OIgnh7mkqTKiTV4e28RmHGoG79o11kvPMdcWA1KS9PX36 deNqdACxXvTIXeAUNktzSTtyimx6opx5epVhlxApxHuPetRYltHscAmdZTvjU50w 23wYGW5Ec0PmBoRmMjND4JaWMS6LNbFkG8wQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d= topicbox.com; h=mime-version:message-id:in-reply-to:references :date:from:to:subject:content-type:content-transfer-encoding; s= arcseal; t=1587870860; bh=LPnIaj+AdhoSlQhHSrFMXtI34vbjrKicrf7ZTd UBLqY=; b=ufYEFy6fsmRcyikvisqtvgdBStZuJatuTlhdQlHt5LBHFwEhUOp/6v iYFFXe419LlB7vob6AHDWuSJttmcHkFUc6gM/TfQTA3Po3iLVDxsShCZQp3HLb5f C0NJnoe4ANd2uFHEPDBiFkQot13iQX9NmvtFwnFWiWNNYrx7sZt9c+1OMC//L3jV L5hTlsbwM4MO5KL43RgrJf1qG2O+1R9V0Tg/qQDg4I3u6BeYI+fu5SdMBJKwCwC2 4ffOaQz/gxY8lDSU7GOPGaWRSdPNE6tooUwtEtf6hqjHZUOZCfaySPnhplE6nuzV nnXap4XCSFi0ENDSDbQJmafR7O/JunIQ== ARC-Authentication-Results: i=1; tb-mx0.topicbox.com; arc=none (no signatures found); bimi=pass header.d=fastmailteam.com selector=default; dkim=pass (2048-bit rsa key sha256) header.d=fastmailteam.com header.i=@fastmailteam.com header.b=bw2njysL header.a=rsa-sha256 header.s=fm2 x-bits=2048; dkim=pass (2048-bit rsa key sha256) header.d=messagingengine.com header.i=@messagingengine.com header.b=bbnfalHs header.a=rsa-sha256 header.s=fm2 x-bits=2048; dmarc=pass policy.published-domain-policy=none policy.applied-disposition=none policy.evaluated-disposition=none (p=none,d=none,d.eval=none) policy.policy-from=p header.from=fastmailteam.com; iprev=pass smtp.remote-ip=66.111.4.29 (out5-smtp.messagingengine.com); spf=pass smtp.mailfrom=calvin@fastmailteam.com smtp.helo=out5-smtp.messagingengine.com; x-aligned-from=pass (Address match); x-ptr=pass smtp.helo=out5-smtp.messagingengine.com policy.ptr=out5-smtp.messagingengine.com; x-return-mx=pass header.domain=fastmailteam.com policy.is_org=yes (MX Records found: in2-smtp.messagingengine.com,in1-smtp.messagingengine.com); x-return-mx=pass smtp.domain=fastmailteam.com policy.is_org=yes (MX Records found: in2-smtp.messagingengine.com,in1-smtp.messagingengine.com); x-tls=pass smtp.version=TLSv1.2 smtp.cipher=ECDHE-RSA-AES256-GCM-SHA384 smtp.bits=256/256; x-vs=clean score=-100 state=0 Authentication-Results: tb-mx0.topicbox.com; arc=none (no signatures found); bimi=pass header.d=fastmailteam.com selector=default; dkim=pass (2048-bit rsa key sha256) header.d=fastmailteam.com header.i=@fastmailteam.com header.b=bw2njysL header.a=rsa-sha256 header.s=fm2 x-bits=2048; dkim=pass (2048-bit rsa key sha256) header.d=messagingengine.com header.i=@messagingengine.com header.b=bbnfalHs header.a=rsa-sha256 header.s=fm2 x-bits=2048; dmarc=pass policy.published-domain-policy=none policy.applied-disposition=none policy.evaluated-disposition=none (p=none,d=none,d.eval=none) policy.policy-from=p header.from=fastmailteam.com; iprev=pass smtp.remote-ip=66.111.4.29 (out5-smtp.messagingengine.com); spf=pass smtp.mailfrom=calvin@fastmailteam.com smtp.helo=out5-smtp.messagingengine.com; x-aligned-from=pass (Address match); x-ptr=pass smtp.helo=out5-smtp.messagingengine.com policy.ptr=out5-smtp.messagingengine.com; x-return-mx=pass header.domain=fastmailteam.com policy.is_org=yes (MX Records found: in2-smtp.messagingengine.com,in1-smtp.messagingengine.com); x-return-mx=pass smtp.domain=fastmailteam.com policy.is_org=yes (MX Records found: in2-smtp.messagingengine.com,in1-smtp.messagingengine.com); x-tls=pass smtp.version=TLSv1.2 smtp.cipher=ECDHE-RSA-AES256-GCM-SHA384 smtp.bits=256/256; x-vs=clean score=-100 state=0 BIMI-Location: v=BIMI1; l=https://www.fastmail.com/static/images/logo-icon-white.svg X-ME-VSCause: gggruggvucftvghtrhhoucdtuddrgeduhedrheehgdeiiecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpggftfghnshhusghstghrihgsvgdpuffr tefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnth hsucdlqddutddtmdenucfjughrpefofgggkfgjfhffhffvufgtgfesthhqredtreerjeen ucfhrhhomhepfdevrghlvhhinhcuofhorhhrihhsohhnfdcuoegtrghlvhhinhesfhgrsh htmhgrihhlthgvrghmrdgtohhmqeenucffohhmrghinhepvghighgvnhhsthgrthgvrdho rhhgpdhtohhpihgtsghogidrtghomhenucfkphepieeirdduuddurdegrddvleenucevlh hushhtvghrufhiiigvpedtnecurfgrrhgrmhepihhnvghtpeeiiedrudduuddrgedrvdel pdhhvghlohepohhuthehqdhsmhhtphdrmhgvshhsrghgihhnghgvnhhgihhnvgdrtghomh dpmhgrihhlfhhrohhmpeeotggrlhhvihhnsehfrghsthhmrghilhhtvggrmhdrtghomheq ucfukfgkgfepuddviedtledpmhgrihhlfhhrohhmpegtrghlvhhinhesfhgrshhtmhgrih hlthgvrghmrdgtohhm X-ME-VSScore: -100 X-ME-VSCategory: clean Received-SPF: pass (fastmailteam.com: Sender is authorized to use 'calvin@fastmailteam.com' in 'mfrom' identity (mechanism 'include:spf.messagingengine.com' matched)) receiver=tb-mx0.topicbox.com; identity=mailfrom; envelope-from="calvin@fastmailteam.com"; helo=out5-smtp.messagingengine.com; client-ip=66.111.4.29 Received: from out5-smtp.messagingengine.com (out5-smtp.messagingengine.com [66.111.4.29]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by tb-mx0.topicbox.com (Postfix) with ESMTPS for <9fans@9fans.net>; Sat, 25 Apr 2020 23:14:20 -0400 (EDT) (envelope-from calvin@fastmailteam.com) Received: from compute3.internal (compute3.nyi.internal [10.202.2.43]) by mailout.nyi.internal (Postfix) with ESMTP id 798685C05B6 for <9fans@9fans.net>; Sat, 25 Apr 2020 23:14:20 -0400 (EDT) Received: from imap7 ([10.202.2.57]) by compute3.internal (MEProxy); Sat, 25 Apr 2020 23:14:20 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= fastmailteam.com; h=mime-version:message-id:in-reply-to :references:date:from:to:subject:content-type :content-transfer-encoding; s=fm2; bh=LPnIaj+AdhoSlQhHSrFMXtI34v bjrKicrf7ZTdUBLqY=; b=bw2njysLSNWkSPCmi9c7rL7Ic1W5yMBxFxNTV+O+qT LIlGCU2Jnjt6+IDE8v5PZRyJNzv0zTl4pSSpJpzR5YnSY9LKQU8ejXjpkUGsO0CS oJk8+4bmkhLuzDJr7880iwb9q0zy/S9n3LraT2S72NO8zrFbpR4qkg6OEnlB62gv Nblm4KQ8ZqPbwIZXTFkanvGzqSucgraGtC/kN8J7B+yswwCa8zRlAjEnIYksqj2n nqcNTC43fyS5dewD4zdEWPj/JyNR+PJ2RAz7eBuFaDx3Gv/+S2mELnqp1+uCuSAK 77s6PXaVoiEXc2ClvSFbOWCUfPSJ9S+0/9MPlIN1jHbA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-transfer-encoding:content-type :date:from:in-reply-to:message-id:mime-version:references :subject:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm2; bh=LPnIaj+AdhoSlQhHSrFMXtI34vbjrKicrf7ZTdUBL qY=; b=bbnfalHsZRovcIVIMZ+lILcWyhPokdXnLEiA73/qT48fN2g1gZHo3n4Ui k3sRJjxBo6umdvjdAf3/Z9YHZP8Q4G4kr3YChhXPkGHNZyYQK4oLUyH7D/OMeijd icsuhqSqt8dWvwFkcWcgkLvwNp2u2vvEFOKAt8USVEGJ/jYXU5JtxyIiV6wM1KJj 74xKY5Ks84PNFoO0Im0mvUoN0n45SRiw6DXsUCE7o/qS68ut6Cgt2eIu9y3JEUDj rccdlie9YdmwC9GBhElEc53ygZIBbyrAcbVtunoy4LeZcFIDpnnJPy+mhPYRWg5c qOyYemDtMBpiJqs6RavHSYemn7sww== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrheehgdeiiecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefofgggkfgjfhffhffvufgtgfesthhqredtreerjeenucfhrhhomhepfdevrghl vhhinhcuofhorhhrihhsohhnfdcuoegtrghlvhhinhesfhgrshhtmhgrihhlthgvrghmrd gtohhmqeenucffohhmrghinhepvghighgvnhhsthgrthgvrdhorhhgpdhtohhpihgtsgho gidrtghomhenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhroh hmpegtrghlvhhinhesfhgrshhtmhgrihhlthgvrghmrdgtohhm X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id 371B6180091; Sat, 25 Apr 2020 23:14:20 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.3.0-dev0-351-g9981f4f-fmstable-20200421v1 Mime-Version: 1.0 Message-Id: <42e9dc9c-28f8-440d-a712-6d6e9bf59bdc@dogfood.fastmail.com> In-Reply-To: <756B454F0747C231D31E8E3D3AFA3113@eigenstate.org> References: <756B454F0747C231D31E8E3D3AFA3113@eigenstate.org> Date: Sat, 25 Apr 2020 23:14:20 -0400 From: "Calvin Morrison" To: "g_patrickb via 9fans" <9fans@9fans.net> Subject: Re: [9fans] libdate Content-Type: text/plain;charset=utf-8 Content-Transfer-Encoding: quoted-printable Topicbox-Policy-Reasoning: allow: sender is a member Topicbox-Message-UUID: 07ffb20c-876c-11ea-88e1-c240cf0f459f > Time zones are loaded by as name. =20 Extra word? On Sat, Apr 25, 2020, at 8:54 PM, ori@eigenstate.org wrote: > Date handling on plan 9 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 > The code lives here: >=20 > https://git.eigenstate.org/ori/date.git >=20 > I'll probably be merging in the changes between Tmd and Tm > soon, and committing to 9front, possibly even as part of libc. >=20 > Some additional work is probably going to be needed to convert > from IANA zoneinfo to actually bring our timezone data up to > date. We may also need some timezone info format changes to > handle political (and leap second) changes. >=20 >=20 > The manpage is attached below for review: >=20 > TMDATE(2) TMDATE(2)= >=20 > NAME > tmnow, tmgetzone, tmtime, tmstime, tmparse, tmfmt, tmnorm, -= > convert date and time >=20 > SYNOPSIS > #include > #include >=20 > typedef struct Tmd Tmd; > struct Tmd { > vlong abs; /* seconds 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 > Tzone *tmgetzone(char *name); > Tmd *tmnow(Tmd *tm, char *tz); > Tmd *tmtime(Tmd *tm, vlong abs, Tzone *tz); > Tmd *tmstime(Tmd *tm, vlong sec, Tzone *tz); > Tmd *tmparse(char *fmt, char *tm, Tzone *zone, Tmd *dst);= > int tmfmt(char *buf, usize nbuf, char *fmt, Tmd *tm); > void tmnorm(Tmd *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 loaded by as name. They can be specified 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, any instant-dependent adjustments > 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. The nil timezone > always refers to GMT. >=20 > Tmgetzone loads a timezone by name. The returned timezone is= > cached for the lifetime of the program, and should not be > freed. Loading a timezone repeatedly by name loads from the= > cache, and does not leak. >=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 > Tmparse parses a time from a string according to the format > argument. The result is returned in the timezone requested. > If there is a timezone in the date, then we tzshift to the > local timezone. >=20 > The format argument takes contains zero or more of the fol- > lowing components: >=20 > Y, YY, YYYY > Represents the year. YY prints the year in 2 digit > form. >=20 > M, MM, MMM, MMMM > The month of the year, in unpadded numeric, padded > numeric, short name, or long name, respectively. >=20 > D, DD > The day of month in unpadded or padded numeric form, > respectively. >=20 > W, WW > The day of week in short or long name form, respec- > tively. >=20 > h, hh > The hour in unpadded or padded form, respectively >=20 > m, mm > The minute in unpadded or padded form, respectively >=20 > s, ss > The second in unpadded or padded form, respectively >=20 > z, Z, ZZ > The timezone in named, [+-]HHMM and [+-]HH:MM form, > respectively >=20 > a, A Lower and uppercase 'am' and 'pm' specifiers, respec- > tively. >=20 > [...] > Quoted text, copied directly to the output. >=20 > Any characters not specified above are copied directly to > output, without modification. >=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 characters are= > written into buf, including the terminator. The format is > identical to tmparse. >=20 > When parsing, any amount of whitespace is treated as a sin- > gle token. All string matches are case insensitive, and > zero padding is optional. >=20 > Tmrecalc takes a manually adjusted Tm structure, and recal- > culates the absolute time from the year, mon, mday, hr, min > and sec fields. Other fields are ignored. This recalcula- > tion respects the time zone stored in struct tm. Out of > range values are wrapped. For example, December 32nd becomes= > January 1st. >=20 > Tmfmtinstall installs a time format specifier %=CF=84. The t= ime > 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; > Tzone *zl, *zp; > if((zl =3D tmgetzone("local") =3D=3D nil) > sysfatal("load zone: %r"); > if((zp =3D tmgetzone("US_Pacific") =3D=3D nil) > sysfatal("load zone: %r"); > print("local: %=CF=84\n", tmnow(&t, zl)); > print("gmt: %=CF=84\n", tmnow(&t, nil)); > print("eastern: %=CF=84\n", tmnow(&t, zp)); >=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("same\n"); > else > print("different\n"); >=20 > Convert from one timezone to another. >=20 > Tm here, there; > Tzone *zl, *zp; > if((zl =3D tmgetzone("local") =3D=3D nil) > sysfatal("load zone: %r"); > if((zp =3D tmgetzone("US_Pacific") =3D=3D nil) > sysfatal("load zone: %r"); > if(tmnow(&here, zl) =3D=3D nil) > sysfatal("get time: %r"); > if(tmtime(&there, here.abs, zp) =3D=3D nil) > sysfatal("shift time: %r"); >=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, "W MMM D hh:mm:ss z YYYY, "Sun Nov 2 13:11:11 PS= T 2019"); > tm.day++; > tmrecalc(&t); > print("%=CF=84", &t); /* Mon Nov 3 13:11:11 PST 2019 */ >=20 >=20 > ------------------------------------------ > 9fans: 9fans > Permalink:=20 > https://9fans.topicbox.com/groups/9fans/T5b9f56a5fac852c2-Mca6c8f44f1a= 159d02b37302b > Delivery options: https://9fans.topicbox.com/groups/9fans/subscription= >