Разбор и форматирование даты на Haskell - PullRequest
24 голосов
/ 13 ноября 2010

Я работал с модулями Date.Time в Haskell для разбора даты вроде 12-4-1999 или 1-31-1999. Я попробовал:

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

И я думаю, что мои месяцы и дни должны иметь ровно две цифры вместо 1 или 2 ...

Как правильно это сделать?

Кроме того, я хотел бы распечатать свой День в следующем формате: 12/4/1999 Каков путь на Haskell?

Спасибо за помощь.

Ответы [ 4 ]

53 голосов
/ 26 января 2012

Вы можете использовать функции в Data.Time.Format для чтения дат.Ниже я включил тривиальную программу, которая считывает дату в одном формате и записывает эту дату обратно в двух разных форматах.Чтобы прочитать однозначные месяцы или дни, поместите один дефис (-) между% и спецификатором формата.Другими словами, для разбора дат, отформатированных как 9-9-2012, нужно включить один дефис между символами% и формата.Таким образом, для разбора "9-9-2012" вам понадобится строка формата "% -d -% - m-% Y".

Примечание: этот ответ становится немного длинным в зубахучитывая скорость, с которой развиваются пакеты Haskell.Возможно, пришло время искать лучшее решение.Я больше не пишу на Haskell, так что было бы неплохо, если бы кто-то создал другой ответ, так как этот вопрос занимает важное место в результатах поиска Google.

По состоянию на июль 2017 года в приведенном ниже коде используется теперьустарел parseTime.Вам рекомендуется использовать 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: build-зависимость: base> = 4.9 && <4.10, время> = 1.6.0.1

По состоянию наАвгуст 2014 года , языковой стандарт был лучше всего получен из пакета «System.Locale», а не из пакета «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 г. ** ответ:

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».

12 голосов
/ 03 июня 2013

Использование% -d и% -m вместо% d и% m означает, что однозначный день / месяц в порядке, т. Е.

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

Это может быть тем, что имел в виду sclv, но его комментарий был немногослишком загадочно для меня.

7 голосов
/ 21 декабря 2010

С недавних пор я буду советовать использовать пакет strptime для всех ваших потребностей в разборе даты / времени.

0 голосов
/ 14 ноября 2010

Вот некоторый старый код, который содержит два типа самодельных дат, даты с просто YMD, без часов или часовых поясов и т. Д.

Он показывает, как разбивать строки на даты, используя readDec.Смотрите функцию parseDatereadDec, считайте число, не имеет значения, что в начале пробела (из-за filter) или в начальных нулях, и анализ останавливается на первой не цифре.Затем использовали tail (чтобы пропустить нецифровое число), чтобы перейти к следующему числовому полю даты.

Он показывает несколько способов форматирования для вывода, но наиболее гибкий способ - использовать Text.printf.Смотри instance Show LtDateprintf все возможно!

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 можно использовать для форматирования даты для отображения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...