2016-11-06 66 views
0

JSON日期数据写入定制的情况下,我有以下形式JSON最新数据:在埃宋

{"date": "2015-04-12"} 

和相应的哈斯克尔类型:

data Date = Date { 
     year :: Int 
    , month :: Int 
    , day :: Int 
    } 

我怎么能写定制FromJSONToJSON函数为 Aeson函数库? 由于格式化,导出实例不起作用。

回答

1

你必须转换Y/M/d /从字符串

{-# LANGUAGE OverloadedStrings #-} 
{-# OPTIONS_GHC -fno-warn-tabs #-} 

import Control.Monad 
import Data.Aeson 
import qualified Data.Text as T 
import Text.Read (readMaybe) 
-- import qualified Data.Attoparsec.Text as A 

data Date = Date Int Int Int deriving (Read, Show) 

instance ToJSON Date where 
    toJSON (Date y m d) = toJSON $ object [ 
     "date" .= T.pack (str 4 y ++ "-" ++ str 2 m ++ "-" ++ str 2 d)] 
     where 
      str n = pad . show where 
       pad s = replicate (n - length s) '0' ++ s 

instance FromJSON Date where 
    parseJSON = withObject "date" $ \v -> do 
     str <- v .: "date" 
     let 
      [email protected](~[y, m, d]) = T.split (== '-') str 
     guard (length ps == 3) 
     Date <$> readNum y <*> readNum m <*> readNum d 
     where 
      readNum = maybe (fail "not num") return . readMaybe . T.unpack 

    -- -- or with attoparsec 
    -- parseJSON = withObject "date" $ \v -> do 
    -- str <- v .: "date" 
    -- [y, m, d] <- either fail return $ 
    --  A.parseOnly (A.decimal `A.sepBy` A.char '-') str 
    -- return $ Date y m d 
5

为什么另起炉灶?在time包中有一个称为Date的半标准表示 - 它被称为Day。它会变得更好:不仅该相同的软件包甚至会为您提供用于从您拥有的格式解析Day的实用程序,这些实用程序甚至可以导出到aeson。是的,目前已经有aesonToJSONFromJSON实例为Day

ghci> :set -XOverloadedStrings 
ghci> import Data.Time.Calendar 
ghci> import Data.Aeson 
ghci> fromJSON "2015-04-12" :: Result Day 
Success 2015-04-12 
ghci> toJSON (fromGregorian 2015 4 12) 
String "2015-04-12" 

如果你真的提取几天,几个月,甚至几年,你可以随时使用toGregorian :: Day -> (Integer, Int, Int)。坚持标准抽象可能是一个很好的长期选择。