module Data.Thyme.Format.Aeson
( DotNetTime (..)
) where
import Prelude
import Control.Applicative
import Data.Aeson hiding (DotNetTime (..))
import Data.Aeson.Types hiding (DotNetTime (..))
import Data.Data
import Data.Monoid
import Data.Text (pack, unpack)
import qualified Data.Text as T
import Data.Thyme
import System.Locale
newtype DotNetTime = DotNetTime {
fromDotNetTime :: UTCTime
} deriving (Eq, Ord, Read, Show, Typeable, FormatTime)
instance ToJSON DotNetTime where
toJSON (DotNetTime t) =
String (pack (secs ++ formatMillis t ++ ")/"))
where secs = formatTime defaultTimeLocale "/Date(%s" t
instance FromJSON DotNetTime where
parseJSON = withText "DotNetTime" $ \t ->
let (s,m) = T.splitAt (T.length t 5) t
t' = T.concat [s,".",m]
in case parseTime defaultTimeLocale "/Date(%s%Q)/" (unpack t') of
Just d -> pure (DotNetTime d)
_ -> fail "could not parse .NET time"
instance ToJSON ZonedTime where
toJSON t = String $ pack $ formatTime defaultTimeLocale format t
where
format = "%FT%T." ++ formatMillis t ++ tzFormat
tzFormat
| 0 == timeZoneMinutes (zonedTimeZone t) = "Z"
| otherwise = "%z"
formatMillis :: (FormatTime t) => t -> String
formatMillis t = take 3 . formatTime defaultTimeLocale "%q" $ t
instance FromJSON ZonedTime where
parseJSON (String t) =
tryFormats alternateFormats
<|> fail "could not parse ECMA-262 ISO-8601 date"
where
tryFormat f =
case parseTime defaultTimeLocale f (unpack t) of
Just d -> pure d
Nothing -> empty
tryFormats = foldr1 (<|>) . map tryFormat
alternateFormats =
dateTimeFmt defaultTimeLocale :
distributeList ["%Y", "%Y-%m", "%F"]
["T%R", "T%T", "T%T%Q", "T%T%QZ", "T%T%Q%z"]
distributeList xs ys =
foldr (\x acc -> acc ++ distribute x ys) [] xs
distribute x = map (mappend x)
parseJSON v = typeMismatch "ZonedTime" v
instance ToJSON UTCTime where
toJSON t = String $ pack $ formatTime defaultTimeLocale format t
where
format = "%FT%T." ++ formatMillis t ++ "Z"
instance FromJSON UTCTime where
parseJSON = withText "UTCTime" $ \t ->
case parseTime defaultTimeLocale "%FT%T%QZ" (unpack t) of
Just d -> pure d
_ -> fail "could not parse ISO-8601 date"