1 ! Copyright (C) 2008 Slava Pestov.
\r
2 ! See http://factorcode.org/license.txt for BSD license.
\r
3 USING: math math.order math.parser math.functions kernel
\r
4 sequences io accessors arrays io.streams.string splitting
\r
5 combinators accessors calendar calendar.format.macros present ;
\r
8 : pad-00 ( n -- str ) number>string 2 CHAR: 0 pad-head ;
\r
10 : pad-0000 ( n -- str ) number>string 4 CHAR: 0 pad-head ;
\r
12 : pad-00000 ( n -- str ) number>string 5 CHAR: 0 pad-head ;
\r
14 : write-00 ( n -- ) pad-00 write ;
\r
16 : write-0000 ( n -- ) pad-0000 write ;
\r
18 : write-00000 ( n -- ) pad-00000 write ;
\r
20 : hh ( time -- ) hour>> write-00 ;
\r
22 : mm ( time -- ) minute>> write-00 ;
\r
24 : ss ( time -- ) second>> >integer write-00 ;
\r
26 : D ( time -- ) day>> number>string write ;
\r
28 : DD ( time -- ) day>> write-00 ;
\r
30 : DAY ( time -- ) day-of-week day-abbreviation3 write ;
\r
32 : MM ( time -- ) month>> write-00 ;
\r
34 : MONTH ( time -- ) month>> month-abbreviation write ;
\r
36 : YYYY ( time -- ) year>> write-0000 ;
\r
38 : YYYYY ( time -- ) year>> write-00000 ;
\r
41 read1 swap member? [ "Parse error" throw ] unless ;
\r
43 : read-00 ( -- n ) 2 read string>number ;
\r
45 : read-000 ( -- n ) 3 read string>number ;
\r
47 : read-0000 ( -- n ) 4 read string>number ;
\r
49 GENERIC: day. ( obj -- )
\r
51 M: integer day. ( n -- )
\r
52 number>string dup length 2 < [ bl ] when write ;
\r
54 M: timestamp day. ( timestamp -- )
\r
57 GENERIC: month. ( obj -- )
\r
59 M: array month. ( pair -- )
\r
61 [ month-name write bl number>string print ]
\r
62 [ 1 zeller-congruence ]
\r
63 [ (days-in-month) day-abbreviations2 " " join print ] 2tri
\r
64 over " " <repetition> concat write
\r
67 1+ + 7 mod zero? [ nl ] [ bl ] if
\r
70 M: timestamp month. ( timestamp -- )
\r
71 [ year>> ] [ month>> ] bi 2array month. ;
\r
73 GENERIC: year. ( obj -- )
\r
75 M: integer year. ( n -- )
\r
76 12 [ 1+ 2array month. nl ] with each ;
\r
78 M: timestamp year. ( timestamp -- )
\r
81 : (timestamp>string) ( timestamp -- )
\r
82 { DAY ", " D " " MONTH " " YYYY " " hh ":" mm ":" ss } formatted ;
\r
84 : timestamp>string ( timestamp -- str )
\r
85 [ (timestamp>string) ] with-string-writer ;
\r
87 : (write-gmt-offset) ( duration -- )
\r
90 : write-gmt-offset ( gmt-offset -- )
\r
92 { +eq+ [ drop "GMT" write ] }
\r
93 { +lt+ [ "-" write before (write-gmt-offset) ] }
\r
94 { +gt+ [ "+" write (write-gmt-offset) ] }
\r
97 : timestamp>rfc822 ( timestamp -- str )
\r
98 #! RFC822 timestamp format
\r
99 #! Example: Tue, 15 Nov 1994 08:12:31 +0200
\r
101 [ (timestamp>string) " " write ]
\r
102 [ gmt-offset>> write-gmt-offset ]
\r
104 ] with-string-writer ;
\r
106 : timestamp>http-string ( timestamp -- str )
\r
107 #! http timestamp format
\r
108 #! Example: Tue, 15 Nov 1994 08:12:31 GMT
\r
109 >gmt timestamp>rfc822 ;
\r
111 : (timestamp>cookie-string) ( timestamp -- )
\r
113 { DAY ", " DD "-" MONTH "-" YYYY " " hh ":" mm ":" ss " GMT" } formatted ;
\r
115 : timestamp>cookie-string ( timestamp -- str )
\r
116 [ (timestamp>cookie-string) ] with-string-writer ;
\r
118 : (write-rfc3339-gmt-offset) ( duration -- )
\r
119 [ hh ":" write ] [ mm ] bi ;
\r
121 : write-rfc3339-gmt-offset ( duration -- )
\r
123 { +eq+ [ drop "Z" write ] }
\r
124 { +lt+ [ "-" write before (write-rfc3339-gmt-offset) ] }
\r
125 { +gt+ [ "+" write (write-rfc3339-gmt-offset) ] }
\r
128 : (timestamp>rfc3339) ( timestamp -- )
\r
130 YYYY "-" MM "-" DD "T" hh ":" mm ":" ss
\r
131 [ gmt-offset>> write-rfc3339-gmt-offset ]
\r
134 : timestamp>rfc3339 ( timestamp -- str )
\r
135 [ (timestamp>rfc3339) ] with-string-writer ;
\r
137 : signed-gmt-offset ( dt ch -- dt' )
\r
138 { { CHAR: + [ 1 ] } { CHAR: - [ -1 ] } } case time* ;
\r
140 : read-rfc3339-gmt-offset ( ch -- dt )
\r
141 dup CHAR: Z = [ drop instant ] [
\r
144 read1 { { CHAR: : [ read-00 ] } { f [ 0 ] } } case minutes
\r
146 ] dip signed-gmt-offset
\r
149 : read-ymd ( -- y m d )
\r
150 read-0000 "-" expect read-00 "-" expect read-00 ;
\r
152 : read-hms ( -- h m s )
\r
153 read-00 ":" expect read-00 ":" expect read-00 ;
\r
155 : read-rfc3339-seconds ( s -- s' ch )
\r
157 [ string>number ] [ length 10 swap ^ ] bi / +
\r
160 : (rfc3339>timestamp) ( -- timestamp )
\r
164 read1 { { CHAR: . [ read-rfc3339-seconds ] } [ ] } case
\r
165 read-rfc3339-gmt-offset
\r
168 : rfc3339>timestamp ( str -- timestamp )
\r
169 [ (rfc3339>timestamp) ] with-string-reader ;
\r
171 ERROR: invalid-timestamp-format ;
\r
173 : check-timestamp ( obj/f -- obj )
\r
174 [ invalid-timestamp-format ] unless* ;
\r
176 : read-token ( seps -- token )
\r
177 [ read-until ] keep member? check-timestamp drop ;
\r
179 : read-sp ( -- token ) " " read-token ;
\r
181 : checked-number ( str -- n )
\r
182 string>number check-timestamp ;
\r
184 : parse-rfc822-gmt-offset ( string -- dt )
\r
185 dup "GMT" = [ drop instant ] [
\r
187 2 cut [ string>number ] bi@ [ hours ] [ minutes ] bi* time+
\r
188 ] dip signed-gmt-offset
\r
191 : (rfc822>timestamp) ( -- timestamp )
\r
193 "," read-token day-abbreviations3 member? check-timestamp drop
\r
194 read1 CHAR: \s assert=
\r
195 read-sp checked-number >>day
\r
196 read-sp month-abbreviations index 1+ check-timestamp >>month
\r
197 read-sp checked-number >>year
\r
198 ":" read-token checked-number >>hour
\r
199 ":" read-token checked-number >>minute
\r
200 " " read-token checked-number >>second
\r
201 readln parse-rfc822-gmt-offset >>gmt-offset ;
\r
203 : rfc822>timestamp ( str -- timestamp )
\r
204 [ (rfc822>timestamp) ] with-string-reader ;
\r
206 : check-day-name ( str -- )
\r
207 [ day-abbreviations3 member? ] [ day-names member? ] bi or
\r
208 check-timestamp drop ;
\r
210 : (cookie-string>timestamp-1) ( -- timestamp )
\r
212 "," read-token check-day-name
\r
213 read1 CHAR: \s assert=
\r
214 "-" read-token checked-number >>day
\r
215 "-" read-token month-abbreviations index 1+ check-timestamp >>month
\r
216 read-sp checked-number >>year
\r
217 ":" read-token checked-number >>hour
\r
218 ":" read-token checked-number >>minute
\r
219 " " read-token checked-number >>second
\r
220 readln parse-rfc822-gmt-offset >>gmt-offset ;
\r
222 : cookie-string>timestamp-1 ( str -- timestamp )
\r
223 [ (cookie-string>timestamp-1) ] with-string-reader ;
\r
225 : (cookie-string>timestamp-2) ( -- timestamp )
\r
227 read-sp check-day-name
\r
228 read-sp month-abbreviations index 1+ check-timestamp >>month
\r
229 read-sp checked-number >>day
\r
230 ":" read-token checked-number >>hour
\r
231 ":" read-token checked-number >>minute
\r
232 " " read-token checked-number >>second
\r
233 read-sp checked-number >>year
\r
234 readln parse-rfc822-gmt-offset >>gmt-offset ;
\r
236 : cookie-string>timestamp-2 ( str -- timestamp )
\r
237 [ (cookie-string>timestamp-2) ] with-string-reader ;
\r
239 : cookie-string>timestamp ( str -- timestamp )
\r
241 [ cookie-string>timestamp-1 ]
\r
242 [ cookie-string>timestamp-2 ]
\r
243 [ rfc822>timestamp ]
\r
244 } attempt-all-quots ;
\r
246 : (ymdhms>timestamp) ( -- timestamp )
\r
247 read-ymd " " expect read-hms instant <timestamp> ;
\r
249 : ymdhms>timestamp ( str -- timestamp )
\r
250 [ (ymdhms>timestamp) ] with-string-reader ;
\r
252 : (hms>timestamp) ( -- timestamp )
\r
253 0 0 0 read-hms instant <timestamp> ;
\r
255 : hms>timestamp ( str -- timestamp )
\r
256 [ (hms>timestamp) ] with-string-reader ;
\r
258 : (ymd>timestamp) ( -- timestamp )
\r
259 read-ymd 0 0 0 instant <timestamp> ;
\r
261 : ymd>timestamp ( str -- timestamp )
\r
262 [ (ymd>timestamp) ] with-string-reader ;
\r
264 : (timestamp>ymd) ( timestamp -- )
\r
265 { YYYY "-" MM "-" DD } formatted ;
\r
267 : timestamp>ymd ( timestamp -- str )
\r
268 [ (timestamp>ymd) ] with-string-writer ;
\r
270 : (timestamp>hms) ( timestamp -- )
\r
271 { hh ":" mm ":" ss } formatted ;
\r
273 : timestamp>hms ( timestamp -- str )
\r
274 [ (timestamp>hms) ] with-string-writer ;
\r
276 : timestamp>ymdhms ( timestamp -- str )
\r
279 { (timestamp>ymd) " " (timestamp>hms) } formatted
\r
280 ] with-string-writer ;
\r
282 : file-time-string ( timestamp -- string )
\r
287 dup now [ year>> ] bi@ =
\r
288 [ [ hh ":" write ] [ mm ] bi ] [ YYYYY ] if
\r
291 ] with-string-writer ;
\r
293 M: timestamp present timestamp>string ;
\r