You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell(Aeson):以惯用方式处理含星期的时间字段解析为UTCTime

解决Aeson解析带星期的时间字符串到UTCTime的问题

针对你的JSONL格式({"mood": "Good", "when": "2022-10-09 Sun 11:51"}),以下是几种Haskell惯用的处理方式,直接去掉时间字符串中的星期部分后解析为UTCTime:

方法一:自定义FromJSON实例(推荐)

直接在解析目标数据结构时,单独处理when字段的字符串内容,过滤掉星期部分再解析。这种方式针对性强,不会影响JSON中的其他字段。

首先定义数据结构和必要的导入:

import Relude
import Data.Aeson
import Data.Time.Clock (UTCTime)
import Data.Time.Format (parseTimeM, defaultTimeLocale)

data MoodEntry = MoodEntry
  { mood :: Text
  , when :: UTCTime
  } deriving (Show, Eq)

然后实现自定义的FromJSON实例,核心是先清理时间字符串:

-- 清理时间字符串:过滤掉三个字母的星期缩写
cleanTimeStr :: Text -> Text
cleanTimeStr = unwords . filter (\s -> length s /= 3) . words

instance FromJSON MoodEntry where
  parseJSON = withObject "MoodEntry" $ \obj -> MoodEntry
    <$> obj .: "mood"
    <*> (obj .: "when" >>= \timeText ->
           case parseTimeM True defaultTimeLocale "%Y-%m-%d %H:%M" (toString $ cleanTimeStr timeText) of
             Just utcTime -> pure utcTime
             Nothing -> fail $ "无效的时间格式: " <> toString timeText)

这样调用decodeFileStrict就能直接解析JSONL文件:

main :: IO ()
main = do
  result <- decodeFileStrict "your-file.jsonl" :: IO (Maybe MoodEntry)
  print result

方法二:预处理整个JSON ByteString

如果确定JSON中没有其他类似" Sun "的子串,可以先批量替换所有星期缩写,再解析整个JSON。这种方式适合结构简单的场景:

import Relude
import Data.Aeson
import Data.Time.Clock (UTCTime)
import qualified Data.ByteString as BS
import qualified Data.Text.Encoding as TE

-- 替换所有星期缩写为空格
preprocessJSON :: BS.ByteString -> BS.ByteString
preprocessJSON = TE.encodeUtf8
  . replace " Sun " " "
  . replace " Mon " " "
  . replace " Tue " " "
  . replace " Wed " " "
  . replace " Thu " " "
  . replace " Fri " " "
  . replace " Sat " " "
  . TE.decodeUtf8

data MoodEntry = MoodEntry
  { mood :: Text
  , when :: UTCTime
  } deriving (Show, Eq, FromJSON) -- 这里用自动派生的FromJSON即可

main :: IO ()
main = do
  rawBS <- BS.readFile "your-file.jsonl"
  let result = decode (preprocessJSON rawBS) :: Maybe MoodEntry
  print result

方法三:用Lens修改JSON Value

如果需要对JSON做多处字段修改,可以用aeson-lens库先修改when字段的内容,再解析为目标类型:

首先添加依赖aeson-lens,然后编写代码:

import Relude
import Data.Aeson
import Data.Aeson.Lens
import Control.Lens
import Data.Time.Clock (UTCTime)
import Data.Time.Format (parseTimeM, defaultTimeLocale)

data MoodEntry = MoodEntry
  { mood :: Text
  , when :: UTCTime
  } deriving (Show, Eq, FromJSON)

cleanTimeStr :: Text -> Text
cleanTimeStr = unwords . filter (\s -> length s /= 3) . words

-- 修改JSON中的when字段值
modifyTimeField :: Value -> Value
modifyTimeField = _Object . at "when" . _Just . _String %~ cleanTimeStr

parseModified :: BS.ByteString -> Maybe MoodEntry
parseModified bs = decode bs >>= \jsonVal -> parseJSON (modifyTimeField jsonVal)

main :: IO ()
main = do
  rawBS <- BS.readFile "your-file.jsonl"
  print $ parseModified rawBS

内容的提问来源于stack exchange,提问作者Steven Pinkerton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 23:01:03