--------------------------------------------------------------- -- Copyright (c) 2013, Enzo Haussecker. All rights reserved. -- --------------------------------------------------------------- {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RecordWildCards #-} {-# OPTIONS -Wall #-} {-# OPTIONS -fno-warn-type-defaults #-} module Data.Time.Exts.Zone where import Control.Arrow (first) import Data.Aeson (FromJSON, ToJSON) import Data.Convertible (Convertible(..)) import Data.Ord (comparing) import Data.Typeable (Typeable) import GHC.Generics (Generic) import System.Random (Random(..)) data City = Aden -- ^ Yemeni Republic | Amman -- ^ Hashemite Kingdom of Jordan | Anchorage -- ^ United States of America | Auckland -- ^ New Zealand | Baghdad -- ^ Republic of Iraq | Berlin -- ^ Federal Republic of Germany | Brussels -- ^ Kingdom of Belgium | Bujumbura -- ^ Republic of Burundi | Cairo -- ^ Arab Republic of Egypt | Chicago -- ^ United States of America | Damascus -- ^ Syrian Arab Republic | Denver -- ^ United States of America | Doha -- ^ State of Qatar | Gaborone -- ^ Republic of Botswana | Hong_Kong -- ^ People's Republic of China | Honolulu -- ^ United States of America | Johannesburg -- ^ Republic of South Africa | Kabul -- ^ Islamic Republic of Afghanistan | Karachi -- ^ Islamic Republic of Pakistan | Kinshasa -- ^ Democratic Republic of the Congo | Kolkata -- ^ Republic of India | Kuwait_City -- ^ State of Kuwait | London -- ^ United Kingdom of Great Britain and Northern Ireland | Los_Angeles -- ^ United States of America | Luanda -- ^ Republic of Angola | Manama -- ^ Kingdom of Bahrain | Minsk -- ^ Republic of Belarus | Mogadishu -- ^ Federal Republic of Somalia | Moscow -- ^ Russian Federation | New_York -- ^ United States of America | Oslo -- ^ Kingdom of Norway | Ouagadougou -- ^ Burkina Faso | Paris -- ^ French Republic | Pyongyang -- ^ Democratic People's Republic of Korea | Riyadh -- ^ Kingdom of Saudi Arabia | Sao_Paulo -- ^ Federative Republic of Brazil | Sarajevo -- ^ Bosnia and Herzegovina | Seoul -- ^ Republic of Korea | Shanghai -- ^ People's Republic of China | Singapore -- ^ Republic of Singapore | Sofia -- ^ Republic of Bulgaria | Stockholm -- ^ Kingdom of Sweden | Tehran -- ^ Islamic Republic of Iran | Tel_Aviv -- ^ State of Israel | Tirana -- ^ Republic of Albania | Tokyo -- ^ Japan | Toronto -- ^ Canada | Universal -- ^ Tnternational Territory | Vienna -- ^ Republic of Austria | Zurich -- ^ Swiss Confederation deriving (Eq,Enum,Generic,Ord,Show,Typeable) data TimeZone = Afghanistan_Time | Alaska_Daylight_Time | Alaska_Hawaii_Daylight_Time | Alaska_Hawaii_Standard_Time | Alaska_Standard_Time | Arabia_Daylight_Time | Arabia_Standard_Time | Brasilia_Summer_Time | Brasilia_Time | British_Summer_Time | Central_Africa_Time | Central_Daylight_Time | Central_European_Summer_Time | Central_European_Time | Central_Standard_Time | China_Daylight_Time | China_Standard_Time | Coordinated_Universal_Time | East_Africa_Time | Eastern_Daylight_Time | Eastern_European_Summer_Time | Eastern_European_Time | Eastern_Standard_Time | Further_Eastern_European_Time | Greenwich_Mean_Time | Gulf_Standard_Time | Hawaii_Aleutian_Standard_Time | Hong_Kong_Summer_Time | Hong_Kong_Time | India_Standard_Time | Iran_Daylight_Time | Iran_Standard_Time | Israel_Daylight_Time | Israel_Standard_Time | Japan_Standard_Time | Karachi_Time | Korea_Daylight_Time | Korea_Standard_Time | Moscow_Daylight_Time | Moscow_Standard_Time | Mountain_Daylight_Time | Mountain_Standard_Time | New_Zealand_Daylight_Time | New_Zealand_Standard_Time | Pacific_Daylight_Time | Pacific_Standard_Time | Pakistan_Standard_Time | Pakistan_Summer_Time | Singapore_Time | South_Africa_Standard_Time | West_Africa_Time | Yukon_Standard_Time deriving (Eq,Enum,Generic,Show,Typeable) data TimeZoneAbbr = TimeZoneAbbr { abbr_city :: City -- ^ Reference location , abbr_str :: String -- ^ Time zone abbreviation string } deriving (Eq,Generic,Typeable) instance Bounded City where minBound = Aden maxBound = Zurich instance Bounded TimeZone where minBound = Afghanistan_Time maxBound = Yukon_Standard_Time instance Convertible TimeZone TimeZoneAbbr where safeConvert = Right . \ case Afghanistan_Time -> TimeZoneAbbr Kabul "AFT" Alaska_Daylight_Time -> TimeZoneAbbr Anchorage "AKDT" Alaska_Hawaii_Daylight_Time -> TimeZoneAbbr Anchorage "AHDT" Alaska_Hawaii_Standard_Time -> TimeZoneAbbr Anchorage "AHST" Alaska_Standard_Time -> TimeZoneAbbr Anchorage "AKST" Arabia_Daylight_Time -> TimeZoneAbbr Baghdad "ADT" Arabia_Standard_Time -> TimeZoneAbbr Riyadh "AST" Brasilia_Summer_Time -> TimeZoneAbbr Sao_Paulo "BRST" Brasilia_Time -> TimeZoneAbbr Sao_Paulo "BRT" British_Summer_Time -> TimeZoneAbbr London "BST" Central_Africa_Time -> TimeZoneAbbr Gaborone "CAT" Central_Daylight_Time -> TimeZoneAbbr Chicago "CDT" Central_European_Summer_Time -> TimeZoneAbbr Paris "CEST" Central_European_Time -> TimeZoneAbbr Paris "CET" Central_Standard_Time -> TimeZoneAbbr Chicago "CST" China_Daylight_Time -> TimeZoneAbbr Shanghai "CDT" China_Standard_Time -> TimeZoneAbbr Shanghai "CST" Coordinated_Universal_Time -> TimeZoneAbbr Universal "UTC" East_Africa_Time -> TimeZoneAbbr Mogadishu "EAT" Eastern_Daylight_Time -> TimeZoneAbbr New_York "EDT" Eastern_European_Summer_Time -> TimeZoneAbbr Sofia "EEST" Eastern_European_Time -> TimeZoneAbbr Sofia "EET" Eastern_Standard_Time -> TimeZoneAbbr New_York "EST" Further_Eastern_European_Time -> TimeZoneAbbr Minsk "FET" Greenwich_Mean_Time -> TimeZoneAbbr London "GMT" Gulf_Standard_Time -> TimeZoneAbbr Manama "GST" Hawaii_Aleutian_Standard_Time -> TimeZoneAbbr Honolulu "HST" Hong_Kong_Time -> TimeZoneAbbr Hong_Kong "HKT" Hong_Kong_Summer_Time -> TimeZoneAbbr Hong_Kong "HKST" India_Standard_Time -> TimeZoneAbbr Kolkata "IST" Iran_Daylight_Time -> TimeZoneAbbr Tehran "IRDT" Iran_Standard_Time -> TimeZoneAbbr Tehran "IRST" Israel_Daylight_Time -> TimeZoneAbbr Tel_Aviv "IDT" Israel_Standard_Time -> TimeZoneAbbr Tel_Aviv "IST" Japan_Standard_Time -> TimeZoneAbbr Tokyo "JST" Karachi_Time -> TimeZoneAbbr Karachi "KART" Korea_Daylight_Time -> TimeZoneAbbr Seoul "KDT" Korea_Standard_Time -> TimeZoneAbbr Seoul "KST" Moscow_Daylight_Time -> TimeZoneAbbr Moscow "MSD" Moscow_Standard_Time -> TimeZoneAbbr Moscow "MSK" Mountain_Daylight_Time -> TimeZoneAbbr Denver "MDT" Mountain_Standard_Time -> TimeZoneAbbr Denver "MST" New_Zealand_Daylight_Time -> TimeZoneAbbr Auckland "NZDT" New_Zealand_Standard_Time -> TimeZoneAbbr Auckland "NZST" Pacific_Daylight_Time -> TimeZoneAbbr Los_Angeles "PDT" Pacific_Standard_Time -> TimeZoneAbbr Los_Angeles "PST" Pakistan_Standard_Time -> TimeZoneAbbr Karachi "PKT" Pakistan_Summer_Time -> TimeZoneAbbr Karachi "PKST" Singapore_Time -> TimeZoneAbbr Singapore "SGT" South_Africa_Standard_Time -> TimeZoneAbbr Johannesburg "SAST" West_Africa_Time -> TimeZoneAbbr Luanda "WAT" Yukon_Standard_Time -> TimeZoneAbbr Anchorage "YST" instance Convertible TimeZoneAbbr TimeZone where safeConvert = Right . \ TimeZoneAbbr{..} -> case abbr_str of "AFT" -> Afghanistan_Time "AHDT" -> Alaska_Hawaii_Daylight_Time "AHST" -> Alaska_Hawaii_Standard_Time "AKDT" -> Alaska_Daylight_Time "AKST" -> Alaska_Standard_Time "ADT" -> Arabia_Daylight_Time "AST" -> Arabia_Standard_Time "BRST" -> Brasilia_Summer_Time "BRT" -> Brasilia_Time "BST" -> British_Summer_Time "CAT" -> Central_Africa_Time "CDT" -> case abbr_city of Chicago -> Central_Daylight_Time Shanghai -> China_Daylight_Time _ -> missing abbr_city "CEST" -> Central_European_Summer_Time "CET" -> Central_European_Time "CST" -> case abbr_city of Chicago -> Central_Standard_Time Shanghai -> China_Standard_Time _ -> missing abbr_city "EAT" -> East_Africa_Time "EDT" -> Eastern_Daylight_Time "EEST" -> Eastern_European_Summer_Time "EET" -> Eastern_European_Time "EST" -> Eastern_Standard_Time "FET" -> Further_Eastern_European_Time "GMT" -> Greenwich_Mean_Time "GST" -> Gulf_Standard_Time "HST" -> Hawaii_Aleutian_Standard_Time "HKST" -> Hong_Kong_Summer_Time "HKT" -> Hong_Kong_Time "IDT" -> Israel_Daylight_Time "IRDT" -> Iran_Daylight_Time "IRST" -> Iran_Standard_Time "IST" -> case abbr_city of Kolkata -> India_Standard_Time Tel_Aviv -> Israel_Standard_Time _ -> missing abbr_city "JST" -> Japan_Standard_Time "KART" -> Karachi_Time "KDT" -> Korea_Daylight_Time "KST" -> Korea_Standard_Time "MDT" -> Mountain_Daylight_Time "MSD" -> Moscow_Daylight_Time "MSK" -> Moscow_Standard_Time "MST" -> Mountain_Standard_Time "NZDT" -> New_Zealand_Daylight_Time "NZST" -> New_Zealand_Standard_Time "PDT" -> Pacific_Daylight_Time "PKST" -> Pakistan_Summer_Time "PKT" -> Pakistan_Standard_Time "PST" -> Pacific_Standard_Time "SAST" -> South_Africa_Standard_Time "SGT" -> Singapore_Time "UTC" -> Coordinated_Universal_Time "WAT" -> West_Africa_Time "YST" -> Yukon_Standard_Time _ -> error $ "safeConvert: missing time zone abbreviation `" ++ abbr_str ++ "'" where missing city = error $ "safeConvert: missing reference location `" ++ show city ++ "'" instance FromJSON City instance FromJSON TimeZone instance FromJSON TimeZoneAbbr instance Ord TimeZone where compare = comparing offset instance Random City where random = first toEnum . randomR (0, 49) randomR (a,b) = first toEnum . randomR (fromEnum a, fromEnum b) instance Random TimeZone where random = first toEnum . randomR (0, 51) randomR (a,b) = first toEnum . randomR (fromEnum a, fromEnum b) instance Show TimeZoneAbbr where show TimeZoneAbbr{abbr_str} = abbr_str instance ToJSON City instance ToJSON TimeZone instance ToJSON TimeZoneAbbr -- | A list of cities in alphabetical order. cities :: [City] cities = [ Aden , Amman , Anchorage , Auckland , Baghdad , Berlin , Brussels , Bujumbura , Cairo , Chicago , Damascus , Denver , Doha , Gaborone , Hong_Kong , Honolulu , Johannesburg , Kabul , Karachi , Kinshasa , Kolkata , Kuwait_City , London , Los_Angeles , Luanda , Manama , Minsk , Mogadishu , Moscow , New_York , Oslo , Ouagadougou , Paris , Pyongyang , Riyadh , Sao_Paulo , Sarajevo , Seoul , Shanghai , Singapore , Sofia , Stockholm , Tehran , Tel_Aviv , Tirana , Tokyo , Toronto , Universal , Vienna , Zurich ] -- | Returns the Olson file associated with the given city. getOlsonFile :: City -> FilePath getOlsonFile = \ case Aden -> "/usr/share/zoneinfo/Asia/Aden" Amman -> "/usr/share/zoneinfo/Asia/Amman" Anchorage -> "/usr/share/zoneinfo/America/Anchorage" Auckland -> "/usr/share/zoneinfo/Pacific/Auckland" Baghdad -> "/usr/share/zoneinfo/Asia/Baghdad" Berlin -> "/usr/share/zoneinfo/Europe/Berlin" Brussels -> "/usr/share/zoneinfo/Europe/Brussels" Bujumbura -> "/usr/share/zoneinfo/Africa/Bujumbura" Cairo -> "/usr/share/zoneinfo/Africa/Cairo" Chicago -> "/usr/share/zoneinfo/America/Chicago" Damascus -> "/usr/share/zoneinfo/Asia/Damascus" Denver -> "/usr/share/zoneinfo/America/Denver" Doha -> "/usr/share/zoneinfo/Asia/Qatar" Gaborone -> "/usr/share/zoneinfo/Africa/Gaborone" Hong_Kong -> "/usr/share/zoneinfo/Asia/Hong_Kong" Honolulu -> "/usr/share/zoneinfo/Pacific/Honolulu" Johannesburg -> "/usr/share/zoneinfo/Africa/Johannesburg" Kabul -> "/usr/share/zoneinfo/Asia/Kabul" Karachi -> "/usr/share/zoneinfo/Asia/Karachi" Kinshasa -> "/usr/share/zoneinfo/Africa/Kinshasa" Kuwait_City -> "/usr/share/zoneinfo/Asia/Kuwait" Kolkata -> "/usr/share/zoneinfo/Asia/Kolkata" London -> "/usr/share/zoneinfo/Europe/London" Los_Angeles -> "/usr/share/zoneinfo/America/Los_Angeles" Luanda -> "/usr/share/zoneinfo/Africa/Luanda" Manama -> "/usr/share/zoneinfo/Asia/Bahrain" Minsk -> "/usr/share/zoneinfo/Europe/Minsk" Mogadishu -> "/usr/share/zoneinfo/Africa/Mogadishu" Moscow -> "/usr/share/zoneinfo/Europe/Moscow" New_York -> "/usr/share/zoneinfo/America/New_York" Oslo -> "/usr/share/zoneinfo/Europe/Oslo" Ouagadougou -> "/usr/share/zoneinfo/Africa/Ouagadougou" Paris -> "/usr/share/zoneinfo/Europe/Paris" Pyongyang -> "/usr/share/zoneinfo/Asia/Pyongyang" Riyadh -> "/usr/share/zoneinfo/Asia/Riyadh" Sao_Paulo -> "/usr/share/zoneinfo/America/Sao_Paulo" Sarajevo -> "/usr/share/zoneinfo/Europe/Sarajevo" Seoul -> "/usr/share/zoneinfo/Asia/Seoul" Shanghai -> "/usr/share/zoneinfo/Asia/Shanghai" Singapore -> "/usr/share/zoneinfo/Asia/Singapore" Sofia -> "/usr/share/zoneinfo/Europe/Sofia" Stockholm -> "/usr/share/zoneinfo/Europe/Stockholm" Tehran -> "/usr/share/zoneinfo/Asia/Tehran" Tel_Aviv -> "/usr/share/zoneinfo/Asia/Tel_Aviv" Tirana -> "/usr/share/zoneinfo/Europe/Tirane" Tokyo -> "/usr/share/zoneinfo/Asia/Tokyo" Toronto -> "/usr/share/zoneinfo/America/Toronto" Universal -> "/usr/share/zoneinfo/Universal" Vienna -> "/usr/share/zoneinfo/Europe/Vienna" Zurich -> "/usr/share/zoneinfo/Europe/Zurich" -- | Returns the offset (in minutes) for the given time zone. offset :: Num a => TimeZone -> a offset = \ case Afghanistan_Time -> 270 Alaska_Daylight_Time -> -480 Alaska_Hawaii_Daylight_Time -> -540 Alaska_Hawaii_Standard_Time -> -600 Alaska_Standard_Time -> -540 Arabia_Daylight_Time -> 240 Arabia_Standard_Time -> 180 Brasilia_Summer_Time -> -120 Brasilia_Time -> -180 British_Summer_Time -> 060 Central_Africa_Time -> 120 Central_Daylight_Time -> -300 Central_European_Summer_Time -> 120 Central_European_Time -> 060 Central_Standard_Time -> -360 China_Daylight_Time -> 540 China_Standard_Time -> 480 Coordinated_Universal_Time -> 000 East_Africa_Time -> 180 Eastern_Daylight_Time -> -240 Eastern_European_Summer_Time -> 180 Eastern_European_Time -> 120 Eastern_Standard_Time -> -300 Further_Eastern_European_Time -> 180 Greenwich_Mean_Time -> 000 Gulf_Standard_Time -> 240 Hawaii_Aleutian_Standard_Time -> -600 Hong_Kong_Summer_Time -> 540 Hong_Kong_Time -> 480 India_Standard_Time -> 330 Iran_Daylight_Time -> 270 Iran_Standard_Time -> 210 Israel_Daylight_Time -> 180 Israel_Standard_Time -> 120 Japan_Standard_Time -> 540 Karachi_Time -> 300 Korea_Daylight_Time -> 600 Korea_Standard_Time -> 540 Moscow_Daylight_Time -> 240 Moscow_Standard_Time -> 240 Mountain_Daylight_Time -> -360 Mountain_Standard_Time -> -420 New_Zealand_Daylight_Time -> 780 New_Zealand_Standard_Time -> 720 Pacific_Daylight_Time -> -420 Pacific_Standard_Time -> -480 Pakistan_Standard_Time -> 300 Pakistan_Summer_Time -> 360 Singapore_Time -> 480 South_Africa_Standard_Time -> 120 West_Africa_Time -> 060 Yukon_Standard_Time -> -540