如何判断现在是夏季还是冬季?

问题描述 投票:0回答:3

我想知道某个

Day
(套餐
time
)是夏季还是冬季。

我对中欧特别感兴趣,那里夏季时区是 CEST = GMT+2,冬季时区是 CEST = GMT+1。

我需要它,因为我需要将

JulianDate
(包
astro
)转换为当地时间并返回。

haskell
3个回答
2
投票

由于时区更改的确切日期因地点而异,我认为您必须编写自己的函数来检查这一点。

我碰巧知道欧洲夏令时从三月的最后一个星期日开始,到十月的最后一个星期日结束。我在下面的函数中使用了这个,很容易更改为其他位置。

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
投票

我正在编写一个程序,需要在UTC的云服务器上运行,但关心美国太平洋时区的时间。我改编了@PHPirate的答案以遵循美国的规则:

  • 开始 3 月第 2 个周日凌晨 2 点(太平洋标准时间 1000)
  • 结束 11 月第一个星期日凌晨 2 点(太平洋夏令时)(0900 UTC)

我将其留在这里,供未来的 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)

0
投票

这是 VB6 / VBA 中的一小段代码:

Private Function summer(ByVal d As Date) As Boolean

    Dim d1 As Date
    Dim d2 As Date
    
    ' last sunday in March:
    d1 = CDate("31.3." & Year(d))
    Do While Weekday(d1, vbMonday) <> vbSunday
        d1 = DateAdd("d", -1, d1)
    Loop
    
    ' last sunday in October:
    d2 = CDate("31.10." & Year(d))
    Do While Weekday(d2, vbMonday) <> vbSunday
        d2 = DateAdd("d", -1, d2)
    Loop
    
    summer = d >= d1 And d <= d2

End Function
© www.soinside.com 2019 - 2024. All rights reserved.