packages feed

lens-datetime 0.1.1 → 0.2

raw patch · 2 files changed

+143/−68 lines, 2 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Data.Time.Lens: data FlexTime
- Data.Time.Lens: dateFlex :: Dateable a => Lens' a FlexDate
- Data.Time.Lens: day :: Dateable d => Lens' d Int
- Data.Time.Lens: hour :: Timeable t => Lens' t Int
- Data.Time.Lens: instance Dateable FlexTime
- Data.Time.Lens: minute :: Timeable t => Lens' t Int
- Data.Time.Lens: month :: Dateable d => Lens' d Int
- Data.Time.Lens: second :: Timeable t => Lens' t Pico
- Data.Time.Lens: year :: Dateable d => Lens' d Integer
+ Data.Time.Lens: FlexDateTime :: FlexDate -> TimeOfDay -> FlexDateTime
+ Data.Time.Lens: _dateFlex :: Dateable a => Lens' a FlexDate
+ Data.Time.Lens: class FlexibleDate a
+ Data.Time.Lens: class FlexibleTime a
+ Data.Time.Lens: data FlexDateTime
+ Data.Time.Lens: days :: Dateable d => Lens' d Int
+ Data.Time.Lens: flexD :: FlexibleDate a => Lens' a FlexDate
+ Data.Time.Lens: flexT :: FlexibleTime a => Lens' a FlexTime
+ Data.Time.Lens: hours :: Timeable t => Lens' t Int
+ Data.Time.Lens: instance Dateable FlexDateTime
+ Data.Time.Lens: instance FlexibleDate Day
+ Data.Time.Lens: instance FlexibleTime TimeOfDay
+ Data.Time.Lens: instance Show FlexDateTime
+ Data.Time.Lens: instance Timeable FlexDateTime
+ Data.Time.Lens: julianDT :: Iso' LocalTime Rational
+ Data.Time.Lens: minutes :: Timeable t => Lens' t Int
+ Data.Time.Lens: months :: Dateable d => Lens' d Int
+ Data.Time.Lens: newtype FlexTime
+ Data.Time.Lens: seconds :: Timeable t => Lens' t Pico
+ Data.Time.Lens: years :: Dateable d => Lens' d Integer
- Data.Time.Lens: FlexTime :: FlexDate -> TimeOfDay -> FlexTime
+ Data.Time.Lens: FlexTime :: TimeOfDay -> FlexTime
- Data.Time.Lens: class Dateable a where date = dateFlex . from gregorianUnflex dateFlex = date . gregorianUnflex
+ Data.Time.Lens: class Dateable a where date = _dateFlex . from gregorianUnflex _dateFlex = date . gregorianUnflex
- Data.Time.Lens: flexDT :: FlexibleDateTime a => Lens' a FlexTime
+ Data.Time.Lens: flexDT :: FlexibleDateTime a => Lens' a FlexDateTime
- Data.Time.Lens: flexDate :: FlexTime -> FlexDate
+ Data.Time.Lens: flexDate :: FlexDateTime -> FlexDate
- Data.Time.Lens: flexTOD :: FlexTime -> TimeOfDay
+ Data.Time.Lens: flexTOD :: FlexDateTime -> TimeOfDay

Files

