2010-11-13 78 views
21

我一直在使用Haskell的Date.Time模塊來解析日期,如12-4-19991-31-1999。我想:Haskell日期解析和格式化

parseDay :: String -> Day 
parseDay s = readTime defaultTimeLocale "%m%d%Y" s 

而且我覺得它想要我的月份和日期有恰好爲兩個數字,而不是1個或2 ...

什麼是做到這一點的正確方法?

另外,我想用這種格式打印我的日期:12/4/1999 Haskell的方式是什麼?

感謝您的幫助。

+1

無論如何你不需要在%m,%d和%Y之間劃線? – sclv 2010-11-14 19:42:44

+0

@AlexBaranosky你可能要考慮接受這個問題的不同答案:) – Ben 2016-10-11 14:23:54

回答

-2

這裏是包含兩種類型的國產日期的一些舊代碼,只有年月日,沒有時間或時區,日期等

它顯示瞭如何解析字符串轉換爲使用readDec日期。請參閱parseDate函數。用readDec,讀取這個數字,關於前導空格(因爲filter)或前導零並不重要,並且解析停在第一個非數字上。然後使用tail(跳過非數字)到達日期的下一個數字字段。

它顯示了輸出格式的幾種方式,但最靈活的方法是使用Text.printf。見instance Show LtDate。有了printf,任何事情都是可能的!

import Char 
import Numeric 
import Data.Time.Calendar 
import Data.Time.Clock 
import Text.Printf 
-- ================================================================ 
--      LtDate 
-- ================================================================ 
type Date=(Int,Int,Int) 
data LtDate = LtDate 
    { ltYear :: Int, 
    ltMonth:: Int, 
    ltDay :: Int 
    } 
instance Show LtDate 
    where show d = printf "%4d-%02d-%02d" (ltYear d) (ltMonth d) (ltDay d) 

toLtDate :: Date -> LtDate 
toLtDate (y,m,d)= LtDate y m d 

-- ============================================================= 
--       Date 
-- ============================================================= 
-- | Parse a String mm/dd/yy into tuple (y,m,d) 
-- accepted formats 
-- 
-- @ 
-- 12\/01\/2004 
-- 12\/ 1\' 4 
-- 12-01-99 
-- @ 
parseDate :: String -> Date 
parseDate s = (y,m,d) 
    where [(m,rest) ] = readDec (filter (not . isSpace) s) 
      [(d,rest1)] = readDec (tail rest) 
      [(y, _) ] = parseDate' rest1 

-- | parse the various year formats used by Quicken dates 
parseDate':: String -> [(Int,String)] 
parseDate' (y:ys) = 
    let [(iy,rest)] = readDec ys 
     year=case y of '\''  -> iy + 2000 
        _ -> 
         if iy < 1900 then iy + 1900 else iy 
    in [(year,rest)] 

