-- |
-- Module      : Data.Hourglass.Zone
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : unknown
--
-- Timezone utility
--
{-# LANGUAGE ExistentialQuantification #-}
module Data.Hourglass.Zone
    ( Timezone(..)
    , UTC(..)
    , TimezoneMinutes(..)
    ) where

-- | standard representation for timezone
class Timezone tz where
    -- | offset in minutes from UTC. valid values should be between -12*60 to +14*60
    timezoneOffset :: tz -> Int
    -- | the name of the timezone. by default will be +-HH:MM encoding.
    timezoneName :: tz -> String
    timezoneName = Int -> String
tzMinutesPrint (Int -> String) -> (tz -> Int) -> tz -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. tz -> Int
forall tz. Timezone tz => tz -> Int
timezoneOffset

-- | Simple timezone containing the number of minutes difference
-- with UTC.
--
-- Valid values should be between -12*60 to +14*60
newtype TimezoneMinutes = TimezoneMinutes Int
    deriving (Int -> TimezoneMinutes -> ShowS
[TimezoneMinutes] -> ShowS
TimezoneMinutes -> String
(Int -> TimezoneMinutes -> ShowS)
-> (TimezoneMinutes -> String)
-> ([TimezoneMinutes] -> ShowS)
-> Show TimezoneMinutes
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TimezoneMinutes] -> ShowS
$cshowList :: [TimezoneMinutes] -> ShowS
show :: TimezoneMinutes -> String
$cshow :: TimezoneMinutes -> String
showsPrec :: Int -> TimezoneMinutes -> ShowS
$cshowsPrec :: Int -> TimezoneMinutes -> ShowS
Show,TimezoneMinutes -> TimezoneMinutes -> Bool
(TimezoneMinutes -> TimezoneMinutes -> Bool)
-> (TimezoneMinutes -> TimezoneMinutes -> Bool)
-> Eq TimezoneMinutes
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: TimezoneMinutes -> TimezoneMinutes -> Bool
$c/= :: TimezoneMinutes -> TimezoneMinutes -> Bool
== :: TimezoneMinutes -> TimezoneMinutes -> Bool
$c== :: TimezoneMinutes -> TimezoneMinutes -> Bool
Eq,Eq TimezoneMinutes
Eq TimezoneMinutes
-> (TimezoneMinutes -> TimezoneMinutes -> Ordering)
-> (TimezoneMinutes -> TimezoneMinutes -> Bool)
-> (TimezoneMinutes -> TimezoneMinutes -> Bool)
-> (TimezoneMinutes -> TimezoneMinutes -> Bool)
-> (TimezoneMinutes -> TimezoneMinutes -> Bool)
-> (TimezoneMinutes -> TimezoneMinutes -> TimezoneMinutes)
-> (TimezoneMinutes -> TimezoneMinutes -> TimezoneMinutes)
-> Ord TimezoneMinutes
TimezoneMinutes -> TimezoneMinutes -> Bool
TimezoneMinutes -> TimezoneMinutes -> Ordering
TimezoneMinutes -> TimezoneMinutes -> TimezoneMinutes
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: TimezoneMinutes -> TimezoneMinutes -> TimezoneMinutes
$cmin :: TimezoneMinutes -> TimezoneMinutes -> TimezoneMinutes
max :: TimezoneMinutes -> TimezoneMinutes -> TimezoneMinutes
$cmax :: TimezoneMinutes -> TimezoneMinutes -> TimezoneMinutes
>= :: TimezoneMinutes -> TimezoneMinutes -> Bool
$c>= :: TimezoneMinutes -> TimezoneMinutes -> Bool
> :: TimezoneMinutes -> TimezoneMinutes -> Bool
$c> :: TimezoneMinutes -> TimezoneMinutes -> Bool
<= :: TimezoneMinutes -> TimezoneMinutes -> Bool
$c<= :: TimezoneMinutes -> TimezoneMinutes -> Bool
< :: TimezoneMinutes -> TimezoneMinutes -> Bool
$c< :: TimezoneMinutes -> TimezoneMinutes -> Bool
compare :: TimezoneMinutes -> TimezoneMinutes -> Ordering
$ccompare :: TimezoneMinutes -> TimezoneMinutes -> Ordering
$cp1Ord :: Eq TimezoneMinutes
Ord)

