module Data.Repa.Bits.Date32
( Date32
, pack, unpack
, next
, range
, readYYYYsMMsDD)
where
import Data.Repa.Array.Material.Foreign as A
import Data.Repa.Array.Material.Unboxed as A
import Data.Repa.Array as A
import Data.Repa.Eval.Array as A
import Data.Word
import Data.Bits
import GHC.Exts
import GHC.Word
import Prelude as P
type Date32
= Word32
pack :: (Word, Word, Word) -> Date32
pack (yy, mm, dd)
= ((fromIntegral yy .&. 0x0ffff) `shiftL` 16)
.|. ((fromIntegral mm .&. 0x0ff) `shiftL` 8)
.|. (fromIntegral dd .&. 0x0ff)
unpack :: Date32 -> (Word, Word, Word)
unpack date
= ( fromIntegral $ (date `shiftR` 16) .&. 0x0ffff
, fromIntegral $ (date `shiftR` 8) .&. 0x0ff
, fromIntegral $ date .&. 0x0ff)
next :: Date32 -> Date32
next (W32# date)
= W32# (next' date)
next' :: Word# -> Word#
next' !date
| (yy, mm, dd) <- unpack (W32# date)
, (yy', mm', dd')
<- case mm of
1 -> if dd >= 31 then (yy, 2, 1) else (yy, mm, dd + 1)
2 -> if yy `mod` 4 == 0
then if dd >= 29
then (yy, 3, 1)
else (yy, mm, dd + 1)
else if dd >= 28
then (yy, 3, 1)
else (yy, mm, dd + 1)
3 -> if dd >= 31 then (yy, 4, 1) else (yy, mm, dd + 1)
4 -> if dd >= 30 then (yy, 5, 1) else (yy, mm, dd + 1)
5 -> if dd >= 31 then (yy, 6, 1) else (yy, mm, dd + 1)
6 -> if dd >= 30 then (yy, 7, 1) else (yy, mm, dd + 1)
7 -> if dd >= 31 then (yy, 8, 1) else (yy, mm, dd + 1)
8 -> if dd >= 31 then (yy, 9, 1) else (yy, mm, dd + 1)
9 -> if dd >= 30 then (yy, 10, 1) else (yy, mm, dd + 1)
10 -> if dd >= 31 then (yy, 11, 1) else (yy, mm, dd + 1)
11 -> if dd >= 30 then (yy, 12, 1) else (yy, mm, dd + 1)
12 -> if dd >= 31 then (yy + 1, 1, 1) else (yy, mm, dd + 1)
_ -> (0, 0, 0)
= case pack (yy', mm', dd') of
W32# w -> w
range :: TargetI l Date32
=> Name l -> Date32 -> Date32 -> Array l Date32
range n from to
| to < from = A.fromList n []
| otherwise = A.fromList n $ go [] from
where
go !acc !d
| d > to = P.reverse acc
| otherwise = go (d : acc) (next d)
readYYYYsMMsDD
:: BulkI l Char
=> Char -> Array l Char -> Maybe Date32
readYYYYsMMsDD sep arr
= case words
$ A.toList
$ A.mapS U (\c -> if c == sep then ' ' else c) arr of
[yy, mm, dd] -> Just $ pack (read yy, read mm, read dd)
_ -> Nothing