hora (empty) → 1.0
raw patch · 20 files changed
+736/−0 lines, 20 filesdep +QuickCheckdep +basedep +hspecsetup-changed
Dependencies added: QuickCheck, base, hspec, regex-do, time
Files
- PublicDomain +24/−0
- Setup.hs +2/−0
- changelog.md +3/−0
- hora.cabal +87/−0
- src/Data/Time/Hora/Convert.hs +61/−0
- src/Data/Time/Hora/Format.hs +83/−0
- src/Data/Time/Hora/Future.hs +34/−0
- src/Data/Time/Hora/Parse.hs +47/−0
- src/Data/Time/Hora/Timestamp.hs +76/−0
- src/Data/Time/Hora/Type/DmyHm.hs +64/−0
- src/Data/Time/Hora/Type/Time.hs +15/−0
- src/Data/Time/Hora/Type/YmdHms.hs +22/−0
- src/Data/Time/Hora/WithTimeZone.hs +18/−0
- test/Main.hs +17/−0
- test/Test/TestConvert.hs +43/−0
- test/Test/TestDiffTime.hs +30/−0
- test/Test/TestDmyHm.hs +25/−0
- test/Test/TestFuture.hs +21/−0
- test/Test/TestPico.hs +30/−0
- test/Test/TestTime.hs +34/−0
+ PublicDomain view
@@ -0,0 +1,24 @@+This is free and unencumbered software released into the public domain.++Anyone is free to copy, modify, publish, use, compile, sell, or+distribute this software, either in source code form or as a compiled+binary, for any purpose, commercial or non-commercial, and by any+means.++In jurisdictions that recognize copyright laws, the author or authors+of this software dedicate any and all copyright interest in the+software to the public domain. We make this dedication for the benefit+of the public at large and to the detriment of our heirs and+successors. We intend this dedication to be an overt act of+relinquishment in perpetuity of all present and future rights to this+software under copyright law.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR+OTHER DEALINGS IN THE SOFTWARE.++For more information, please refer to <http://unlicense.org>
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ changelog.md view
@@ -0,0 +1,3 @@+##### 1.0+ initial version+
+ hora.cabal view
@@ -0,0 +1,87 @@+name: hora+version: 1.0+build-type: Simple+cabal-version: >=1.10++synopsis: date time+description: date time functions to pico precision+author: Imants Cekusins+maintainer: Imants Cekusins+category: System, Time+license: PublicDomain+license-file: PublicDomain+extra-source-files: changelog.md++homepage: https://github.com/ciez/hora+source-repository head+ type: git+ location: https://github.com/ciez/hora.git+++library+ exposed-modules:+ Data.Time.Hora.Convert+ Data.Time.Hora.Future+ Data.Time.Hora.Timestamp+ Data.Time.Hora.Type.YmdHms+ Data.Time.Hora.Type.DmyHm+ Data.Time.Hora.Type.Time+ Data.Time.Hora.Parse+ Data.Time.Hora.Format++ other-modules: + Data.Time.Hora.WithTimeZone+ ghc-options: -fwarn-unused-imports + + build-depends: base >=4.7 && <5.0,+ time,+ regex-do+ + hs-source-dirs: src+ default-language: Haskell2010+ default-extensions: FlexibleInstances+ MultiParamTypeClasses+ TypeSynonymInstances+ BangPatterns+ InstanceSigs+ OverloadedStrings+ FunctionalDependencies+ StandaloneDeriving+ ScopedTypeVariables+ ConstraintKinds+ GeneralizedNewtypeDeriving+ RecordWildCards+ ++test-suite spec+ default-language:Haskell2010+ type: exitcode-stdio-1.0+ ghc-options: -fwarn-unused-imports+ hs-source-dirs: test, src+ default-extensions: FlexibleInstances+ MultiParamTypeClasses+ TypeSynonymInstances+ BangPatterns+ InstanceSigs+ OverloadedStrings+ FunctionalDependencies+ StandaloneDeriving+ ScopedTypeVariables+ ConstraintKinds+ GeneralizedNewtypeDeriving+ RecordWildCards++ main-is: Main.hs+ other-modules:+ Test.TestConvert+ Test.TestDiffTime+ Test.TestFuture+ Test.TestTime+ Test.TestDmyHm+ Test.TestPico++ build-depends: base >= 4.8,+ hspec >= 2.1.7,+ QuickCheck >= 2.8.1,+ time,+ regex-do
+ src/Data/Time/Hora/Convert.hs view
@@ -0,0 +1,61 @@+module Data.Time.Hora.Convert + (-- ** multipliers+ picoSec,+ picoMs,+ msSec,+ -- ** conversion+ toPico,+ toMilli,+ toSec,+ -- ** diff time+ toDiffTime,+ nominalDiff + ) where++import Data.Ratio+import Data.Time.Clock+import Data.Time.Hora.Type.Time+++-- | pico in 1 second+picoSec::Integral a => a+picoSec = 1000000000000 -- 12++-- | pico in 1 milli+picoMs::Integral a => a+picoMs = 1000000000 -- 9++-- | milli in 1 sec+msSec::Integral a => a+msSec = 1000++{- | >>> toPico (Milli 1) + 1000000000 -}+toPico::TwoInt a b => TimeSpan a -> b+toPico (Pico i0) = fromIntegral i0+toPico (Milli i0) = fromIntegral $ i0 * picoMs+toPico (Sec i0) = fromIntegral $ i0 * picoSec++{- | >>> toMilli (Sec 1)+ 1000 -}+toMilli::TwoInt a b => TimeSpan a -> b+toMilli (Pico i0) = fromIntegral $ i0 `div` picoMs+toMilli (Milli i0) = fromIntegral $ i0+toMilli (Sec i0) = fromIntegral $ i0 * msSec+++toSec::TwoInt a b => TimeSpan a -> b+toSec (Pico i0) = fromIntegral $ i0 `div` picoSec+toSec (Milli i0) = fromIntegral $ i0 `div` msSec+toSec (Sec i0) = fromIntegral $ i0+++toDiffTime::Integral a => TimeSpan a -> DiffTime+toDiffTime (Sec s0) = secondsToDiffTime $ fromIntegral s0+toDiffTime (Pico s0) = picosecondsToDiffTime $ fromIntegral s0+toDiffTime t0@(Milli s0) = picosecondsToDiffTime $ toPico t0+++nominalDiff::Integral a => TimeSpan a -> NominalDiffTime+nominalDiff ts0 = let s1 = toPico ts0::Integer+ in fromRational $ s1 % picoSec
+ src/Data/Time/Hora/Format.hs view
@@ -0,0 +1,83 @@+module Data.Time.Hora.Format where++import Data.Time.Format (formatTime,defaultTimeLocale)+import Data.Time.Clock+import Data.Time.Hora.Type.DmyHm as M+import Data.Time.LocalTime as L+import qualified Text.Regex.Do.Replace.Template as F+import qualified Text.Regex.Do.Pad as F+import Data.Time.Calendar+import Data.Time.Hora.Type.Time+++{- | yyyymmdd -}+ymd::TimeZone -> UTCTime -> Tz String+ymd tz0 utc0 =+ let lt2 = L.utcToLocalTime tz0 utc0+ day2 = localDay lt2+ (y3,m3,d3) = toGregorian day2+ f4 i4 = F.pad '0' 2 $ show i4+ in Tz tz0 $ "{0}{1}{2}" F.< (f4 <$> [fromIntegral y3,m3,d3])+ ++{- | format UTCTime just as you need it. uses 'defaultTimeLocale' ++@+import Text.Regex.Do.Replace.Template +import Prelude hiding ((\<),(\>))+...++it "formatUTCTime" $ do+ t1 <- getCurrentTime + let p1@DmyHm{..} = partFormats+ traceIO $ formatUTCTime (("{day}/{month} {hour}:{minute}") < + [("day",day),("month",month),("hour",hour),("minute",minute)])+ t1++12/12 18:39 +@ -}+formatUTCTime::String -- ^ see 'formatTime'. can also make format with functions in this module + -> UTCTime+ -> String+formatUTCTime format0 = formatTime defaultTimeLocale format0+++-- | %T%Q+hmsFraction::String+hmsFraction = "%T%Q"++-- | %T %Q+hmsFraction'::String+hmsFraction' = "%T %Q"+++-- | %F %T+ymdHms::String+ymdHms = "%F %T"++{- | %S.%-q ++second.pico -}+spicoFormat::String+spicoFormat = "%S.%-q" ++++{- | some formats /no padding/ ++ see 'formatTime' for full measure++@+day %-d+month %-m+year %Y+hour %-H+minute %-M @ -}+partFormats::DmyHm String+partFormats = DmyHm {+ M.day = "%-d",+ M.month = "%-m",+ M.year = "%Y",+ M.hour = "%-H",+ M.minute = "%-M"+ }
+ src/Data/Time/Hora/Future.hs view
@@ -0,0 +1,34 @@+module Data.Time.Hora.Future where++import Data.Time.Clock+import Data.Time.Hora.Type.Time+import Data.Time.Hora.Convert+++{- | 'getCurrentTime' +/- offset++from unit test:++@+getCurrentTime+futureUTCTime $ Milli 100+futureUTCTime $ Sec 3++2016-12-12 15:34:03.138798524 UTC+2016-12-12 15:34:03.23893359 UTC+2016-12-12 15:34:06.138978355 UTC+@ -}+futureUTCTime::Integral a => TimeSpan a -> IO UTCTime+futureUTCTime ts0 = getCurrentTime >>=+ pure . (addUTCTime diff1)+ where diff1 = nominalDiff ts0+++-- | time diff in milli+timeDiffMs::UTCTime -> UTCTime -> Int+timeDiffMs t1 t2 =+ let t1_ = utctDayTime t1+ t2_ = utctDayTime t2+ d3 = diffTimeToPicoseconds $ t2_ - t1_+ in toMilli $ Pico d3+
+ src/Data/Time/Hora/Parse.hs view
@@ -0,0 +1,47 @@+module Data.Time.Hora.Parse where++import Data.Time.Hora.Type.DmyHm as M+import Data.Time.Hora.Type.Time+import Data.Time.Clock+import Data.Time.Calendar+import Data.Time.LocalTime as L+import Data.Time.Hora.Format++++{- | specified time in specified zone, to 'DmyHmP' -}+parse'::TimeZone -> UTCTime -> Tz DmyHmp+parse' tz0 utc0 =+ let lt2 = L.utcToLocalTime tz0 utc0+ day2 = localDay lt2+ time2 = localTimeOfDay lt2+ (y3,m3,d3) = toGregorian day2+ d4 = DmyHm{+ M.year = fromIntegral y3,+ M.month = m3,+ M.day = d3,+ M.hour = todHour time2,+ M.minute = todMin time2+ }+ pico4 = todSec time2+ in Tz tz0 $ DmyHmp (d4,pico4)+++{- | from specified 'UTCTime' -}+class Parse out where+ parse::UTCTime -> out+ + +instance Parse DmyHmp where+ parse::UTCTime -> DmyHmp+ parse t0 = let (dm1,pico1) = parse t0+ in DmyHmp (read <$> dm1,read pico1)+++instance Parse DmyHmp' where+ parse::UTCTime -> DmyHmp'+ parse t1 =+ let dm1 = flip formatUTCTime t1 <$> partFormats+ pico2 = formatUTCTime spicoFormat t1+ in (dm1,pico2)+
+ src/Data/Time/Hora/Timestamp.hs view
@@ -0,0 +1,76 @@+module Data.Time.Hora.Timestamp + (-- ** numerical+ now,+ -- ** string+ t,+ t',+ dt,+ d) where++import Data.Time.Clock+import Data.Time.Hora.WithTimeZone+import Data.Time.Hora.Format+import Data.Time.Hora.Type.DmyHm+import Data.Time.Hora.Type.Time+import Data.Time.Hora.Parse+++{-| time with Pico in current timezone ++>>> now+Tz CET (DmyHm {day = 12, month = 12, year = 2016, hour = 19, minute = 33},15.546562180000)+-}+now::IO (Tz DmyHmp)+now = withTimeZone parse'++++{- | timestamp ++second.fraction. __UTC__++>>> t+14:41:29.785834836+-}+t::IO String+t = do+ utc0 <- getCurrentTime+ pure $ formatUTCTime hmsFraction utc0+++{- | timestamp ++second.fraction. __UTC__++>>> t'+14:41:29 .785834836+-}+t'::IO String+t' = do+ utc0 <- getCurrentTime+ pure $ formatUTCTime hmsFraction' utc0+++{- | date, time (to second) __UTC__++>>> dt+2016-12-12 14:43:13+-}+dt::IO String+dt = do+ utc0 <- getCurrentTime+ pure $ formatUTCTime ymdHms utc0+++++{- | date stamp /yyyymmdd/ ++__local__ timezone++>>> d+Tz CET "20161212"+-}+d::IO (Tz String)+d = withTimeZone ymd+
+ src/Data/Time/Hora/Type/DmyHm.hs view
@@ -0,0 +1,64 @@+module Data.Time.Hora.Type.DmyHm where++import Data.Fixed+import qualified Data.Time.Hora.Type.YmdHms as S+++-- | Date, Time w/out second+data DmyHm a = DmyHm {+ day::a,+ month::a,+ year::a,+ hour::a,+ minute::a+ } deriving Eq+++instance Functor DmyHm where+ fmap f0 d0 = d0 {+ day = f0 (day d0),+ month = f0 (month d0),+ year = f0 (year d0),+ hour = f0 (hour d0),+ minute = f0 (minute d0)+ } ++deriving instance Show (DmyHm Int)+deriving instance Show (DmyHm String)+++-- | @(DmyHm {day = "12", month = "12", year = "2016", hour = "17", minute = "32"},"59.727280400000")@+type DmyHmp' = (DmyHm String, String) -- dmyhm+++-- | @DmyHmp (DmyHm {day = 12, month = 12, year = 2016, hour = 17, minute = 32},59.727482058000)@+newtype DmyHmp = DmyHmp (DmyHm Int, Pico) deriving (Eq,Show) -- dmyhm, pico+++{- | convert from more precise to more common type -}+pico2second::DmyHmp -> S.YmdHms+pico2second (DmyHmp (r0,pico0)) = S.YmdHms {+ S.year = year r0,+ S.month = month r0,+ S.day = day r0,+ S.hour = hour r0,+ S.minute = minute r0,+ S.second = round pico0+ }+ ++instance Ord DmyHmp where+ (<=) (DmyHmp(a1,p1)) (DmyHmp(a2,p2)) = + if a1 <= a2 then p1 <= p2+ else False+++instance Ord (DmyHm Int) where+ (<=) a0 b0 = not $ + year a0 > (year b0)+ || month a0 > (month b0)+ || day a0 > (day b0)+ || hour a0 > (hour b0)+ || minute a0 > (minute b0)+ +
+ src/Data/Time/Hora/Type/Time.hs view
@@ -0,0 +1,15 @@+module Data.Time.Hora.Type.Time where++import Data.Time.LocalTime+++data TimeSpan a = Sec a+ | Pico a+ | Milli a deriving (Show, Eq, Ord)+++data Tz a = Tz TimeZone a deriving Show+++-- | constraint+type TwoInt a b = (Integral a, Integral b)
+ src/Data/Time/Hora/Type/YmdHms.hs view
@@ -0,0 +1,22 @@+module Data.Time.Hora.Type.YmdHms where+++data YmdHms = YmdHms {+ year::Int,+ month::Int,+ day::Int,+ hour::Int,+ minute::Int,+ second::Int+ } deriving (Show,Eq)+++instance Ord YmdHms where+ (<=) a0 b0 = not $+ year a0 > (year b0)+ || month a0 > (month b0)+ || day a0 > (day b0)+ || hour a0 > (hour b0)+ || minute a0 > (minute b0)+ || second a0 > (second b0)+
+ src/Data/Time/Hora/WithTimeZone.hs view
@@ -0,0 +1,18 @@+module Data.Time.Hora.WithTimeZone where++import Data.Time.Clock+import Data.Time.LocalTime as L+import Data.Time.Hora.Type.Time+++type WithTimeZone a = TimeZone -> UTCTime -> Tz a++{- | do calc with current time zone from 'getCurrentTimeZone'++ probably don't need it+-}+withTimeZone::WithTimeZone a -> IO (Tz a)+withTimeZone fn0 = do+ z1 <- getCurrentTimeZone -- CET | CEST+ t1 <- getCurrentTime+ pure $ fn0 z1 t1
+ test/Main.hs view
@@ -0,0 +1,17 @@+module Main where++import qualified Test.TestDiffTime as T+import qualified Test.TestConvert as Conv+import qualified Test.TestFuture as Fut+import qualified Test.TestTime as Tt+import qualified Test.TestPico as P+import qualified Test.TestDmyHm as D ++main::IO()+main = do+ T.main+ Conv.main+ Fut.main+ Tt.main+ P.main+ D.main
+ test/Test/TestConvert.hs view
@@ -0,0 +1,43 @@+module Test.TestConvert where++import Test.Hspec+import Data.Time.Hora.Type.Time+import Data.Time.Hora.Convert+import Data.Time.Clock+import Data.Time.Hora.Type.DmyHm as D+import Data.Time.Hora.Type.YmdHms as Y+++main::IO()+main = do + test+ doc++++test::IO()+test = hspec $ do+ describe "Case.Convert" $ do+ it "pico 1" $ do+ toPico (Sec $ i 12) `shouldBe` (toPico $ Milli $ toMilli $ Sec $ i 12)+ toMilli (Sec $ i 17) `shouldBe` (toMilli $ Pico $ toPico $ Sec $ i 17)+ toMilli (Milli $ i 170) `shouldBe` (toMilli $ Pico $ toPico $ Milli $ i 170)+ s1 `shouldBe` i3+ where p1 = toPico (Sec i3)::Int+ m1 = toMilli (Pico p1)::Int+ s1 = toSec (Milli m1)::Int+ i3 = 3::Int++doc::IO()+doc = hspec $ do+ describe "doc Convert" $ do+ it "toPicos milli" $ toPico (Milli 1) `shouldBe` 1000000000+ it "toPicos sec" $ toPico (Sec 1) `shouldBe` 1000000000000+ it "toMillis sec" $ toMilli (Sec 1) `shouldBe` 1000+ it "toDiffTime sec" $ toDiffTime (Sec 1) `shouldBe` (secondsToDiffTime 1)+ it "pico2second" $ pico2second (DmyHmp (DmyHm {D.day = 3, D.month = 4, D.year = 2016, D.hour = 10, D.minute = 31}, 21.2589))+ `shouldBe` YmdHms { Y.day = 3, Y.month = 4, Y.year = 2016, Y.hour = 10, Y.minute = 31, Y.second = 21}+ ++i::Int -> Int+i = id
+ test/Test/TestDiffTime.hs view
@@ -0,0 +1,30 @@+module Test.TestDiffTime where++import Test.Hspec+import Debug.Trace+import Data.Time.Clock+import Control.Concurrent+import Data.Time.Hora.Timestamp+import Data.Time.Hora.Future+import Data.Time.Hora.Type.Time++++main::IO()+main = hspec $ do+ describe "TestDiffTime" $ do+ it "diff time" $ do+ t1 <- getCurrentTime+ threadDelay 7000+ t2 <- getCurrentTime+ let diff3 = timeDiffMs t1 t2+ traceIO $ show diff3+ 1 `shouldBe` 1+ it "DmyHmP" $ do+ Tz tz1 dmy2 <- now+ traceIO $ show dmy2+ 1 `shouldBe` 1+ it "dmy_local" $ do+ Tz tz1 l1 <- d+ traceIO $ show l1+ 1 `shouldBe` 1
+ test/Test/TestDmyHm.hs view
@@ -0,0 +1,25 @@+module Test.TestDmyHm where++import Test.Hspec+import Data.Time.Hora.Type.DmyHm+++main::IO()+main = hspec $ do+ describe "Test.TestDmyHm" $ do+ it "case 1" $ do+ a1 `shouldSatisfy` (< b1)+ where a1 = DmyHm {+ year = 2016,+ month = 10,+ day = 3,+ hour = 15,+ minute = 23+ }::DmyHm Int+ b1 = DmyHm {+ year = 2016,+ month = 10,+ day = 3,+ hour = 15,+ minute = 24+ }::DmyHm Int
+ test/Test/TestFuture.hs view
@@ -0,0 +1,21 @@+module Test.TestFuture where++import Test.Hspec+import Debug.Trace+import Data.Time.Hora.Future+import Data.Time.Hora.Type.Time+import Data.Time.Clock++++main::IO()+main = hspec $ do+ describe "Case.TestFuture" $ do+ it "3 second from now" $ do+ t1 <- getCurrentTime+ traceIO $ show t1+ f2 <- futureUTCTime $ Milli 100+ traceIO $ show f2+ f3 <- futureUTCTime $ Sec 3+ traceIO $ show f3+ 1 `shouldBe` 1
+ test/Test/TestPico.hs view
@@ -0,0 +1,30 @@+module Test.TestPico where++import Test.Hspec+import Debug.Trace+import Data.Time.Hora.Parse+import Data.Time.Clock+import Data.Time.Hora.Type.DmyHm+import Data.Time.LocalTime+import Data.Time.Hora.Timestamp+++main::IO()+main = hspec $ do+ describe "Test.TestPico" $ do+ it "now" $ do+ now >>= traceIO . show+ 1 `shouldBe` 1+ it "parse DmyHmsFormat" $ do+ getCurrentTime >>= pure . parse >>= \(f1::DmyHmp') -> traceIO $ show f1 + 1 `shouldBe` 1+ it "parse DmyHmP" $ do+ getCurrentTime >>= pure . parse >>= \(f1::DmyHmp) -> traceIO $ show f1+ 1 `shouldBe` 1+ it "parse' DmyHmP curr timezone" $ do+ getCurrentTime >>= \t1 -> do+ z1 <- getCurrentTimeZone + let f1 = parse' z1 t1+ traceIO $ show f1+ 1 `shouldBe` 1+
+ test/Test/TestTime.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE NoOverloadedStrings #-}+module Test.TestTime where++import Test.Hspec+import Debug.Trace+import Data.Time.Hora.Timestamp+import Text.Regex.Do.Replace.Template +import Prelude hiding ((<),(>))+import Data.Time.Hora.Type.DmyHm+import Data.Time.Clock+import Data.Time.Hora.Format+++main::IO()+main = hspec $ do+ describe "Test.TestTime" $ do+ it "timestamp" $ do+ t >>= traceIO+ 1 `shouldBe` 1+ it "timestamp'" $ do+ t' >>= traceIO+ 1 `shouldBe` 1+ it "datetimestamp" $ do+ dt >>= traceIO+ 1 `shouldBe` 1+ it "ymd_local" $ do+ d >>= traceIO . show+ 1 `shouldBe` 1+ it "formatUTCTime" $ do+ t1 <- getCurrentTime + let p1@DmyHm{..} = partFormats+ traceIO $ formatUTCTime (("{day}/{month} {hour}:{minute}") < [("day",day),("month",month),("hour",hour),("minute",minute)])+ t1 + 1 `shouldBe` 1