a question or two regarding Gregor

78 views
Skip to first unread message

Tim Hanson

unread,
Apr 27, 2020, 2:37:56 AM4/27/20
to Racket Users
hi, I've installed and am trying out

Gregor: a date and time library for Racket

and find it to be very powerful and useful.

In my current application (digging through mail headers) I'm wondering whether there is a way to test whether a given date-time format matches without using exceptions. (I assume that would generally be more efficient than catching exceptions.)

I've forked https://github.com/97jaz/gregor

and successfully added a couple of tests that work to tests/parse.rkt:

(test-suite
"some datetime particulars"
(check-equal?
(parse-datetime "2015-03-15T02:02:02-04:00" "yyyy-MM-dd'T'HH:mm:ssxxx") (datetime 2015 3 15 2 2 2))

(parameterize ([current-locale "en"])
(check-equal?
(parse-datetime "21 Jun 2015 15:45:40" "dd MMM yyyy HH:mm:ss") (datetime 2015 6 21 15 45 40)))

(check-exn
exn:gregor:parse?
(lambda ()
(parse-datetime "21 Jun 2015 15:45:40 -0000" "yyyy-MM-dd'T'HH:mm:ssxxx")))
)


I'd like to add something along these lines:

(check-equal?
(parsable-as-datetime? "2015-03-15T02:02:02-04:00" "yyyy-MM-dd'T'HH:mm:ssxxx")
#t)
(check-equal?
(parsable-as-datetime?"21 Jun 2015 15:45:40 -0000" "yyyy-MM-dd'T'HH:mm:ssxxx")
#f)

but implementing them would take me longer than I have at the moment. (Maybe using an err lambda that doesn't throw an exception?)

I thought I'd check here:
- does this seem like a reasonable idea?
- is mine an unusual use case and most folks know what format to expect and the exception approach is fine?
- is there perhaps an elegant way for me to test with a regular expression first rather than adding this function to Gregor?

Cheers,

Tim

Ben Greenman

unread,
Apr 27, 2020, 1:04:47 PM4/27/20
to Racket Users
On 4/27/20, Tim Hanson <tbh...@gmail.com> wrote:
>
> I thought I'd check here:
> - does this seem like a reasonable idea?
> - is mine an unusual use case and most folks know what format to expect and
> the exception approach is fine?

I've written code like this before and used it in a contract.

```
(define (iso8601-string? x)
(and (string? x)
(with-handlers ((exn:gregor:parse? (lambda (e) #false)))
(date? (iso8601->date x)))))

(module+ test
(test-case "iso8601-string?"
(check-pred iso8601-string? "2018-10-02T01:00:00")))
```

I haven't had to worry about its performance; it was fast enough!

Tim Hanson

unread,
Apr 27, 2020, 1:31:58 PM4/27/20
to Racket Users
Thanks. Something like that will let me proceed for now.

I'd still be curious what folks think about an approach avoiding exceptions.

Jon Zeppieri

unread,
Apr 27, 2020, 1:37:47 PM4/27/20
to Tim Hanson, Racket Users
On Mon, Apr 27, 2020 at 2:38 AM Tim Hanson <tbh...@gmail.com> wrote:
>
> hi, I've installed and am trying out
>
> Gregor: a date and time library for Racket
>
> and find it to be very powerful and useful.

Thanks!

>
> In my current application (digging through mail headers) I'm wondering whether there is a way to test whether a given date-time format matches without using exceptions. (I assume that would generally be more efficient than catching exceptions.)
> [...]
>
> I thought I'd check here:
> - does this seem like a reasonable idea?

It does to me.

> - is mine an unusual use case and most folks know what format to expect and the exception approach is fine?

Good question. If you're expecting dates/times to come in a variety of
formats, I can see why you'd want to try out a few of them. And that
is made more difficult by having these functions raise exceptions. So
I think it would have been wiser to make these functions behave the
way you've indicated.

Or maybe partially so...?

The exceptions that occur during a parse can come from three (I hope I
counted them all) three distinct sources:
- Your pattern may be lexically invalid (e.g., `(parse-datetime
"2/29/2000" "M/f/y")`.)
- Your pattern may fail to match the input (e.g., `(parse-datetime
"2/29/2000" "MMM/d/y")`.).
- Your pattern may match the input, but the interpretation of the
input as a date, datetime, etc. may refer to a date that does not
exist in the Gregorian calendar (e.g., `(parse-datetime "2/29/1999"
"M/d/y")` or a date-time that does not exist in a local time zone
(e.g., a time between 2-3 am during a transition to Daylight Saving
Time from Standard Time in the U.S.).

I think the first of these would definitely remain an exception. The
second is the most obvious candidate for returning #f instead of
raising. The third is (to me) the least obvious.

> - is there perhaps an elegant way for me to test with a regular expression first rather than adding this function to Gregor?

That would depend on the particular formats you're expecting.

>
> Cheers,
>
> Tim

Tim Hanson

unread,
Apr 28, 2020, 2:17:11 AM4/28/20
to Racket Users
Thanks, Jon!

I agree with your analysis and thoughts about which cases should always raise exceptions. (I can't recall whether you scan patterns that include semi-redundant information such as day-of-week; wondered just now whether a contradictory day of week would be another category of exception -- or whether you just ignore it.)

I guess I will try an approach like the one Ben posted for now, just to find out how many patterns turn up.

Later I'd be interested in an elegant way to pre-test "parse-ability", though I have a healthy respect for the effort involved.

(And you've done a great job, I think, of keeping just what is needed and hiding lots of details in the "private" sections. One doesn't want to add more than is needed.)

Tim Hanson

unread,
Apr 30, 2020, 11:33:38 AM4/30/20
to Racket Users
p.s. I'm stuck on parsing one pattern that comes up in my data. Here's a corresponding test:

(parameterize ([current-locale "en"])
(check-equal?

(parse-datetime "Sun, 21 Jun 2015 17:50:44 -0500 (CDT)" "EEE, dd MMM yyyy HH:mm:ss xxxx (zzzz)") (datetime 2015 6 21 17 50 44)))

that fails with
../../../../../Library/Racket/7.6/pkgs/gregor-lib/gregor/private/pattern/ast/zone.rkt:40:2: match: no matching clause for (Zone ... 'offset-name 'long)


I'm looking at the source code but am not quite sure. Are zone descriptors such as CDT supported? (I also tried (zzz), but it also fails with
no matching clause for (Zone ... 'offset-name 'short).)


In
https://unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns

I find an example:

Pattern Result (in a particular locale)
yyyy.MM.dd G 'at' HH:mm:ss zzz 1996.07.10 AD at 15:08:56 PDT

which makes me think it should perhaps work.

Jon Zeppieri

unread,
Apr 30, 2020, 11:36:30 AM4/30/20
to Tim Hanson, Racket Users
Only a small number of zone formats are supported in parsing mode.
This is discussed a bit in https://github.com/97jaz/gregor/issues/25.
The situation could definitely be improved.

- Jon
> --
> You received this message because you are subscribed to the Google Groups "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to racket-users...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/10f6f25d-6da8-4bbb-9459-ce63ae071c34%40googlegroups.com.

Tim Hanson

unread,
Apr 30, 2020, 11:48:00 AM4/30/20
to Racket Users
Thanks for the quick reply, Jon!

OK, good to know. Maybe I can add the ones I need (if I can figure out how...). :)

Tim Hanson

unread,
May 1, 2020, 2:36:24 AM5/1/20
to Racket Users
very helpful that you linked to the issue, thank you. I now understand there are non-trivial problem domain issues (for example, “CDT” is ambiguous, probably even with locale specified.)

I will think about how to tackle my specific problem and whether I can help with issues like these.
Reply all
Reply to author
Forward
0 new messages