blob: 03e8dd109f5164f142c8a95e8d32e84e5dc8869f (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
;;; Commentary:
;; Datatype for holding timechanges and time offesets.
;; Used both for timespecs from the TZ-database, and for UTC-OFFSET from RFC5545.
;;; Code:
(define-module (datetime timespec)
:use-module ((hnh util) :select (set unless))
:use-module ((hnh util exceptions) :select (warning))
:use-module (datetime)
:use-module (srfi srfi-1)
:use-module (srfi srfi-71)
:use-module (srfi srfi-9 gnu)
:use-module (calp translation)
:export (make-timespec
timespec?
timespec-time
timespec-sign
timespec-type
timespec-zero
timespec-add
parse-time-spec
))
;; timespec as defined by the TZ-database
;; also used UTC-OFFSET defined by RFC5545. Then type should equal #\z
;; and be ignored.
(define-immutable-record-type <timespec> ; EXPORTED
(make-timespec timespec-time sign type)
timespec?
(timespec-time timespec-time) ; <time>
(sign timespec-sign) ; '+ | '-
;; types:
;; w - wall clock time (local time)
;; s - standard time without daylight savings adjustments
;; u, g, z - Universal time
(type timespec-type)) ; char
(define (timespec-zero)
(make-timespec (time) '+ #\w))
(define (timespec-add . specs)
(unless (apply eqv? (map timespec-type specs))
(warning (_ "Adding timespecs of differing types")))
(reduce (lambda (spec done)
(cond
;; - -
;; + +
[(eq? (timespec-sign done)
(timespec-sign spec))
(set (timespec-time done) = (time+ (timespec-time spec)))]
;; - +
[(and (eq? '- (timespec-sign done))
(eq? '+ (timespec-sign spec)))
(let ((time-a (timespec-time done))
(time-b (timespec-time spec)))
(if (time< time-a time-b)
(make-timespec (time- time-b time-a)
'- (timespec-type done))
(make-timespec (time- time-a time-b)
'+ (timespec-type done))
))]
;; + -
[(and (eq? '+ (timespec-sign done))
(eq? '- (timespec-sign spec)))
(let ((time-a (timespec-time done))
(time-b (timespec-time spec)))
(if (time< time-a time-b)
(make-timespec (time- time-b time-a)
'- (timespec-type done))
(make-timespec (time- time-a time-b)
'+ (timespec-type done))
))]))
(timespec-zero)
specs))
(define* (parse-time-spec
string optional: (suffixes '(#\s #\w #\u #\g #\z)))
(let ((type string
(cond [(string-rindex string (list->char-set suffixes))
=> (lambda (idx)
(values (string-ref string idx)
(substring string 0 idx)))]
[else (values #\w string)])))
;; Note that string->time allows a longer format than the input
(cond [(string=? "-" string)
(make-timespec (time) '+ type)]
[(string-prefix? "-" string)
(make-timespec (string->time (string-drop string 1) "~H:~M:~S")
'- type)]
[else
(make-timespec (string->time string "~H:~M:~S")
'+ type)])))
|