我想确定在某个Day
(包装time
)上是夏季还是冬季。
我对中欧特别感兴趣,在欧洲中部,夏季时区为CEST = GMT + 2,冬季时区为CEST = GMT + 1。
我需要它,因为我需要将JulianDate
(包astro
)转换为本地时间并返回。
答案 0 :(得分:3)
由于每个地区的时区变化的确切日期不同,我认为您必须编写自己的函数进行检查。
我碰巧知道在欧洲,夏季开始于3月的最后一个星期日,结束于10月的最后一个星期日。我在下面的函数中使用了它,很容易将其更改为其他位置。
import Data.Time.Calendar
import Data.Time.Calendar.WeekDate
import Data.Tuple.Select
-- | Uses only days, it does not take the exact hour into account at which summer time starts and ends.
isSummerTime :: Day -- ^ Date to check if summer time is active
-> Bool -- ^ Whether summer time is active
isSummerTime date = date > lastSundayMarch && date < lastSundayOctober
where
year = sel1 $ toGregorian date
-- Find last Sunday in March
aprilOne = fromGregorian year 4 1
-- 1 is Monday, ..., 7 is Sunday
aprilOneWeekDay = sel3 $ toWeekDate aprilOne
-- Use the day number to find Sunday of the previous week: the last Sunday in March
lastSundayMarch = addDays (-(toInteger aprilOneWeekDay)) aprilOne
-- Same for end of summer time in October
novemberOne = fromGregorian year 11 1
novemberOneWeekDay = sel3 $ toWeekDate novemberOne
lastSundayOctober = addDays (-(toInteger novemberOneWeekDay)) novemberOne
isSummerTime $ fromGregorian 2018 3 25 -- False
isSummerTime $ fromGregorian 2018 3 26 -- True
isSummerTime $ fromGregorian 2018 10 27 -- True
isSummerTime $ fromGregorian 2018 10 28 -- False
答案 1 :(得分:1)
我正在编写一个程序,需要在 UTC 的云服务器上运行,但关心美国太平洋时区的时间。我改编了@PHPirate 的回答以遵守美国的规则:
我将把这个留在这里,让未来的 Haskellers 寻找代码来了解夏令时
import Data.Time
import Data.Time.Calendar.WeekDate
-- | Get the current time in the Pacific time zone, accounting for Daylight
-- Savings Time
getCurrentTimePacific :: IO ZonedTime
getCurrentTimePacific = do
rightNow <- getCurrentTime
let timeZoneStr = if isDaylightSavings rightNow then "PDT" else "PST"
pacificTimeZone = read timeZoneStr
return $ utcToZonedTime pacificTimeZone rightNow
-- | Determine whether the USA Pacific time zone is in Daylight Savings time
isDaylightSavings :: UTCTime -> Bool
isDaylightSavings utcIn = utcIn >= dstStart && utcIn < dstEnd
where
(year, _, _) = toGregorian (utctDay utcIn)
(dstStart, dstEnd) = pacificDSTBoundsInUTC year
-- | Start and end boundaries of daylight savings time for Pacific zone, in UTC
pacificDSTBoundsInUTC ::
Integer -- ^ Year for Daylight Savings calculation
-> (UTCTime, UTCTime) -- ^ (start, end) of Pacific daylight savings in UTC
pacificDSTBoundsInUTC year = let
secondSundayMarch = getNthSundayOfMonth year 3 2
firstSundayNovember = getNthSundayOfMonth year 11 1
dstChangeTime = TimeOfDay 2 0 0 -- 2 AM
toDaylightSavingsPoint = ZonedTime
(LocalTime secondSundayMarch dstChangeTime) (read "PST")
fromDaylightSavingsPoint = ZonedTime
(LocalTime firstSundayNovember dstChangeTime) (read "PDT")
in
( zonedTimeToUTC toDaylightSavingsPoint
, zonedTimeToUTC fromDaylightSavingsPoint)
-- | Get the nth Sunday of a month
getNthSundayOfMonth ::
Integer -- ^ Year
-> Int -- ^ Month
-> Int -- ^ nth Sunday to get
-> Day -- Day object for nth Sunday
getNthSundayOfMonth year month sundayN = let
sundayDay = 7
firstOfMonth = fromGregorian year month 1
(_, _, firstOfMonthWeekDay) = toWeekDate firstOfMonth
daysDiffToFirstSunday = sundayDay - firstOfMonthWeekDay
daysToAddToFirst = daysDiffToFirstSunday + (sundayN - 1) * sundayDay
in
addDays (toInteger daysToAddToFirst) firstOfMonth
计算 DST 边界的核心函数给出了这些结果
pacificDSTBoundsInUTC 2021 == (2021-03-14 10:00:00 UTC,2021-11-07 09:00:00 UTC)
pacificDSTBoundsInUTC 2020 == (2020-03-08 10:00:00 UTC,2020-11-01 09:00:00 UTC)
pacificDSTBoundsInUTC 2019 == (2019-03-10 10:00:00 UTC,2019-11-03 09:00:00 UTC)