-- | Note some functions sort by this format 
-- | So be careful when changing it. 
showDate::(Int, Int, Int) -> String 
showDate (y,m,d)= yy ++ '-':mm ++ '-':dd 
    where dd=zpad (show d) 
      mm = zpad (show m) 
      yy = show y 
      zpad [email protected](_:ds') 
      | ds'==[] = '0':ds 
      | otherwise = ds 


-- | from LtDate to Date 
fromLtDate :: LtDate -> Date 
fromLtDate lt = (ltYear lt, ltMonth lt, ltDay lt) 

一旦你有(Y,M,d),可以很容易地轉換成一個Haskell庫類型的數據操作。完成HS庫之後,可以使用Text.printf來格式化顯示日期。

+5

這似乎很可笑地複雜!必須有一個更簡單的方法,上帝幫助我 – 2010-11-14 00:17:12

+0

請仔細看看,代碼是一個例子,並不是所有必要的:解析日期'parseDate'只需要4行;調用'readDec' 3次。要顯示日期,請使用Text.printf'一次。加載文件並在你的日期運行它看看它的工作原理,然後看看'parseDat'e和'printf'。這parseDate忽略空格,並不關心日期中的分隔符' - '或'/'。它改變了'55到1955年等等。它是10行(包括'parseDate'')'ShowDate','fromLtDate'和'data'語句是不需要的。時鐘和日曆都不包括在內。 – frayser 2010-11-14 13:19:16

+1

刪除'parseDate'和'parseDate''之外的所有內容,這會使它看起來更簡單。保留'Data.Char'和'Numeric'的包含年解析器''parseDate''可以被另一個調用'readDec'替代。 – frayser 2010-11-14 13:30:49

7

因爲最近,我會建議您使用strptime包來滿足您所有的日期/時間解析需求。

46

您可以使用Data.Time.Format中的函數來讀取日期。我在下面列出了一個簡單的程序,它以一種格式讀取日期,並以兩種不同的格式寫出日期。要讀取單位數月或數天,請在%和格式說明符之間放置一個連字符( - )。

import Locale 
import Data.Time 
import Data.Time.Format 

main = 
    do 
    let dateString = "26 Jan 2012 10:54 AM" 
    let timeFromString = readTime defaultTimeLocale "%d %b %Y %l:%M %p" dateString :: UTCTime 
    -- Format YYYY/MM/DD HH:MM 
    print $ formatTime defaultTimeLocale "%Y/%m/%d %H:%M" timeFromString 
    -- Format MM/DD/YYYY hh:MM AM/PM 
    print $ formatTime defaultTimeLocale "%m/%d/%Y %I:%M %p" timeFromString 

輸出看起來是這樣的:

"2012/01/26 10:54" 
"01/26/2012 10:54 AM" 

Data.Time.Format可從 「時間」 包。如果您需要解析一位數的月份或日期,換言之,像9-9-2012這樣的日期,那麼在%和格式字符之間包含一個連字符。因此,要解析「9-9-2012」,您需要格式字符串「%-d - % - m-%Y」。

截至2014年8月,語言環境現在最好從「System.Locale」包而不是Haskell 1998「Locale」包中獲得。考慮到這一點,從現在上面的代碼示例如下:

import System.Locale 
import Data.Time 
import Data.Time.Format 

main = 
    do 
    let dateString = "26 Jan 2012 10:54 AM" 
    let timeFromString = readTime defaultTimeLocale "%d %b %Y %l:%M %p" dateString :: UTCTime 
    -- Format YYYY/MM/DD HH:MM 
    print $ formatTime defaultTimeLocale "%Y/%m/%d %H:%M" timeFromString 
    -- Format MM/DD/YYYY hh:MM AM/PM 
    print $ formatTime defaultTimeLocale "%m/%d/%Y %I:%M %p" timeFromString 

    -- now for a string with single digit months and days: 
    let dateString = "9-8-2012 10:54 AM" 
    let timeFromString = readTime defaultTimeLocale "%-d-%-m-%Y %l:%M %p" dateString :: UTCTime 
    -- Format YYYY/MM/DD HH:MM 
    print $ formatTime defaultTimeLocale "%Y/%m/%d %H:%M" timeFromString 

輸出現在看起來像這樣:

"2012/01/26 10:54" 
"01/26/2012 10:54 AM" 
"2012/08/09 10:54" 

隨着2017年7月的,上面的代碼使用現在已經過時分析時。鼓勵您現在使用parseTimeOrError。代碼變爲:

import Data.Time 

main = 
    do 
    let dateString = "26 Jan 2012 10:54 AM" 
    let timeFromString = parseTimeOrError True defaultTimeLocale "%d %b %Y %l:%M %p" dateString :: UTCTime 
    -- Format YYYY/MM/DD HH:MM 
    print $ formatTime defaultTimeLocale "%Y/%m/%d %H:%M" timeFromString 
    -- Format MM/DD/YYYY hh:MM AM/PM 
    print $ formatTime defaultTimeLocale "%m/%d/%Y %I:%M %p" timeFromString 

    -- now for a string with single digit months and days: 
    let dateString = "9-8-2012 10:54 AM" 
    let timeFromString = parseTimeOrError True defaultTimeLocale "%-d-%-m-%Y %l:%M %p" dateString :: UTCTime 
    -- Format YYYY/MM/DD HH:MM 
    print $ formatTime defaultTimeLocale "%Y/%m/%d %H:%M" timeFromString 

的從.cabal文件版本: 集結取決於:基礎> = 4.9 & & < 4.10,時間> = 1.6.0.1

這就是說,這個答案越來越在哈斯克爾軟件包發展速度方面有點長久。現在可能是尋找更好解決方案的時候了。

+5

對於懶惰,這是在'時間'包。 – user239558 2013-06-27 19:19:05

+1

男人!該%-d技巧應該在文檔中。 – Bzzt 2014-11-18 05:53:50

+0

我得到'不明確的發生'defaultTimeLocale''這是它,'Data.Time.defaultTimeLocale'或'System.Locale.defaultTimeLocale'? – peer 2017-07-08 21:26:51

9

使用%D和%-m代替%d和%m表示單數位日/月是確定的,即

parseDay :: String -> Day 
parseDay s = readTime defaultTimeLocale "%-m%-d%Y" s 

這可能是什麼sclv意思,但他的評論有點太對我來說很神祕。

+1

用於表示可能的單位數月/日的'-'標誌。我把頭髮拉出來,轉向正規表演! – 2014-07-10 19:21:46