从[Char]中提取YYYYMMDD并创建DateTime值

时间:2018-04-09 09:19:39

标签: haskell

我的字符串包含具有以下格式“YYYYMMDD”的日期。这是理所当然的,没有错误的可能性。

我想从他们那里创建DateTime。

我设法让事情有效,但这些小事似乎很复杂:

-- Only works in base 10 , for positive values
stringToInt :: String -> Int
stringToInt [] = 0
stringToInt (x:xs) = (digitToInt x * 10^length xs ) + (stringToInt xs) 

-- Expecting format = "YYYYMMDD"
stringToDateTime :: String -> DateTime
stringToDateTime s = DateTime year month day 0 0 0
  where year = stringToInt $ take 4 s 
        month = stringToInt $ take(6-4) . drop 4 $ s
        day = stringToInt $ take(8-6) . drop 6 $ s

date1 = stringToDateTime "20180409"

我尝试了parseDate函数,但无法让它工作,因为我无法找到它所期望的String格式(这里是Data.Dates doc:我们怎么知道预期的格式?)

这就是为什么我最终自己从我的String创建一个DateTime的功能,这样做我必须创建一个从[Char]转换Int的函数,因为我找不到一个已经存在的函数。

4 个答案:

答案 0 :(得分:5)

使用dates包,我认为您需要parseDateFormat

> import Data.Dates
> import Data.Dates.Formats (parseDateFormat)
> parseDateFormat "YYYYMMDD" "20180409"
Right 9 April 2018, 0:0:0

如果您确定您的字符串具有正确的日期格式,则可以使用Right fromRight'extra> import Data.Either.Extra > fromRight' $ parseDateFormat "YYYYMMDD" "20180409" 9 April 2018, 0:0:0 中提取结果:

  services.AddMvc(options =>
        {

             options.RespectBrowserAcceptHeader = true;

             options.InputFormatters.Add(new XmlSerializerInputFormatter());
             options.OutputFormatters.Add(new XmlSerializerOutputFormatter());

        }

答案 1 :(得分:2)

为了“正确”完成这些工作,你应该阅读解析器组合库。使用megaparsec library的一个(非常矫枉过正的)解决方案:

import Text.Megaparsec
import Text.Megaparsec.Char
import Control.Monad

type Parser = Parsec String String

decimalNInt :: Int -> Parser Int
decimalNInt nDigits = read <$> replicateM nDigits digitChar

data DateTime = DateTime Int Int Int Int Int Int deriving (Show)

dateYYYYMMDD :: Parser DateTime
dateYYYYMMDD = DateTime <$>
       decimalNInt 4 <*> decimalNInt 2 <*> decimalNInt 2
   <*> pure 0 <*> pure 0 <*> pure 0
> runParser dateYYYYMMDD "" "20180409"
    Right (DateTime 2018 4 9 0 0 0)
> runParser dateYYYYMMDD "" "2018009"
    Left (TrivialError (SourcePos {sourceName = "", sourceLine = Pos 1, sourceColumn = Pos 8} :| []) (Just EndOfInput) (fromList [Label ('d' :| "igit")]))
> runParser dateYYYYMMDD "" "abcdefgh"
    Left (TrivialError (SourcePos {sourceName = "", sourceLine = Pos 1, sourceColumn = Pos 1} :| []) (Just (Tokens ('a' :| ""))) (fromList [Label ('d' :| "igit")]))

或许更好理解的monadic符号,解析器看起来如此:

dateYYYYMMDD = do
    year <- decimalNInt 4
    month <- decimalNInt 2
    day <- decimalNInt 2
    return $ DateTime year month day 0 0 0

答案 2 :(得分:1)

切片我认为你必须自己做,但是要从字符串中读取整数,你应该使用函数read,如下所示:

read "1234" :: Int

要使此函数处理任何数据类型,它必须是类Read的实例。不幸的是,查看文档时,DateTime不是。

答案 3 :(得分:1)

使用parseTimeM,来自唯一真正认真对待日期和时间的Haskell软件包time。这是一个相当全面的图书馆;它唯一真正缺乏的是自然语言处理和生产。

Data.Time> parseTimeM False defaultTimeLocale "%0Y%m%d" "20180409" :: Maybe Day
Just 2018-04-09

上面链接的文档和formatTime的文档提供了可用格式说明符的完整列表。

如果您确实需要DateTime并且无法替代,则可以使用toGregorianDay中提取年,月和日。