time 1.14 → 1.15
raw patch · 56 files changed
+1407/−743 lines, 56 filesdep ~basedep ~deepseqdep ~template-haskell
Dependency ranges changed: base, deepseq, template-haskell
Files
- changelog.md +20/−0
- configure +9/−9
- configure.ac +1/−1
- lib/Data/Format.hs +33/−17
- lib/Data/Time/Calendar.hs +66/−3
- lib/Data/Time/Calendar/CalendarDiffDays.hs +3/−16
- lib/Data/Time/Calendar/Days.hs +7/−16
- lib/Data/Time/Calendar/Gregorian.hs +1/−42
- lib/Data/Time/Calendar/Julian.hs +2/−0
- lib/Data/Time/Calendar/JulianYearDay.hs +1/−4
- lib/Data/Time/Calendar/Month.hs +5/−4
- lib/Data/Time/Calendar/Quarter.hs +5/−5
- lib/Data/Time/Calendar/Week.hs +3/−12
- lib/Data/Time/Calendar/WeekDate.hs +2/−2
- lib/Data/Time/Clock.hs +31/−4
- lib/Data/Time/Clock/Internal/AbsoluteTime.hs +3/−10
- lib/Data/Time/Clock/Internal/CTimespec.hsc +26/−17
- lib/Data/Time/Clock/Internal/CTimeval.hs +1/−1
- lib/Data/Time/Clock/Internal/DiffTime.hs +32/−17
- lib/Data/Time/Clock/Internal/NominalDiffTime.hs +17/−18
- lib/Data/Time/Clock/Internal/SystemTime.hs +6/−4
- lib/Data/Time/Clock/Internal/UTCTime.hs +3/−24
- lib/Data/Time/Clock/Internal/UniversalTime.hs +3/−8
- lib/Data/Time/Clock/TAI.hs +12/−4
- lib/Data/Time/Format.hs +16/−1
- lib/Data/Time/Format/Format/Class.hs +19/−4
- lib/Data/Time/Format/Format/Instances.hs +15/−5
- lib/Data/Time/Format/ISO8601.hs +5/−3
- lib/Data/Time/Format/Locale.hs +1/−6
- lib/Data/Time/Format/Parse.hs +1/−12
- lib/Data/Time/Format/Parse/Class.hs +2/−1
- lib/Data/Time/Format/Parse/Instances.hs +364/−179
- lib/Data/Time/LocalTime.hs +42/−3
- lib/Data/Time/LocalTime/Internal/CalendarDiffTime.hs +28/−12
- lib/Data/Time/LocalTime/Internal/Foreign.hs +119/−0
- lib/Data/Time/LocalTime/Internal/LocalTime.hs +26/−12
- lib/Data/Time/LocalTime/Internal/TimeOfDay.hs +7/−19
- lib/Data/Time/LocalTime/Internal/TimeZone.hs +2/−88
- lib/Data/Time/LocalTime/Internal/ZonedTime.hs +4/−8
- lib/cbits/HsTime.c +1/−1
- lib/include/HsTime.h +1/−1
- test/ForeignCalls.hs +50/−0
- test/main/Main.hs +2/−2
- test/main/Test/Arbitrary.hs +41/−11
- test/main/Test/Calendar/CalendarProps.hs +1/−1
- test/main/Test/Calendar/MonthDay.hs +19/−4
- test/main/Test/Clock/Lift.hs +0/−18
- test/main/Test/Clock/Pattern.hs +32/−0
- test/main/Test/Format/Compile.hs +0/−2
- test/main/Test/Format/Format.hs +10/−10
- test/main/Test/Format/ISO8601.hs +89/−60
- test/main/Test/Format/ParseTime.hs +115/−1
- test/main/Test/TestUtil.hs +3/−0
- test/template/Main.hs +24/−0
- test/unix/Test/Format/Format.hs +6/−1
- time.cabal +70/−40
changelog.md view
@@ -1,5 +1,25 @@ # Change Log +## [1.15] - 2025-08-04++- support compiler / GHC backends (with CI):+ - JavaScript+ - WebAssembly+ - MicroHs+- add diffTimeOfDay+- add \[add/diff\]\[UTC/Local\]Duration\[Clip/Rollover\]+- add patterns for DiffTime & NominalDiffTime+- UNIXish formatting/parsing:+ - add instance ParseTime DayOfWeek+ - make use of %s specifiers in parsing various types+ - instances for Quarter and QuarterOfYear+ - %v specifier for quarter-of-year+- ISO8601 formatting/parsing:+ - loosen up parsing time-zone modifiers+- add Lift instances to all types (really this time)+- hide Data.Time.Format.Internal+- fix MonthDay and QuarterDay clipping+ ## [1.14] - 2024-03-10 - add Lift instances to all types - add Generic instances to all types that have exposed constructors
configure view
@@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles.-# Generated by GNU Autoconf 2.71 for Haskell time package 1.14.+# Generated by GNU Autoconf 2.71 for Haskell time package 1.15. # # Report bugs to <ashley@semantic.org>. #@@ -610,8 +610,8 @@ # Identity of this package. PACKAGE_NAME='Haskell time package' PACKAGE_TARNAME='time'-PACKAGE_VERSION='1.14'-PACKAGE_STRING='Haskell time package 1.14'+PACKAGE_VERSION='1.15'+PACKAGE_STRING='Haskell time package 1.15' PACKAGE_BUGREPORT='ashley@semantic.org' PACKAGE_URL='' @@ -1258,7 +1258,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF-\`configure' configures Haskell time package 1.14 to adapt to many kinds of systems.+\`configure' configures Haskell time package 1.15 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1320,7 +1320,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in- short | recursive ) echo "Configuration of Haskell time package 1.14:";;+ short | recursive ) echo "Configuration of Haskell time package 1.15:";; esac cat <<\_ACEOF @@ -1406,7 +1406,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF-Haskell time package configure 1.14+Haskell time package configure 1.15 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc.@@ -1736,7 +1736,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by Haskell time package $as_me 1.14, which was+It was created by Haskell time package $as_me 1.15, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw@@ -4334,7 +4334,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log="-This file was extended by Haskell time package $as_me 1.14, which was+This file was extended by Haskell time package $as_me 1.15, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES@@ -4389,7 +4389,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\-Haskell time package config.status 1.14+Haskell time package config.status 1.15 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\"
configure.ac view
@@ -1,4 +1,4 @@-AC_INIT([Haskell time package],[1.14],[ashley@semantic.org],[time])+AC_INIT([Haskell time package],[1.15],[ashley@semantic.org],[time]) # Safety check: Ensure that we are in the correct source directory. AC_CONFIG_SRCDIR([lib/include/HsTime.h])
lib/Data/Format.hs view
@@ -15,6 +15,7 @@ literalFormat, specialCaseShowFormat, specialCaseFormat,+ specialCaseReadFormat, optionalFormat, casesFormat, optionalSignFormat,@@ -177,6 +178,13 @@ in MkFormat s' r' +specialCaseReadFormat :: (a, String) -> Format a -> Format a+specialCaseReadFormat (val, str) (MkFormat s r) =+ let+ r' = r <++ (string str >> return val)+ in+ MkFormat s r'+ optionalFormat :: Eq a => a -> Format a -> Format a optionalFormat val = specialCaseFormat (val, "") @@ -222,36 +230,44 @@ return $ '.' : dd return $ sign $ read $ digits ++ moredigits -zeroPad :: Maybe Int -> String -> String-zeroPad Nothing s = s-zeroPad (Just i) s = replicate (i - length s) '0' ++ s+zeroPad :: Maybe Int -> String -> Maybe String+zeroPad Nothing s = Just s+zeroPad (Just i) s =+ let+ padCount = i - length s+ in+ if padCount >= 0+ then Just $ replicate padCount '0' ++ s+ else Nothing trimTrailing :: String -> String-trimTrailing "" = ""-trimTrailing "." = ""-trimTrailing s- | last s == '0' = trimTrailing $ init s-trimTrailing s = s+trimTrailing =+ (\s -> if s == "." then "" else s)+ . reverse+ . dropWhile (== '0')+ . reverse showNumber :: Show t => SignOption -> Maybe Int -> t -> Maybe String showNumber signOpt mdigitcount t = let- showIt str =+ showIt str = do let (intPart, decPart) = break ((==) '.') str- in- (zeroPad mdigitcount intPart) ++ trimTrailing decPart+ paddedIntPart <- zeroPad mdigitcount intPart+ return $ paddedIntPart ++ trimTrailing decPart in case show t of ('-' : str) -> case signOpt of NoSign -> Nothing- _ -> Just $ '-' : showIt str- str ->- Just $- case signOpt of- PosNegSign -> '+' : showIt str- _ -> showIt str+ _ -> do+ s <- showIt str+ return $ '-' : s+ str -> do+ s <- showIt str+ return $ case signOpt of+ PosNegSign -> '+' : s+ _ -> s integerFormat :: (Show t, Read t, Num t) => SignOption -> Maybe Int -> Format t integerFormat signOpt mdigitcount = MkFormat (showNumber signOpt mdigitcount) (readNumber signOpt mdigitcount False)
lib/Data/Time/Calendar.hs view
@@ -1,14 +1,77 @@ {-# LANGUAGE Safe #-} module Data.Time.Calendar (- module Data.Time.Calendar.Days,+ -- * Days+ Day (..),+ addDays,+ diffDays,++ -- * DayPeriod+ DayPeriod (..),+ periodAllDays,+ periodLength,+ periodFromDay,+ periodToDay,+ periodToDayClip,+ periodToDayValid,++ -- * Calendar Duration module Data.Time.Calendar.CalendarDiffDays,- module Data.Time.Calendar.Gregorian,- module Data.Time.Calendar.Week,++ -- * Year, month and day+ Year,+ pattern CommonEra,+ pattern BeforeCommonEra,+ MonthOfYear,+ pattern January,+ pattern February,+ pattern March,+ pattern April,+ pattern May,+ pattern June,+ pattern July,+ pattern August,+ pattern September,+ pattern October,+ pattern November,+ pattern December,+ DayOfMonth,++ -- * Gregorian calendar+ toGregorian,+ fromGregorian,+ pattern YearMonthDay,+ fromGregorianValid,+ showGregorian,+ gregorianMonthLength,+ -- calendrical arithmetic+ -- e.g. "one month after March 31st"+ addGregorianMonthsClip,+ addGregorianMonthsRollOver,+ addGregorianYearsClip,+ addGregorianYearsRollOver,+ addGregorianDurationClip,+ addGregorianDurationRollOver,+ diffGregorianDurationClip,+ diffGregorianDurationRollOver,+ -- re-exported from OrdinalDate+ isLeapYear,++ -- * Week+ DayOfWeek (..),+ dayOfWeek,+ dayOfWeekDiff,+ firstDayOfWeekOnAfter,+ weekAllDays,+ weekFirstDay,+ weekLastDay, ) where import Data.Time.Calendar.CalendarDiffDays import Data.Time.Calendar.Days import Data.Time.Calendar.Gregorian+import Data.Time.Calendar.MonthDay+import Data.Time.Calendar.OrdinalDate+import Data.Time.Calendar.Types import Data.Time.Calendar.Week import Data.Time.Format ()
lib/Data/Time/Calendar/CalendarDiffDays.hs view
@@ -1,30 +1,17 @@ {-# LANGUAGE Safe #-} -module Data.Time.Calendar.CalendarDiffDays (- -- * Calendar Duration- module Data.Time.Calendar.CalendarDiffDays,-) where+module Data.Time.Calendar.CalendarDiffDays where import Control.DeepSeq import Data.Data import GHC.Generics-import qualified Language.Haskell.TH.Syntax as TH+import Language.Haskell.TH.Syntax qualified as TH data CalendarDiffDays = CalendarDiffDays { cdMonths :: Integer , cdDays :: Integer }- deriving- ( Eq- , -- | @since 1.9.2- Data- , -- | @since 1.9.2- Typeable- , -- | @since 1.14- TH.Lift- , -- | @since 1.14- Generic- )+ deriving (Eq, Typeable, Data, Generic, TH.Lift) instance NFData CalendarDiffDays where rnf (CalendarDiffDays m d) = rnf m `seq` rnf d `seq` ()
lib/Data/Time/Calendar/Days.hs view
@@ -1,31 +1,19 @@ {-# LANGUAGE Safe #-} -module Data.Time.Calendar.Days (- -- * Days- Day (..),- addDays,- diffDays,-- -- * DayPeriod- DayPeriod (..),- periodAllDays,- periodLength,- periodFromDay,- periodToDay,- periodToDayValid,-) where+module Data.Time.Calendar.Days where import Control.DeepSeq import Data.Data import Data.Ix+import Data.Time.Calendar.Private import GHC.Generics-import qualified Language.Haskell.TH.Syntax as TH+import Language.Haskell.TH.Syntax qualified as TH -- | The Modified Julian Day is a standard count of days, with zero being the day 1858-11-17. newtype Day = ModifiedJulianDay { toModifiedJulianDay :: Integer }- deriving (Eq, Ord, Data, Typeable, TH.Lift, Generic)+ deriving (Eq, Ord, Typeable, Data, Generic, TH.Lift) instance NFData Day where rnf (ModifiedJulianDay a) = rnf a@@ -96,6 +84,9 @@ -- @since 1.12.1 periodToDay :: DayPeriod p => p -> Int -> Day periodToDay p i = addDays (toInteger $ pred i) $ periodFirstDay p++periodToDayClip :: DayPeriod p => p -> Int -> Day+periodToDayClip p i = periodToDay p $ clip 1 (periodLength p) i -- | Validating inverse of 'periodFromDay'. --
lib/Data/Time/Calendar/Gregorian.hs view
@@ -1,55 +1,14 @@ {-# LANGUAGE Safe #-}-{-# LANGUAGE TypeSynonymInstances #-} {-# OPTIONS -fno-warn-orphans #-} -module Data.Time.Calendar.Gregorian (- -- * Year, month and day- Year,- pattern CommonEra,- pattern BeforeCommonEra,- MonthOfYear,- pattern January,- pattern February,- pattern March,- pattern April,- pattern May,- pattern June,- pattern July,- pattern August,- pattern September,- pattern October,- pattern November,- pattern December,- DayOfMonth,-- -- * Gregorian calendar- toGregorian,- fromGregorian,- pattern YearMonthDay,- fromGregorianValid,- showGregorian,- gregorianMonthLength,- -- calendrical arithmetic- -- e.g. "one month after March 31st"- addGregorianMonthsClip,- addGregorianMonthsRollOver,- addGregorianYearsClip,- addGregorianYearsRollOver,- addGregorianDurationClip,- addGregorianDurationRollOver,- diffGregorianDurationClip,- diffGregorianDurationRollOver,- -- re-exported from OrdinalDate- isLeapYear,-) where+module Data.Time.Calendar.Gregorian where import Data.Time.Calendar.CalendarDiffDays import Data.Time.Calendar.Days import Data.Time.Calendar.MonthDay import Data.Time.Calendar.OrdinalDate import Data.Time.Calendar.Private-import Data.Time.Calendar.Types -- | Convert to proleptic Gregorian calendar. toGregorian :: Day -> (Year, MonthOfYear, DayOfMonth)
lib/Data/Time/Calendar/Julian.hs view
@@ -17,6 +17,8 @@ pattern December, DayOfMonth, DayOfYear,++ -- * Year and day format module Data.Time.Calendar.JulianYearDay, toJulian, fromJulian,
lib/Data/Time/Calendar/JulianYearDay.hs view
@@ -1,9 +1,6 @@ {-# LANGUAGE Safe #-} -module Data.Time.Calendar.JulianYearDay (- -- * Year and day format- module Data.Time.Calendar.JulianYearDay,-) where+module Data.Time.Calendar.JulianYearDay where import Data.Time.Calendar.Days import Data.Time.Calendar.Private
lib/Data/Time/Calendar/Month.hs view
@@ -18,14 +18,15 @@ import Data.Time.Calendar.Days import Data.Time.Calendar.Gregorian import Data.Time.Calendar.Private+import Data.Time.Calendar.Types import GHC.Generics-import qualified Language.Haskell.TH.Syntax as TH+import Language.Haskell.TH.Syntax qualified as TH import Text.ParserCombinators.ReadP import Text.Read -- | An absolute count of common calendar months. -- Number is equal to @(year * 12) + (monthOfYear - 1)@.-newtype Month = MkMonth Integer deriving (Eq, Ord, Data, Typeable, TH.Lift, Generic)+newtype Month = MkMonth Integer deriving (Eq, Ord, Typeable, Data, Generic, TH.Lift) instance NFData Month where rnf (MkMonth m) = rnf m@@ -74,7 +75,7 @@ -- Invalid months of year will be clipped to the correct range. pattern YearMonth :: Year -> MonthOfYear -> Month pattern YearMonth y my <-- MkMonth ((\m -> divMod' m 12) -> (y, succ . fromInteger -> my))+ MkMonth ((\m -> divMod' m 12) -> (y, (succ . fromInteger -> my))) where YearMonth y my = MkMonth $ (y * 12) + toInteger (pred $ clip 1 12 my) @@ -91,7 +92,7 @@ pattern MonthDay m dm <- (periodFromDay -> (m, dm)) where- MonthDay = periodToDay+ MonthDay = periodToDayClip fromMonthDayValid :: Month -> DayOfMonth -> Maybe Day fromMonthDayValid = periodToDayValid
lib/Data/Time/Calendar/Quarter.hs view
@@ -23,12 +23,12 @@ import Data.Time.Calendar.Private import Data.Time.Calendar.Types import GHC.Generics-import qualified Language.Haskell.TH.Syntax as TH+import Language.Haskell.TH.Syntax qualified as TH import Text.ParserCombinators.ReadP import Text.Read -- | Quarters of each year. Each quarter corresponds to three months.-data QuarterOfYear = Q1 | Q2 | Q3 | Q4 deriving (Eq, Ord, Data, Typeable, Read, Show, Ix, TH.Lift, Generic)+data QuarterOfYear = Q1 | Q2 | Q3 | Q4 deriving (Eq, Ord, Read, Show, Ix, Typeable, Data, Generic, TH.Lift) -- | maps Q1..Q4 to 1..4 instance Enum QuarterOfYear where@@ -55,7 +55,7 @@ -- | An absolute count of year quarters. -- Number is equal to @(year * 4) + (quarterOfYear - 1)@.-newtype Quarter = MkQuarter Integer deriving (Eq, Ord, Data, Typeable, Generic)+newtype Quarter = MkQuarter Integer deriving (Eq, Ord, Typeable, Data, Generic, TH.Lift) instance NFData Quarter where rnf (MkQuarter m) = rnf m@@ -113,7 +113,7 @@ -- | Bidirectional abstract constructor. pattern YearQuarter :: Year -> QuarterOfYear -> Quarter pattern YearQuarter y qy <-- MkQuarter ((\q -> divMod' q 4) -> (y, toEnum . succ . fromInteger -> qy))+ MkQuarter ((\q -> divMod' q 4) -> (y, (toEnum . succ . fromInteger -> qy))) where YearQuarter y qy = MkQuarter $ (y * 4) + toInteger (pred $ fromEnum qy) @@ -142,6 +142,6 @@ pattern QuarterDay q dq <- (periodFromDay -> (q, dq)) where- QuarterDay = periodToDay+ QuarterDay = periodToDayClip {-# COMPLETE QuarterDay #-}
lib/Data/Time/Calendar/Week.hs view
@@ -1,15 +1,6 @@ {-# LANGUAGE Safe #-} -module Data.Time.Calendar.Week (- -- * Week- DayOfWeek (..),- dayOfWeek,- dayOfWeekDiff,- firstDayOfWeekOnAfter,- weekAllDays,- weekFirstDay,- weekLastDay,-) where+module Data.Time.Calendar.Week where import Control.DeepSeq import Data.Data@@ -17,7 +8,7 @@ import Data.Ix import Data.Time.Calendar.Days import GHC.Generics-import qualified Language.Haskell.TH.Syntax as TH+import Language.Haskell.TH.Syntax qualified as TH data DayOfWeek = Monday@@ -27,7 +18,7 @@ | Friday | Saturday | Sunday- deriving (Eq, Show, Read, Data, Typeable, Ord, Ix, TH.Lift, Generic)+ deriving (Eq, Ord, Ix, Show, Read, Typeable, Data, Generic, TH.Lift) instance NFData DayOfWeek where rnf Monday = ()
lib/Data/Time/Calendar/WeekDate.hs view
@@ -23,7 +23,7 @@ import Data.Time.Calendar.OrdinalDate import Data.Time.Calendar.Private import Data.Time.Calendar.Week-import qualified Language.Haskell.TH.Syntax as TH+import Language.Haskell.TH.Syntax qualified as TH data FirstWeekType = -- | first week is the first whole week of the year@@ -124,7 +124,7 @@ -- Invalid week values will be clipped to the correct range. pattern YearWeekDay :: Year -> WeekOfYear -> DayOfWeek -> Day pattern YearWeekDay y wy dw <-- (toWeekDate -> (y, wy, toEnum -> dw))+ (toWeekDate -> (y, wy, (toEnum -> dw))) where YearWeekDay y wy dw = fromWeekDate y wy (fromEnum dw)
lib/Data/Time/Clock.hs view
@@ -2,10 +2,37 @@ -- | Types and functions for UTC and UT1 module Data.Time.Clock (- module Data.Time.Clock.Internal.UniversalTime,- module Data.Time.Clock.Internal.DiffTime,- module Data.Time.Clock.Internal.UTCTime,- module Data.Time.Clock.Internal.NominalDiffTime,+ -- * Universal Time++ -- | Time as measured by the Earth.+ UniversalTime (..),++ -- * Absolute intervals+ DiffTime,+ pattern Picoseconds,+ pattern Seconds,+ pattern Minutes,+ pattern Hours,+ secondsToDiffTime,+ picosecondsToDiffTime,+ diffTimeToPicoseconds,++ -- * UTC++ -- | UTC is time as measured by a clock, corrected to keep pace with the earth by adding or removing+ -- occasional seconds, known as \"leap seconds\".+ -- These corrections are not predictable and are announced with six month's notice.+ -- No table of these corrections is provided, as any program compiled with it would become+ -- out of date in six months.+ --+ -- If you don't care about leap seconds, use 'UTCTime' and 'NominalDiffTime' for your clock calculations,+ -- and you'll be fine.+ UTCTime (..),+ NominalDiffTime,+ pattern Nominal,+ secondsToNominalDiffTime,+ nominalDiffTimeToSeconds,+ nominalDay, module Data.Time.Clock.Internal.UTCDiff, getCurrentTime, getTime_resolution,
lib/Data/Time/Clock/Internal/AbsoluteTime.hs view
@@ -1,25 +1,18 @@ {-# LANGUAGE Safe #-} -- | TAI and leap-second maps for converting to UTC: most people won't need this module.-module Data.Time.Clock.Internal.AbsoluteTime (- -- TAI arithmetic- AbsoluteTime,- taiEpoch,- addAbsoluteTime,- diffAbsoluteTime,- taiNominalDayStart,-) where+module Data.Time.Clock.Internal.AbsoluteTime where import Control.DeepSeq import Data.Data import Data.Time.Calendar.Days import Data.Time.Clock.Internal.DiffTime-import qualified Language.Haskell.TH.Syntax as TH+import Language.Haskell.TH.Syntax qualified as TH -- | AbsoluteTime is TAI, time as measured by a clock. newtype AbsoluteTime = MkAbsoluteTime DiffTime- deriving (Eq, Ord, Data, Typeable, TH.Lift)+ deriving (Eq, Ord, Typeable, Data, TH.Lift) instance NFData AbsoluteTime where rnf (MkAbsoluteTime a) = rnf a
lib/Data/Time/Clock/Internal/CTimespec.hsc view
@@ -6,7 +6,7 @@ #include "HsTimeConfig.h" -#if !defined(mingw32_HOST_OS) && HAVE_CLOCK_GETTIME+#if !defined(mingw32_HOST_OS) && HAVE_CLOCK_GETTIME && !defined(__MHS__) import Foreign import Foreign.C@@ -34,18 +34,31 @@ foreign import ccall unsafe "time.h clock_gettime" clock_gettime :: ClockID -> Ptr CTimespec -> IO CInt-foreign import ccall unsafe "time.h clock_getres"- clock_getres :: ClockID -> Ptr CTimespec -> IO CInt -#else+#else /* defined(javascript_HOST_ARCH) */ foreign import capi unsafe "time.h clock_gettime" clock_gettime :: ClockID -> Ptr CTimespec -> IO CInt++#endif /* defined(javascript_HOST_ARCH) */++-- | Get the current time from the given clock.+clockGetTime :: ClockID -> IO CTimespec+clockGetTime clockid = alloca (\ptspec -> do+ throwErrnoIfMinus1_ "clock_gettime" $ clock_gettime clockid ptspec+ peek ptspec+ )++#if defined(javascript_HOST_ARCH)++clockGetRes :: ClockID -> IO (Either Errno CTimespec)+clockGetRes _ = return $ Right $ MkCTimespec 0 0++#else /* defined(javascript_HOST_ARCH) */+ foreign import capi unsafe "time.h clock_getres" clock_getres :: ClockID -> Ptr CTimespec -> IO CInt -#endif- -- | Get the resolution of the given clock. clockGetRes :: ClockID -> IO (Either Errno CTimespec) clockGetRes clockid = alloca $ \ptspec -> do@@ -58,28 +71,23 @@ errno <- getErrno return $ Left errno --- | Get the current time from the given clock.-clockGetTime :: ClockID -> IO CTimespec-clockGetTime clockid = alloca (\ptspec -> do- throwErrnoIfMinus1_ "clock_gettime" $ clock_gettime clockid ptspec- peek ptspec- )+#endif /* defined(javascript_HOST_ARCH) */ #if defined(javascript_HOST_ARCH) -- JS backend doesn't support foreign imports with capi convention clock_REALTIME :: ClockID clock_REALTIME = #{const CLOCK_REALTIME}-#else+#else /* defined(javascript_HOST_ARCH) */ foreign import capi unsafe "HsTime.h value HS_CLOCK_REALTIME" clock_REALTIME :: ClockID-#endif+#endif /* defined(javascript_HOST_ARCH) */ clock_TAI :: Maybe ClockID clock_TAI = #if defined(CLOCK_TAI) Just #{const CLOCK_TAI}-#else+#else /* defined(CLOCK_TAI) */ Nothing-#endif+#endif /* defined(CLOCK_TAI) */ realtimeRes :: CTimespec realtimeRes = unsafePerformIO $ do@@ -95,4 +103,5 @@ Left _ -> return Nothing Right res -> return $ Just res -#endif+#endif /* !defined(mingw32_HOST_OS) && HAVE_CLOCK_GETTIME */+
lib/Data/Time/Clock/Internal/CTimeval.hs view
@@ -26,7 +26,7 @@ pokeElemOff (castPtr p) 0 s pokeElemOff (castPtr p) 1 mus -#if defined(javascript_HOST_ARCH)+#if defined(javascript_HOST_ARCH) || defined(__MHS__) foreign import ccall unsafe "sys/time.h gettimeofday" gettimeofday :: Ptr CTimeval -> Ptr () -> IO CInt
lib/Data/Time/Clock/Internal/DiffTime.hs view
@@ -1,23 +1,17 @@-{-# LANGUAGE InstanceSigs #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE Trustworthy #-} -module Data.Time.Clock.Internal.DiffTime (- -- * Absolute intervals- DiffTime,- secondsToDiffTime,- picosecondsToDiffTime,- diffTimeToPicoseconds,-) where+module Data.Time.Clock.Internal.DiffTime where import Control.DeepSeq import Data.Data import Data.Fixed+#ifdef __GLASGOW_HASKELL__ import GHC.Read-import qualified Language.Haskell.TH.Syntax as TH+#endif+import Language.Haskell.TH.Syntax qualified as TH import Text.ParserCombinators.ReadP-import Text.ParserCombinators.ReadPrec+import Text.Read -- | This is a length of time, as measured by a clock. -- Conversion functions such as 'fromInteger' and 'realToFrac' will treat it as seconds.@@ -26,7 +20,7 @@ -- It has a precision of one picosecond (= 10^-12 s). Enumeration functions will treat it as picoseconds. newtype DiffTime = MkDiffTime Pico- deriving (Eq, Ord, Data, Typeable)+ deriving (Eq, Ord, Typeable, Data, TH.Lift) instance NFData DiffTime where rnf (MkDiffTime t) = rnf t@@ -78,10 +72,31 @@ ceiling (MkDiffTime a) = ceiling a floor (MkDiffTime a) = floor a --- Let GHC derive the instances when 'Fixed' has 'TH.Lift' instance.-instance TH.Lift DiffTime where- liftTyped :: TH.Quote m => DiffTime -> TH.Code m DiffTime- liftTyped (MkDiffTime (MkFixed a)) = [||MkDiffTime (MkFixed $$(TH.liftTyped a))||]+pattern Picoseconds :: Integer -> DiffTime+pattern Picoseconds a <- (diffTimeToPicoseconds -> a)+ where+ Picoseconds a = picosecondsToDiffTime a++{-# COMPLETE Picoseconds #-}++pattern Seconds :: Pico -> DiffTime+pattern Seconds a = MkDiffTime a++{-# COMPLETE Seconds #-}++pattern Minutes :: Pico -> DiffTime+pattern Minutes a <- Seconds ((/ 60) -> a)+ where+ Minutes a = Seconds $ a * 60++{-# COMPLETE Minutes #-}++pattern Hours :: Pico -> DiffTime+pattern Hours a <- Minutes ((/ 60) -> a)+ where+ Hours a = Minutes $ a * 60++{-# COMPLETE Hours #-} -- | Create a 'DiffTime' which represents an integral number of seconds. secondsToDiffTime :: Integer -> DiffTime
lib/Data/Time/Clock/Internal/NominalDiffTime.hs view
@@ -1,38 +1,42 @@-{-# LANGUAGE InstanceSigs #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE Trustworthy #-} -module Data.Time.Clock.Internal.NominalDiffTime (- NominalDiffTime,- secondsToNominalDiffTime,- nominalDiffTimeToSeconds,- nominalDay,-) where+module Data.Time.Clock.Internal.NominalDiffTime where import Control.DeepSeq import Data.Data import Data.Fixed+#ifdef __GLASGOW_HASKELL__ import GHC.Read-import qualified Language.Haskell.TH.Syntax as TH+#endif+import Data.Time.Clock.Internal.DiffTime+import Language.Haskell.TH.Syntax qualified as TH import Text.ParserCombinators.ReadP import Text.ParserCombinators.ReadPrec -- | This is a length of time, as measured by UTC.--- It has a precision of 10^-12 s.+-- It has a precision of one picosecond (10^-12 s). -- -- Conversion functions such as 'fromInteger' and 'realToFrac' will treat it as seconds. -- For example, @(0.010 :: NominalDiffTime)@ corresponds to 10 milliseconds. ----- It has a precision of one picosecond (= 10^-12 s). Enumeration functions will treat it as picoseconds.+-- Enumeration functions will treat it as picoseconds. -- -- It ignores leap-seconds, so it's not necessarily a fixed amount of clock time. -- For instance, 23:00 UTC + 2 hours of NominalDiffTime = 01:00 UTC (+ 1 day), -- regardless of whether a leap-second intervened. newtype NominalDiffTime = MkNominalDiffTime Pico- deriving (Eq, Ord, Data, Typeable)+ deriving (Eq, Ord, Typeable, Data, TH.Lift) +-- | convert from DiffTime+pattern Nominal :: DiffTime -> NominalDiffTime+pattern Nominal dt <- MkNominalDiffTime (realToFrac -> dt)+ where+ Nominal dt = MkNominalDiffTime $ realToFrac dt++{-# COMPLETE Nominal #-}+ -- | Create a 'NominalDiffTime' from a number of seconds. -- -- @since 1.9.1@@ -44,11 +48,6 @@ -- @since 1.9.1 nominalDiffTimeToSeconds :: NominalDiffTime -> Pico nominalDiffTimeToSeconds (MkNominalDiffTime t) = t---- Let GHC derive the instances when 'Fixed' has 'TH.Lift' instance.-instance TH.Lift NominalDiffTime where- liftTyped :: TH.Quote m => NominalDiffTime -> TH.Code m NominalDiffTime- liftTyped (MkNominalDiffTime (MkFixed a)) = [||MkNominalDiffTime (MkFixed $$(TH.liftTyped a))||] instance NFData NominalDiffTime where rnf (MkNominalDiffTime t) = rnf t
lib/Data/Time/Clock/Internal/SystemTime.hs view
@@ -1,6 +1,8 @@ {-# LANGUAGE CPP #-} +#if !defined(__MHS__) #include "HsTimeConfig.h"+#endif #if defined(mingw32_HOST_OS) || !defined(HAVE_CLOCK_GETTIME) {-# LANGUAGE Safe #-}@@ -21,11 +23,11 @@ import Data.Time.Clock.Internal.DiffTime import Data.Word import GHC.Generics-import qualified Language.Haskell.TH.Syntax as TH+import Language.Haskell.TH.Syntax qualified as TH #ifdef mingw32_HOST_OS import qualified System.Win32.Time as Win32-#elif defined(HAVE_CLOCK_GETTIME)+#elif defined(HAVE_CLOCK_GETTIME) && !defined(__MHS__) import Data.Time.Clock.Internal.CTimespec import Foreign.C.Types (CLong(..), CTime(..)) #else@@ -41,7 +43,7 @@ { systemSeconds :: {-# UNPACK #-} !Int64 , systemNanoseconds :: {-# UNPACK #-} !Word32 }- deriving (Eq, Ord, Show, Data, Typeable, TH.Lift, Generic)+ deriving (Eq, Ord, Show, Typeable, Data, Generic, TH.Lift) instance NFData SystemTime where rnf a = a `seq` ()@@ -74,7 +76,7 @@ getTime_resolution = 100E-9 -- 100ns getTAISystemTime = Nothing-#elif defined(HAVE_CLOCK_GETTIME)+#elif defined(HAVE_CLOCK_GETTIME) && !defined(__MHS__) -- Use hi-res clock_gettime timespecToSystemTime :: CTimespec -> SystemTime timespecToSystemTime (MkCTimespec (CTime s) (CLong ns)) = (MkSystemTime (fromIntegral s) (fromIntegral ns))
lib/Data/Time/Clock/Internal/UTCTime.hs view
@@ -1,25 +1,13 @@ {-# LANGUAGE Safe #-} -module Data.Time.Clock.Internal.UTCTime (- -- * UTC-- -- | UTC is time as measured by a clock, corrected to keep pace with the earth by adding or removing- -- occasional seconds, known as \"leap seconds\".- -- These corrections are not predictable and are announced with six month's notice.- -- No table of these corrections is provided, as any program compiled with it would become- -- out of date in six months.- --- -- If you don't care about leap seconds, use 'UTCTime' and 'NominalDiffTime' for your clock calculations,- -- and you'll be fine.- UTCTime (..),-) where+module Data.Time.Clock.Internal.UTCTime where import Control.DeepSeq import Data.Data import Data.Time.Calendar.Days import Data.Time.Clock.Internal.DiffTime import GHC.Generics-import qualified Language.Haskell.TH.Syntax as TH+import Language.Haskell.TH.Syntax qualified as TH -- | This is the simplest representation of UTC. -- It consists of the day number, and a time offset from midnight.@@ -30,16 +18,7 @@ , utctDayTime :: DiffTime -- ^ the time from midnight, 0 <= t < 86401s (because of leap-seconds) }- deriving (Data, Typeable, TH.Lift, Generic)+ deriving (Eq, Ord, Typeable, Data, Generic, TH.Lift) instance NFData UTCTime where rnf (UTCTime d t) = rnf d `seq` rnf t `seq` ()--instance Eq UTCTime where- (UTCTime da ta) == (UTCTime db tb) = (da == db) && (ta == tb)--instance Ord UTCTime where- compare (UTCTime da ta) (UTCTime db tb) =- case (compare da db) of- EQ -> compare ta tb- cmp -> cmp
lib/Data/Time/Clock/Internal/UniversalTime.hs view
@@ -1,23 +1,18 @@ {-# LANGUAGE Safe #-} -module Data.Time.Clock.Internal.UniversalTime (- -- * Universal Time-- -- | Time as measured by the Earth.- UniversalTime (..),-) where+module Data.Time.Clock.Internal.UniversalTime where import Control.DeepSeq import Data.Data import GHC.Generics-import qualified Language.Haskell.TH.Syntax as TH+import Language.Haskell.TH.Syntax qualified as TH -- | The Modified Julian Date is the day with the fraction of the day, measured from UT midnight. -- It's used to represent UT1, which is time as measured by the earth's rotation, adjusted for various wobbles. newtype UniversalTime = ModJulianDate { getModJulianDate :: Rational }- deriving (Eq, Ord, Data, Typeable, TH.Lift, Generic)+ deriving (Eq, Ord, Typeable, Data, Generic, TH.Lift) instance NFData UniversalTime where rnf (ModJulianDate a) = rnf a
lib/Data/Time/Clock/TAI.hs view
@@ -1,14 +1,19 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE Safe #-} {-# OPTIONS -fno-warn-orphans #-} -- | TAI and leap-second maps for converting to UTC: most people won't need this module. module Data.Time.Clock.TAI (- -- TAI arithmetic- module Data.Time.Clock.Internal.AbsoluteTime,- -- leap-second map type+ -- * Absolute Time+ AbsoluteTime,+ taiEpoch,+ addAbsoluteTime,+ diffAbsoluteTime,+ taiNominalDayStart,++ -- * Leap-Second Map LeapSecondMap,- -- conversion between UTC and TAI with map utcDayLength, utcToTAITime, taiToUTCTime,@@ -23,6 +28,9 @@ import Data.Time.Clock.Internal.SystemTime import Data.Time.Clock.System import Data.Time.LocalTime+#ifdef __MHS__+import Data.Tuple.Instances+#endif instance Show AbsoluteTime where show t = show (utcToLocalTime utc (fromJust (taiToUTCTime (const (Just 0)) t))) ++ " TAI" -- ugly, but standard apparently
lib/Data/Time/Format.hs view
@@ -4,10 +4,25 @@ -- * UNIX-style formatting FormatTime (), formatTime,- module Data.Time.Format.Parse,++ -- * UNIX-style parsing+ parseTimeM,+ parseTimeMultipleM,+ parseTimeOrError,+ readSTime,+ readPTime,+ ParseTime (),++ -- * Locale+ TimeLocale (..),+ defaultTimeLocale,+ iso8601DateFormat,+ rfc822DateFormat, ) where import Data.Time.Format.Format.Class import Data.Time.Format.Format.Instances () import Data.Time.Format.ISO8601 ()+import Data.Time.Format.Locale import Data.Time.Format.Parse+import Data.Time.Format.Parse.Class
lib/Data/Time/Format/Format/Class.hs view
@@ -211,15 +211,26 @@ -- -- [@%A@] day of week, long form ('fst' from 'wDays' @locale@), @Sunday@ - @Saturday@ ----- === 'Month'--- For 'Month' (and 'Day' and 'LocalTime' and 'ZonedTime' and 'UTCTime' and 'UniversalTime'):+-- === 'QuarterOfYear'+-- For 'QuarterOfYear' (and 'Quarter' and 'Month' and 'Day' and 'LocalTime' and 'ZonedTime' and 'UTCTime' and 'UniversalTime'): --+-- [@%v@] quarter number, @1@ - @4@+--+-- === 'Quarter'+-- For 'Quarter' (and 'Month' and 'Day' and 'LocalTime' and 'ZonedTime' and 'UTCTime' and 'UniversalTime'):+-- -- [@%Y@] year, no padding. Note @%0Y@ and @%_Y@ pad to four chars -- -- [@%y@] year of century, 0-padded to two chars, @00@ - @99@ -- -- [@%C@] century, no padding. Note @%0C@ and @%_C@ pad to two chars --+-- [@%v@] quarter number, @1@ - @4@+--+--+-- === 'Month'+-- For 'Month' (and 'Day' and 'LocalTime' and 'ZonedTime' and 'UTCTime' and 'UniversalTime'):+-- -- [@%B@] month name, long form ('fst' from 'months' @locale@), @January@ - @December@ -- -- [@%b@, @%h@] month name, short form ('snd' from 'months' @locale@), @Jan@ - @Dec@@@ -241,9 +252,13 @@ -- -- [@%j@] day of year, 0-padded to three chars, @001@ - @366@ ----- [@%f@] century for Week Date format, no padding. Note @%0f@ and @%_f@ pad to two chars+-- [@%G@] year for ISO 8601 Week Date format. Note @%0G@ and @%_G@ pad to four chars ----- [@%V@] week of year for Week Date format, 0-padded to two chars, @01@ - @53@+-- [@%g@] year of century for ISO 8601 Week Date format, 0-padded to two chars, @00@ - @99@+--+-- [@%f@] century for ISO 8601 Week Date format, no padding. Note @%0f@ and @%_f@ pad to two chars+--+-- [@%V@] week of year for ISO 8601 Week Date format, 0-padded to two chars, @01@ - @53@ -- -- [@%U@] week of year where weeks start on Sunday (as 'sundayStartWeek'), 0-padded to two chars, @00@ - @53@ --
lib/Data/Time/Format/Format/Instances.hs view
@@ -15,6 +15,7 @@ import Data.Time.Calendar.Month import Data.Time.Calendar.OrdinalDate import Data.Time.Calendar.Private+import Data.Time.Calendar.Quarter import Data.Time.Calendar.Week import Data.Time.Calendar.WeekDate import Data.Time.Clock.Internal.DiffTime@@ -110,11 +111,20 @@ formatCharacter _ 'A' = Just $ formatString $ \locale wd -> fst $ (wDays locale) !! (mod (fromEnum wd) 7) formatCharacter _ _ = Nothing -instance FormatTime Month where+instance FormatTime QuarterOfYear where+ -- Quarter of Year+ formatCharacter _ 'v' = Just $ formatNumber False 1 '0' fromEnum+ formatCharacter _ _ = Nothing++instance FormatTime Quarter where -- Year Count- formatCharacter _ 'Y' = Just $ formatNumber False 4 '0' $ \(YearMonth y _) -> y- formatCharacter _ 'y' = Just $ formatNumber True 2 '0' $ \(YearMonth y _) -> mod100 y- formatCharacter _ 'C' = Just $ formatNumber False 2 '0' $ \(YearMonth y _) -> div100 y+ formatCharacter _ 'Y' = Just $ formatNumber False 4 '0' $ \(YearQuarter y _) -> y+ formatCharacter _ 'y' = Just $ formatNumber True 2 '0' $ \(YearQuarter y _) -> mod100 y+ formatCharacter _ 'C' = Just $ formatNumber False 2 '0' $ \(YearQuarter y _) -> div100 y+ -- Default+ formatCharacter alt c = mapFormatCharacter (\(YearQuarter _ q) -> q) $ formatCharacter alt c++instance FormatTime Month where -- Month of Year formatCharacter _ 'B' = Just $ formatString $ \locale (YearMonth _ my) -> fst $ (months locale) !! (my - 1)@@ -124,7 +134,7 @@ Just $ formatString $ \locale (YearMonth _ my) -> snd $ (months locale) !! (my - 1) formatCharacter _ 'm' = Just $ formatNumber True 2 '0' $ \(YearMonth _ m) -> m -- Default- formatCharacter _ _ = Nothing+ formatCharacter alt c = mapFormatCharacter monthQuarter $ formatCharacter alt c instance FormatTime Day where -- Aggregate
lib/Data/Time/Format/ISO8601.hs view
@@ -276,7 +276,7 @@ -- | @xZ@ [ISO 8601:2004(E) sec. 4.2.4] withUTCDesignator :: Format t -> Format t-withUTCDesignator f = f <** literalFormat "Z"+withUTCDesignator f = f <** specialCaseReadFormat ((), "") (literalFormat "Z") -- | @±hh:mm@ (extended), @±hhmm@ (basic) [ISO 8601:2004(E) sec. 4.2.5.1] timeOffsetFormat :: FormatExtension -> Format TimeZone@@ -295,8 +295,10 @@ (signum mm, Right (h, m)) digits2 = integerFormat NoSign (Just 2) in- isoMap toTimeZone fromTimeZone $- mandatorySignFormat <**> (digits2 <++> extColonFormat fe digits2 digits2)+ specialCaseReadFormat (utc, "") $+ specialCaseReadFormat (utc, "Z") $+ isoMap toTimeZone fromTimeZone $+ mandatorySignFormat <**> (digits2 <++> extColonFormat fe digits2 digits2) -- | @hh:mm:ss±hh:mm@ (extended), @hhmmss±hhmm@ (basic) [ISO 8601:2004(E) sec. 4.2.5.2] timeOfDayAndOffsetFormat :: FormatExtension -> Format (TimeOfDay, TimeZone)
lib/Data/Time/Format/Locale.hs view
@@ -1,12 +1,7 @@ {-# LANGUAGE Safe #-} -- Note: this file derives from old-locale:System.Locale.hs, which is copyright (c) The University of Glasgow 2001-module Data.Time.Format.Locale (- TimeLocale (..),- defaultTimeLocale,- iso8601DateFormat,- rfc822DateFormat,-) where+module Data.Time.Format.Locale where import Data.Time.LocalTime.Internal.TimeZone
lib/Data/Time/Format/Parse.hs view
@@ -2,18 +2,7 @@ {-# OPTIONS -fno-warn-orphans #-} -module Data.Time.Format.Parse (- -- * UNIX-style parsing- parseTimeM,- parseTimeMultipleM,- parseTimeOrError,- readSTime,- readPTime,- ParseTime (),-- -- * Locale- module Data.Time.Format.Locale,-) where+module Data.Time.Format.Parse where import Control.Monad.Fail import Data.Char
lib/Data/Time/Format/Parse/Class.hs view
@@ -1,7 +1,6 @@ {-# LANGUAGE Safe #-} module Data.Time.Format.Parse.Class (- -- * Parsing ParseNumericPadding (..), ParseTime (..), parseSpecifiers,@@ -194,6 +193,8 @@ -- year of century 'y' -> parseDigitsUsual ZeroPadding 2 'g' -> parseDigitsUsual ZeroPadding 2+ -- quarter of year+ 'v' -> parseDigitsUsual ZeroPadding 1 -- month of year 'B' -> oneOf (map fst (months l)) 'b' -> oneOf (map snd (months l))
lib/Data/Time/Format/Parse/Instances.hs view
@@ -10,6 +10,7 @@ import Data.Char import Data.Fixed import Data.List (elemIndex, find)+import Data.Maybe import Data.Ratio import Data.Time.Calendar.CalendarDiffDays import Data.Time.Calendar.Days@@ -17,6 +18,8 @@ import Data.Time.Calendar.Month import Data.Time.Calendar.OrdinalDate import Data.Time.Calendar.Private (clipValid)+import Data.Time.Calendar.Quarter+import Data.Time.Calendar.Types import Data.Time.Calendar.WeekDate import Data.Time.Clock.Internal.DiffTime import Data.Time.Clock.Internal.NominalDiffTime@@ -33,24 +36,98 @@ import Data.Traversable import Text.Read (readMaybe) -data DayComponent- = DCCentury Integer -- century of all years- | DCCenturyYear Integer -- 0-99, last two digits of both real years and week years- | DCYearMonth MonthOfYear -- 1-12- | DCMonthDay DayOfMonth -- 1-31- | DCYearDay DayOfYear -- 1-366- | DCWeekDay Int -- 1-7 (mon-sun)- | DCYearWeek- WeekType- WeekOfYear -- 1-53 or 0-53- data WeekType = ISOWeek | SundayWeek | MondayWeek+ deriving Eq -makeDayComponent :: TimeLocale -> Char -> String -> Maybe [DayComponent]-makeDayComponent l c x =+mkDayFromWeekType :: WeekType -> Year -> WeekOfYear -> DayOfWeek -> Maybe Day+mkDayFromWeekType wt y woy dow =+ case wt of+ ISOWeek -> fromWeekDateValid y woy $ fromEnum dow+ SundayWeek -> fromSundayStartWeekValid y woy $ mod (fromEnum dow) 7+ MondayWeek -> fromMondayStartWeekValid y woy $ fromEnum dow++data DayFact+ = CenturyDayFact Integer -- century of all years+ | YearOfCenturyDayFact Integer -- 0-99, last two digits of both real years and week years+ | QuarterOfYearDayFact QuarterOfYear+ | MonthOfYearDayFact MonthOfYear -- 1-12+ | DayOfMonthDayFact DayOfMonth -- 1-31+ | DayOfYearDayFact DayOfYear -- 1-366+ | DayOfWeekDayFact DayOfWeek+ | WeekOfYearDayFact+ WeekType+ WeekOfYear -- 1-53 or 0-53+ | UTCTimeDayFact UTCTime+ | TimeZoneDayFact TimeZone++lastMatch :: (a -> Maybe b) -> [a] -> Maybe b+lastMatch f aa = listToMaybe $ reverse $ catMaybes $ fmap f aa++dayFactGetCentury :: [DayFact] -> Maybe Integer+dayFactGetCentury = lastMatch $ \case+ CenturyDayFact x -> Just x+ _ -> Nothing++dayFactGetYearOfCentury :: [DayFact] -> Maybe Integer+dayFactGetYearOfCentury = lastMatch $ \case+ YearOfCenturyDayFact x -> Just x+ _ -> Nothing++dayFactGetQuarterOfYear :: [DayFact] -> Maybe QuarterOfYear+dayFactGetQuarterOfYear = lastMatch $ \case+ QuarterOfYearDayFact x -> Just x+ _ -> Nothing++dayFactGetMonthOfYear :: [DayFact] -> Maybe MonthOfYear+dayFactGetMonthOfYear = lastMatch $ \case+ MonthOfYearDayFact x -> Just x+ _ -> Nothing++dayFactGetDayOfMonth :: [DayFact] -> Maybe DayOfMonth+dayFactGetDayOfMonth = lastMatch $ \case+ DayOfMonthDayFact x -> Just x+ _ -> Nothing++dayFactGetDayOfYear :: [DayFact] -> Maybe DayOfYear+dayFactGetDayOfYear = lastMatch $ \case+ DayOfYearDayFact x -> Just x+ _ -> Nothing++dayFactGetDayOfWeek :: [DayFact] -> Maybe DayOfWeek+dayFactGetDayOfWeek = lastMatch $ \case+ DayOfWeekDayFact x -> Just x+ _ -> Nothing++dayFactGetWeekOfYear :: [DayFact] -> Maybe (WeekType, WeekOfYear)+dayFactGetWeekOfYear = lastMatch $ \case+ WeekOfYearDayFact wt x -> Just (wt, x)+ _ -> Nothing++dayFactGetUTCTime :: [DayFact] -> Maybe UTCTime+dayFactGetUTCTime = lastMatch $ \case+ UTCTimeDayFact x -> Just x+ _ -> Nothing++dayFactGetTimeZone :: [DayFact] -> Maybe TimeZone+dayFactGetTimeZone = lastMatch $ \case+ TimeZoneDayFact x -> Just x+ _ -> Nothing++readSpec_z :: String -> Maybe Int+readSpec_z = readTzOffset++readSpec_Z :: TimeLocale -> String -> Maybe TimeZone+readSpec_Z _ str | Just offset <- readTzOffset str = Just $ TimeZone offset False ""+readSpec_Z l str | Just zone <- getKnownTimeZone l str = Just zone+readSpec_Z _ "UTC" = Just utc+readSpec_Z _ [c] | Just zone <- getMilZone c = Just zone+readSpec_Z _ _ = Nothing++makeDayFact :: TimeLocale -> Char -> String -> Maybe [DayFact]+makeDayFact l c x = let ra :: Read a => Maybe a ra = readMaybe x@@ -65,177 +142,214 @@ -- %C: century (all but the last two digits of the year), 00 - 99 'C' -> do a <- ra- return [DCCentury a]+ return [CenturyDayFact a] -- %f century (all but the last two digits of the year), 00 - 99 'f' -> do a <- ra- return [DCCentury a]+ return [CenturyDayFact a] -- %Y: year 'Y' -> do a <- ra- return [DCCentury (a `div` 100), DCCenturyYear (a `mod` 100)]+ return [CenturyDayFact (a `div` 100), YearOfCenturyDayFact (a `mod` 100)] -- %G: year for Week Date format 'G' -> do a <- ra- return [DCCentury (a `div` 100), DCCenturyYear (a `mod` 100)]+ return [CenturyDayFact (a `div` 100), YearOfCenturyDayFact (a `mod` 100)] -- %y: last two digits of year, 00 - 99 'y' -> do a <- ra- return [DCCenturyYear a]+ return [YearOfCenturyDayFact a] -- %g: last two digits of year for Week Date format, 00 - 99 'g' -> do a <- ra- return [DCCenturyYear a]+ return [YearOfCenturyDayFact a]+ -- %v: quarter of year, 1 - 4+ 'v' -> do+ raw <- ra+ a <- clipValid 1 4 raw+ return [QuarterOfYearDayFact $ toEnum a] -- %B: month name, long form (fst from months locale), January - December 'B' -> do a <- oneBasedListIndex $ fmap fst $ months l- return [DCYearMonth a]+ return [MonthOfYearDayFact a] -- %b: month name, short form (snd from months locale), Jan - Dec 'b' -> do a <- oneBasedListIndex $ fmap snd $ months l- return [DCYearMonth a]+ return [MonthOfYearDayFact a] -- %m: month of year, leading 0 as needed, 01 - 12 'm' -> do raw <- ra a <- clipValid 1 12 raw- return [DCYearMonth a]+ return [MonthOfYearDayFact a] -- %d: day of month, leading 0 as needed, 01 - 31 'd' -> do raw <- ra a <- clipValid 1 31 raw- return [DCMonthDay a]+ return [DayOfMonthDayFact a] -- %e: day of month, leading space as needed, 1 - 31 'e' -> do raw <- ra a <- clipValid 1 31 raw- return [DCMonthDay a]+ return [DayOfMonthDayFact a] -- %V: week for Week Date format, 01 - 53 'V' -> do raw <- ra a <- clipValid 1 53 raw- return [DCYearWeek ISOWeek a]+ return [WeekOfYearDayFact ISOWeek a] -- %U: week number of year, where weeks start on Sunday (as sundayStartWeek), 00 - 53 'U' -> do raw <- ra a <- clipValid 0 53 raw- return [DCYearWeek SundayWeek a]+ return [WeekOfYearDayFact SundayWeek a] -- %W: week number of year, where weeks start on Monday (as mondayStartWeek), 00 - 53 'W' -> do raw <- ra a <- clipValid 0 53 raw- return [DCYearWeek MondayWeek a]+ return [WeekOfYearDayFact MondayWeek a] -- %u: day for Week Date format, 1 - 7 'u' -> do raw <- ra a <- clipValid 1 7 raw- return [DCWeekDay a]+ return [DayOfWeekDayFact $ toEnum a] -- %a: day of week, short form (snd from wDays locale), Sun - Sat 'a' -> do- a' <- zeroBasedListIndex $ fmap snd $ wDays l- let- a =- if a' == 0- then 7- else a'- return [DCWeekDay a]+ a <- zeroBasedListIndex $ fmap snd $ wDays l+ return [DayOfWeekDayFact $ toEnum a] -- %A: day of week, long form (fst from wDays locale), Sunday - Saturday 'A' -> do- a' <- zeroBasedListIndex $ fmap fst $ wDays l- let- a =- if a' == 0- then 7- else a'- return [DCWeekDay a]+ a <- zeroBasedListIndex $ fmap fst $ wDays l+ return [DayOfWeekDayFact $ toEnum a] -- %w: day of week number, 0 (= Sunday) - 6 (= Saturday) 'w' -> do raw <- ra- a' <- clipValid 0 6 raw- let- a =- if a' == 0- then 7- else a'- return [DCWeekDay a]+ a <- clipValid 0 6 raw+ return [DayOfWeekDayFact $ toEnum a] -- %j: day of year for Ordinal Date format, 001 - 366 'j' -> do raw <- ra a <- clipValid 1 366 raw- return [DCYearDay a]+ return [DayOfYearDayFact a]+ -- %s: number of whole seconds since the Unix epoch.+ 's' -> do+ raw <- ra+ return [UTCTimeDayFact $ posixSecondsToUTCTime $ fromInteger raw]+ 'z' -> do+ a <- readSpec_z x+ return [TimeZoneDayFact $ TimeZone a False ""]+ 'Z' -> do+ a <- readSpec_Z l x+ return [TimeZoneDayFact a] -- unrecognised, pass on to other parsers _ -> return [] -makeDayComponents :: TimeLocale -> [(Char, String)] -> Maybe [DayComponent]-makeDayComponents l pairs = do- components <- for pairs $ \(c, x) -> makeDayComponent l c x- return $ concat components+makeDayFacts :: TimeLocale -> [(Char, String)] -> Maybe [DayFact]+makeDayFacts l pairs = do+ factss <- for pairs $ \(c, x) -> makeDayFact l c x+ return $ mconcat factss -safeLast :: a -> [a] -> a-safeLast x xs = last (x : xs)+dayFactYear :: [DayFact] -> Integer+dayFactYear facts =+ let+ d = fromMaybe 70 $ dayFactGetYearOfCentury facts+ c =+ fromMaybe+ ( if d >= 69+ then 19+ else 20+ )+ $ dayFactGetCentury facts+ in+ 100 * c + d -instance ParseTime Day where- substituteTimeSpecifier _ = timeSubstituteTimeSpecifier- parseTimeSpecifier _ = timeParseTimeSpecifier- buildTime l pairs = do- cs <- makeDayComponents l pairs- -- 'Nothing' indicates a parse failure,- -- while 'Just []' means no information- let- y =+dayFactDay :: [DayFact] -> Maybe Day+dayFactDay facts =+ case dayFactYear facts of+ y | Just doy <- dayFactGetDayOfYear facts -> fromOrdinalDateValid y doy+ y+ | Just moy <- dayFactGetMonthOfYear facts -> let- d = safeLast 70 [x | DCCenturyYear x <- cs]- c =- safeLast- ( if d >= 69- then 19- else 20- )- [x | DCCentury x <- cs]+ dom = fromMaybe 1 $ dayFactGetDayOfMonth facts in- 100 * c + d- rest (DCYearMonth m : _) =+ fromGregorianValid y moy dom+ y+ | Just (wt, woy) <- dayFactGetWeekOfYear facts -> let- d = safeLast 1 [x | DCMonthDay x <- cs]+ dow = fromMaybe Thursday $ dayFactGetDayOfWeek facts in- fromGregorianValid y m d- rest (DCYearDay d : _) = fromOrdinalDateValid y d- rest (DCYearWeek wt w : _) =+ mkDayFromWeekType wt y woy dow+ y+ | Just qoy <- dayFactGetQuarterOfYear facts -> let- d = safeLast 4 [x | DCWeekDay x <- cs]+ moy = case qoy of+ Q1 -> 1+ Q2 -> 4+ Q3 -> 7+ Q4 -> 10+ dom = fromMaybe 1 $ dayFactGetDayOfMonth facts in- case wt of- ISOWeek -> fromWeekDateValid y w d- SundayWeek -> fromSundayStartWeekValid y w (d `mod` 7)- MondayWeek -> fromMondayStartWeekValid y w d- rest (_ : xs) = rest xs- rest [] = rest [DCYearMonth 1]- rest cs+ fromGregorianValid y moy dom+ _+ | Just ut <- dayFactGetUTCTime facts ->+ let+ tz = fromMaybe utc $ dayFactGetTimeZone facts+ in+ Just $ localDay $ utcToLocalTime tz ut+ y | Just dom <- dayFactGetDayOfMonth facts -> fromGregorianValid y 1 dom+ y | Just dow <- dayFactGetDayOfWeek facts -> fromWeekDateValid y 1 $ fromEnum dow+ y -> fromOrdinalDateValid y 1 +instance ParseTime Day where+ substituteTimeSpecifier _ = timeSubstituteTimeSpecifier+ parseTimeSpecifier _ = timeParseTimeSpecifier+ buildTime l pairs = do+ facts <- makeDayFacts l pairs+ dayFactDay facts++instance ParseTime DayOfWeek where+ substituteTimeSpecifier _ = timeSubstituteTimeSpecifier+ parseTimeSpecifier _ = timeParseTimeSpecifier+ buildTime l pairs = do+ facts <- makeDayFacts l pairs+ dayFactGetDayOfWeek facts+ <|> (fmap dayOfWeek $ dayFactDay facts)+ instance ParseTime Month where substituteTimeSpecifier _ = timeSubstituteTimeSpecifier parseTimeSpecifier _ = timeParseTimeSpecifier buildTime l pairs = do- cs <- makeDayComponents l pairs- -- 'Nothing' indicates a parse failure,- -- while 'Just []' means no information- let- y =+ facts <- makeDayFacts l pairs+ case dayFactGetMonthOfYear facts of+ Just moy -> let- d = safeLast 70 [x | DCCenturyYear x <- cs]- c =- safeLast- ( if d >= 69- then 19- else 20- )- [x | DCCentury x <- cs]+ y = dayFactYear facts in- 100 * c + d- rest (DCYearMonth m : _) = fromYearMonthValid y m- rest (_ : xs) = rest xs- rest [] = fromYearMonthValid y 1- rest cs+ Just $ YearMonth y moy+ Nothing -> fmap dayPeriod $ dayFactDay facts +instance ParseTime QuarterOfYear where+ substituteTimeSpecifier _ = timeSubstituteTimeSpecifier+ parseTimeSpecifier _ = timeParseTimeSpecifier+ buildTime l pairs = do+ facts <- makeDayFacts l pairs+ case dayFactGetQuarterOfYear facts of+ Just qoy -> Just qoy+ Nothing -> do+ QuarterDay (YearQuarter _ qoy) _ <- dayFactDay facts+ return qoy++instance ParseTime Quarter where+ substituteTimeSpecifier _ = timeSubstituteTimeSpecifier+ parseTimeSpecifier _ = timeParseTimeSpecifier+ buildTime l pairs = do+ facts <- makeDayFacts l pairs+ case dayFactGetQuarterOfYear facts of+ Just qoy ->+ let+ y = dayFactYear facts+ in+ Just $ YearQuarter y qoy+ Nothing -> fmap dayPeriod $ dayFactDay facts+ mfoldl :: Monad m => (a -> b -> m a) -> m a -> [b] -> m a mfoldl f = let@@ -245,74 +359,150 @@ in foldl mf +data AMPM = AM | PM++data TimeFact+ = AMAPMTimeFact AMPM+ | HourTimeFact Int+ | MinuteTimeFact Int+ | WholeSecondTimeFact Int+ | FractSecondTimeFact Pico+ | UTCTimeFact UTCTime+ | ZoneTimeFact TimeZone++timeFactGetAMPM :: [TimeFact] -> Maybe AMPM+timeFactGetAMPM = lastMatch $ \case+ AMAPMTimeFact x -> Just x+ _ -> Nothing++timeFactGetHour :: [TimeFact] -> Maybe Int+timeFactGetHour = lastMatch $ \case+ HourTimeFact x -> Just x+ _ -> Nothing++timeFactGetMinute :: [TimeFact] -> Maybe Int+timeFactGetMinute = lastMatch $ \case+ MinuteTimeFact x -> Just x+ _ -> Nothing++timeFactGetWholeSecond :: [TimeFact] -> Maybe Int+timeFactGetWholeSecond = lastMatch $ \case+ WholeSecondTimeFact x -> Just x+ _ -> Nothing++timeFactGetFractSecond :: [TimeFact] -> Maybe Pico+timeFactGetFractSecond = lastMatch $ \case+ FractSecondTimeFact x -> Just x+ _ -> Nothing++timeFactGetUTC :: [TimeFact] -> Maybe UTCTime+timeFactGetUTC = lastMatch $ \case+ UTCTimeFact x -> Just x+ _ -> Nothing++timeFactGetZone :: [TimeFact] -> Maybe TimeZone+timeFactGetZone = lastMatch $ \case+ ZoneTimeFact x -> Just x+ _ -> Nothing++makeTimeFact :: TimeLocale -> Char -> String -> Maybe [TimeFact]+makeTimeFact l c x =+ let+ ra :: Read a => Maybe a+ ra = readMaybe x+ getAmPm =+ let+ upx = map toUpper x+ (amStr, pmStr) = amPm l+ in+ if upx == amStr+ then Just [AMAPMTimeFact AM]+ else+ if upx == pmStr+ then Just [AMAPMTimeFact PM]+ else Nothing+ in+ case c of+ 'P' -> getAmPm+ 'p' -> getAmPm+ 'H' -> do+ raw <- ra+ a <- clipValid 0 23 raw+ return [HourTimeFact a]+ 'I' -> do+ raw <- ra+ a <- clipValid 1 12 raw+ return [HourTimeFact a]+ 'k' -> do+ raw <- ra+ a <- clipValid 0 23 raw+ return [HourTimeFact a]+ 'l' -> do+ raw <- ra+ a <- clipValid 1 12 raw+ return [HourTimeFact a]+ 'M' -> do+ raw <- ra+ a <- clipValid 0 59 raw+ return [MinuteTimeFact a]+ 'S' -> do+ raw <- ra+ a <- clipValid 0 60 raw+ return [WholeSecondTimeFact $ fromInteger a]+ 'q' -> do+ ps <- (readMaybe $ take 12 $ rpad 12 '0' x) <|> return 0+ return [FractSecondTimeFact $ mkPico 0 ps]+ 'Q' ->+ if null x+ then return []+ else do+ ps <- (readMaybe $ take 12 $ rpad 12 '0' x) <|> return 0+ return [FractSecondTimeFact $ mkPico 0 ps]+ 's' -> do+ raw <- ra+ return [UTCTimeFact $ posixSecondsToUTCTime $ fromInteger raw]+ 'z' -> do+ a <- readSpec_z x+ return [ZoneTimeFact $ TimeZone a False ""]+ 'Z' -> do+ a <- readSpec_Z l x+ return [ZoneTimeFact a]+ _ -> return []++makeTimeFacts :: TimeLocale -> [(Char, String)] -> Maybe [TimeFact]+makeTimeFacts l pairs = do+ factss <- for pairs $ \(c, x) -> makeTimeFact l c x+ return $ mconcat factss+ instance ParseTime TimeOfDay where substituteTimeSpecifier _ = timeSubstituteTimeSpecifier parseTimeSpecifier _ = timeParseTimeSpecifier- buildTime l =- let- f t@(TimeOfDay h m s) (c, x) =+ buildTime l pairs = do+ facts <- makeTimeFacts l pairs+ -- 'Nothing' indicates a parse failure,+ -- while 'Just []' means no information+ case timeFactGetUTC facts of+ Just t -> let- ra :: Read a => Maybe a- ra = readMaybe x- getAmPm =- let- upx = map toUpper x- (amStr, pmStr) = amPm l- in- if upx == amStr- then Just $ TimeOfDay (h `mod` 12) m s- else- if upx == pmStr- then- Just $- TimeOfDay- ( if h < 12- then h + 12- else h- )- m- s- else Nothing+ zone = fromMaybe utc $ timeFactGetZone facts+ sf = fromMaybe 0 $ timeFactGetFractSecond facts+ TimeOfDay h m s = localTimeOfDay $ utcToLocalTime zone t in- case c of- 'P' -> getAmPm- 'p' -> getAmPm- 'H' -> do- raw <- ra- a <- clipValid 0 23 raw- return $ TimeOfDay a m s- 'I' -> do- raw <- ra- a <- clipValid 1 12 raw- return $ TimeOfDay a m s- 'k' -> do- raw <- ra- a <- clipValid 0 23 raw- return $ TimeOfDay a m s- 'l' -> do- raw <- ra- a <- clipValid 1 12 raw- return $ TimeOfDay a m s- 'M' -> do- raw <- ra- a <- clipValid 0 59 raw- return $ TimeOfDay h a s- 'S' -> do- raw <- ra- a <- clipValid 0 60 raw- return $ TimeOfDay h m (fromInteger a)- 'q' -> do- ps <- (readMaybe $ take 12 $ rpad 12 '0' x) <|> return 0- return $ TimeOfDay h m (mkPico (floor s) ps)- 'Q' ->- if null x- then Just t- else do- ps <- (readMaybe $ take 12 $ rpad 12 '0' x) <|> return 0- return $ TimeOfDay h m (mkPico (floor s) ps)- _ -> Just t- in- mfoldl f (Just midnight)+ return $ TimeOfDay h m $ s + sf+ Nothing ->+ let+ h = fromMaybe 0 $ timeFactGetHour facts+ m = fromMaybe 0 $ timeFactGetMinute facts+ si = fromMaybe 0 $ timeFactGetWholeSecond facts+ sf = fromMaybe 0 $ timeFactGetFractSecond facts+ s :: Pico+ s = fromIntegral si + sf+ h' = case timeFactGetAMPM facts of+ Nothing -> h+ Just AM -> mod h 12+ Just PM -> if h < 12 then h + 12 else h+ in+ return $ TimeOfDay h' m s rpad :: Int -> a -> [a] -> [a] rpad n c xs = xs ++ replicate (n - length xs) c@@ -359,17 +549,10 @@ buildTime l = let f :: Char -> String -> TimeZone -> Maybe TimeZone- f 'z' str (TimeZone _ dst name)- | Just offset <- readTzOffset str = Just $ TimeZone offset dst name- f 'z' _ _ = Nothing- f 'Z' str _- | Just offset <- readTzOffset str = Just $ TimeZone offset False ""- f 'Z' str _- | Just zone <- getKnownTimeZone l str = Just zone- f 'Z' "UTC" _ = Just utc- f 'Z' [c] _- | Just zone <- getMilZone c = Just zone- f 'Z' _ _ = Nothing+ f 'z' str (TimeZone _ dst name) = do+ offset <- readSpec_z str+ return $ TimeZone offset dst name+ f 'Z' str _ = readSpec_Z l str f _ _ tz = Just tz in foldl (\mt (c, s) -> mt >>= f c s) (Just $ minutesToTimeZone 0)@@ -416,6 +599,8 @@ substituteTimeSpecifier _ = timeSubstituteTimeSpecifier parseTimeSpecifier _ = timeParseTimeSpecifier buildTime l xs = localTimeToUT1 0 <$> buildTime l xs++--- Duration buildTimeMonths :: [(Char, String)] -> Maybe Integer buildTimeMonths xs = do
lib/Data/Time/LocalTime.hs view
@@ -11,14 +11,53 @@ -- getting the locale time zone getTimeZone, getCurrentTimeZone,- module Data.Time.LocalTime.Internal.TimeOfDay,++ -- * Time of day+ TimeOfDay (..),+ midnight,+ midday,+ makeTimeOfDayValid,+ timeToDaysAndTimeOfDay,+ daysAndTimeOfDayToTime,+ utcToLocalTimeOfDay,+ localToUTCTimeOfDay,+ timeToTimeOfDay,+ pastMidnight,+ timeOfDayToTime,+ sinceMidnight,+ diffTimeOfDay,+ dayFractionToTimeOfDay,+ timeOfDayToDayFraction,++ -- * Calendar Duration module Data.Time.LocalTime.Internal.CalendarDiffTime,- module Data.Time.LocalTime.Internal.LocalTime,- module Data.Time.LocalTime.Internal.ZonedTime,++ -- * Local Time+ LocalTime (..),+ addLocalTime,+ diffLocalTime,+ -- converting UTC and UT1 times to LocalTime+ utcToLocalTime,+ localTimeToUTC,+ ut1ToLocalTime,+ localTimeToUT1,+ -- using CalendarDiffTime+ addLocalDurationClip,+ addLocalDurationRollOver,+ diffLocalDurationClip,+ diffLocalDurationRollOver,++ -- * Zoned Time+ ZonedTime (..),+ utcToZonedTime,+ zonedTimeToUTC,+ getZonedTime,+ utcToLocalZonedTime, ) where import Data.Time.Format () import Data.Time.LocalTime.Internal.CalendarDiffTime+import Data.Time.LocalTime.Internal.Foreign import Data.Time.LocalTime.Internal.LocalTime import Data.Time.LocalTime.Internal.TimeOfDay import Data.Time.LocalTime.Internal.TimeZone hiding (timeZoneOffsetString'')
lib/Data/Time/LocalTime/Internal/CalendarDiffTime.hs view
@@ -1,28 +1,22 @@ {-# LANGUAGE Safe #-} -module Data.Time.LocalTime.Internal.CalendarDiffTime (- -- * Calendar Duration- module Data.Time.LocalTime.Internal.CalendarDiffTime,-) where+module Data.Time.LocalTime.Internal.CalendarDiffTime where import Control.DeepSeq import Data.Data import Data.Time.Calendar.CalendarDiffDays+import Data.Time.Calendar.Gregorian import Data.Time.Clock.Internal.NominalDiffTime+import Data.Time.Clock.Internal.UTCDiff+import Data.Time.Clock.Internal.UTCTime import GHC.Generics+import Language.Haskell.TH.Syntax qualified as TH data CalendarDiffTime = CalendarDiffTime { ctMonths :: Integer , ctTime :: NominalDiffTime }- deriving- ( Eq- , -- | @since 1.9.2- Data- , -- | @since 1.9.2- Typeable- , Generic- )+ deriving (Eq, Typeable, Data, Generic, TH.Lift) instance NFData CalendarDiffTime where rnf (CalendarDiffTime m t) = rnf m `seq` rnf t `seq` ()@@ -45,3 +39,25 @@ -- | Scale by a factor. Note that @scaleCalendarDiffTime (-1)@ will not perfectly invert a duration, due to variable month lengths. scaleCalendarDiffTime :: Integer -> CalendarDiffTime -> CalendarDiffTime scaleCalendarDiffTime k (CalendarDiffTime m d) = CalendarDiffTime (k * m) (fromInteger k * d)++addUTCDurationClip :: CalendarDiffTime -> UTCTime -> UTCTime+addUTCDurationClip (CalendarDiffTime m d) (UTCTime day t) =+ addUTCTime d $ UTCTime (addGregorianMonthsClip m day) t++addUTCDurationRollOver :: CalendarDiffTime -> UTCTime -> UTCTime+addUTCDurationRollOver (CalendarDiffTime m d) (UTCTime day t) =+ addUTCTime d $ UTCTime (addGregorianMonthsRollOver m day) t++diffUTCDurationClip :: UTCTime -> UTCTime -> CalendarDiffTime+diffUTCDurationClip (UTCTime day1 t1) (UTCTime day2 t2) =+ let+ CalendarDiffTime m t = calendarTimeDays $ diffGregorianDurationClip day1 day2+ in+ CalendarDiffTime m $ t + realToFrac (t1 - t2)++diffUTCDurationRollOver :: UTCTime -> UTCTime -> CalendarDiffTime+diffUTCDurationRollOver (UTCTime day1 t1) (UTCTime day2 t2) =+ let+ CalendarDiffTime m t = calendarTimeDays $ diffGregorianDurationRollOver day1 day2+ in+ CalendarDiffTime m $ t + realToFrac (t1 - t2)
+ lib/Data/Time/LocalTime/Internal/Foreign.hs view
@@ -0,0 +1,119 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE Safe #-}++module Data.Time.LocalTime.Internal.Foreign (+ getTimeZone,+ getCurrentTimeZone,+) where++import Data.Time.Clock.Internal.UTCTime+import Data.Time.Clock.POSIX+import Data.Time.Clock.System+import Data.Time.LocalTime.Internal.TimeZone+import Foreign+import Foreign.C+#if defined(javascript_HOST_ARCH)+import Data.Time.Calendar.Gregorian+import Data.Time.Clock.Internal.NominalDiffTime+import Data.Time.LocalTime.Internal.LocalTime+import Data.Time.LocalTime.Internal.TimeOfDay+#endif++#if defined(javascript_HOST_ARCH)++foreign import javascript "((dy,dm,dd,th,tm,ts) => { return new Date(dy,dm,dd,th,tm,ts).getTimezoneOffset(); })"+ js_get_timezone_minutes :: Int -> Int -> Int -> Int -> Int -> Int -> IO Int++get_timezone_minutes :: UTCTime -> IO Int+get_timezone_minutes ut = let+ lt :: LocalTime+ lt = utcToLocalTime utc ut+ in case lt of+ LocalTime (YearMonthDay dy dm dd) (TimeOfDay th tm ts) ->+ js_get_timezone_minutes (fromInteger dy) (pred dm) dd th tm (floor ts)++getTimeZoneCTime :: CTime -> IO TimeZone+getTimeZoneCTime ct = do+ let+ ut :: UTCTime+ ut = posixSecondsToUTCTime $ secondsToNominalDiffTime $ fromIntegral $ fromCTime ct+ mins <- get_timezone_minutes ut+ return $ TimeZone mins False ""++fromCTime :: CTime -> Int64+fromCTime (CTime tt) = fromIntegral tt++#else+{-# CFILES cbits/HsTime.c #-}+foreign import ccall unsafe "HsTime.h get_current_timezone_seconds"+ get_current_timezone_seconds ::+ CTime -> Ptr CInt -> Ptr CString -> IO CLong++getTimeZoneCTime :: CTime -> IO TimeZone+getTimeZoneCTime ctime =+ with 0 $ \pdst ->+ with nullPtr $ \pcname -> do+ secs <- get_current_timezone_seconds ctime pdst pcname+ case secs of+ 0x80000000 -> fail "localtime_r failed"+ _ -> do+ dst <- peek pdst+ cname <- peek pcname+ name <- peekCString cname+ return (TimeZone (div (fromIntegral secs) 60) (dst == 1) name)+#endif++-- there's no instance Bounded CTime, so this is the easiest way to check for overflow+toCTime :: Int64 -> IO CTime+toCTime t =+ let+ tt = fromIntegral t+ t' = fromIntegral tt+ in+ if t' == t+ then return $ CTime tt+ else fail "Data.Time.LocalTime.Internal.TimeZone.toCTime: Overflow"++-- | Get the configured time-zone for a given time (varying as per summertime adjustments).+getTimeZoneSystem :: SystemTime -> IO TimeZone+getTimeZoneSystem t = do+ ctime <- toCTime $ systemSeconds t+ getTimeZoneCTime ctime++-- | Get the configured time-zone for a given time (varying as per summertime adjustments).+--+-- On Unix systems the output of this function depends on:+--+-- 1. The value of @TZ@ environment variable (if set)+--+-- 2. The system time zone (usually configured by @\/etc\/localtime@ symlink)+--+-- For details see tzset(3) and localtime(3).+--+-- Example:+--+-- @+-- > let t = `UTCTime` (`Data.Time.Calendar.fromGregorian` 2021 7 1) 0+-- > `getTimeZone` t+-- CEST+-- > `System.Environment.setEnv` \"TZ\" \"America/New_York\" >> `getTimeZone` t+-- EDT+-- > `System.Environment.setEnv` \"TZ\" \"Europe/Berlin\" >> `getTimeZone` t+-- CEST+-- @+--+-- On Windows systems the output of this function depends on:+--+-- 1. The value of @TZ@ environment variable (if set).+-- See [here](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/tzset) for how Windows interprets this variable.+--+-- 2. The system time zone, configured in Settings+getTimeZone :: UTCTime -> IO TimeZone+getTimeZone t = do+ ctime <- toCTime $ floor $ utcTimeToPOSIXSeconds t+ getTimeZoneCTime ctime++-- | Get the configured time-zone for the current time.+getCurrentTimeZone :: IO TimeZone+getCurrentTimeZone = getSystemTime >>= getTimeZoneSystem
lib/Data/Time/LocalTime/Internal/LocalTime.hs view
@@ -2,17 +2,7 @@ {-# OPTIONS -fno-warn-orphans #-} -module Data.Time.LocalTime.Internal.LocalTime (- -- * Local Time- LocalTime (..),- addLocalTime,- diffLocalTime,- -- converting UTC and UT1 times to LocalTime- utcToLocalTime,- localTimeToUTC,- ut1ToLocalTime,- localTimeToUT1,-) where+module Data.Time.LocalTime.Internal.LocalTime where import Control.DeepSeq import Data.Data@@ -22,9 +12,11 @@ import Data.Time.Clock.Internal.UTCDiff import Data.Time.Clock.Internal.UTCTime import Data.Time.Clock.Internal.UniversalTime+import Data.Time.LocalTime.Internal.CalendarDiffTime import Data.Time.LocalTime.Internal.TimeOfDay import Data.Time.LocalTime.Internal.TimeZone import GHC.Generics+import Language.Haskell.TH.Syntax qualified as TH -- | A simple day and time aggregate, where the day is of the specified parameter, -- and the time is a TimeOfDay.@@ -34,7 +26,7 @@ { localDay :: Day , localTimeOfDay :: TimeOfDay }- deriving (Eq, Ord, Data, Typeable, Generic)+ deriving (Eq, Ord, Typeable, Data, Generic, TH.Lift) instance NFData LocalTime where rnf (LocalTime d t) = rnf d `seq` rnf t `seq` ()@@ -79,3 +71,25 @@ -- orphan instance instance Show UniversalTime where show t = show (ut1ToLocalTime 0 t)++addLocalDurationClip :: CalendarDiffTime -> LocalTime -> LocalTime+addLocalDurationClip (CalendarDiffTime m d) (LocalTime day t) =+ addLocalTime d $ LocalTime (addGregorianMonthsClip m day) t++addLocalDurationRollOver :: CalendarDiffTime -> LocalTime -> LocalTime+addLocalDurationRollOver (CalendarDiffTime m d) (LocalTime day t) =+ addLocalTime d $ LocalTime (addGregorianMonthsRollOver m day) t++diffLocalDurationClip :: LocalTime -> LocalTime -> CalendarDiffTime+diffLocalDurationClip (LocalTime day1 t1) (LocalTime day2 t2) =+ let+ CalendarDiffTime m t = calendarTimeDays $ diffGregorianDurationClip day1 day2+ in+ CalendarDiffTime m $ t + diffTimeOfDay t1 t2++diffLocalDurationRollOver :: LocalTime -> LocalTime -> CalendarDiffTime+diffLocalDurationRollOver (LocalTime day1 t1) (LocalTime day2 t2) =+ let+ CalendarDiffTime m t = calendarTimeDays $ diffGregorianDurationRollOver day1 day2+ in+ CalendarDiffTime m $ t + diffTimeOfDay t1 t2
lib/Data/Time/LocalTime/Internal/TimeOfDay.hs view
@@ -1,22 +1,6 @@ {-# LANGUAGE Safe #-} -module Data.Time.LocalTime.Internal.TimeOfDay (- -- * Time of day- TimeOfDay (..),- midnight,- midday,- makeTimeOfDayValid,- timeToDaysAndTimeOfDay,- daysAndTimeOfDayToTime,- utcToLocalTimeOfDay,- localToUTCTimeOfDay,- timeToTimeOfDay,- pastMidnight,- timeOfDayToTime,- sinceMidnight,- dayFractionToTimeOfDay,- timeOfDayToDayFraction,-) where+module Data.Time.LocalTime.Internal.TimeOfDay where import Control.DeepSeq import Data.Data@@ -26,6 +10,7 @@ import Data.Time.Clock.Internal.NominalDiffTime import Data.Time.LocalTime.Internal.TimeZone import GHC.Generics+import Language.Haskell.TH.Syntax qualified as TH -- | Time of day as represented in hour, minute and second (with picoseconds), typically used to express local time of day. --@@ -37,10 +22,10 @@ , todMin :: Int -- ^ range 0 - 59 , todSec :: Pico- -- ^ Note that 0 <= 'todSec' < 61, accomodating leap seconds.+ -- ^ Note that 0 <= 'todSec' < 61, accommodating leap seconds. -- Any local minute may have a leap second, since leap seconds happen in all zones simultaneously }- deriving (Eq, Ord, Data, Typeable, Generic)+ deriving (Eq, Ord, Typeable, Data, Generic, TH.Lift) instance NFData TimeOfDay where rnf (TimeOfDay h m s) = rnf h `seq` rnf m `seq` rnf s `seq` ()@@ -126,3 +111,6 @@ -- | Get the fraction of a day since midnight given a time of day. timeOfDayToDayFraction :: TimeOfDay -> Rational timeOfDayToDayFraction tod = realToFrac (timeOfDayToTime tod) / realToFrac posixDayLength++diffTimeOfDay :: TimeOfDay -> TimeOfDay -> NominalDiffTime+diffTimeOfDay t1 t2 = realToFrac $ daysAndTimeOfDayToTime 0 t1 - daysAndTimeOfDayToTime 0 t2
lib/Data/Time/LocalTime/Internal/TimeZone.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE ForeignFunctionInterface #-} {-# LANGUAGE Safe #-} module Data.Time.LocalTime.Internal.TimeZone (@@ -10,20 +9,13 @@ minutesToTimeZone, hoursToTimeZone, utc,- -- getting the locale time zone- getTimeZone,- getCurrentTimeZone, ) where import Control.DeepSeq import Data.Data import Data.Time.Calendar.Private-import Data.Time.Clock.Internal.UTCTime-import Data.Time.Clock.POSIX-import Data.Time.Clock.System-import Foreign-import Foreign.C import GHC.Generics+import Language.Haskell.TH.Syntax qualified as TH -- | A TimeZone is a whole number of minutes offset from UTC, together with a name and a \"just for summer\" flag. data TimeZone = TimeZone@@ -34,7 +26,7 @@ , timeZoneName :: String -- ^ The name of the zone, typically a three- or four-letter acronym. }- deriving (Eq, Ord, Data, Typeable, Generic)+ deriving (Eq, Ord, Typeable, Data, Generic, TH.Lift) instance NFData TimeZone where rnf (TimeZone m so n) = rnf m `seq` rnf so `seq` rnf n `seq` ()@@ -79,81 +71,3 @@ -- | The UTC time zone. utc :: TimeZone utc = TimeZone 0 False "UTC"--{-# CFILES cbits/HsTime.c #-}-foreign import ccall unsafe "HsTime.h get_current_timezone_seconds"- get_current_timezone_seconds ::- CTime -> Ptr CInt -> Ptr CString -> IO CLong--getTimeZoneCTime :: CTime -> IO TimeZone-getTimeZoneCTime ctime =- with- 0- ( \pdst ->- with- nullPtr- ( \pcname -> do- secs <- get_current_timezone_seconds ctime pdst pcname- case secs of- 0x80000000 -> fail "localtime_r failed"- _ -> do- dst <- peek pdst- cname <- peek pcname- name <- peekCString cname- return (TimeZone (div (fromIntegral secs) 60) (dst == 1) name)- )- )---- there's no instance Bounded CTime, so this is the easiest way to check for overflow-toCTime :: Int64 -> IO CTime-toCTime t =- let- tt = fromIntegral t- t' = fromIntegral tt- in- if t' == t- then return $ CTime tt- else fail "Data.Time.LocalTime.Internal.TimeZone.toCTime: Overflow"---- | Get the configured time-zone for a given time (varying as per summertime adjustments).-getTimeZoneSystem :: SystemTime -> IO TimeZone-getTimeZoneSystem t = do- ctime <- toCTime $ systemSeconds t- getTimeZoneCTime ctime---- | Get the configured time-zone for a given time (varying as per summertime adjustments).------ On Unix systems the output of this function depends on:------ 1. The value of @TZ@ environment variable (if set)------ 2. The system time zone (usually configured by @\/etc\/localtime@ symlink)------ For details see tzset(3) and localtime(3).------ Example:------ @--- > let t = `UTCTime` (`Data.Time.Calendar.fromGregorian` 2021 7 1) 0--- > `getTimeZone` t--- CEST--- > `System.Environment.setEnv` \"TZ\" \"America/New_York\" >> `getTimeZone` t--- EDT--- > `System.Environment.setEnv` \"TZ\" \"Europe/Berlin\" >> `getTimeZone` t--- CEST--- @------ On Windows systems the output of this function depends on:------ 1. The value of @TZ@ environment variable (if set).--- See [here](https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/tzset) for how Windows interprets this variable.------ 2. The system time zone, configured in Settings-getTimeZone :: UTCTime -> IO TimeZone-getTimeZone t = do- ctime <- toCTime $ floor $ utcTimeToPOSIXSeconds t- getTimeZoneCTime ctime---- | Get the configured time-zone for the current time.-getCurrentTimeZone :: IO TimeZone-getCurrentTimeZone = getSystemTime >>= getTimeZoneSystem
lib/Data/Time/LocalTime/Internal/ZonedTime.hs view
@@ -2,21 +2,17 @@ {-# OPTIONS -fno-warn-orphans #-} -module Data.Time.LocalTime.Internal.ZonedTime (- ZonedTime (..),- utcToZonedTime,- zonedTimeToUTC,- getZonedTime,- utcToLocalZonedTime,-) where+module Data.Time.LocalTime.Internal.ZonedTime where import Control.DeepSeq import Data.Data import Data.Time.Clock.Internal.UTCTime import Data.Time.Clock.POSIX+import Data.Time.LocalTime.Internal.Foreign import Data.Time.LocalTime.Internal.LocalTime import Data.Time.LocalTime.Internal.TimeZone import GHC.Generics+import Language.Haskell.TH.Syntax qualified as TH -- | A local time together with a time zone. --@@ -27,7 +23,7 @@ { zonedTimeToLocalTime :: LocalTime , zonedTimeZone :: TimeZone }- deriving (Data, Typeable, Generic)+ deriving (Typeable, Data, Generic, TH.Lift) instance NFData ZonedTime where rnf (ZonedTime lt z) = rnf lt `seq` rnf z `seq` ()
lib/cbits/HsTime.c view
@@ -35,7 +35,7 @@ *pname = dst ? _tzname[1] : _tzname[0]; return - (dst ? _timezone - 3600 : _timezone); #else-# if HAVE_TZNAME+# if HAVE_TZNAME || defined(__MHS__) *pname = *tzname; # else # error "Don't know how to get timezone name on your OS"
lib/include/HsTime.h view
@@ -1,7 +1,7 @@ #ifndef __HSTIME_H__ #define __HSTIME_H__ -#if defined(_MSC_VER) || defined(__MINGW32__) || defined(_WIN32)+#if defined(_MSC_VER) || defined(__MINGW32__) || defined(_WIN32) || defined(__MHS__) #define HAVE_TIME_H 1 #else
+ test/ForeignCalls.hs view
@@ -0,0 +1,50 @@+module Main (main) where++import Control.Exception+import Control.Monad+import Data.Foldable+import Data.Monoid+import Data.Time+import Data.Time.Clock.POSIX+import Data.Time.Clock.System+import Data.Time.Clock.TAI+import Data.Traversable+import System.Exit+import System.IO++data Test = MkTest String (IO ())++tests :: [Test]+tests =+ [ MkTest "getCurrentTime" $ void $ getCurrentTime+ , MkTest "getZonedTime" $ void $ getZonedTime+ , MkTest "getCurrentTimeZone" $ void $ getCurrentTimeZone+ , MkTest "getTimeZone" $ void $ getCurrentTime >>= getTimeZone+ , MkTest "getPOSIXTime" $ void $ getPOSIXTime+ , MkTest "getSystemTime" $ void $ getSystemTime+ , MkTest "getTime_resolution" $ void $ evaluate getTime_resolution+ , MkTest "taiClock time" $ for_ taiClock $ \(_, getTime) -> void $ getTime+ , MkTest "taiClock resolution" $ for_ taiClock $ \(res, _) -> void $ evaluate res+ ]++runTest :: Test -> IO Bool+runTest (MkTest name action) = do+ hPutStr stderr $ name <> ": "+ result <- try action+ case result of+ Left err -> do+ hPutStrLn stderr $ "FAILED: " <> show (err :: SomeException)+ return False+ Right () -> do+ hPutStrLn stderr "PASSED"+ return True++main :: IO ()+main = do+ results <- for tests $ \test -> do+ passed <- runTest test+ return (Sum $ if passed then 1 else 0 :: Int, Sum 1)+ let+ (Sum i, Sum n) = mconcat results+ hPutStrLn stderr $ show i <> " out of " <> show n <> " tests passed"+ exitWith $ if i == n then ExitSuccess else ExitFailure 1
test/main/Main.hs view
@@ -15,7 +15,7 @@ import Test.Calendar.Week import Test.Calendar.Year import Test.Clock.Conversion-import Test.Clock.Lift (testLift)+import Test.Clock.Pattern import Test.Clock.Resolution import Test.Clock.TAI import Test.Format.Compile ()@@ -49,7 +49,7 @@ , testYear , testDuration ]- , testGroup "Clock" [testClockConversion, testResolutions, testTAI, testLift]+ , testGroup "Clock" [testClockPatterns, testClockConversion, testResolutions, testTAI] , testGroup "Format" [testFormat, testParseTime, testISO8601] , testGroup "LocalTime" [testTime, testTimeOfDay, testCalendarDiffTime] ]
test/main/Test/Arbitrary.hs view
@@ -1,6 +1,6 @@ {-# OPTIONS -fno-warn-orphans #-} -module Test.Arbitrary where+module Test.Arbitrary (supportedDayRange) where import Control.Monad import Data.Fixed@@ -23,14 +23,51 @@ deriving instance Show FirstWeekType +deriving instance Random Month++supportedMonthRange :: (Month, Month)+supportedMonthRange = (YearMonth (-9899) 1, YearMonth 9999 12)++shrinkYear :: Integer -> [Integer]+shrinkYear y =+ let+ yearShrink =+ if y > 2000+ then [pred y]+ else+ if y < 2000+ then [succ y]+ else []+ year10Shrink =+ if y > 2010+ then fmap (\i -> y - i) [1 .. 10]+ else+ if y < 1990+ then fmap (\i -> y + i) [1 .. 10]+ else []+ year100Shrink =+ if y > 2100+ then [y - 100]+ else+ if y < 1900+ then [y + 100]+ else []+ in+ year100Shrink <> year10Shrink <> yearShrink+ instance Arbitrary Month where- arbitrary = liftM MkMonth $ choose (-30000, 200000)+ arbitrary = choose supportedMonthRange instance Arbitrary Quarter where- arbitrary = liftM MkQuarter $ choose (-30000, 200000)+ arbitrary = fmap monthQuarter arbitrary+ shrink (YearQuarter y qoy) =+ fmap (\y' -> YearQuarter y' qoy) (shrinkYear y)+ <> fmap (YearQuarter y) (shrink qoy) instance Arbitrary QuarterOfYear where arbitrary = liftM toEnum $ choose (1, 4)+ shrink Q1 = []+ shrink _ = [Q1] deriving instance Random Day @@ -50,15 +87,8 @@ if m > 1 then [fromGregorian y (m - 1) d] else []- yearShrink =- if y > 2000- then [fromGregorian (y - 1) m d]- else- if y < 2000- then [fromGregorian (y + 1) m d]- else [] in- dayShrink ++ monthShrink ++ yearShrink+ dayShrink <> monthShrink <> fmap (\y' -> fromGregorian y' m d) (shrinkYear y) instance CoArbitrary Day where coarbitrary (ModifiedJulianDay d) = coarbitrary d
test/main/Test/Calendar/CalendarProps.hs view
@@ -21,4 +21,4 @@ YearQuarter y qy -> q == YearQuarter y qy testCalendarProps :: TestTree-testCalendarProps = nameTest "calender-props" [testYearMonth, testMonthDay, testYearQuarter]+testCalendarProps = nameTest "calendar-props" [testYearMonth, testMonthDay, testYearQuarter]
test/main/Test/Calendar/MonthDay.hs view
@@ -2,6 +2,8 @@ testMonthDay, ) where +import Data.Time.Calendar+import Data.Time.Calendar.Month import Data.Time.Calendar.MonthDay import Test.Calendar.MonthDayRef import Test.Tasty@@ -14,10 +16,23 @@ testMonthDay :: TestTree testMonthDay =- testCase "testMonthDay" $- assertEqual "" testMonthDayRef $- concat $- map (\isL -> unlines (leap isL : yearDays isL)) [False, True]+ testGroup+ "MonthDay"+ [ testCase "good" $+ assertEqual "" testMonthDayRef $+ concat $+ map (\isL -> unlines (leap isL : yearDays isL)) [False, True]+ , testGroup+ "clip"+ [ testCase "12" $ assertEqual "" (YearMonthDay 2005 05 12) (MonthDay (MkMonth 24064) 12)+ , testCase "1" $ assertEqual "" (YearMonthDay 2005 05 1) (MonthDay (MkMonth 24064) 1)+ , testCase "0" $ assertEqual "" (YearMonthDay 2005 05 1) (MonthDay (MkMonth 24064) 0)+ , testCase "-1" $ assertEqual "" (YearMonthDay 2005 05 1) (MonthDay (MkMonth 24064) (-1))+ , testCase "31" $ assertEqual "" (YearMonthDay 2005 05 31) (MonthDay (MkMonth 24064) 31)+ , testCase "32" $ assertEqual "" (YearMonthDay 2005 05 31) (MonthDay (MkMonth 24064) 32)+ , testCase "33" $ assertEqual "" (YearMonthDay 2005 05 31) (MonthDay (MkMonth 24064) 33)+ ]+ ] where leap isLeap = if isLeap
− test/main/Test/Clock/Lift.hs
@@ -1,18 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}--module Test.Clock.Lift (- testLift,-) where--import Data.Time.Clock-import qualified Language.Haskell.TH.Syntax as TH-import Test.Tasty-import Test.Tasty.HUnit--testLift :: TestTree-testLift =- testGroup- "Lift instances"- [ testCase "DiffTime" $ $$(TH.liftTyped (secondsToDiffTime 100)) @?= secondsToDiffTime 100- , testCase "NominalDiffTime" $ $$(TH.liftTyped (secondsToNominalDiffTime 100)) @?= secondsToNominalDiffTime 100- ]
+ test/main/Test/Clock/Pattern.hs view
@@ -0,0 +1,32 @@+module Test.Clock.Pattern (+ testClockPatterns,+) where++import Data.Time.Clock+import Test.Tasty+import Test.Tasty.HUnit++testClockPatterns :: TestTree+testClockPatterns =+ let+ testSame :: forall a. (Eq a, Show a) => TestName -> a -> a -> TestTree+ testSame name expected found = testCase name $ assertEqual "" expected found+ in+ testGroup "pattern" $+ [ testGroup+ "construct"+ [ testSame "Seconds" 52.4 (Seconds 52.4)+ , testSame "Seconds-Picoseconds" (Picoseconds 7_276_000_000_000) (Seconds 7.276)+ , testSame "Minutes-Seconds" (Seconds 210) (Minutes 3.5)+ , testSame "Hours-Minutes" (Minutes 120) (Hours 2)+ , testSame "Nominal" 37.4 (Nominal 37.4)+ ]+ , testGroup+ "deconstruct"+ [ testSame "Seconds" 52.4 ((\(Seconds x) -> x) 52.4)+ , testSame "Seconds-Picoseconds" 7.276 ((\(Seconds x) -> x) $ Picoseconds 7_276_000_000_000)+ , testSame "Minutes-Seconds" 3.5 ((\(Minutes x) -> x) $ Seconds 210)+ , testSame "Hours-Minutes" 2 ((\(Hours x) -> x) $ Minutes 120)+ , testSame "Nominal" 37.4 ((\(Nominal x) -> x) 37.4)+ ]+ ]
test/main/Test/Format/Compile.hs view
@@ -1,6 +1,4 @@ -- Tests succeed if module compiles-{-# LANGUAGE GeneralizedNewtypeDeriving #-}- module Test.Format.Compile ( ) where
test/main/Test/Format/Format.hs view
@@ -9,12 +9,12 @@ import Test.TestUtil -- as found in http://www.opengroup.org/onlinepubs/007908799/xsh/strftime.html--- plus FgGklz+-- plus FgGklvz -- f not supported -- P not always supported -- s time-zone dependent chars :: [Char]-chars = "aAbBcCdDeFgGhHIjklmMnprRStTuUVwWxXyYzZ%"+chars = "aAbBcCdDeFgGhHIjklmMnprRStTuUvVwWxXyYzZ%" -- as found in "man strftime" on a glibc system. '#' is different, though modifiers :: [Char]@@ -163,20 +163,20 @@ , testAFormat "%3ES" "01.245" (61.24582 :: DiffTime) ] -testCalenderDiffDays :: TestTree-testCalenderDiffDays =+testCalendarDiffDays :: TestTree+testCalendarDiffDays = testGroup- "CalenderDiffDays"+ "CalendarDiffDays" [ testAFormat "%yy%Bm%ww%Dd" "5y4m3w2d" $ CalendarDiffDays 64 23 , testAFormat "%bm %dd" "64m 23d" $ CalendarDiffDays 64 23 , testAFormat "%yy%Bm%ww%Dd" "-5y-4m-3w-2d" $ CalendarDiffDays (-64) (-23) , testAFormat "%bm %dd" "-64m -23d" $ CalendarDiffDays (-64) (-23) ] -testCalenderDiffTime :: TestTree-testCalenderDiffTime =+testCalendarDiffTime :: TestTree+testCalendarDiffTime = testGroup- "CalenderDiffTime"+ "CalendarDiffTime" [ testAFormat "%yy%Bm%ww%Dd%Hh%Mm%Ss" "5y4m3w2d2h22m8s" $ CalendarDiffTime 64 $ 23 * 86400 + 8528.21 , testAFormat "%yy%Bm%ww%Dd%Hh%Mm%ESs" "5y4m3w2d2h22m8.21s" $ CalendarDiffTime 64 $ 23 * 86400 + 8528.21 , testAFormat "%yy%Bm%ww%Dd%Hh%Mm%0ESs" "5y4m3w2d2h22m08.210000000000s" $@@ -207,6 +207,6 @@ , testTimeZone , testNominalDiffTime , testDiffTime- , testCalenderDiffDays- , testCalenderDiffTime+ , testCalendarDiffDays+ , testCalendarDiffTime ]
test/main/Test/Format/ISO8601.hs view
@@ -4,10 +4,10 @@ testISO8601, ) where +import Data.Coerce import Data.Ratio import Data.Time import Data.Time.Format.ISO8601-import Data.Time.Format.Internal import Test.Arbitrary () import Test.QuickCheck.Property import Test.Tasty@@ -33,32 +33,45 @@ else failed{reason = show str ++ ": expected " ++ (show expected) ++ ", found " ++ (show found)} class SpecialTestValues a where+ testGen :: Gen a+ default testGen :: Arbitrary a => Gen a+ testGen = arbitrary+ -- | values that should always be tested specialTestValues :: [a]--instance {-# OVERLAPPABLE #-} SpecialTestValues a where specialTestValues = [] +instance {-# OVERLAPPABLE #-} Arbitrary a => SpecialTestValues a+ instance SpecialTestValues TimeOfDay where specialTestValues = [TimeOfDay 0 0 0, TimeOfDay 0 0 60, TimeOfDay 1 0 60, TimeOfDay 24 0 0] -readShowTestCheck :: (Eq a, Show a, Arbitrary a, SpecialTestValues a) => (a -> Bool) -> Format a -> [TestTree]-readShowTestCheck skip fmt = [nameTest "random" $ readShowProperty skip fmt, nameTest "special" $ fmap (\a -> nameTest (show a) $ readShowProperty skip fmt a) $ filter (not . skip) specialTestValues]+instance SpecialTestValues (Integer, Int) where+ testGen = do+ Small y <- arbitrary+ woy <- choose (-10, 120)+ pure (y, woy) -readShowTest :: (Eq a, Show a, Arbitrary a, SpecialTestValues a) => Format a -> [TestTree]+readShowTestCheck :: (Eq a, Show a, SpecialTestValues a) => (a -> Bool) -> Format a -> [TestTree]+readShowTestCheck skip fmt =+ [ nameTest "random" $ fmap (readShowProperty skip fmt) testGen+ , nameTest "special" $ fmap (\a -> nameTest (show a) $ readShowProperty skip fmt a) $ filter (not . skip) specialTestValues+ ]++readShowTest :: (Eq a, Show a, SpecialTestValues a) => Format a -> [TestTree] readShowTest = readShowTestCheck $ \_ -> False readBoth :: NameTest t => (FormatExtension -> t) -> [TestTree] readBoth fmts = [nameTest "extended" $ fmts ExtendedFormat, nameTest "basic" $ fmts BasicFormat] -readShowTestsCheck :: (Eq a, Show a, Arbitrary a, SpecialTestValues a) => (a -> Bool) -> (FormatExtension -> Format a) -> [TestTree]+readShowTestsCheck :: (Eq a, Show a, SpecialTestValues a) => (a -> Bool) -> (FormatExtension -> Format a) -> [TestTree] readShowTestsCheck skip fmts = readBoth $ \fe -> readShowTestCheck skip $ fmts fe -readShowTests :: (Eq a, Show a, Arbitrary a, SpecialTestValues a) => (FormatExtension -> Format a) -> [TestTree]+readShowTests :: (Eq a, Show a, SpecialTestValues a) => (FormatExtension -> Format a) -> [TestTree] readShowTests = readShowTestsCheck $ \_ -> False -newtype Durational t = MkDurational {unDurational :: t}- deriving (Eq)+newtype Durational t = MkDurational t+ deriving Eq instance Show t => Show (Durational t) where show (MkDurational t) = show t@@ -81,59 +94,60 @@ return $ MkDurational $ CalendarDiffTime mm $ fromRational $ ss % picofactor durationalFormat :: Format a -> Format (Durational a)-durationalFormat (MkFormat sa ra) = MkFormat (\b -> sa $ unDurational b) (fmap MkDurational ra)+durationalFormat = coerce testReadShowFormat :: TestTree testReadShowFormat =- nameTest- "read-show format"- [ nameTest "calendarFormat" $ readShowTests $ calendarFormat- , nameTest "yearMonthFormat" $ readShowTest $ yearMonthFormat- , nameTest "yearFormat" $ readShowTest $ yearFormat- , nameTest "centuryFormat" $ readShowTest $ centuryFormat- , nameTest "expandedCalendarFormat" $ readShowTests $ expandedCalendarFormat 6- , nameTest "expandedYearMonthFormat" $ readShowTest $ expandedYearMonthFormat 6- , nameTest "expandedYearFormat" $ readShowTest $ expandedYearFormat 6- , nameTest "expandedCenturyFormat" $ readShowTest $ expandedCenturyFormat 4- , nameTest "ordinalDateFormat" $ readShowTests $ ordinalDateFormat- , nameTest "expandedOrdinalDateFormat" $ readShowTests $ expandedOrdinalDateFormat 6- , nameTest "weekDateFormat" $ readShowTests $ weekDateFormat- , nameTest "yearWeekFormat" $ readShowTests $ yearWeekFormat- , nameTest "expandedWeekDateFormat" $ readShowTests $ expandedWeekDateFormat 6- , nameTest "expandedYearWeekFormat" $ readShowTests $ expandedYearWeekFormat 6- , nameTest "timeOfDayFormat" $ readShowTests $ timeOfDayFormat- , nameTest "hourMinuteFormat" $ readShowTestsCheck (\(TimeOfDay _ _ s) -> s >= 60) $ hourMinuteFormat- , nameTest "hourFormat" $ readShowTestCheck (\(TimeOfDay _ _ s) -> s >= 60) $ hourFormat- , nameTest "withTimeDesignator" $ readShowTests $ \fe -> withTimeDesignator $ timeOfDayFormat fe- , nameTest "withUTCDesignator" $ readShowTests $ \fe -> withUTCDesignator $ timeOfDayFormat fe- , nameTest "timeOffsetFormat" $ readShowTests $ timeOffsetFormat- , nameTest "timeOfDayAndOffsetFormat" $ readShowTests $ timeOfDayAndOffsetFormat- , nameTest "localTimeFormat" $- readShowTests $- \fe -> localTimeFormat (calendarFormat fe) (timeOfDayFormat fe)- , nameTest "zonedTimeFormat" $- readShowTests $- \fe -> zonedTimeFormat (calendarFormat fe) (timeOfDayFormat fe) fe- , nameTest "utcTimeFormat" $ readShowTests $ \fe -> utcTimeFormat (calendarFormat fe) (timeOfDayFormat fe)- , nameTest "dayAndTimeFormat" $- readShowTests $- \fe -> dayAndTimeFormat (calendarFormat fe) (timeOfDayFormat fe)- , nameTest "timeAndOffsetFormat" $ readShowTests $ \fe -> timeAndOffsetFormat (timeOfDayFormat fe) fe- , nameTest "durationDaysFormat" $ readShowTest $ durationDaysFormat- , nameTest "durationTimeFormat" $ readShowTest $ durationTimeFormat- , nameTest "alternativeDurationDaysFormat" $- readBoth $- \fe -> readShowTest (durationalFormat $ alternativeDurationDaysFormat fe)- , nameTest "alternativeDurationTimeFormat" $- readBoth $- \fe -> readShowTest (durationalFormat $ alternativeDurationTimeFormat fe)- , nameTest "intervalFormat" $- readShowTests $ \fe ->- intervalFormat (localTimeFormat (calendarFormat fe) (timeOfDayFormat fe)) durationTimeFormat- , nameTest "recurringIntervalFormat" $- readShowTests $ \fe ->- recurringIntervalFormat (localTimeFormat (calendarFormat fe) (timeOfDayFormat fe)) durationTimeFormat- ]+ localOption (QuickCheckTests 1000) $+ nameTest+ "read-show format"+ [ nameTest "calendarFormat" $ readShowTests $ calendarFormat+ , nameTest "yearMonthFormat" $ readShowTest $ yearMonthFormat+ , nameTest "yearFormat" $ readShowTest $ yearFormat+ , nameTest "centuryFormat" $ readShowTest $ centuryFormat+ , nameTest "expandedCalendarFormat" $ readShowTests $ expandedCalendarFormat 6+ , nameTest "expandedYearMonthFormat" $ readShowTest $ expandedYearMonthFormat 6+ , nameTest "expandedYearFormat" $ readShowTest $ expandedYearFormat 6+ , nameTest "expandedCenturyFormat" $ readShowTest $ expandedCenturyFormat 4+ , nameTest "ordinalDateFormat" $ readShowTests $ ordinalDateFormat+ , nameTest "expandedOrdinalDateFormat" $ readShowTests $ expandedOrdinalDateFormat 6+ , nameTest "weekDateFormat" $ readShowTests $ weekDateFormat+ , nameTest "yearWeekFormat" $ readShowTests $ yearWeekFormat+ , nameTest "expandedWeekDateFormat" $ readShowTests $ expandedWeekDateFormat 6+ , nameTest "expandedYearWeekFormat" $ readShowTests $ expandedYearWeekFormat 6+ , nameTest "timeOfDayFormat" $ readShowTests $ timeOfDayFormat+ , nameTest "hourMinuteFormat" $ readShowTestsCheck (\(TimeOfDay _ _ s) -> s >= 60) $ hourMinuteFormat+ , nameTest "hourFormat" $ readShowTestCheck (\(TimeOfDay _ _ s) -> s >= 60) $ hourFormat+ , nameTest "withTimeDesignator" $ readShowTests $ \fe -> withTimeDesignator $ timeOfDayFormat fe+ , nameTest "withUTCDesignator" $ readShowTests $ \fe -> withUTCDesignator $ timeOfDayFormat fe+ , nameTest "timeOffsetFormat" $ readShowTests $ timeOffsetFormat+ , nameTest "timeOfDayAndOffsetFormat" $ readShowTests $ timeOfDayAndOffsetFormat+ , nameTest "localTimeFormat" $+ readShowTests $+ \fe -> localTimeFormat (calendarFormat fe) (timeOfDayFormat fe)+ , nameTest "zonedTimeFormat" $+ readShowTests $+ \fe -> zonedTimeFormat (calendarFormat fe) (timeOfDayFormat fe) fe+ , nameTest "utcTimeFormat" $ readShowTests $ \fe -> utcTimeFormat (calendarFormat fe) (timeOfDayFormat fe)+ , nameTest "dayAndTimeFormat" $+ readShowTests $+ \fe -> dayAndTimeFormat (calendarFormat fe) (timeOfDayFormat fe)+ , nameTest "timeAndOffsetFormat" $ readShowTests $ \fe -> timeAndOffsetFormat (timeOfDayFormat fe) fe+ , nameTest "durationDaysFormat" $ readShowTest $ durationDaysFormat+ , nameTest "durationTimeFormat" $ readShowTest $ durationTimeFormat+ , nameTest "alternativeDurationDaysFormat" $+ readBoth $+ \fe -> readShowTest (durationalFormat $ alternativeDurationDaysFormat fe)+ , nameTest "alternativeDurationTimeFormat" $+ readBoth $+ \fe -> readShowTest (durationalFormat $ alternativeDurationTimeFormat fe)+ , nameTest "intervalFormat" $+ readShowTests $ \fe ->+ intervalFormat (localTimeFormat (calendarFormat fe) (timeOfDayFormat fe)) durationTimeFormat+ , nameTest "recurringIntervalFormat" $+ readShowTests $ \fe ->+ recurringIntervalFormat (localTimeFormat (calendarFormat fe) (timeOfDayFormat fe)) durationTimeFormat+ ] testShowReadFormat :: (Show t, Eq t) => String -> Format t -> String -> t -> TestTree testShowReadFormat name fmt str val =@@ -281,6 +295,16 @@ iso8601Format "2024-07-06T08:45:56.553+06" (ZonedTime (LocalTime (fromGregorian 2024 07 06) (TimeOfDay 8 45 56.553)) (minutesToTimeZone 360))+ , testReadFormat+ "zonedTimeFormat"+ iso8601Format+ "2024-05-30T16:15:18Z"+ (ZonedTime (LocalTime (fromGregorian 2024 05 30) (TimeOfDay 16 15 18)) utc)+ , testReadFormat+ "zonedTimeFormat"+ iso8601Format+ "2024-05-30T16:15:18"+ (ZonedTime (LocalTime (fromGregorian 2024 05 30) (TimeOfDay 16 15 18)) utc) , testShowReadFormat "utcTimeFormat" iso8601Format@@ -290,6 +314,11 @@ "utcTimeFormat" iso8601Format "2028-12-31T23:59:60.9Z"+ (UTCTime (fromGregorian 2028 12 31) (timeOfDayToTime $ TimeOfDay 23 59 60.9))+ , testReadFormat+ "utcTimeFormat"+ iso8601Format+ "2028-12-31T23:59:60.9" (UTCTime (fromGregorian 2028 12 31) (timeOfDayToTime $ TimeOfDay 23 59 60.9)) , testShowReadFormat "weekDateFormat" (weekDateFormat ExtendedFormat) "1994-W52-7" (fromGregorian 1995 1 1) , testShowReadFormat "weekDateFormat" (weekDateFormat ExtendedFormat) "1995-W01-1" (fromGregorian 1995 1 2)
test/main/Test/Format/ParseTime.hs view
@@ -480,6 +480,18 @@ instance HasFormatCodes TimeOfDay where allFormatCodes _ = [(False, s) | s <- "RTXrPpHkIlMSqQ"] +instance HasFormatCodes DayOfWeek where+ allFormatCodes _ = [(False, s) | s <- "uwaA"]++instance HasFormatCodes Month where+ allFormatCodes _ = [(False, s) | s <- "YyCBbhm"]++instance HasFormatCodes QuarterOfYear where+ allFormatCodes _ = [(False, s) | s <- "v"]++instance HasFormatCodes Quarter where+ allFormatCodes _ = allFormatCodes (Proxy :: Proxy QuarterOfYear) ++ [(False, s) | s <- "YyC"]+ instance HasFormatCodes LocalTime where allFormatCodes _ = allFormatCodes (Proxy :: Proxy Day) ++ allFormatCodes (Proxy :: Proxy TimeOfDay) @@ -542,6 +554,7 @@ typedTests prop = [ nameTest "Day" $ tgroup dayFormats prop , nameTest "Month" $ tgroup monthFormats prop+ , nameTest "Quarter" $ tgroup quarterFormats prop , nameTest "TimeOfDay" $ tgroup timeOfDayFormats prop , nameTest "LocalTime" $ tgroup localTimeFormats prop , nameTest "TimeZone" $ tgroup timeZoneFormats prop@@ -552,7 +565,7 @@ , nameTest "UTCTime" $ tgroup utcTimeAlmostFormats $ \fmt t -> utctDayTime t < 86400 ==> prop fmt t , nameTest "UniversalTime" $ tgroup universalTimeFormats prop , nameTest "CalendarDiffDays" $ tgroup calendarDiffDaysFormats prop- , nameTest "CalenderDiffTime" $ tgroup calendarDiffTimeFormats prop+ , nameTest "CalendarDiffTime" $ tgroup calendarDiffTimeFormats prop , nameTest "DiffTime" $ tgroup diffTimeFormats prop , nameTest "NominalDiffTime" $ tgroup nominalDiffTimeFormats prop ]@@ -563,6 +576,10 @@ allTypes f = [ f "Day" (Proxy :: Proxy Day) , f "TimeOfDay" (Proxy :: Proxy TimeOfDay)+ , f "DayOfWeek" (Proxy :: Proxy DayOfWeek)+ , f "Month" (Proxy :: Proxy Month)+ , f "QuarterOfYear" (Proxy :: Proxy QuarterOfYear)+ , f "Quarter" (Proxy :: Proxy Quarter) , f "LocalTime" (Proxy :: Proxy LocalTime) , f "TimeZone" (Proxy :: Proxy TimeZone) , f "ZonedTime" (Proxy :: Proxy ZonedTime)@@ -605,6 +622,85 @@ parseEmptyTests :: TestTree parseEmptyTests = nameTest "parse empty" $ allTypes $ \name p -> nameTest name $ parseEmptyTest p +class (Eq a, Show a, ParseTime a) => TestParse a where+ nonPosixValue :: a -> Bool+ nonPosixValue _ = False++instance TestParse UTCTime where+ nonPosixValue (UTCTime _ dt) = dt >= 86400 || dt < 0++instance TestParse ZonedTime where+ nonPosixValue (ZonedTime t _) = nonPosixValue t++instance TestParse TimeZone++instance TestParse LocalTime where+ nonPosixValue (LocalTime _ t) = nonPosixValue t++instance TestParse Day++instance TestParse Month++instance TestParse DayOfWeek++instance TestParse TimeOfDay where+ nonPosixValue (TimeOfDay _ _ s) = s >= 60 || s < 0++prop_parse_s :: forall a. TestParse a => (UTCTime -> a) -> UTCTime -> Result+prop_parse_s f t =+ if nonPosixValue t+ then succeeded+ else+ let+ str = format "%s%Q" t+ found = parse False "%s%Q" str+ expected = f t+ in+ compareResult (Just expected) found++prop_parse_sz :: forall a. TestParse a => (ZonedTime -> a) -> ZonedTime -> Result+prop_parse_sz f t =+ if nonPosixValue t+ then succeeded+ else+ let+ str = format "%s%Q %z" t+ found = parse False "%s%Q %z" str+ expected = f t+ in+ compareResult (Just expected) found++zeroTimeZone :: TimeZone+zeroTimeZone = TimeZone 0 False ""++parse_s_tests :: TestTree+parse_s_tests =+ nameTest+ "parse_s"+ [ nameTest "UTCTime" $ prop_parse_s @UTCTime id+ , nameTest "ZonedTime" $ prop_parse_s @ZonedTime $ utcToZonedTime zeroTimeZone+ , nameTest "TimeZone" $ prop_parse_s @TimeZone $ \_ -> zeroTimeZone+ , nameTest "LocalTime" $ prop_parse_s @LocalTime $ utcToLocalTime zeroTimeZone+ , nameTest "Day" $ prop_parse_s @Day utctDay+ , nameTest "Month" $ prop_parse_s @Month $ (\(MonthDay m _) -> m) . utctDay+ , nameTest "DayOfWeek" $ prop_parse_s @DayOfWeek $ dayOfWeek . utctDay+ , nameTest "TimeOfDay" $ prop_parse_s @TimeOfDay $ localTimeOfDay . utcToLocalTime zeroTimeZone+ ]++parse_sz_tests :: TestTree+parse_sz_tests =+ nameTest+ "parse_sz"+ [ nameTest "UTCTime" $ prop_parse_sz @UTCTime zonedTimeToUTC+ , nameTest "ZonedTime" $ prop_parse_sz @ZonedTime id+ , nameTest "TimeZone" $ prop_parse_sz @TimeZone zonedTimeZone+ , nameTest "LocalTime" $ prop_parse_sz @LocalTime zonedTimeToLocalTime+ , nameTest "Day" $ prop_parse_sz @Day $ localDay . zonedTimeToLocalTime+ , nameTest "Month" $ prop_parse_sz @Month $ (\(MonthDay m _) -> m) . localDay . zonedTimeToLocalTime+ , nameTest "DayOfWeek" $ prop_parse_sz @DayOfWeek $ dayOfWeek . localDay . zonedTimeToLocalTime+ , nameTest "TimeOfDay" $ prop_parse_sz @TimeOfDay $ localTimeOfDay . zonedTimeToLocalTime+ ]+ formatParseFormatTests :: TestTree formatParseFormatTests = nameTest@@ -680,6 +776,8 @@ , nameTest "parse_format_lower" $ typedTests prop_parse_format_lower , nameTest "parse_format_upper" $ typedTests prop_parse_format_upper , parseEmptyTests+ , parse_s_tests+ , parse_sz_tests , formatParseFormatTests , badInputTests ]@@ -752,6 +850,22 @@ , "%C-%y-%B" , "%C-%y-%b" , "%C-%y-%h"+ ]++quarterFormats :: [FormatString Quarter]+quarterFormats =+ map+ FormatString+ -- numeric year, quarter+ [ "%Y-%v"+ , "%Y-Q%v"+ , "%YQ%v"+ , "%C%y%v"+ , "%Y %v"+ , "%v/%Y"+ , "%v/%Y"+ , "%Y/%vm"+ , "%C %y %v" ] timeOfDayFormats :: [FormatString TimeOfDay]
test/main/Test/TestUtil.hs view
@@ -32,5 +32,8 @@ instance (Arbitrary a, Show a, Testable b) => NameTest (a -> b) where nameTest name = nameTest name . property +instance Testable a => NameTest (Gen a) where+ nameTest name = nameTest name . property+ tgroup :: (Show a, NameTest t) => [a] -> (a -> t) -> [TestTree] tgroup aa f = fmap (\a -> nameTest (show a) $ f a) aa
+ test/template/Main.hs view
@@ -0,0 +1,24 @@+module Main (main) where++import Data.Time.Clock+import Language.Haskell.TH.Syntax qualified as TH+import Test.Tasty+import Test.Tasty.HUnit++testLift :: TestTree+testLift =+ testGroup+ "Lift instances"+ [ testCase "DiffTime" $ $$(TH.liftTyped (secondsToDiffTime 100)) @?= secondsToDiffTime 100+ , testCase "NominalDiffTime" $ $$(TH.liftTyped (secondsToNominalDiffTime 100)) @?= secondsToNominalDiffTime 100+ ]++tests :: TestTree+tests =+ testGroup+ "time-template"+ [ testLift+ ]++main :: IO ()+main = defaultMain tests
test/unix/Test/Format/Format.hs view
@@ -150,9 +150,14 @@ isPadChar _ = False unixWorkarounds _ s = s +lastM :: [a] -> Maybe a+lastM [] = Nothing+lastM [a] = Just a+lastM (_ : aa) = lastM aa+ compareFormat :: (String -> String) -> String -> TimeZone -> UTCTime -> Result compareFormat _modUnix fmt zone _time- | last fmt == 'Z' && timeZoneName zone == "" = rejected+ | lastM fmt == Just 'Z' && timeZoneName zone == "" = rejected compareFormat modUnix fmt zone time = let ctime = utcToZonedTime zone time
time.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: time-version: 1.14+version: 1.15 stability: stable license: BSD-2-Clause license-file: LICENSE@@ -13,9 +13,9 @@ category: Time build-type: Configure tested-with:- GHC == 9.4.8,- GHC == 9.6.4,- GHC == 9.8.2+ GHC == 9.8.4,+ GHC == 9.10.2,+ GHC == 9.12.2 x-follows-version-policy: extra-source-files:@@ -40,21 +40,22 @@ library hs-source-dirs: lib- default-language: Haskell2010+ default-language: GHC2021 default-extensions:- Rank2Types- DeriveDataTypeable- DeriveLift- DeriveGeneric- StandaloneDeriving+ NoGeneralizedNewtypeDeriving+ LambdaCase PatternSynonyms ViewPatterns- ghc-options: -Wall -fwarn-tabs+ ghc-options:+ -Wall+ -fwarn-tabs+ -Wno-deriving-typeable c-sources: lib/cbits/HsTime.c build-depends:- base >= 4.14 && < 5,+ base >= 4.19 && < 5, deepseq >= 1.1,- template-haskell >= 2.16,+ if impl(ghc)+ build-depends: template-haskell >= 2.17, if os(windows) build-depends: Win32 exposed-modules:@@ -72,7 +73,6 @@ Data.Time.Clock.TAI, Data.Time.LocalTime, Data.Time.Format,- Data.Time.Format.Internal, Data.Time.Format.ISO8601, Data.Time other-modules:@@ -84,6 +84,7 @@ Data.Time.Calendar.Private, Data.Time.Calendar.Types, Data.Time.Calendar.Week,+ Data.Time.Format.Internal, Data.Time.Clock.Internal.DiffTime, Data.Time.Clock.Internal.AbsoluteTime, Data.Time.Clock.Internal.NominalDiffTime,@@ -92,8 +93,8 @@ Data.Time.Clock.Internal.SystemTime, Data.Time.Clock.Internal.UTCTime, Data.Time.Clock.Internal.CTimeval,- Data.Time.Clock.Internal.CTimespec, Data.Time.Clock.Internal.UTCDiff,+ Data.Time.LocalTime.Internal.Foreign, Data.Time.LocalTime.Internal.TimeZone, Data.Time.LocalTime.Internal.TimeOfDay, Data.Time.LocalTime.Internal.CalendarDiffTime,@@ -105,6 +106,9 @@ Data.Time.Format.Format.Instances, Data.Time.Format.Parse.Class, Data.Time.Format.Parse.Instances+ if !impl(mhs)+ other-modules:+ Data.Time.Clock.Internal.CTimespec include-dirs: lib/include if os(windows) install-includes:@@ -119,7 +123,7 @@ test-suite ShowDefaultTZAbbreviations type: exitcode-stdio-1.0 hs-source-dirs: test- default-language: Haskell2010+ default-language: GHC2021 ghc-options: -Wall -fwarn-tabs build-depends: base,@@ -129,32 +133,39 @@ test-suite ShowTime type: exitcode-stdio-1.0 hs-source-dirs: test- default-language: Haskell2010+ default-language: GHC2021 ghc-options: -Wall -fwarn-tabs build-depends: base, time main-is: ShowTime.hs +test-suite ForeignCalls+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ default-language: GHC2021+ ghc-options: -Wall -fwarn-tabs+ build-depends:+ base,+ time+ main-is: ForeignCalls.hs+ test-suite test-main+ if arch (javascript)+ -- blocked by splitmix+ -- https://github.com/haskellari/splitmix/issues/93+ buildable: False type: exitcode-stdio-1.0 hs-source-dirs: test/main- default-language: Haskell2010+ default-language: GHC2021 default-extensions:- Rank2Types- TypeApplications- GeneralizedNewtypeDeriving- DeriveDataTypeable- StandaloneDeriving+ DefaultSignatures DerivingStrategies- ExistentialQuantification- MultiParamTypeClasses- FlexibleInstances- UndecidableInstances- ScopedTypeVariables- TupleSections RecordWildCards+ UndecidableInstances ghc-options: -Wall -fwarn-tabs+ if !arch (wasm32)+ ghc-options: -threaded -rtsopts -with-rtsopts=-N build-depends: base, deepseq,@@ -191,7 +202,7 @@ Test.Calendar.Week Test.Calendar.Year Test.Clock.Conversion- Test.Clock.Lift+ Test.Clock.Pattern Test.Clock.Resolution Test.Clock.TAI Test.Format.Compile@@ -203,22 +214,41 @@ Test.LocalTime.TimeOfDay Test.LocalTime.TimeRef +test-suite test-template+ if arch (wasm32)+ buildable: False+ type: exitcode-stdio-1.0+ hs-source-dirs: test/template+ default-language: GHC2021+ default-extensions:+ DerivingStrategies+ UndecidableInstances+ RecordWildCards+ TemplateHaskell+ ghc-options: -Wall -fwarn-tabs+ build-depends:+ base,+ deepseq,+ time,+ random,+ QuickCheck,+ tasty,+ tasty-hunit,+ tasty-quickcheck,+ template-haskell+ main-is: Main.hs+ test-suite test-unix- if os(windows)+ if os(windows) || arch (javascript) || arch (wasm32) buildable: False type: exitcode-stdio-1.0 hs-source-dirs: test/unix- default-language: Haskell2010+ default-language: GHC2021 default-extensions:- Rank2Types- DeriveDataTypeable- StandaloneDeriving- ExistentialQuantification- MultiParamTypeClasses- FlexibleInstances UndecidableInstances- ScopedTypeVariables ghc-options: -Wall -fwarn-tabs+ if !arch (wasm32)+ ghc-options: -threaded -rtsopts -with-rtsopts=-N c-sources: test/unix/Test/Format/FormatStuff.c build-depends: base,@@ -238,7 +268,7 @@ benchmark time-bench type: exitcode-stdio-1.0 hs-source-dirs: benchmark- default-language: Haskell2010+ default-language: GHC2021 ghc-options: -Wall -fwarn-tabs build-depends: base,