Haskell 日期解析和格式化

发布于 2024-10-02 20:03:46 字数 351 浏览 3 评论 0原文

我一直在使用 Haskell 的 Date.Time 模块来解析像 12-4-19991-31-1999 这样的日期。我尝试过:

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

而且我认为它希望我的月份和日期恰好有两位数而不是 1 或 2...

执行此操作的正确方法是什么?

另外,我想以这种格式打印我的一天:12/4/1999 Haskell 的方式是什么?

感谢您的帮助。

I've been working with Haskell's Date.Time modules to parse a date like 12-4-1999 or 1-31-1999. I tried:

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

And I think it wants my months and days to have exactly two digits instead of 1 or 2...

What's the proper way to do this?

Also, I'd like to print out my Day in this format: 12/4/1999 what's the Haskell way to?

Thanks for the help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

影子是时光的心 2024-10-09 20:03:46

您可以使用Data.Time.Format 中的函数读取日期。我在下面包含了一个简单的程序,它以一种格式读入日期并以两种不同的格式写回该日期。要以单位数月份或天数读取,请在 % 和格式说明符之间放置一个连字符 (-)。换句话说,要解析 9-9-2012 等格式的日期,请在 % 和格式字符之间包含一个连字符。因此,要解析“9-9-2012”,您需要格式字符串“%-d-%-m-%Y”。

注意:考虑到 Haskell 包的发展速度,这个答案有点过时了。也许是时候寻找更好的解决方案了。我不再写 Haskell,所以如果其他人创建了另一个答案,那就太好了,因为这个问题在 Google 结果中排名很高。

自 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, time >= 1.6.0.1

截至 2014 年 8 月,最好从 System.Locale 包获取语言环境,而不是从 Haskell 1998 区域设置包。考虑到这一点,上面的示例代码现在如下所示:

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"

原始,2012 年 1 月 答案:

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可从 time 包中获取。如果您需要解析个位数的月份或日期,换句话说,像 9-9-2012 这样的日期,则在 % 和格式字符之间包含一个连字符。因此,要解析“9-9-2012”,您需要格式字符串“%-d-%-m-%Y”。

You can use the functions in Data.Time.Format to read in the dates. I've included a trivial program below that reads in a date in one format and writes that date back out in two different formats. To read in single-digit months or days, place a single hyphen (-) between the % and format specifier. In other words to parse dates formatted like 9-9-2012 then include a single hyphen between the % and the format characters. So to parse "9-9-2012" you would need the format string "%-d-%-m-%Y".

Note: This answer is getting a bit long-in-the-tooth given the rate at which Haskell packages evolve. It might be time to look for a better solution. I'm no longer writing Haskell so it would be nice if someone else created another answer since this question ranks highly in Google results.

As of July 2017, you are encouraged to use parseTimeOrError. The code becomes:

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

The versions from the .cabal file:
build-depends: base >=4.9 && <4.10, time >= 1.6.0.1

As of August, 2014, the locale was best obtained from the System.Locale package rather than the Haskell 1998 Locale package. With that in mind, the sample code from above now reads:

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

output now looks like this:

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

Original, January 2012 answer:

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

The output looks like this:

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

Data.Time.Format is available from the time package. If you need to parse single-digit months or days, in other words dates like 9-9-2012 then include a single hyphen between the % and the format characters. So to parse "9-9-2012" you would need the format string "%-d-%-m-%Y".

人事已非 2024-10-09 20:03:46

使用 %-d 和 %-m 而不是 %d 和 %m 意味着单位数日/月是可以的,即

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

这可能就是 sclv 的意思,但他的评论对我来说有点太神秘了。

Using %-d and %-m instead of %d and %m means single digit day/month is OK, i.e.

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

This may be what sclv meant, but his comment was a little too cryptic for me.

相权↑美人 2024-10-09 20:03:46

从最近开始,我建议使用 strptime 包来满足您的所有日期/时间解析需求。

Since recently, I'll advice to use strptime package for all your date/time parsing needs.

天气好吗我好吗 2024-10-09 20:03:46

这是一些旧代码,其中包含两种类型的自制日期,仅包含 YMD 的日期,没有时间或时区等。

它展示了如何使用 readDec 将字符串解析为日期。请参阅 parseDate 函数。使用readDec读取数字,前导空格(因为过滤器)或前导零并不重要,并且解析停止于第一个非数字。然后使用 tail (跳过非数字)到达日期的下一个数字字段。

它显示了几种输出格式设置的方法,但最灵活的方法是使用 Text.printf。请参阅实例显示 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 ds@(_: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 来设置显示日期的格式。

Here is some old code that contains two types of homemade dates, dates with just YMD, no time or timezones, etc.

It shows how to parse strings into dates using readDec. See the parseDate function. With readDec, read the number, it doesn't matter about leading spaces(because of filter) or leading zeros,and the parse stops at the first non-digit. Then used tail (to skip the non digit) to get to the next numerical field of the date.

It shows several ways of formatting for output, but the most flexible way is to use Text.printf. See instance Show LtDate. With printf, anything is possible!

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 ds@(_:ds')
           | ds'==[] = '0':ds
           | otherwise = ds


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

Once you have (Y,M,D), it's easy to convert to a Haskell library type for data manipulations. Once you are done with the HS libraries, Text.printf can be used to format a date for display.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文