{-# LANGUAGE CPP #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Graphics.Rendering.Chart.Axis.LocalTime
-- Copyright   :  (c) Tim Docker 2010, 2014
-- License     :  BSD-style (see chart/COPYRIGHT)
--
-- Calculate and render time axes

module Graphics.Rendering.Chart.Axis.LocalTime
    {-# DEPRECATED "Use Graphics.Rendering.Chart.Axis.Time module" #-}
    (
    TimeSeq,
    TimeLabelFn,
    TimeLabelAlignment(..),

    timeAxis,
    autoTimeAxis,

    days, months, years,

    -- * Utilities
    doubleFromLocalTime

    )
    where

import Data.Default.Class
#if MIN_VERSION_time(1,5,0)
import Data.Time hiding (months)
#else
import Data.Time
import System.Locale (defaultTimeLocale)
#endif
import Data.Fixed
import Control.Lens

import Graphics.Rendering.Chart.Axis.Types
import Graphics.Rendering.Chart.Axis.Time ()

----------------------------------------------------------------------

-- | Map a LocalTime value to a plot coordinate.
doubleFromLocalTime :: LocalTime -> Double
doubleFromLocalTime :: LocalTime -> Double
doubleFromLocalTime LocalTime
lt = forall a b. (Integral a, Num b) => a -> b
fromIntegral (Day -> Integer
toModifiedJulianDay (LocalTime -> Day
localDay LocalTime
lt))
              forall a. Num a => a -> a -> a
+ forall a. Fractional a => Rational -> a
fromRational (TimeOfDay -> Rational
timeOfDayToDayFraction (LocalTime -> TimeOfDay
localTimeOfDay LocalTime
lt))

-- | Map a plot coordinate to a LocalTime.
localTimeFromDouble :: Double -> LocalTime
localTimeFromDouble :: Double -> LocalTime
localTimeFromDouble Double
v =
  Day -> TimeOfDay -> LocalTime
LocalTime (Integer -> Day
ModifiedJulianDay Integer
i) (Rational -> TimeOfDay
dayFractionToTimeOfDay (forall a. Real a => a -> Rational
toRational Double
d))
 where
   (Integer
i,Double
d) = forall a b. (RealFrac a, Integral b) => a -> (b, a)
properFraction Double
v

-- | TimeSeq is a (potentially infinite) set of times. When passed
--   a reference time, the function returns a a pair of lists. The first
--   contains all times in the set less than the reference time in
--   decreasing order. The second contains all times in the set greater
--   than or equal to the reference time, in increasing order.
type TimeSeq = LocalTime-> ([LocalTime],[LocalTime])

coverTS :: TimeSeq -> LocalTime -> LocalTime -> [LocalTime]
coverTS :: TimeSeq -> LocalTime -> LocalTime -> [LocalTime]
coverTS TimeSeq
tseq LocalTime
minT LocalTime
maxT = [LocalTime]
min' forall a. [a] -> [a] -> [a]
++ TimeSeq -> LocalTime -> LocalTime -> [LocalTime]
enumerateTS TimeSeq
tseq LocalTime
minT LocalTime
maxT forall a. [a] -> [a] -> [a]
++ [LocalTime]
max'
  where
    min' :: [LocalTime]
min' =  if LocalTime -> TimeSeq -> Bool
elemTS LocalTime
minT TimeSeq
tseq then [] else forall a. Int -> [a] -> [a]
take Int
1 (forall a b. (a, b) -> a
fst (TimeSeq
tseq LocalTime
minT))
    max' :: [LocalTime]
max' =  if LocalTime -> TimeSeq -> Bool
elemTS LocalTime
maxT TimeSeq
tseq then [] else forall a. Int -> [a] -> [a]
take Int
1 (forall a b. (a, b) -> b
snd (TimeSeq
tseq LocalTime
maxT))

enumerateTS :: TimeSeq -> LocalTime -> LocalTime -> [LocalTime]
enumerateTS :: TimeSeq -> LocalTime -> LocalTime -> [LocalTime]
enumerateTS TimeSeq
tseq LocalTime
minT LocalTime
maxT =
    forall a. [a] -> [a]
reverse (forall a. (a -> Bool) -> [a] -> [a]
takeWhile (forall a. Ord a => a -> a -> Bool
>=LocalTime
minT) [LocalTime]
ts1)  forall a. [a] -> [a] -> [a]
++ forall a. (a -> Bool) -> [a] -> [a]
takeWhile (forall a. Ord a => a -> a -> Bool
<=LocalTime
maxT) [LocalTime]
ts2
  where
    ([LocalTime]
ts1,[LocalTime]
ts2) = TimeSeq
tseq LocalTime
minT

elemTS :: LocalTime -> TimeSeq -> Bool
elemTS :: LocalTime -> TimeSeq -> Bool
elemTS LocalTime
t TimeSeq
tseq = case TimeSeq
tseq LocalTime
t of
    ([LocalTime]
_,LocalTime
t0:[LocalTime]
_) | LocalTime
t forall a. Eq a => a -> a -> Bool
== LocalTime
t0 -> Bool
True
    ([LocalTime], [LocalTime])
_                  -> Bool
False

-- | How to display a time
type TimeLabelFn = LocalTime -> String

data TimeLabelAlignment = UnderTicks
                        | BetweenTicks
                        deriving (Int -> TimeLabelAlignment -> ShowS
[TimeLabelAlignment] -> ShowS
TimeLabelAlignment -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [TimeLabelAlignment] -> ShowS
$cshowList :: [TimeLabelAlignment] -> ShowS
show :: TimeLabelAlignment -> String
$cshow :: TimeLabelAlignment -> String
showsPrec :: Int -> TimeLabelAlignment -> ShowS
$cshowsPrec :: Int -> TimeLabelAlignment -> ShowS
Show)

-- | Create an 'AxisFn' to for a time axis.
--
--   The values to be plotted against this axis can be created with
--   'doubleFromLocalTime'.
timeAxis ::
  TimeSeq
  -- ^ Set the minor ticks, and the final range will be aligned to its
  --   elements.
  -> TimeSeq
  -- ^ Set the labels and grid.
  -> TimeLabelFn
  -> TimeLabelAlignment
  -> TimeSeq
  -- ^ Set the second line of labels.
  -> TimeLabelFn
  -- ^ Format `LocalTime` for labels.
  -> TimeLabelAlignment
  -> AxisFn LocalTime
timeAxis :: TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
tseq TimeSeq
lseq TimeLabelFn
labelf TimeLabelAlignment
lal TimeSeq
cseq TimeLabelFn
contextf TimeLabelAlignment
clal [LocalTime]
pts = AxisData {
    _axis_visibility :: AxisVisibility
_axis_visibility = forall a. Default a => a
def,
    _axis_viewport :: Range -> LocalTime -> Double
_axis_viewport = forall x. PlotValue x => (x, x) -> Range -> x -> Double
vmap(LocalTime
min', LocalTime
max'),
    _axis_tropweiv :: Range -> Double -> LocalTime
_axis_tropweiv = forall x. PlotValue x => (x, x) -> Range -> Double -> x
invmap(LocalTime
min', LocalTime
max'),
    _axis_ticks :: [(LocalTime, Double)]
_axis_ticks    = [ (LocalTime
t,Double
2) | LocalTime
t <- [LocalTime]
times] forall a. [a] -> [a] -> [a]
++ [ (LocalTime
t,Double
5) | LocalTime
t <- [LocalTime]
ltimes, LocalTime -> Bool
visible LocalTime
t],
    _axis_labels :: [[(LocalTime, String)]]
_axis_labels   = [ [ (LocalTime
t,String
l) | (LocalTime
t,String
l) <- forall {b}.
(LocalTime -> b)
-> [LocalTime] -> TimeLabelAlignment -> [(LocalTime, b)]
labels TimeLabelFn
labelf   [LocalTime]
ltimes TimeLabelAlignment
lal, LocalTime -> Bool
visible LocalTime
t]
                     , [ (LocalTime
t,String
l) | (LocalTime
t,String
l) <- forall {b}.
(LocalTime -> b)
-> [LocalTime] -> TimeLabelAlignment -> [(LocalTime, b)]
labels TimeLabelFn
contextf [LocalTime]
ctimes TimeLabelAlignment
clal, LocalTime -> Bool
visible LocalTime
t]
                     ],
    _axis_grid :: [LocalTime]
_axis_grid     = [ LocalTime
t     | LocalTime
t <- [LocalTime]
ltimes, LocalTime -> Bool
visible LocalTime
t]
    }
  where
    (LocalTime
minT,LocalTime
maxT)  = case [LocalTime]
pts of
                       [] -> (LocalTime
refLocalTime,LocalTime
refLocalTime)
                       [LocalTime]
ps -> (forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [LocalTime]
ps, forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [LocalTime]
ps)
    refLocalTime :: LocalTime
refLocalTime = Day -> TimeOfDay -> LocalTime
LocalTime (Integer -> Day
ModifiedJulianDay Integer
0) TimeOfDay
midnight
    times :: [LocalTime]
times        = TimeSeq -> LocalTime -> LocalTime -> [LocalTime]
coverTS TimeSeq
tseq LocalTime
minT LocalTime
maxT
    ltimes :: [LocalTime]
ltimes       = TimeSeq -> LocalTime -> LocalTime -> [LocalTime]
coverTS TimeSeq
lseq LocalTime
minT LocalTime
maxT
    ctimes :: [LocalTime]
ctimes       = TimeSeq -> LocalTime -> LocalTime -> [LocalTime]
coverTS TimeSeq
cseq LocalTime
minT LocalTime
maxT
    min' :: LocalTime
min'         = forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [LocalTime]
times
    max' :: LocalTime
max'         = forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [LocalTime]
times
    visible :: LocalTime -> Bool
visible LocalTime
t    = LocalTime
min' forall a. Ord a => a -> a -> Bool
<= LocalTime
t Bool -> Bool -> Bool
&& LocalTime
t forall a. Ord a => a -> a -> Bool
<= LocalTime
max'
    labels :: (LocalTime -> b)
-> [LocalTime] -> TimeLabelAlignment -> [(LocalTime, b)]
labels LocalTime -> b
f [LocalTime]
ts TimeLabelAlignment
lal' =
        [ (TimeLabelAlignment -> LocalTime -> LocalTime -> LocalTime
align TimeLabelAlignment
lal' LocalTime
m1' LocalTime
m2', LocalTime -> b
f LocalTime
m1)
          | (LocalTime
m1,LocalTime
m2) <- forall a b. [a] -> [b] -> [(a, b)]
zip [LocalTime]
ts (forall a. [a] -> [a]
tail [LocalTime]
ts)
          , let m1' :: LocalTime
m1' = if LocalTime
m1forall a. Ord a => a -> a -> Bool
<LocalTime
min' then LocalTime
min' else LocalTime
m1
          , let m2' :: LocalTime
m2' = if LocalTime
m2forall a. Ord a => a -> a -> Bool
>LocalTime
max' then LocalTime
max' else LocalTime
m2 ]

    align :: TimeLabelAlignment -> LocalTime -> LocalTime -> LocalTime
align TimeLabelAlignment
BetweenTicks LocalTime
m1 LocalTime
m2 = LocalTime -> LocalTime -> LocalTime
avg LocalTime
m1 LocalTime
m2
    align TimeLabelAlignment
UnderTicks   LocalTime
m1 LocalTime
_  = LocalTime
m1

    avg :: LocalTime -> LocalTime -> LocalTime
avg LocalTime
m1 LocalTime
m2    = Double -> LocalTime
localTimeFromDouble forall a b. (a -> b) -> a -> b
$ Double
m1' forall a. Num a => a -> a -> a
+ (Double
m2' forall a. Num a => a -> a -> a
- Double
m1')forall a. Fractional a => a -> a -> a
/Double
2
     where
      m1' :: Double
m1' = LocalTime -> Double
doubleFromLocalTime LocalTime
m1
      m2' :: Double
m2' = LocalTime -> Double
doubleFromLocalTime LocalTime
m2

normalizeTimeOfDay :: LocalTime -> LocalTime
normalizeTimeOfDay :: LocalTime -> LocalTime
normalizeTimeOfDay t :: LocalTime
t@(LocalTime Day
day (TimeOfDay Int
h Int
m Pico
s))
  | Pico
s forall a. Ord a => a -> a -> Bool
<  Pico
0    = LocalTime -> LocalTime
normalizeTimeOfDay (Day -> TimeOfDay -> LocalTime
LocalTime Day
day (Int -> Int -> Pico -> TimeOfDay
TimeOfDay Int
h (Int
mforall a. Num a => a -> a -> a
-Int
1) (Pico
sforall a. Num a => a -> a -> a
+Pico
60)))
  | Int
m forall a. Ord a => a -> a -> Bool
<  Int
0    = LocalTime -> LocalTime
normalizeTimeOfDay (Day -> TimeOfDay -> LocalTime
LocalTime Day
day (Int -> Int -> Pico -> TimeOfDay
TimeOfDay (Int
hforall a. Num a => a -> a -> a
-Int
1) (Int
mforall a. Num a => a -> a -> a
+Int
60) Pico
s))
  | Int
h forall a. Ord a => a -> a -> Bool
<  Int
0    = LocalTime -> LocalTime
normalizeTimeOfDay (Day -> TimeOfDay -> LocalTime
LocalTime (Integer -> Day -> Day
addDays (-Integer
1) Day
day) (Int -> Int -> Pico -> TimeOfDay
TimeOfDay (Int
hforall a. Num a => a -> a -> a
+Int
24) Int
m Pico
s))
  | Pico
s forall a. Ord a => a -> a -> Bool
>= Pico
60   = LocalTime -> LocalTime
normalizeTimeOfDay (Day -> TimeOfDay -> LocalTime
LocalTime Day
day (Int -> Int -> Pico -> TimeOfDay
TimeOfDay Int
h (Int
mforall a. Num a => a -> a -> a
+Pico
sforall a b. (Real a, Integral b) => a -> a -> b
`div'`Pico
60)
                                                               (Pico
sforall a. Real a => a -> a -> a
`mod'`Pico
60)))
  | Int
m forall a. Ord a => a -> a -> Bool
>= Int
60   = LocalTime -> LocalTime
normalizeTimeOfDay (Day -> TimeOfDay -> LocalTime
LocalTime Day
day (Int -> Int -> Pico -> TimeOfDay
TimeOfDay (Int
hforall a. Num a => a -> a -> a
+Int
mforall a. Integral a => a -> a -> a
`div`Int
60)
                                                             (Int
mforall a. Integral a => a -> a -> a
`mod`Int
60) Pico
s))
  | Int
h forall a. Ord a => a -> a -> Bool
>= Int
24   = Day -> TimeOfDay -> LocalTime
LocalTime (Integer -> Day -> Day
addDays (forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
hforall a. Integral a => a -> a -> a
`div`Int
24)) Day
day)
                          (Int -> Int -> Pico -> TimeOfDay
TimeOfDay (Int
hforall a. Integral a => a -> a -> a
`mod`Int
24) Int
m Pico
s)
  | Bool
otherwise = LocalTime
t

addTod :: Int -> Int -> Pico -> LocalTime -> LocalTime
addTod :: Int -> Int -> Pico -> LocalTime -> LocalTime
addTod Int
dh Int
dm Pico
ds (LocalTime Day
day (TimeOfDay Int
h Int
m Pico
s)) = LocalTime -> LocalTime
normalizeTimeOfDay LocalTime
t'
  where t' :: LocalTime
t' = Day -> TimeOfDay -> LocalTime
LocalTime Day
day (Int -> Int -> Pico -> TimeOfDay
TimeOfDay (Int
hforall a. Num a => a -> a -> a
+Int
dh) (Int
mforall a. Num a => a -> a -> a
+Int
dm) (Pico
sforall a. Num a => a -> a -> a
+Pico
ds))

truncateTo :: (HasResolution a) => Fixed a -> Fixed a -> Fixed a
truncateTo :: forall a. HasResolution a => Fixed a -> Fixed a -> Fixed a
truncateTo Fixed a
t Fixed a
step = Fixed a
t forall a. Num a => a -> a -> a
- Fixed a
t forall a. Real a => a -> a -> a
`mod'` Fixed a
step

secondSeq :: Pico -> TimeSeq
secondSeq :: Pico -> TimeSeq
secondSeq Pico
step LocalTime
t = (forall a. (a -> a) -> a -> [a]
iterate LocalTime -> LocalTime
rev LocalTime
t1, forall a. [a] -> [a]
tail (forall a. (a -> a) -> a -> [a]
iterate LocalTime -> LocalTime
fwd LocalTime
t1))
  where h0 :: Int
h0       = TimeOfDay -> Int
todHour (LocalTime -> TimeOfDay
localTimeOfDay LocalTime
t)
        m0 :: Int
m0       = TimeOfDay -> Int
todMin  (LocalTime -> TimeOfDay
localTimeOfDay LocalTime
t)
        s0 :: Pico
s0       = TimeOfDay -> Pico
todSec  (LocalTime -> TimeOfDay
localTimeOfDay LocalTime
t) forall a. HasResolution a => Fixed a -> Fixed a -> Fixed a
`truncateTo` (Pico
1 forall a. Fractional a => a -> a -> a
/ Pico
1000)
        t0 :: LocalTime
t0       = Day -> TimeOfDay -> LocalTime
LocalTime (LocalTime -> Day
localDay LocalTime
t) (Int -> Int -> Pico -> TimeOfDay
TimeOfDay Int
h0 Int
m0 Pico
s0)
        t1 :: LocalTime
t1       = if LocalTime
t0 forall a. Ord a => a -> a -> Bool
< LocalTime
t then LocalTime
t0 else LocalTime -> LocalTime
rev LocalTime
t0
        rev :: LocalTime -> LocalTime
rev      = Int -> Int -> Pico -> LocalTime -> LocalTime
addTod Int
0 Int
0 (forall a. Num a => a -> a
negate Pico
step)
        fwd :: LocalTime -> LocalTime
fwd      = Int -> Int -> Pico -> LocalTime -> LocalTime
addTod Int
0 Int
0 Pico
step

millis1, millis10, millis100, seconds, fiveSeconds  :: TimeSeq
millis1 :: TimeSeq
millis1 = Pico -> TimeSeq
secondSeq (Pico
1 forall a. Fractional a => a -> a -> a
/ Pico
1000)
millis10 :: TimeSeq
millis10 = Pico -> TimeSeq
secondSeq (Pico
1 forall a. Fractional a => a -> a -> a
/ Pico
100)
millis100 :: TimeSeq
millis100 = Pico -> TimeSeq
secondSeq (Pico
1 forall a. Fractional a => a -> a -> a
/ Pico
10)
seconds :: TimeSeq
seconds = Pico -> TimeSeq
secondSeq Pico
1
fiveSeconds :: TimeSeq
fiveSeconds = Pico -> TimeSeq
secondSeq Pico
5

minuteSeq :: Int -> TimeSeq
minuteSeq :: Int -> TimeSeq
minuteSeq Int
step LocalTime
t = (forall a. (a -> a) -> a -> [a]
iterate LocalTime -> LocalTime
rev LocalTime
t1, forall a. [a] -> [a]
tail (forall a. (a -> a) -> a -> [a]
iterate LocalTime -> LocalTime
fwd LocalTime
t1))
  where h0 :: Int
h0       = TimeOfDay -> Int
todHour (LocalTime -> TimeOfDay
localTimeOfDay LocalTime
t)
        m0 :: Int
m0       = TimeOfDay -> Int
todMin  (LocalTime -> TimeOfDay
localTimeOfDay LocalTime
t)
        t0 :: LocalTime
t0       = Day -> TimeOfDay -> LocalTime
LocalTime (LocalTime -> Day
localDay LocalTime
t) (Int -> Int -> Pico -> TimeOfDay
TimeOfDay Int
h0 Int
m0 Pico
0)
        t1 :: LocalTime
t1       = if LocalTime
t0 forall a. Ord a => a -> a -> Bool
< LocalTime
t then LocalTime
t0 else LocalTime -> LocalTime
rev LocalTime
t0
        rev :: LocalTime -> LocalTime
rev      = Int -> Int -> Pico -> LocalTime -> LocalTime
addTod Int
0 (forall a. Num a => a -> a
negate Int
step) Pico
0
        fwd :: LocalTime -> LocalTime
fwd      = Int -> Int -> Pico -> LocalTime -> LocalTime
addTod Int
0 Int
step Pico
0

minutes, fiveMinutes :: TimeSeq
minutes :: TimeSeq
minutes = Int -> TimeSeq
minuteSeq Int
1
fiveMinutes :: TimeSeq
fiveMinutes = Int -> TimeSeq
minuteSeq Int
5

-- | A 'TimeSeq' for hours.
hours :: TimeSeq
hours :: TimeSeq
hours LocalTime
t = (forall a. (a -> a) -> a -> [a]
iterate LocalTime -> LocalTime
rev LocalTime
t1, forall a. [a] -> [a]
tail (forall a. (a -> a) -> a -> [a]
iterate LocalTime -> LocalTime
fwd LocalTime
t1))
  where h0 :: Int
h0       = TimeOfDay -> Int
todHour (LocalTime -> TimeOfDay
localTimeOfDay LocalTime
t)
        t0 :: LocalTime
t0       = Day -> TimeOfDay -> LocalTime
LocalTime (LocalTime -> Day
localDay LocalTime
t) (Int -> Int -> Pico -> TimeOfDay
TimeOfDay Int
h0 Int
0 Pico
0)
        t1 :: LocalTime
t1       = if LocalTime
t0 forall a. Ord a => a -> a -> Bool
< LocalTime
t then LocalTime
t0 else LocalTime -> LocalTime
rev LocalTime
t0
        rev :: LocalTime -> LocalTime
rev      = Int -> Int -> Pico -> LocalTime -> LocalTime
addTod (-Int
1) Int
0 Pico
0
        fwd :: LocalTime -> LocalTime
fwd      = Int -> Int -> Pico -> LocalTime -> LocalTime
addTod Int
1    Int
0 Pico
0

-- | A 'TimeSeq' for calendar days.
days :: TimeSeq
days :: TimeSeq
days LocalTime
t = (forall a b. (a -> b) -> [a] -> [b]
map Day -> LocalTime
toTime forall a b. (a -> b) -> a -> b
$ forall a. (a -> a) -> a -> [a]
iterate Day -> Day
rev Day
t1, forall a b. (a -> b) -> [a] -> [b]
map Day -> LocalTime
toTime forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [a]
tail (forall a. (a -> a) -> a -> [a]
iterate Day -> Day
fwd Day
t1))
  where t0 :: Day
t0       = LocalTime -> Day
localDay LocalTime
t
        t1 :: Day
t1       = if Day -> LocalTime
toTime Day
t0 forall a. Ord a => a -> a -> Bool
< LocalTime
t then Day
t0 else Day -> Day
rev Day
t0
        rev :: Day -> Day
rev      = forall a. Enum a => a -> a
pred
        fwd :: Day -> Day
fwd      = forall a. Enum a => a -> a
succ
        toTime :: Day -> LocalTime
toTime Day
d = Day -> TimeOfDay -> LocalTime
LocalTime Day
d TimeOfDay
midnight

-- | A 'TimeSeq' for calendar months.
months :: TimeSeq
months :: TimeSeq
months LocalTime
t = (forall a b. (a -> b) -> [a] -> [b]
map Day -> LocalTime
toTime forall a b. (a -> b) -> a -> b
$ forall a. (a -> a) -> a -> [a]
iterate Day -> Day
rev Day
t1, forall a b. (a -> b) -> [a] -> [b]
map Day -> LocalTime
toTime forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [a]
tail (forall a. (a -> a) -> a -> [a]
iterate Day -> Day
fwd Day
t1))
  where t0 :: Day
t0       = let (Integer
y,Int
m,Int
_) = Day -> (Integer, Int, Int)
toGregorian forall a b. (a -> b) -> a -> b
$ LocalTime -> Day
localDay LocalTime
t in Integer -> Int -> Int -> Day
fromGregorian Integer
y Int
m Int
1
        t1 :: Day
t1       = if Day -> LocalTime
toTime Day
t0 forall a. Ord a => a -> a -> Bool
< LocalTime
t then Day
t0 else Day -> Day
rev Day
t0
        rev :: Day -> Day
rev      = Integer -> Day -> Day
addGregorianMonthsClip (-Integer
1)
        fwd :: Day -> Day
fwd      = Integer -> Day -> Day
addGregorianMonthsClip Integer
1
        toTime :: Day -> LocalTime
toTime Day
d = Day -> TimeOfDay -> LocalTime
LocalTime Day
d TimeOfDay
midnight

-- | A 'TimeSeq' for calendar years.
years :: TimeSeq
years :: TimeSeq
years LocalTime
t = (forall a b. (a -> b) -> [a] -> [b]
map Integer -> LocalTime
toTime forall a b. (a -> b) -> a -> b
$ forall a. (a -> a) -> a -> [a]
iterate Integer -> Integer
rev Integer
t1, forall a b. (a -> b) -> [a] -> [b]
map Integer -> LocalTime
toTime forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [a]
tail (forall a. (a -> a) -> a -> [a]
iterate Integer -> Integer
fwd Integer
t1))
  where t0 :: Integer
t0       = Day -> (Integer, Int, Int)
toGregorian (LocalTime -> Day
localDay LocalTime
t) forall s a. s -> Getting a s a -> a
^. forall s t a b. Field1 s t a b => Lens s t a b
_1
        t1 :: Integer
t1       = if Integer -> LocalTime
toTime Integer
t0 forall a. Ord a => a -> a -> Bool
< LocalTime
t then Integer
t0 else Integer -> Integer
rev Integer
t0
        rev :: Integer -> Integer
rev      = forall a. Enum a => a -> a
pred
        fwd :: Integer -> Integer
fwd      = forall a. Enum a => a -> a
succ
        toTime :: Integer -> LocalTime
toTime Integer
y = Day -> TimeOfDay -> LocalTime
LocalTime (Integer -> Int -> Int -> Day
fromGregorian Integer
y Int
1 Int
1) TimeOfDay
midnight

-- | A 'TimeSeq' for no sequence at all.
noTime :: TimeSeq
noTime :: TimeSeq
noTime LocalTime
_ = ([],[])

-- | Automatically choose a suitable time axis, based upon the time range
--   of data.  The values to be plotted against this axis can be created
--   with 'doubleFromLocalTime'.
autoTimeAxis :: AxisFn LocalTime
autoTimeAxis :: AxisFn LocalTime
autoTimeAxis [LocalTime]
pts
    | forall (t :: * -> *) a. Foldable t => t a -> Bool
null [LocalTime]
pts              = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
days    TimeSeq
days    (String -> TimeLabelFn
ft String
"%d-%b-%y") TimeLabelAlignment
UnderTicks
                                               TimeSeq
noTime  (String -> TimeLabelFn
ft String
"") TimeLabelAlignment
UnderTicks []
    | Integer
tdiffforall a. Eq a => a -> a -> Bool
==Integer
0 Bool -> Bool -> Bool
&& Pico
100forall a. Num a => a -> a -> a
*Pico
dsecforall a. Ord a => a -> a -> Bool
<Pico
1= TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
millis1   TimeSeq
millis1  (String -> TimeLabelFn
ft String
"%S%Q") TimeLabelAlignment
UnderTicks
                                                 TimeSeq
noTime (String -> TimeLabelFn
ft String
"%S%Q") TimeLabelAlignment
UnderTicks [LocalTime]
pts
    | Integer
tdiffforall a. Eq a => a -> a -> Bool
==Integer
0 Bool -> Bool -> Bool
&& Pico
10forall a. Num a => a -> a -> a
*Pico
dsecforall a. Ord a => a -> a -> Bool
<Pico
1 = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
millis10  TimeSeq
millis10  (String -> TimeLabelFn
ft String
"%S%Q") TimeLabelAlignment
UnderTicks
                                                 TimeSeq
noTime (String -> TimeLabelFn
ft String
"%S%Q") TimeLabelAlignment
UnderTicks [LocalTime]
pts
    | Integer
tdiffforall a. Eq a => a -> a -> Bool
==Integer
0 Bool -> Bool -> Bool
&& Pico
dsecforall a. Ord a => a -> a -> Bool
<Pico
1    = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
millis10  TimeSeq
millis100 (String -> TimeLabelFn
ft String
"%S%Q") TimeLabelAlignment
UnderTicks
                                                 TimeSeq
seconds (String -> TimeLabelFn
ft String
"%M:%S") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiffforall a. Eq a => a -> a -> Bool
==Integer
0 Bool -> Bool -> Bool
&& Pico
dsecforall a. Ord a => a -> a -> Bool
<Pico
5    = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
millis100 TimeSeq
seconds (String -> TimeLabelFn
ft String
"%M:%S%Q") TimeLabelAlignment
UnderTicks
                                                 TimeSeq
seconds (String -> TimeLabelFn
ft String
"%M:%S") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiffforall a. Eq a => a -> a -> Bool
==Integer
0 Bool -> Bool -> Bool
&& Pico
dsecforall a. Ord a => a -> a -> Bool
<Pico
32   = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
seconds TimeSeq
seconds (String -> TimeLabelFn
ft String
"%Ss") TimeLabelAlignment
UnderTicks
                                               TimeSeq
minutes (String -> TimeLabelFn
ft String
"%d-%b-%y %H:%M") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiffforall a. Eq a => a -> a -> Bool
==Integer
0 Bool -> Bool -> Bool
&& Pico
dsecforall a. Ord a => a -> a -> Bool
<Pico
120  = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
seconds TimeSeq
fiveSeconds (String -> TimeLabelFn
ft String
"%Ss") TimeLabelAlignment
UnderTicks
                                               TimeSeq
minutes (String -> TimeLabelFn
ft String
"%d-%b-%y %H:%M") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiffforall a. Eq a => a -> a -> Bool
==Integer
0 Bool -> Bool -> Bool
&& Int
dminforall a. Ord a => a -> a -> Bool
<Int
7    = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
fiveSeconds TimeSeq
minutes (String -> TimeLabelFn
ft String
"%Mm") TimeLabelAlignment
UnderTicks
                                               TimeSeq
hours   (String -> TimeLabelFn
ft String
"%d-%b-%y %H:00") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiffforall a. Eq a => a -> a -> Bool
==Integer
0 Bool -> Bool -> Bool
&& Int
dminforall a. Ord a => a -> a -> Bool
<Int
32   = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
minutes TimeSeq
minutes (String -> TimeLabelFn
ft String
"%Mm") TimeLabelAlignment
UnderTicks
                                               TimeSeq
hours   (String -> TimeLabelFn
ft String
"%d-%b-%y %H:00") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiffforall a. Eq a => a -> a -> Bool
==Integer
0 Bool -> Bool -> Bool
&& Int
dminforall a. Ord a => a -> a -> Bool
<Int
90   = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
minutes TimeSeq
fiveMinutes (String -> TimeLabelFn
ft String
"%Mm") TimeLabelAlignment
UnderTicks
                                               TimeSeq
hours   (String -> TimeLabelFn
ft String
"%d-%b-%y %H:00") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiff forall a. Ord a => a -> a -> Bool
< Integer
2 Bool -> Bool -> Bool
&& Int
dhourforall a. Ord a => a -> a -> Bool
<Int
4  = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
fiveMinutes TimeSeq
hours (String -> TimeLabelFn
ft String
"%H:%M") TimeLabelAlignment
UnderTicks
                                                   TimeSeq
days  (String -> TimeLabelFn
ft String
"%d-%b-%y") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiff forall a. Ord a => a -> a -> Bool
< Integer
2 Bool -> Bool -> Bool
&& Int
dhourforall a. Ord a => a -> a -> Bool
<Int
32 = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
hours  TimeSeq
hours  (String -> TimeLabelFn
ft String
"%H:%M") TimeLabelAlignment
UnderTicks
                                              TimeSeq
days   (String -> TimeLabelFn
ft String
"%d-%b-%y") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiff forall a. Ord a => a -> a -> Bool
< Integer
4             = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
hours  TimeSeq
days   (String -> TimeLabelFn
ft String
"%d-%b-%y") TimeLabelAlignment
BetweenTicks
                                              TimeSeq
noTime (String -> TimeLabelFn
ft String
"") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiff forall a. Ord a => a -> a -> Bool
< Integer
12            = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
days   TimeSeq
days   (String -> TimeLabelFn
ft String
"%d-%b") TimeLabelAlignment
BetweenTicks
                                              TimeSeq
years  (String -> TimeLabelFn
ft String
"%Y") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiff forall a. Ord a => a -> a -> Bool
< Integer
45            = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
days   TimeSeq
days   (String -> TimeLabelFn
ft String
"%d") TimeLabelAlignment
BetweenTicks
                                              TimeSeq
months (String -> TimeLabelFn
ft String
"%b-%y") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiff forall a. Ord a => a -> a -> Bool
< Integer
95            = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
days   TimeSeq
months (String -> TimeLabelFn
ft String
"%b-%y") TimeLabelAlignment
BetweenTicks
                                              TimeSeq
noTime (String -> TimeLabelFn
ft String
"") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiff forall a. Ord a => a -> a -> Bool
< Integer
450           = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
months TimeSeq
months (String -> TimeLabelFn
ft String
"%b-%y") TimeLabelAlignment
BetweenTicks
                                              TimeSeq
noTime (String -> TimeLabelFn
ft String
"") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiff forall a. Ord a => a -> a -> Bool
< Integer
735           = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
months TimeSeq
months (String -> TimeLabelFn
ft String
"%b") TimeLabelAlignment
BetweenTicks
                                              TimeSeq
years  (String -> TimeLabelFn
ft String
"%Y") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Integer
tdiff forall a. Ord a => a -> a -> Bool
< Integer
1800          = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
months TimeSeq
years (String -> TimeLabelFn
ft String
"%Y") TimeLabelAlignment
BetweenTicks
                                              TimeSeq
noTime (String -> TimeLabelFn
ft String
"") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
    | Bool
otherwise             = TimeSeq
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> TimeSeq
-> TimeLabelFn
-> TimeLabelAlignment
-> AxisFn LocalTime
timeAxis TimeSeq
years  TimeSeq
years (String -> TimeLabelFn
ft String
"%Y") TimeLabelAlignment
BetweenTicks
                                              TimeSeq
noTime (String -> TimeLabelFn
ft String
"") TimeLabelAlignment
BetweenTicks [LocalTime]
pts
  where
    tdiff :: Integer
tdiff = Day -> Day -> Integer
diffDays (LocalTime -> Day
localDay LocalTime
t1) (LocalTime -> Day
localDay LocalTime
t0)
    dhour :: Int
dhour = if Integer
tdiffforall a. Eq a => a -> a -> Bool
==Integer
0 then Int
h1forall a. Num a => a -> a -> a
-Int
h0 else Int
24forall a. Num a => a -> a -> a
*forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
tdiff forall a. Num a => a -> a -> a
+Int
h1forall a. Num a => a -> a -> a
-Int
h0
    dmin :: Int
dmin  = Int
60forall a. Num a => a -> a -> a
*Int
dhourforall a. Num a => a -> a -> a
+(Int
m1forall a. Num a => a -> a -> a
-Int
m0)
    dsec :: Pico
dsec  = forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
60forall a. Num a => a -> a -> a
*Int
dmin) forall a. Num a => a -> a -> a
+ (Pico
s1forall a. Num a => a -> a -> a
-Pico
s0)
    (TimeOfDay Int
h0 Int
m0 Pico
s0) = LocalTime -> TimeOfDay
localTimeOfDay LocalTime
t0
    (TimeOfDay Int
h1 Int
m1 Pico
s1) = LocalTime -> TimeOfDay
localTimeOfDay LocalTime
t1
    t1 :: LocalTime
t1    = forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [LocalTime]
pts
    t0 :: LocalTime
t0    = forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [LocalTime]
pts
    ft :: String -> TimeLabelFn
ft    = forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale