X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=src%2FTSN%2FPicklers.hs;h=4f0020b6ad167123c10a66224a0b5092f09b8489;hb=HEAD;hp=6f131a75b921f4aac3490a39214a5106db0f6160;hpb=4ad960facfe0b939e71e4afe4502fce3108d90e3;p=dead%2Fhtsn-import.git diff --git a/src/TSN/Picklers.hs b/src/TSN/Picklers.hs index 6f131a7..4f0020b 100644 --- a/src/TSN/Picklers.hs +++ b/src/TSN/Picklers.hs @@ -1,9 +1,12 @@ +{-# LANGUAGE ScopedTypeVariables #-} + -- | (Un)picklers for data types present in The Sports Network XML -- feed. -- module TSN.Picklers ( pickler_tests, xp_ambiguous_time, + xp_attr_option, xp_date, xp_date_padded, xp_datetime, @@ -11,6 +14,7 @@ module TSN.Picklers ( xp_earnings, xp_fracpart_only_double, xp_gamedate, + xp_tba_int, xp_tba_time, xp_time, xp_time_dots, @@ -23,7 +27,7 @@ import Data.List ( intercalate ) import Data.List.Split ( chunksOf ) import Data.Maybe ( catMaybes, listToMaybe ) import Data.String.Utils ( replace ) -import Data.Time.Clock ( NominalDiffTime, UTCTime, addUTCTime ) +import Data.Time.Clock ( UTCTime ) import Data.Time.Format ( formatTime, parseTime ) import Data.Tree.NTree.TypeDefs ( NTree(..) ) import System.Locale ( TimeLocale( wDays, months ), defaultTimeLocale ) @@ -270,8 +274,8 @@ xp_datetime = -- -- >>> import Data.Maybe ( fromJust ) -- >>> :{ --- let parse_date :: String -> Maybe UTCTime; --- parse_date = parseTime defaultTimeLocale date_format; +-- let parse_date :: String -> Maybe UTCTime +-- parse_date = parseTime defaultTimeLocale date_format -- :} -- -- >>> let dates = [ "1/" ++ (d : "/1970") | d <- ['1'..'9'] ] @@ -448,35 +452,79 @@ xp_tba_time = from_time (Just t) = formatTime defaultTimeLocale time_format t +-- | (Un)pickle a 'Int', allowing for a value of \"TBA\" (which gets +-- translated to 'Nothing'). +-- +-- /Examples/: +-- +-- A failed parse will return 'Nothing': +-- +-- >>> let tn = text_node "YO" +-- >>> unpickleDoc xp_tba_int tn +-- Just Nothing +-- +-- And so will parsing a \"TBA\": +-- +-- >>> let tn = text_node "TBA" +-- >>> unpickleDoc xp_tba_int tn +-- Just Nothing +-- +-- But re-pickling 'Nothing' gives only \"TBA\": +-- +-- >>> pickleDoc xp_tba_int Nothing +-- NTree (XTag "/" []) [NTree (XText "TBA") []] +-- +-- A normal integer is also parsed successfully, of course: +-- +-- >>> let tn = text_node "110" +-- >>> unpickleDoc xp_tba_int tn +-- Just (Just 110) +-- +xp_tba_int :: PU (Maybe Int) +xp_tba_int = + (to_int, from_int) `xpWrap` xpText + where + to_int :: String -> Maybe Int + to_int = readMaybe + + from_int :: Maybe Int -> String + from_int Nothing = "TBA" + from_int (Just t) = show t + + -- | (Un)pickle the \ element format to/from a 'UTCTime'. -- The time_stamp elements look something like, -- -- \ January 6, 2014, at 10:11 PM ET \ -- --- TSN doesn't provide a proper time zone name, so we assume that --- it's always Eastern Standard Time. EST is UTC-5, so we --- add/subtract 5 hours to convert to/from UTC. +-- TSN doesn't provide a proper time zone name, only \"ET\" for +-- \"Eastern Time\". But \"Eastern Time\" changes throughout the +-- year, depending on one's location, for daylight-savings +-- time. It's really not any more useful to be off by one hour than +-- it is to be off by 5 hours, so rather than guess at EDT/EST, we +-- just store the timestamp as UTC. -- -- Examples: -- -- >>> let tn = text_node " January 6, 2014, at 10:11 PM ET " --- >>> unpickleDoc xp_time_stamp tn --- Just 2014-01-07 03:11:00 UTC +-- >>> let (Just tstamp) = unpickleDoc xp_time_stamp tn +-- >>> tstamp +-- 2014-01-06 22:11:00 UTC +-- >>> pickleDoc xp_time_stamp tstamp +-- NTree (XTag "/" []) [NTree (XText " January 6, 2014, at 10:11 PM ET ") []] -- xp_time_stamp :: PU UTCTime xp_time_stamp = (parse_time_stamp, from_time_stamp) `xpWrapMaybe` xpText where - five_hours :: NominalDiffTime - five_hours = 5 * 60 * 60 - - subtract_five :: UTCTime -> UTCTime - subtract_five = addUTCTime (-1 * five_hours) - + -- | We have to re-pad the time_stamp_format with a leading and + -- trailing space; see the documentation of 'time_stamp_format' + -- for more information. from_time_stamp :: UTCTime -> String from_time_stamp = - formatTime defaultTimeLocale time_stamp_format . subtract_five + formatTime defaultTimeLocale (" " ++ time_stamp_format ++ " ") + -- | (Un)pickle an ambiguous 12-hour AM/PM time, which is ambiguous @@ -565,6 +613,23 @@ xp_early_line_date = fmt = "%A, %B %-d" ++ upper_suffix ++ " (" ++ date_format_padded ++ ")" +-- | This is a replacement for @xpOption xpFoo@ within an 'xpAttr'. +-- There's a bug in +-- newer versions of HXT that prevents us from using the usual +-- 'xpOption' solution, so this is our stopgap. It should work on +-- any type that can be unpickled with a plain read/show. +-- +xp_attr_option :: forall a. (Read a, Show a) => PU (Maybe a) +xp_attr_option = + (to_a, from_a) `xpWrap` xpText + where + to_a :: String -> Maybe a + to_a = readMaybe + + from_a :: Maybe a -> String + from_a Nothing = "" + from_a (Just x) = show x + -- | Create an 'XmlTree' containing only the given text. This is -- useful for testing (un)picklers, where we don't want to have to