Simpler way to deal with Time and Date?

haskell

Solution

Edit: Fixed to use `timezone-olson` / `timezone-series` for correct timezone processing.

You should be able to do almost everything with the `time` package, except that proper timezone processing will require `timezone-olson` and `timezone-series` packages on Linux systems; I'm not sure how to do it on Windows systems. Maybe someone else has a better way.

Here's the code:

module Time where

import Data.Time                             -- package "time"
import Data.Time.Calendar.WeekDate           -- package "time"
import Data.Time.LocalTime.TimeZone.Olson    -- package "timezone-olson"
import Data.Time.LocalTime.TimeZone.Series   -- package "timezone-series"

-- |POSIX-specific timezone lookup
lookupTimeZone :: String -> IO TimeZoneSeries
lookupTimeZone tz =
  getTimeZoneSeriesFromOlsonFile ("/usr/share/zoneinfo/" ++ tz)

data MyTime = MyTime
  { year :: Integer
  , month :: Int
  , week :: Int
  , dayOfMonth :: Int
  , dayOfWeek :: Int
  , hour :: Int
  , minutes :: Int
  , seconds :: Int
  } deriving (Show)

getMyTime :: TimeZoneSeries -> UTCTime -> MyTime
getMyTime tz t =
  let LocalTime day (TimeOfDay hh mm ss) = utcToLocalTime' tz t
      (yr, mn, dom) = toGregorian day
      (_,  wk, dow) = toWeekDate day
  in MyTime yr mn wk dom dow hh mm (round ss)

main :: IO ()
main = do
  currentTime <- getCurrentTime
  -- Note: if you want time in local timezone, use:
  -- tz <- getTimeZoneSeriesFromOlsonFile "/etc/localtime"
  tz <- lookupTimeZone "Asia/Tokyo"
  print $ getMyTime tz currentTime

A few cautionary notes:

- `lookupTimeZone` will throw an exception if it can't find the timezone file at `/usr/share/zoneinfo/your/timezone`

- If by "week", you meant "week of the year", you may want to consult the documentation for `toWeekDate` to see exactly how that's defined.

- If you want months or days in string format, you can use the functions in `Data.Time.Format` (still in the `time` package) to format them in the current (or some other) locale.

Problem

So I am trying to learn Haskell, so I am sorry if this has already been asked, but I could not find a question that properly answered my doubts. So my question is given `UTCTime` what is the easiest and straightforward way of getting the following: - Year - Month - Week - Date (Eg: 24) - Day (Eg: Monday) - Hour - Minutes - Seconds Also if there is convenient way of converting `UTCTime` to some local time using just `Asia/Tokyo` or similar strings. I couldn't find a single library that gave all of these features and got confused and to be quite honest irritated that I need to convert between different types and use multiple libraries to achieve the above. Maybe I was not looking properly. My effort so far: ``` import Data.Time -- Difference between JST and UTC in seconds -- JST is 9 hours ahead of UTC utcJSTDiff :: Int utcJSTDiff = 32400 getHour :: UTCTime -> Int getHour time = todHour (timeToTimeOfDay (utctDayTime time)) getMinutes :: UTCTime -> Int getMinutes time = todMin (timeToTimeOfDay (utctDayTime time)) isReminderHour :: Int -> Bool isReminderHour hour | hour == morningReminderHour || hour == eveningReminderHour = True | otherwise = False isReminderMins :: Int -> Bool isReminderMins mins | mins <= reminderMinuteLimit = True | otherwise = False timeforReminder :: UTCTime -> Bool timeforReminder time | isReminderHour (getHour time) && isReminderMins (getMinutes time) = True | otherwise = False utcToJST :: UTCTime -> UTCTime utcToJST = addUTCTime (realToFrac utcJSTDiff) main :: IO() main = do currentTime <- getCurrentTime let jstTime = utcToJST currentTime if timeforReminder jstTime then action1 else action2 ```

Original source