2016-11-06 68 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)。堅持標準抽象可能是一個很好的長期選擇。