Skip to content

Commit

Permalink
core,script: add Timestamp.fromisostring
Browse files Browse the repository at this point in the history
  • Loading branch information
Bogdanp committed Dec 20, 2023
1 parent 20d873d commit 3ec0c32
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 3 deletions.
14 changes: 14 additions & 0 deletions core/extlib/timestamp.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#lang lua

local seconds_to_date = racket["seconds->date"]
local date_to_seconds = racket.lib("racket/date", "date*->seconds")
local date_to_string = _ENV["#%date->isostring"]
local string_to_date = _ENV["#%isostring->date"]

local Timestamp = Class {
name = "Timestamp",
Expand Down Expand Up @@ -44,6 +46,14 @@ function Timestamp.at(year, month, day, hour, minute, second, localtime)
return Timestamp(seconds, localtime)
end

function Timestamp.fromisostring(s)
local d = string_to_date(s or "")
if not d then
error(string.format("Timestamp.fromisostring: invalid date '%s'", s))
end
return Timestamp(date_to_seconds(d, false))
end

function Timestamp:components()
return os.date(self.localtime and "*t" or "!*t", self.ts)
end
Expand All @@ -66,6 +76,10 @@ function Timestamp:toutc()
return Timestamp(self.ts, false)
end

function Timestamp:__eq(other)
return self.ts == other.ts
end

function Timestamp:__le(other)
return self.ts <= other.ts
end
Expand Down
2 changes: 2 additions & 0 deletions core/fixtures/timestamp.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ assert(components.min == 30, "minute component")
assert(components.sec == 45, "second component")
assert(not components.isdst, "isdst component")

assert(t == Timestamp.fromisostring("2023-05-29T12:30:45Z"))

return true
60 changes: 57 additions & 3 deletions core/script.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
racket/contract
racket/date
racket/file
racket/match
racket/port
racket/runtime-path
"iterator.rkt"
Expand Down Expand Up @@ -365,6 +366,60 @@ SCRIPT

;; extlib ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define nanos/second
(* 1 1000 1000 1000))

(define (date->isostring d)
(parameterize ([date-display-format 'iso-8601])
(string->bytes/utf-8 (date->string d #t))))

(define (isostring->date s)
(with-handlers ([(λ (e)
(or (regexp-match? #rx"match-define: no matching clause" (exn-message e))
(regexp-match? #rx"find-seconds: non-existent date" (exn-message e))))
(λ (_) #f)])
(match-define
(regexp #px"^(....)-(..)-(..)[ T](..):(..):(..)(\\.([0-9]{1,9}))?(Z|([-+]..:..))?$"
(list _
(app string->number year)
(app string->number month)
(app string->number day)
(app string->number hour)
(app string->number minute)
(app string->number second)
_ ;; nanosecond with prefix
nanosecond-str
timezone-str
_ ;; +- offset
))
(bytes->string/utf-8 s))
(define nanosecond
(let ([n (or (and nanosecond-str (string->number nanosecond-str)) 0)])
(if (zero? n)
0
(inexact->exact
(* (/ n (expt 10 (add1 (floor (log n 10))))) nanos/second)))))
(define utc-seconds
(find-seconds second minute hour day month year #f))
(define utc-date
(struct-copy date*
(seconds->date utc-seconds #f)
[nanosecond nanosecond]))
(match timezone-str
[(or "" "Z" "+00:00" "-00:00") utc-date]
[(regexp #rx"([-+])([0-9]+):([0-9]+)"
(list _
sign-str
(app string->number hours)
(app string->number minutes)))
(define offset
(let ([offset (+ (* hours 3600)
(* minutes 60))])
(case sign-str
[("-") offset]
[("+") (- offset)])))
(seconds->date (+ (date*->seconds utc-date #f) offset) #f)])))

(define-syntax (defmod stx)
(syntax-parse stx
[(_ name:id)
Expand Down Expand Up @@ -433,9 +488,8 @@ SCRIPT
(make-class-module class.lua #"class" #"Class")
(make-class-module
timestamp.lua #"timestamp" #"Timestamp"
`((#"#%date->isostring" ,(lambda (d)
(parameterize ([date-display-format 'iso-8601])
(string->bytes/utf-8 (date->string d #t)))))))
`((#"#%date->isostring" ,date->isostring)
(#"#%isostring->date" ,isostring->date)))
(make-table-module
avro.lua #"avro"
`((#"#%avro-make-codec" ,make-codec)
Expand Down
4 changes: 4 additions & 0 deletions manual/index.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,10 @@ Confluent Schema Registry.
argument defaults to @tt{true}.
}

@deflua[Timestamp.fromisostring (str) Timestamp]{
Parses the given ISO8601-formatted timestamp.
}

@deflua[Timestamp:tolocal () Timestamp]{
Returns a new timestamp at the same instant as this timestamp, but
set to local time.
Expand Down

0 comments on commit 3ec0c32

Please sign in to comment.