3

TL;DR:     The predicate datime/2 (offered by SICStus Prolog and SWI-Prolog) relates UNIX time to a record containing year, month, day, hour, minute, and second.

For some corner cases I got weird answers which made me wonder: Which error(s) should ISO-compliant Prolog systems raise in these cases?


First, here's the datime/2 documentation—part of the SICStus Prolog Manual:

now(-When)     Unifies the current date and time as a UNIX timestamp with When.

datime(-Datime)     Unifies Datime with the current date and time as a datime/6 record of the form datime(Year,Month,Day,Hour,Min,Sec). All fields are integers.

datime(+When,-Datime) datime(-When,+Datime)     Convert a time stamp, as obtained by now/1, to a datime/6 record. Can be used in both directions.

So here is some spurious SICStus Prolog 4.6.0 output:

| ?- use_module(library(system)).
yes
| ?- datime(X,Y).
no                           % expected: result | error
| ?- datime(-67768200000000000,X).
no                           % expected: result | error
| ?- datime(X,datime(19700000000000,1,1,1,0,0)).
X = -32029950380687608 ? ;   % expected: X >= 0
no

And here come some weird "answers" given by SWI-Prolog 8.2.0:

?- use_module(library(dialect/sicstus/system)).
true.

?- datime(X,datime(1970,1,1,1,0,0)).
ERROR: Arguments are not sufficiently instantiated
% expected: X = 0

?- datime(10000000000000000000000000,X).
X = datime(1901, 1461302465, 32753, 9, 35, 13).

?- datime(1000000000000000000000000000,X).
X = datime(1901, 1461302465, 32753, 9, 35, 13).

?- datime(100000000000000000000000000000,X).
X = datime(1901, 1461302465, 32753, 9, 35, 13).
% expected: different answers for different queries

So: Which error(s) should a ISO-compliant Prolog system raise in these cases?

repeat
  • 18,496
  • 4
  • 54
  • 166
  • It is my contention that you can either 1) Stay ISO compliant or 2) Have meaningful exceptions. But not both. – David Tonhofer Apr 19 '21 at 13:10
  • 1
    @DavidTonhofer: Could you give one (1) example, that affirms your contention? – false Apr 19 '21 at 14:15
  • @false Does it suffice if I say that Java does not list the set of allowed Exceptions in the language specification? But ok: There is no exception for "Contract Violation" or "Assertion Failure", for one. – David Tonhofer Apr 19 '21 at 14:32
  • @DavidTonhofer: how does this relate to 2? – false Apr 19 '21 at 14:35
  • @false It's because you need to shoehorn the semantics about the problem you encountered into one of the available exceptions that the standard designers happened to think of at the time. In a next iteration of the standard, it would be cool to open that up. – David Tonhofer Apr 19 '21 at 14:40
  • 1
    @DavidTonhofer: So far, you have not given one **concrete** example for your initial contention. You have made just some highly abstract remarks. – false Apr 19 '21 at 14:43
  • 1
    @DavidTonhofer. Let's keep the focus on Prolog. I can't worry about both Prolog and Java at the same time. – repeat Apr 19 '21 at 16:06

1 Answers1

2

You want to determine the appropriate error for cases were the Unix timestamp value is unreasonably off the "intended" range. It is unclear to me whether or not negative numbers make sense. But at least, they seem to produce reasonable dates in the years 0..1972. The second argument could be a proper domain, or simply fail for non-unifiable terms.

From the existing error classification in 7.12.2 we have the following candidates:

b) a type error. Designating a special type seems a bit too far fetched. After all, not even the non-negative numbers deserve a separate type, instead they are a domain not_less_than_zero.

c) a domain error. This seems to be a good candidate. So the domain may be unix_timestamp - should that be a well defined data type; or datime.

f) a representation error. While type and domain errors imply semantic failure ("such a time cannot exist"), a representation error doesn't. It just states that the current processor cannot represent that date but no conclusion is given about what this could mean.

So I have some tendency to favor f, simply because the notion of time does not seem to have a limit not even for the year (or timestamp) 7^7^7. I know that is true optimism...

Both implementations seem to have some problems with instantiation errors, SWI produces too many of them and SICStus not enough - this library is relatively new in SICStus and from Quintus descent.

As a general rule for instantiation errors, consider what is required for new options in 5.5.12. So if an instance of the second argument is a valid date, then there has to be an instantiation error. But the instantiation error may also be produced, if there is no instance that is valid but where a component is still a variable. Think of datime(T, datime(noyear,_,_,_,_,_)). You could go as far as producing the instantiation error for any nonground term.

false
  • 10,264
  • 13
  • 101
  • 209
  • Suppose I go for representation_error... As the actual value is not part of the error/2 compound, could I use, say, `representation_error(datetime)` for both modes (+,-) *and* (-,+) ? – repeat Apr 19 '21 at 19:49
  • I'm not worrying a whole lot about this corner case, it is way beyond the year 2525... Still, as a matter of principle, I want to avoid resorting to "silent failure". – repeat Apr 19 '21 at 19:52
  • By (-,+) you mean what exactly? A too large year is OK. But what about the over values? It seems at least in SWI, that you can put there larger values too. Such that you can easily determine the timestamp, say, 100 days away from the current one. Or 1000s etc. – false Apr 19 '21 at 19:53
  • 1
    I like that. It *is* a bit sloppy, but in a way that is useful sometimes. I guess I will need to write a program to find out about the *exact* limits of the underlying function. – repeat Apr 19 '21 at 19:56
  • OTOH permitting larger values for, say the day number means that `datime/2` would not be a relation... – false Apr 19 '21 at 20:04
  • Ideally, there are two relations, one 1to1 which fails/produces a domain error for months, days, hours, ... out of their range. And then one infinitelymany to 1 which accepts also values that are larger. The same is the case for number_chars/2 – false Apr 20 '21 at 08:14