Data/Time/Lens.hs view
@@ -8,8 +8,8 @@  /Usage:/ -Basic interface consists of the following six lenses: 'year',-'month', 'day', 'hour', 'minute' and 'second' with which you can+Basic interface consists of the following six lenses: 'years',+'months', 'days', 'hours', 'minutes' and 'seconds' with which you can access the corresponding \"fields\" of 'LocalTime' and 'UTCTime' in a unified way. Also, use 'date' and 'time' if you want to access the 'Day' and 'TimeOfDay' parts as a whole.@@ -32,17 +32,17 @@  Then you can use the above lenses as follows: ->>> aLocal ^. year+>>> aLocal ^. years 2013->>> aUTC ^. month+>>> aUTC ^. months 8->>> aDay ^. day+>>> aDay ^. days 22 >>> aLocal & time .~ midnight 2013-08-22 00:00:00->>> aUTC & day .~ 1 & month .~ 1+>>> aUTC & days .~ 1 & months .~ 1 2013-01-01 02:04:18.9 UTC->>> aLocal & hour +~ 1            -- But see the note below!+>>> aLocal & hours +~ 1            -- But see the note below! 2013-08-22 14:45:28  @@ -50,21 +50,21 @@  For 'LocalTime' and 'UTCTime' these lenses provide the most straightforward implementation: via 'toGregorian'/'fromGregorian'-in the case of 'year', 'month' and 'day'; and directly to the-fields of 'TimeOfDay' in the case of 'hour', 'minute' and 'second'.+in the case of 'years', 'months' and 'days'; and directly to the+fields of 'TimeOfDay' in the case of 'hours', 'minutes' and 'seconds'.  Which means, on one hand, that the date \"parts\" will be clipped to valid values: ->>> aLocal & month +~ 12+>>> aLocal & months +~ 12 2013-12-22 13:45:28        -- instead of: 2014-08-22 13:45:28->>> aUTC & day +~ 100+>>> aUTC & days +~ 100 2013-08-31 02:04:18.9 UTC  -- instead of: 2013-11-30 02:04:18.9 UTC  And on the other hand, that the time \"parts\" will not roll over and produce invalid values: ->>> aLocal & minute +~ 120+>>> aLocal & minutes +~ 120 2013-08-22 13:165:28       -- instead of: 2013-08-22 15:45:28  Also, this means that the date lenses are not proper lenses: they@@ -76,17 +76,17 @@ value. Instead use the 'FlexibleDateTime' mechanism and the 'flexDT' isomorphism, which correctly rolls over: ->>> aLocal & flexDT.month +~ 12+>>> aLocal & flexDT.months +~ 12 2014-08-22 13:45:28->>> aUTC & flexDT.day +~ 100+>>> aUTC & flexDT.days +~ 100 2013-11-30 02:04:18.9 UTC->>> aLocal & flexDT.minute +~ 120+>>> aLocal & flexDT.minutes +~ 120 2013-08-22 15:45:28  If you need to set multiple fields try to make only one round-trip via flexDT: ->>> aLocal & flexDT %~ ((day +~ 7) . (hour +~ 2))+>>> aLocal & flexDT %~ ((days +~ 7) . (hours +~ 2)) 2013-08-22 13:45:28  Note that even with 'flexDT' we completely ignore all the issues@@ -108,9 +108,9 @@ >        print (tz, t ^. utcInTZ tz) > >  printInLocal baseT->  printInLocal $ baseT & flexDT %~ ((day +~ 1) . (hour +~ 0) . (minute +~ 5))->  printInLocal $ baseT & flexDT %~ ((day +~ 1) . (hour +~ 1) . (minute +~ 5))->  printInLocal $ baseT & flexDT %~ ((day +~ 1) . (hour +~ 2) . (minute +~ 5))+>  printInLocal $ baseT & flexDT %~ ((days +~ 1) . (hours +~ 0) . (minutes +~ 5))+>  printInLocal $ baseT & flexDT %~ ((days +~ 1) . (hours +~ 1) . (minutes +~ 5))+>  printInLocal $ baseT & flexDT %~ ((days +~ 1) . (hours +~ 2) . (minutes +~ 5))  >>> dstExample (CEST,2013-10-26 02:00:00)@@ -126,18 +126,22 @@ module Data.Time.Lens (   -- * Lenses for the date parts     Dateable(..)-  , year, month, day+  , years, months, days   -- * Lenses for the time parts   , Timeable(..)-  , hour, minute, second+  , hours, minutes, seconds   -- * Support for the correct roll-over of fields+  , FlexDateTime(..)   , FlexDate(..)   , FlexTime(..)   , FlexibleDateTime(..)+  , FlexibleDate(..)+  , FlexibleTime(..)   -- * Miscellaneous   , utcInTZ   , utcAsLocal   , julianDay+  , julianDT   , gregorianDate   ) where @@ -156,10 +160,12 @@                          , flexDay :: Int                          } deriving (Show) -data FlexTime = FlexTime { flexDate :: FlexDate-                         , flexTOD :: TimeOfDay-                         } deriving (Show)+data FlexDateTime = FlexDateTime { flexDate :: FlexDate+                                 , flexTOD :: TimeOfDay+                                 } deriving (Show) +newtype FlexTime = FlexTime TimeOfDay deriving (Show)+ flexDateTriple :: Iso' FlexDate (Integer,Int,Int) flexDateTriple = iso (\(FlexDate y m d) -> (y,m,d)) (\(y,m,d) -> FlexDate y m d) {-# INLINE flexDateTriple #-}@@ -184,17 +190,17 @@ -- -- See examples in the general overview part. class FlexibleDateTime a where-  flexDT :: Lens' a FlexTime+  flexDT :: Lens' a FlexDateTime  instance FlexibleDateTime LocalTime where   {-# INLINE flexDT #-}   flexDT = lens convert rollOver     where-      convert (LocalTime d t) = FlexTime (d ^. gregorianUnflex) t+      convert (LocalTime d t) = FlexDateTime (d ^. gregorianUnflex) t       {-# INLINE convert #-}        {-# INLINABLE rollOver #-}-      rollOver _ (FlexTime (FlexDate y m d) tod) = result+      rollOver _ (FlexDateTime (FlexDate y m d) tod) = result         where           (secs0, p0) = properFraction $ tod ^. from diffTOD           (secs, p) = if p0 < 0 then (secs0 - 1, p0 + 1) else (secs0, p0)@@ -211,6 +217,55 @@   flexDT = utcAsLocal.flexDT   {-# INLINE flexDT #-} +-- | Type class to provide correct roll-over behavior for date lenses.+--+-- Used exactly as 'flexDT', but for values that have only \"date\"+-- and no \"time\" part.+class FlexibleDate a where+  flexD :: Lens' a FlexDate++instance FlexibleDate Day where+  {-# INLINE flexD #-}+  flexD = lens (view gregorianUnflex) rollOver+    where+      {-# INLINABLE rollOver #-}+      rollOver _ (FlexDate y m d) = result+        where+          date0 = if m >= 1 && m <= 12+                  then fromGregorian y m 1+                  else fromGregorian y 1 1 & addGregorianMonthsRollOver (fromIntegral $ m-1)+          result = addDays (fromIntegral $ d  - 1) date0++-- | Type class to provide correct roll-over behavior for time lenses.+--+-- Used exactly as 'flexDT', but for values that have only \"time\"+-- and no \"date\" part.+--+-- If the time rolls-over more than 24 hours the day carry is+-- discarded. Ex.:+--+-- >>> let t = TimeOfDay 1 12 3+-- >>> t+-- 01:12:03+-- >>> t & flexT.seconds +~ (-7200)+-- 23:12:03+--+class FlexibleTime a where+  flexT :: Lens' a FlexTime++instance FlexibleTime TimeOfDay where+  {-# INLINABLE flexT #-}+  flexT = lens FlexTime rollOver+    where+      {-# INLINABLE rollOver #-}+      rollOver _ (FlexTime tod) = tod'+        where+          secs0 :: Int+          (secs0, p0) = properFraction $ tod ^. from diffTOD+          (secs, p) = if p0 < 0 then (secs0 - 1, p0 + 1) else (secs0, p0)+          secs1 = secs `mod` (24*60*60)+          tod' = (fromIntegral secs1 + p) ^. diffTOD+ -------------------------------------------------------------------------------- -- Date parts @@ -219,12 +274,12 @@ -- You can implement either of the two methods. class Dateable a where   date :: Lens' a Day-  date = dateFlex.from gregorianUnflex+  date = _dateFlex.from gregorianUnflex   {-# INLINE date #-} -  dateFlex :: Lens' a FlexDate-  dateFlex = date.gregorianUnflex-  {-# INLINE dateFlex #-}+  _dateFlex :: Lens' a FlexDate+  _dateFlex = date.gregorianUnflex+  {-# INLINE _dateFlex #-}  instance Dateable UTCTime where   date f (UTCTime d t) = flip UTCTime t <$> f d@@ -239,12 +294,12 @@   {-# INLINE date #-}  instance Dateable FlexDate where-  dateFlex = id-  {-# INLINE dateFlex #-}+  _dateFlex = id+  {-# INLINE _dateFlex #-} -instance Dateable FlexTime where-  dateFlex f (FlexTime d t) = flip FlexTime t <$> f d-  {-# INLINE dateFlex #-}+instance Dateable FlexDateTime where+  _dateFlex f (FlexDateTime d t) = flip FlexDateTime t <$> f d+  {-# INLINE _dateFlex #-}  -- | View 'Day' as an 'Integer' day number in the Julian calendar. --@@ -260,6 +315,20 @@ gregorianDate = iso toGregorian (\(y,m,d) -> fromGregorian y m d) {-# INLINE gregorianDate #-} +-- | View 'LocalTime' as a fractional day in the modified Julian calendar.+--+-- See the description of 'ModifiedJulianDay' and 'timeOfDayToDayFraction'.+julianDT :: Iso' LocalTime Rational+julianDT = iso there back+  where+    {-# INLINE there #-}+    there (LocalTime d tod) =+      fromIntegral (toModifiedJulianDay d) + timeOfDayToDayFraction tod+    {-# INLINE back #-}+    back r = let (d,t) = properFraction r in+      LocalTime (ModifiedJulianDay d) (dayFractionToTimeOfDay t)+{-# INLINE julianDT #-}+ -- | Lens into the year value of a 'Dateable'. -- -- Warning: this is not a proper lens for 'LocalTime' and 'UTCTime':@@ -267,9 +336,9 @@ -- year value in a date is modified the month and day values might -- also change. This happens when the original date was a February -- 29th and we change to a non-leap year.-year :: Dateable d => Lens' d Integer-year = dateFlex._1-{-# INLINE year #-}+years :: Dateable d => Lens' d Integer+years = _dateFlex._1+{-# INLINE years #-}  -- | Lens into the month value of a 'Dateable'. --@@ -278,9 +347,9 @@ -- month value will be clipped to a valid month value. Also note that -- the day value might also be modified (clipped to a valid day in -- that month).-month :: Dateable d => Lens' d Int-month = dateFlex._2-{-# INLINE month #-}+months :: Dateable d => Lens' d Int+months = _dateFlex._2+{-# INLINE months #-}  -- | Lens into the day value of a 'Dateable'. --@@ -288,9 +357,9 @@ -- it only obeys the lens laws if used with valid values. The updated -- day value will be clipped to a valid day value in the given -- year-month.-day :: Dateable d => Lens' d Int-day = dateFlex._3-{-# INLINE day #-}+days :: Dateable d => Lens' d Int+days = _dateFlex._3+{-# INLINE days #-}  -------------------------------------------------------------------------------- -- Time of day parts@@ -324,39 +393,42 @@   time = id   {-# INLINE time #-} -instance Timeable FlexTime where-  time f (FlexTime d t) = FlexTime d <$> f t+instance Timeable FlexDateTime where+  time f (FlexDateTime d t) = FlexDateTime d <$> f t   {-# INLINE time #-} +instance Timeable FlexTime where+  time f (FlexTime t) = FlexTime <$> f t+ -- | Lens into the hour value of a 'Timeable'. -- -- Warning: this is not a proper lens for 'UTCTime': it only obeys the -- lens laws if used with valid values.-hour :: Timeable t => Lens' t Int-hour = time.hour'+hours :: Timeable t => Lens' t Int+hours = time.hours'   where-    hour' f (TimeOfDay h m s) = (\h' -> TimeOfDay h' m s) <$> f h-{-# INLINE hour #-}+    hours' f (TimeOfDay h m s) = (\h' -> TimeOfDay h' m s) <$> f h+{-# INLINE hours #-}  -- | Lens into the minute value of a 'Timeable'. -- -- Warning: this is not a proper lens for 'UTCTime': it only obeys the -- lens laws if used with valid values.-minute :: Timeable t => Lens' t Int-minute = time.minute'+minutes :: Timeable t => Lens' t Int+minutes = time.minutes'   where-    minute' f (TimeOfDay h m s) = (\m' -> TimeOfDay h m' s) <$> f m-{-# INLINE minute #-}+    minutes' f (TimeOfDay h m s) = (\m' -> TimeOfDay h m' s) <$> f m+{-# INLINE minutes #-}  -- | Lens into the second value of a 'Timeable'. -- -- Warning: this is not a proper lens for 'UTCTime': it only obeys the -- lens laws if used with valid values.-second :: Timeable t => Lens' t Pico-second = time.second'+seconds :: Timeable t => Lens' t Pico+seconds = time.seconds'   where-    second' f (TimeOfDay h m s) = TimeOfDay h m <$> f s-{-# INLINE second #-}+    seconds' f (TimeOfDay h m s) = TimeOfDay h m <$> f s+{-# INLINE seconds #-}  -------------------------------------------------------------------------------- -- Misc
lens-datetime.cabal view
@@ -1,5 +1,5 @@ name: lens-datetime-version: 0.1.1+version: 0.2 license: BSD3 license-file: LICENSE author: Mihaly Barasz <mihaly@barasz.com>@@ -15,7 +15,10 @@ description:   The @lens-datetime@ library provides a unified lens based accessors   to the various types in @Data.Time.Clock@, @Data.Time.Calendar@ and-  @Data.Time.LocalTime@.+  @Data.Time.LocalTime@. This library only tries to make some of the+  common use-cases convenient, it doesn't aim for completeness. If you+  want completeness and/or efficiency try the @thyme@ package instead+  (<http://hackage.haskell.org/package/thyme>).   .   Demonstration of basic uses.   .@@ -34,25 +37,25 @@   .   You can then do the following:   .-  >> aLocal ^. year+  >> aLocal ^. years   >2013-  >> aUTC ^. month+  >> aUTC ^. months   >8   >> aLocal & time .~ midnight   >2013-08-22 00:00:00-  >> aUTC & day .~ 1 & month .~ 1+  >> aUTC & days .~ 1 & months .~ 1   >2013-01-01 02:04:18.9 UTC   .   You can manipulate the date-time values with proper roll-over   behavior via the @FlexibleDateTime@ mechanism:   .-  >> aLocal & flexDT.month +~ 12+  >> aLocal & flexDT.months +~ 12   >2014-08-22 13:45:28-  >> aUTC & flexDT.day +~ 100+  >> aUTC & flexDT.days +~ 100   >2013-11-30 02:04:18.9 UTC-  >> aLocal & flexDT.minute +~ 120+  >> aLocal & flexDT.minutes +~ 120   >2013-08-22 15:45:28-  >> aLocal & flexDT %~ ((day +~ 7) . (hour +~ 2))+  >> aLocal & flexDT %~ ((days +~ 7) . (hours +~ 2))   >2013-08-22 13:45:28  extra-source-files: