Haskell日期解析和格式化
我一直在使用Haskell的Date.Time模块来解析日期,如12-4-1999
或1-31-1999
。我想:Haskell日期解析和格式化
parseDay :: String -> Day
parseDay s = readTime defaultTimeLocale "%m%d%Y" s
而且我觉得它想要我的月份和日期有恰好为两个数字,而不是1个或2 ...
什么是做到这一点的正确方法?
另外,我想用这种格式打印我的日期:12/4/1999
Haskell的方式是什么?
感谢您的帮助。
这里是包含两种类型的国产日期的一些旧代码,只有年月日,没有时间或时区,日期等
它显示了如何解析字符串转换为使用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
来格式化显示日期。
这似乎很可笑地复杂!必须有一个更简单的方法,上帝帮助我 – 2010-11-14 00:17:12
请仔细看看,代码是一个例子,并不是所有必要的:解析日期'parseDate'只需要4行;调用'readDec' 3次。要显示日期,请使用Text.printf'一次。加载文件并在你的日期运行它看看它的工作原理,然后看看'parseDat'e和'printf'。这parseDate忽略空格,并不关心日期中的分隔符' - '或'/'。它改变了'55到1955年等等。它是10行(包括'parseDate'')'ShowDate','fromLtDate'和'data'语句是不需要的。时钟和日历都不包括在内。 – frayser 2010-11-14 13:19:16
删除'parseDate'和'parseDate''之外的所有内容,这会使它看起来更简单。保留'Data.Char'和'Numeric'的包含年解析器''parseDate''可以被另一个调用'readDec'替代。 – frayser 2010-11-14 13:30:49
您可以使用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
这就是说,这个答案越来越在哈斯克尔软件包发展速度方面有点长久。现在可能是寻找更好解决方案的时候了。
对于懒惰,这是在'时间'包。 – user239558 2013-06-27 19:19:05
男人!该%-d技巧应该在文档中。 – Bzzt 2014-11-18 05:53:50
我得到'不明确的发生'defaultTimeLocale''这是它,'Data.Time.defaultTimeLocale'或'System.Locale.defaultTimeLocale'? – peer 2017-07-08 21:26:51
使用%D和%-m代替%d和%m表示单数位日/月是确定的,即
parseDay :: String -> Day
parseDay s = readTime defaultTimeLocale "%-m%-d%Y" s
这可能是什么sclv意思,但他的评论有点太对我来说很神秘。
用于表示可能的单位数月/日的'-'标志。我把头发拉出来,转向正规表演! – 2014-07-10 19:21:46
无论如何你不需要在%m,%d和%Y之间划线? – sclv 2010-11-14 19:42:44
@AlexBaranosky你可能要考虑接受这个问题的不同答案:) – Ben 2016-10-11 14:23:54