-
Notifications
You must be signed in to change notification settings - Fork 0
/
ybot_placetime.xtm
153 lines (124 loc) · 4.79 KB
/
ybot_placetime.xtm
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
(sys:load-preload-check 'ybot_placetime)
(define *xtmlib-ybot_placetime-loaded* #f)
(impc:aot:suppress-aot-do
(sys:load "libs/contrib/ybot/ybot_base.xtm"))
(impc:aot:insert-forms
(sys:load "libs/contrib/ybot/ybot_base.xtm" 'quiet))
;;; Calendar-ness
;; year, month, day.
(bind-val January enum 1)
(bind-val February enum 2)
(bind-val March enum 3)
(bind-val April enum 4)
(bind-val May enum 5)
(bind-val June enum 6)
(bind-val July enum 7)
(bind-val August enum 8)
(bind-val September enum 9)
(bind-val October enum 10)
(bind-val November enum 11)
(bind-val December enum 12)
(bind-type YbotDate <i64,i64,i64> (constructor? . #f) (printer? . #f))
(bind-func YbotDate:[YbotDate*,i64,i64,i64]*
(lambda (year month day)
(let ((output:YbotDate* (alloc))
(d:i64 (- day 1)))
(tfill! output year month day)
(cond
((or
(= (i64toi32 month) April)
(= (i64toi32 month) June)
(= (i64toi32 month) September)
(= (i64toi32 month) November))
(if (<= 30 d)
(begin
(tset! output 2 (+ (modulo d 30) 1))
(tset! output 1 (+ month (/ d 30)))))
void)
((= (i64toi32 month) February)
(cond
((and (= (modulo year 4) 0) (or (= (modulo year 400) 0) (not (= (modulo year 100) 0))))
(if (<= 29 d)
(begin
(tset! output 2 (+ (modulo d 29) 1))
(tset! output 1 (+ month (/ d 29)))))
void)
(else
(if (<= 28 d)
(begin
(tset! output 2 (+ (modulo d 28) 1))
(tset! output 1 (+ month (/ d 28)))))
void)))
(else void))
output)))
(bind-func year:[i64,YbotDate*]* (lambda (date) (tref date 0)))
(bind-func year:[i64,YbotDate*,i64]* (lambda (date value) (tset! date 0 value)))
(bind-func month:[i64,YbotDate*]* (lambda (date) (tref date 1)))
(bind-func month:[i64,YbotDate*,i64]* (lambda (date value) (tset! date 1 value)))
(bind-func day:[i64,YbotDate*]* (lambda (date) (tref date 2)))
(bind-func day:[i64,YbotDate*,i64]* (lambda (date value) (tset! date 2 value)))
(bind-func toString:[String*,YbotDate*]*
(lambda (date)
(let ((str:i8* (alloc 64)))
(sprintf str "%02lld / %02lld / %04lld" (tref date 2) (tref date 1) (tref date 0))
(String str))))
(bind-func print:[void,YbotDate*]*
(lambda (date)
(print:[void,String*]* (toString date))
void))
;; The following algorithms take March 1st of the year 0AD as the start of time (day 0)
;; This is convenient because it makes February come at the end of each 'year' which
;; simplifies the calculation for dealing with leap days.
(bind-func YbotDate2DayNumber:[i64,YbotDate*]*
(lambda (date)
(let* ((m:i64 (% (+ (tref date 1) 9) 12))
(y:i64 (- (tref date 0) (/ m 10)))
(d:i64 (tref date 2)))
(+ (* y 365) (/ y 4) (* -1 (/ y 100)) (/ y 400) (/ (+ (* m 306) 5) 10) (- d 1)))))
(bind-func YbotDayNumber2Date:[YbotDate*,i64]*
(lambda (n)
(let* ((y:i64 (/ (+ (* 10000 n) 14780) 3652425))
(ddd:i64 (- n (+ (* y 365) (/ y 4) (* -1 (/ y 100)) (/ y 400)))))
(if (< ddd 0) (begin (set! y (- y 1)) (set! ddd (- n (+ (* y 365) (/ y 4) (* -1 (/ y 100)) (/ y 400))))))
(let* ((mi:i64 (/ (+ 52 (* 100 ddd)) 3060))
(yy:i64 (+ y (/ (+ mi 2) 12)))
(mm (+ (% (+ mi 2) 12) 1))
(dd (+ ddd 1 (* -1 (/ (+ (* mi 306) 5) 10)))))
(YbotDate yy mm dd)))))
($ (println (YbotDate2DayNumber (YbotDate 2017 11 15))))
(bind-func Epoch2Day
(let ((SECONDS_PER_DAY:i64 (* 60 60 24))
(OFFSET:i64 (YbotDate2DayNumber (YbotDate 1970 1 1))))
(lambda (t:double)
(+ OFFSET (/ (dtoi64 t) SECONDS_PER_DAY)))))
(bind-func Date:[YbotDate*]*
(lambda ()
(YbotDayNumber2Date (Epoch2Day (clock_clock)))))
(bind-func UTC:[i64]*
(let ((SECONDS_PER_DAY:i64 (* 60 60 24)))
(lambda ()
(modulo (dtoi64 (clock_clock)) SECONDS_PER_DAY))))
(bind-func LocalTime:[i64,i64]*
(lambda (timezone:i64)
(+ (UTC) (* timezone 3600))))
(bind-func ClockReadout:[String*,i64]*
(let* ((HOUR_PER_DAY:i64 24)
(MIN_PER_HOUR:i64 60)
(SEC_PER_MIN:i64 60)
(MIN_PER_DAY (* MIN_PER_HOUR HOUR_PER_DAY))
(SEC_PER_HOUR (* MIN_PER_HOUR SEC_PER_MIN))
(SEC_PER_DAY (* SEC_PER_MIN MIN_PER_HOUR HOUR_PER_DAY)))
(lambda (t:i64)
(let* ((str:i8* (alloc 16))
(second:i64 (modulo t SEC_PER_MIN))
(rm:i64 (/ t SEC_PER_MIN))
(minute:i64 (modulo rm MIN_PER_HOUR))
(hour:i64 (/ rm (MIN_PER_HOUR))))
(sprintf str "%02lld:%02lld:%02lld" hour minute second)
(Str str)))))
($ (println (ClockReadout (LocalTime 11))))
;; How old am I?
;; ($ (/ (- (YbotDate2DayNumber (Date))
;; (YbotDate2DayNumber (YbotDate 1973 11 6)))
;; 365))
(set! *xtmlib-ybot_placetime-loaded* #t)