Time Library Date Normalisation and Arithmetic

Ashley Yakeley ashley at semantic.org
Sat Jul 9 07:36:41 EDT 2005


I'm thinking of something along these lines:


Normalisation
-------------

  class (Eq a,Ord a) => Normalisable a where
    isNormal :: a -> Bool
    normaliseTruncate :: a -> a
    normaliseRollover :: a -> a


The normalise functions would work like this:

normaliseTruncate
2005/14/32 -> 2005/12/32 -> 2005/12/31
2005/-2/-4 -> 2005/01/-4 -> 2005/01/01

normaliseRollover
2005/14/32 -> 2006/02/32 -> 2006/03/04
2005/-2/-4 -> 2004/10/-4 -> 2004/09/26

(doing both steps in each call)


Calendar Arithmetic
-------------------

This is one way of providing arithmetic for such things as Gregorian 
dates:

  data TimeUnit d = TimeUnit
    addTimeUnitTruncate :: Integer -> d -> d
    addTimeUnitRollover :: Integer -> d -> d
    diffTimeUnitFloor :: d -> d -> Integer

  days :: (DayEncoding d) => TimeUnit d
  gregorianMonths :: (DayEncoding d) => TimeUnit d
  gregorianYears :: (DayEncoding d) => TimeUnit d

So for instance, to add three months to a date d, you do this:

  d' = addTimeUnitTruncate gregorianMonths 3 d

This might also be used for minutes and so forth. And you might also be 
able to do this:

  multipleTimeUnit :: Integer -> TimeUnit d -> TimeUnit d
  weeks = multipleTimeUnit 7 days

There's an alternative way using classes, for days only:

  class (Integral u) => TimeUnit u where
    addTimeUnitTruncate :: (DayEncoding d) => u -> d -> d
    addTimeUnitRollover :: (DayEncoding d) => u -> d -> d
    diffTimeUnitFloor :: (DayEncoding d) => d -> d -> u

  newtype Days = Days Integer
  instance TimeUnit Days
  newtype GregorianMonths = GregorianMonths Integer
  instance TimeUnit GregorianMonths
  newtype GregorianYears = GregorianYears Integer
  instance TimeUnit GregorianYears

  d' = addTimeUnitTruncate (GregorianMonths 3) d

My preference is for the former.

-- 
Ashley Yakeley, Seattle WA



More information about the Libraries mailing list