tzinfo: adding parsers for timezone files.

db4
John Benediktsson 2013-09-04 18:43:54 -07:00
parent 4dca0e6651
commit 73f2fac980
3 changed files with 109 additions and 0 deletions

1
extra/tzinfo/authors.txt Normal file
View File

@ -0,0 +1 @@
John Benediktsson

1
extra/tzinfo/summary.txt Normal file
View File

@ -0,0 +1 @@
Parsing timezone files.

107
extra/tzinfo/tzinfo.factor Normal file
View File

@ -0,0 +1,107 @@
USING: accessors alien.c-types alien.data alien.endian arrays
assocs calendar classes.struct combinators hashtables io
io.binary io.encodings.binary io.files kernel locals math
math.order sequences strings ;
IN: tzinfo
<PRIVATE
STRUCT: tzhead
{ tzh_magic char[4] }
{ tzh_reserved char[16] }
{ tzh_ttisgmtcnt be32 }
{ tzh_ttisstdcnt be32 }
{ tzh_leapcnt be32 }
{ tzh_timecnt be32 }
{ tzh_typecnt be32 }
{ tzh_charcnt be32 } ;
PACKED-STRUCT: ttinfo
{ tt_gmtoff be32 }
{ tt_isdst uchar }
{ tt_abbrind uchar } ;
ERROR: bad-magic ;
: check-magic ( header -- header )
dup tzh_magic>> "TZif" sequence= [ bad-magic ] unless ;
TUPLE: tzfile header transition-times local-times types abbrevs
leaps is-std is-gmt ;
C: <tzfile> tzfile
: read-be32 ( -- n )
4 read be32 deref ;
: read-tzfile ( -- tzfile )
tzhead read-struct check-magic dup {
[ tzh_timecnt>> [ read-be32 ] replicate ]
[ tzh_timecnt>> [ read1 ] replicate ]
[ tzh_typecnt>> [ ttinfo read-struct ] replicate ]
[ tzh_charcnt>> read ]
[ tzh_leapcnt>> [ read-be32 read-be32 2array ] replicate ]
[ tzh_ttisstdcnt>> read ]
[ tzh_ttisgmtcnt>> read ]
} cleave <tzfile> ;
:: tznames ( abbrevs -- assoc )
0 [
0 over abbrevs index-from dup
] [
[ dupd abbrevs subseq >string 2array ] keep 1 + swap
] produce 2nip >hashtable ;
TUPLE: local-time gmt-offset dst? abbrev std? gmt? ;
C: <local-time> local-time
TUPLE: transition seconds timestamp local-time ;
C: <transition> transition
:: tzfile>transitions ( tzfile -- transitions )
tzfile abbrevs>> tznames :> abbrevs
tzfile is-std>> :> is-std
tzfile is-gmt>> :> is-gmt
tzfile types>> [
[
{
[ tt_gmtoff>> seconds ]
[ tt_isdst>> 1 = ]
[ tt_abbrind>> abbrevs at ]
} cleave
] dip
[ is-std ?nth dup [ 1 = ] when ]
[ is-gmt ?nth dup [ 1 = ] when ] bi <local-time>
] map-index :> local-times
tzfile transition-times>>
tzfile local-times>> [
[ dup unix-time>timestamp ] [ local-times nth ] bi*
<transition>
] 2map ;
TUPLE: tzinfo tzfile transitions ;
C: <tzinfo> tzinfo
: find-transition ( timestamp tzinfo -- transition )
[ timestamp>unix-time ] [ transitions>> ] bi*
[ [ seconds>> before? ] with find drop ]
[ swap [ 1 [-] swap nth ] [ last ] if* ] bi ;
PRIVATE>
: file>tzinfo ( path -- tzinfo )
binary [
read-tzfile dup tzfile>transitions <tzinfo>
] with-file-reader ;
: from-utc ( timestamp tzinfo -- timestamp' )
[ drop instant >>gmt-offset ]
[ find-transition local-time>> gmt-offset>> ] 2bi
convert-timezone ;
: normalize ( timestamp tzinfo -- timestamp' )
[ instant convert-timezone ] [ from-utc ] bi* ;