-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
period arithmetic? #46
Comments
@sorawee You can add periods already:
There's actually an open issue regarding |
Oh, but you wouldn't be able to scale a period by an arbitrary real number. It would need to be an exact integer. (Or, at least, I don't see how I could make it work for any |
A more general operation (I think) is to scale by an arbitrary real number, but rounds the result to the closest representable period. Would that be possible? |
If you stipulate a meaning of "closest," then yes, but it sounds like a pretty confusing interface to me. Do you have a motivating example? |
Design-wise, I wish that
where I don't recall off the top of my head what I was trying to do, but I do recall doing time interval halving a lot when I wrote Python. |
Thank you, that's very helpful. So, first off, there's one huge difference between a For example, how many seconds are in Time periods (i.e., periods that satisfy I've never been very happy with the period API. It definitely has some design mistakes and infelicities. Maybe I should have provided different representations for:
I did consider this and then didn't do it. Unfortunately, I can't remember why I decided against it. |
In my unpublished, forever-in-progress, rarely-worked-on ;;;;
;; Exports
(provide/contract
[period? (-> any/c boolean?)]
[period-empty? (-> period? boolean?)]
[date-period? (-> period? boolean?)]
[time-period? (-> period? boolean?)]
[period-negate (-> period? period?)]
[period-scale (-> period? exact-integer? period?)]
[period->date-period (-> period? date-period?)]
[period->time-period (-> period? time-period?)]
[time-period->nanoseconds (-> time-period? exact-integer?)]
[empty-period (and/c date-period? time-period? period?)]
[period-ref (-> period? temporal-unit/c exact-integer?)]
[period-set (-> period? temporal-unit/c exact-integer? period?)]
[period-add-years (-> period? exact-integer? period?)]
[period-add-months (-> period? exact-integer? period?)]
[period-add-weeks (-> period? exact-integer? period?)]
[period-add-days (-> period? exact-integer? period?)]
[period-add-date-period (-> period? date-period? period?)]
[period-add-hours (-> period? exact-integer? period?)]
[period-add-minutes (-> period? exact-integer? period?)]
[period-add-seconds (-> period? exact-integer? period?)]
[period-add-milliseconds (-> period? exact-integer? period?)]
[period-add-microseconds (-> period? exact-integer? period?)]
[period-add-nanoseconds (-> period? exact-integer? period?)]
[period-add-time-period (-> period? time-period? period?)]
[time-period-normalize (->* (time-period?) ((listof temporal-unit/c)) time-period?)]
[period->list (->* (period?)
((listof temporal-unit/c))
(listof (cons/c temporal-unit/c exact-integer?)))]
[list->period (-> (listof (cons/c temporal-unit/c exact-integer?)) period?)]
[years (-> exact-integer? date-period?)]
[months (-> exact-integer? date-period?)]
[weeks (-> exact-integer? date-period?)]
[days (-> exact-integer? date-period?)]
[hours (-> exact-integer? time-period?)]
[minutes (-> exact-integer? time-period?)]
[seconds (-> exact-integer? time-period?)]
[milliseconds (-> exact-integer? time-period?)]
[microseconds (-> exact-integer? time-period?)]
[nanoseconds (-> exact-integer? time-period?)]
[date-units (listof symbol?)]
[time-units (listof symbol?)]
[temporal-units (listof symbol?)]
[date-unit/c flat-contract?]
[time-unit/c flat-contract?]
[temporal-unit/c flat-contract?])
|
The fact that Reading the And yep, that's right. So:
But that's wrong. There absolutely are not 86400 seconds between those two times. Gregor gets this right by understanding the distinction between a day, considered from the standpoint of date arithmetic, and a period of 86400 seconds:
|
Actually, looking closer at what the python repl is telling me, it's even worse. The UTC offset isn't being adjusted as we cross a DST boundary:
These are both wrong. Unless I've managed to confuse myself, there is no 2:30 at UTC-04:00 on that day; instead of hitting 02:00 at -04:00, we go to 01:00 at -05:00. I realize that some of this criticism is more directed at the [Edit] So, if there weren't a DST boundary there, then the results would both be right, so without knowing more about these libraries, I can't confidently say either that:
|
I concur that converting seconds to days is problematic, so we should not replicate the entire What this feature request should really be titled is "time period arithmetic?"
What is the restriction? Perhaps I miss something, but I don't see why it's impossible to write:
|
Oh, it's definitely possible, and I understand why you'd want that. Your example of wanting to halve time periods is compelling. But what this discussion has wound up convincing me of (well, at least for now) is that trying to carve out a subspecies of period to represent a specific quantity of time wasn't a very good idea. I wish I had created a separate Here's an example of what I mean. You wrote:
And I can see why you'd want to do it this way (I mean: convert to ns, scale, then normalize), but it runs counter to the general way that periods work, which is that they don't automatically normalize anything but instead preserve the user's choice of fields. So it would be more in keeping with current behavior to scale each time field separately, but that would give a lower precision answer, and no one would want that. That's how I know I made a design mistake: both options seem wrong. Considering that It's probably worth noting that your #lang racket/base
(require gregor
gregor/period
racket/contract/base
racket/math)
(define units+ns-per
(list (cons 'seconds (expt 10 9))
(cons 'milliseconds (expt 10 6))
(cons 'microseconds (expt 10 3))
(cons 'nanoseconds (expt 10 0))))
(define (time-period->nanoseconds tp)
(for/sum ([pair (in-list units+ns-per)])
(* (period-ref tp (car pair))
(cdr pair))))
(define (nanoseconds->normalized-time-period ns)
(for/fold ([result empty-period]
[remaining ns]
#:result result)
([pair (in-list units+ns-per)])
(values (period-set result (car pair) (quotient remaining (cdr pair)))
(remainder remaining (cdr pair)))))
(define (scale-time-period tp c #:round-proc [round-proc exact-round])
(define ns0 (time-period->nanoseconds tp))
(define ns (round-proc (* ns0 c)))
(nanoseconds->normalized-time-period ns))
(provide/contract
[time-period->nanoseconds (-> time-period? exact-integer?)]
[nanoseconds->normalized-time-period (-> exact-integer? time-period?)]
[scale-time-period (->i ([tp time-period?]
[c real?])
(#:round-proc [round-proc (-> rational? exact-integer?)])
[result time-period?])]) |
Just one note on the above code: I think we'd want the contract for |
@97jaz Internally at my workplace there's a very good document about datetime APIs called How To Think About Time, and one of the main things it recommends is separating physical time ("how many seconds does it take for a pound of Caesium-137 to decay?") from civil time ("how long was the month of December 1927 in Shanghai?"). Periods in Gregor are used for both, which is why |
Is it possible to add period arithmetic? For example, we should be able to add two periods together, or perhaps scale one period by a real number.
The text was updated successfully, but these errors were encountered: