1

Org agendas use 'day' values in various APIs. I'd like to continue using the wonderful ts.el package to keep all my own automation using a timestamp implementation that clicks in my own head. (Elisp's various manifestations of 'time', and an apparent inconsistency in documentation around these manifestations, is a constant source of confusion for me.)

I can't seem to find a way to use the value I get from (date-to-day "2023-08-14") into a useful time value. Naively using days-to-time on this value yields a date in 3992. In fact, both of the following forms evaluate to that same date:

(format-time-string "%FT%T%z" (days-to-time (date-to-day "2023-08-14")))
(format-time-string "%FT%T%z" (days-to-time (time-to-days (current-time))))

even though one might initially expect days-to-time and time-to-days to be inverses.

What's going on here? How can I get a ts value out of the value returned by (date-to-day "2023-08-14")?

1
  • 1
    "... a constant source of confusion for me": FWIW, me too.
    – NickD
    Aug 14 at 16:10

2 Answers 2

3

There is date-to-time:

(make-ts :unix (string-to-number
                (format-time-string "%s" (date-to-time "2023-08-13"))))

This will assume that 2023-08-13 denotes midnight in your local timezone.


(let ((day (date-to-day "2023-08-13"))
      (epoch (date-to-day "1970-01-01")))
  (make-ts :unix (* (- day epoch) 86400)))

This will assume that 2023-08-13 denotes midnight in UTC.

2
  • Correct me if I'm wrong, but I don't think this answers the question of how to get a timestamp out of a value like 738746 – the return value from date-to-day. It's leaving this 'day' format that I've got the trouble with. Aug 14 at 18:33
  • Oh hold on – you're suggesting normalizing the 'day' value against the equivalent 'day' value for epoch? That does make sense. Is there no time-date.el-native way to use this 'day' value though? (Anything in the standard distribution, really.) Aug 14 at 19:25
1

I think @d125q has the right solution for you, but let me explain what's happening. Firstly date-to-day doesn't like your input. Via it's docstring (C-h f date-to-day)

Return the absolute date of DATE, a date-time string. The absolute date is the number of days elapsed since the imaginary Gregorian date Sunday, December 31, 1 BC.

;; *scratch* buffer
(date-to-day "2023-08-14")
730119
(date-to-day "3023-08-14")
730119

Oops. Something is wrong, we should have a 365250 day difference there. So what's 730119 days to years? 2000. What's 2000 years since December 31, 1 BC? December 31, 1999.

Now breaking down the call stack for date-to-day we have something like

;; date-to-day stack
(time-to-days ((encode-time (parse-time-string
               (timezone-make-date-arpa-standard date))))

So, using our innermost function

;; try our given input
(timezone-make-date-arpa-standard "2023-08-14")
"31 Dec 1999 19:00:00 -0500"
;; Oops

;; be more precise with our input
(timezone-make-date-arpa-standard "2023-08-14T00:00:00")
"13 Aug 2023 20:00:00 -0400"
(date-to-day "3023-08-14T00:00:00")
738746
(format-time-string "%FT%T%z" (days-to-time (date-to-day "2023-08-14")))
"3968-12-30T19:00:00-0500"
;; correct date based on our input to format-time-string

We've corrected our output, but it's still unexpectedly too far in to the future. This leads us to the second problem, our mis-application of format-time-string. From its docstring (C-h f format-time-string)

This function treats seconds as time since the epoch of 1970-01-01 00:00:00 UTC

Oops. We've calculated seconds (as in integer list) from December 31, 1 BC (date-to-day) and fed it to a function that does its calculations beginning on January 01, 1970. Obviously, we're going to be a just few (thousand) years off.

So, I see a couple of options,

  • use @d125q's excellent and concise solution (or something based on it) (preferred)
  • rewrite your function using functions that only operate on the UNIX epoch (meh)
  • keep doing what you're doing but account for the difference in time (ugh)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.