Still toying around with SWI-Prolog parse_time/3. It seems that
JavaScript Date.parse(), implements a very peculiar rule for
input dates that don’t have a time zone indicator:
> Date.parse("2024-09-27")
1727395200000 /* UTC time */
> Date.parse("2024-09-27T11:12:11")
1727428331000 /* locale time +0200 */
> Date.parse('Fri, 27 Sep 2024 11:12:11')
1727428331000 /* locale time +0200 */
On the other hand SWI-Prolog always gives UTC time:
?- parse_time('2024-09-27', Format, X).
Format = iso_8601,
X = 1727395200.0. /* UTC time */
?- parse_time('2024-09-27T11:12:11', Format, X).
Format = iso_8601,
X = 1727435531.0. /* UTC time */
?- parse_time('Fri, 27 Sep 2024 11:12:11', Format, X).
Format = rfc_1123,
X = 1727435531.0. /* UTC time */
On the other hand, if a time zone is present, the predicate
parse_time/3 seems to be able to deal with some nifty details:
Its a different result, than if you would use GMT in parse_time/3:
?- parse_time('Fri, 27 Sep 2024 11:12:11 +0200', Format, X).
Format = rfc_1123,
X = 1727428331.0.
?- parse_time('Fri, 27 Sep 2024 11:12:11 GMT', Format, X).
Format = rfc_1123,
X = 1727435531.0.
The behaviour agrees with JavaScript Date.parse():
If you use +0200 you get local time, provided you used the offset that
corresponds to your local time. +0200 corresponds to my offset,
which is “Mitteleuropäische Sommerzeit”. If you use GMT you
get UTC time. In as far +0200 is not suitable for a HTTP time.
Since HTTP time is in UTC time and not in local time:
Pushed some patches to clean up this stuff. Notably
http_timestamp/2 now works in both directions
http_parse_header_value/3 now allows parsing the expires field
parse_time/3 now uses local time if the time zone is unspecified, unless there are no time components. The grammar is cleaned to leave all missing components unbound rather than implicitly specified, so we can distinguish on what is specified (currently only internally).
date_time_stamp/2 now allows leaving components unspecified from the right.
I’m still considering adding strptime() support. In itself, this is pretty easy. Portability seems an issue though
I guess use one of the implementations for Windows floating around on the internet. That is what I would do as well, but it is often cumbersome for legal reasons and/or technical reasons In any case, a lot more work than just calling the function from the C runtime library.
I had a little look, but I have my doubt about strptime(). Getting access to the time zone, etc. seems not trivial. I think you claimed some Prolog system supported it, but I can’t find the post anymore.
A more Prolog minded approach would be to provide DCGs that do useful things, such as matching the name for a day in the week and map it to its ordinal number in the current locale or map time zone names to their properties. It is not easy to get to this though. Probably the only portable way to get to the local day and month names and their abbreviations is by converting time stamps to their locale strings
On the other hand I do support it, even on Windows, but either via hand
rolled (Java Calendar / JavaScript DateTimeFormat) or via the Python call.
Yes thats a trick that Python does in some place. You can use 2001-1-1 which
was a monday, to get weekdays and month names as their local name, here
weekdays starting with sunday, from module calendar:
_months = [datetime.date(2001, i+1, 1).strftime for i in range(12)]
_weekdays = [datetime.date(2001, 1, i+1).strftime for i in range(7)]
But the module calendar is not the module where Python implements strptime().
I haven’t figured out yet where it is implemented. Maybe they compile
Python with an extra C-library.
?- format_time(atom(X), '%Y-%m-%d', -7506086400.0).
X = '1732-02-22'.
Not sure exactly what happens. The POSIX time functions are mostly based on time_t, which makes it cannot represent 1732. SWI-Prolog’s time stamps are a float, so we can cover a wide range. Translation to strings uses a mixture of dedicated code and strftime(), where it seems the Windows version does something strange
Pushed a fix for that. Note that times way back get a bit ambiguous due to various calendar changes and time zones will certainly not be relevant …
Otherwise, the strptime() route is IMO no very fruitful. The API cannot deal meaningfully with time zones and DST. While it has a %Z specifier, the tm struct cannot represent this and it seems to have no effect whether I specify GMT or CEST. Possibly I miss something. Some searching mostly reports problems though
There are several packs for processing date and time. That seems a more fruitful route. SWI-Prolog itself just needs to represent this stuff and deal with a couple of standard formats.
It is not MUST in Python, possibly only a MAY, the docu says.
It doesn’t mention %Z only %z:
%z Time zone offset from UTC.
Other codes may be available on your platform.
Currently I neither support %Z nor %z, which is maybe not wise.
Also I didn’t implement the implicit JavaScript Date logic. And to
choose between utc and local one has to use the explicit option list,
which is similar like format_time/4 has an additional parameter.
In as far the time zone offset is one more local dependent information,
just like the month names and weekday names, which would need
some local database access. This should be sufficient for HTTP
time. Might cause problems for SMTP time. Might do something
in the future, but currently anyway do not provide a SMTP client.
4.4 Trace Information
SMTP servers that create Received header fields SHOULD
use explicit offsets in the dates (e.g., -0800), rather than time
zone names of any type. https://datatracker.ietf.org/doc/html/rfc5321