Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simpler way to deal with Time and Date?

Tags:

haskell

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
like image 746
BinaryHexer Avatar asked Mar 09 '23 03:03

BinaryHexer


1 Answers

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.
like image 64
K. A. Buhr Avatar answered Mar 28 '23 23:03

K. A. Buhr