1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
{-# LANGUAGE OverloadedStrings #-}
module Birthdate
( Birthdate(..)
, fullname
, age
, readBirthdates
, filterBirthday
) where
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Text.Read as T
import Data.Either (partitionEithers)
import Date (Date(Date), sameDayAndMonth, yearsGap)
data Birthdate = Birthdate
{ date :: Date
, lastname :: Text
, firstname :: Text
} deriving (Eq, Show)
fullname :: Birthdate -> Text
fullname d = T.concat [firstname d, " ", lastname d]
age :: Date -> Birthdate -> Int
age currentDate birthdate = yearsGap currentDate (date birthdate)
readBirthdates :: FilePath -> IO (Either Text [Birthdate])
readBirthdates path = do
eitherBirthdates <- map parseBirthdate . zip [1..] . T.lines <$> T.readFile path
return $
case partitionEithers eitherBirthdates of
([], birthdates) ->
Right birthdates
(errors, _) ->
Left $ T.intercalate "\n" errors
parseBirthdate :: (Int, Text) -> Either Text Birthdate
parseBirthdate (line, text) =
case map T.strip $ T.splitOn "," text of
[date, lastname, firstname] ->
case map T.decimal $ T.splitOn "/" date of
[Right (day, ""), Right (month, ""), Right (year, "")] ->
Right Birthdate
{ date = Date year month day
, lastname = lastname
, firstname = firstname
}
_ ->
Left $ T.concat
[ lineOutput line
, " birthdate: "
, date
, ". (Required: year/month/day)"
]
_ ->
Left $ T.concat
[ lineOutput line
, " line: "
, text
, ". (Required: date, lastname, firstname)"
]
lineOutput :: Int -> Text
lineOutput line =
T.concat
[ "[L"
, T.pack . show $ line
, "]"
]
filterBirthday :: Date -> [Birthdate] -> [Birthdate]
filterBirthday d = filter (sameDayAndMonth d . date)
|