-- | Universal Time Coordinated. The generic computer "timezone".
data UTC = UTC
    deriving (Int -> UTC -> ShowS
[UTC] -> ShowS
UTC -> String
(Int -> UTC -> ShowS)
-> (UTC -> String) -> ([UTC] -> ShowS) -> Show UTC
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [UTC] -> ShowS
$cshowList :: [UTC] -> ShowS
show :: UTC -> String
$cshow :: UTC -> String
showsPrec :: Int -> UTC -> ShowS
$cshowsPrec :: Int -> UTC -> ShowS
Show,UTC -> UTC -> Bool
(UTC -> UTC -> Bool) -> (UTC -> UTC -> Bool) -> Eq UTC
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UTC -> UTC -> Bool
$c/= :: UTC -> UTC -> Bool
== :: UTC -> UTC -> Bool
$c== :: UTC -> UTC -> Bool
Eq,Eq UTC
Eq UTC
-> (UTC -> UTC -> Ordering)
-> (UTC -> UTC -> Bool)
-> (UTC -> UTC -> Bool)
-> (UTC -> UTC -> Bool)
-> (UTC -> UTC -> Bool)
-> (UTC -> UTC -> UTC)
-> (UTC -> UTC -> UTC)
-> Ord UTC
UTC -> UTC -> Bool
UTC -> UTC -> Ordering
UTC -> UTC -> UTC
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: UTC -> UTC -> UTC
$cmin :: UTC -> UTC -> UTC
max :: UTC -> UTC -> UTC
$cmax :: UTC -> UTC -> UTC
>= :: UTC -> UTC -> Bool
$c>= :: UTC -> UTC -> Bool
> :: UTC -> UTC -> Bool
$c> :: UTC -> UTC -> Bool
<= :: UTC -> UTC -> Bool
$c<= :: UTC -> UTC -> Bool
< :: UTC -> UTC -> Bool
$c< :: UTC -> UTC -> Bool
compare :: UTC -> UTC -> Ordering
$ccompare :: UTC -> UTC -> Ordering
$cp1Ord :: Eq UTC
Ord)

instance Timezone UTC where
    timezoneOffset :: UTC -> Int
timezoneOffset UTC
_ = Int
0
    timezoneName :: UTC -> String
timezoneName UTC
_   = String
"UTC"

instance Timezone TimezoneMinutes where
    timezoneOffset :: TimezoneMinutes -> Int
timezoneOffset (TimezoneMinutes Int
minutes) = Int
minutes

-- | print a minute offset in format:
-- (+-)HH:MM
tzMinutesPrint :: Int -> String
tzMinutesPrint :: Int -> String
tzMinutesPrint Int
offset =
      (if Int
offset Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0 then Char
'+' else Char
'-')
    Char -> ShowS
forall a. a -> [a] -> [a]
: (Int -> String
forall a. (Ord a, Num a, Show a) => a -> String
pad0 Int
h String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
":" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. (Ord a, Num a, Show a) => a -> String
pad0 Int
m)
  where (Int
h,Int
m)  = Int -> Int
forall a. Num a => a -> a
abs Int
offset Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`divMod` Int
60
        pad0 :: a -> String
pad0 a
v
            | a
v a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
10    = Char
'0'Char -> ShowS
forall a. a -> [a] -> [a]
:a -> String
forall a. Show a => a -> String
show a
v
            | Bool
otherwise = a -> String
forall a. Show a => a -> String
show a
v