dotnet-timespan (empty) → 0.0.1.0
raw patch · 9 files changed
+575/−0 lines, 9 filesdep +basesetup-changed
Dependencies added: base
Files
- .gitignore +17/−0
- .travis.yml +88/−0
- CHANGELOG.markdown +0/−0
- Data/DotNet/TimeSpan.hs +37/−0
- Data/DotNet/TimeSpan/Internal.hs +312/−0
- LICENSE +27/−0
- README.md +13/−0
- Setup.hs +2/−0
- dotnet-timespan.cabal +79/−0
+ .gitignore view
@@ -0,0 +1,17 @@+dist+cabal-dev+*.o+*.hi+*.chi+*.chs.h+*.dyn_o+*.dyn_hi+.hpc+.hsenv+.cabal-sandbox/+cabal.sandbox.config+*.prof+*.aux+*.hp+.stack-work/+*~
+ .travis.yml view
@@ -0,0 +1,88 @@+# This file has been generated -- see https://github.com/hvr/multi-ghc-travis+language: c+sudo: false++cache:+ directories:+ - $HOME/.cabsnap+ - $HOME/.cabal/packages++before_cache:+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log+ - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar++matrix:+ include:+ - env: CABALVER=1.18 GHCVER=7.8.3+ compiler: ": #GHC 7.8.3"+ addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.3], sources: [hvr-ghc]}}+ - env: CABALVER=1.18 GHCVER=7.8.4+ compiler: ": #GHC 7.8.4"+ addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4], sources: [hvr-ghc]}}+ - env: CABALVER=1.22 GHCVER=7.10.1+ compiler: ": #GHC 7.10.1"+ addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.1], sources: [hvr-ghc]}}+ - env: CABALVER=1.22 GHCVER=7.10.2+ compiler: ": #GHC 7.10.2"+ addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.2], sources: [hvr-ghc]}}+ - env: CABALVER=1.22 GHCVER=7.10.3+ compiler: ": #GHC 7.10.3"+ addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3], sources: [hvr-ghc]}}++before_install:+ - unset CC+ - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH++install:+ - cabal --version+ - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"+ - if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ];+ then+ zcat $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz >+ $HOME/.cabal/packages/hackage.haskell.org/00-index.tar;+ fi+ - travis_retry cabal update -v+ - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config+ - cabal install --only-dependencies --enable-tests --enable-benchmarks --dry -v > installplan.txt+ - sed -i -e '1,/^Resolving /d' installplan.txt; cat installplan.txt++# check whether current requested install-plan matches cached package-db snapshot+ - if diff -u installplan.txt $HOME/.cabsnap/installplan.txt;+ then+ echo "cabal build-cache HIT";+ rm -rfv .ghc;+ cp -a $HOME/.cabsnap/ghc $HOME/.ghc;+ cp -a $HOME/.cabsnap/lib $HOME/.cabsnap/share $HOME/.cabsnap/bin $HOME/.cabal/;+ else+ echo "cabal build-cache MISS";+ rm -rf $HOME/.cabsnap;+ mkdir -p $HOME/.ghc $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin;+ cabal install --only-dependencies --enable-tests --enable-benchmarks;+ fi++# snapshot package-db on cache miss+ - if [ ! -d $HOME/.cabsnap ];+ then+ echo "snapshotting package-db to build-cache";+ mkdir $HOME/.cabsnap;+ cp -a $HOME/.ghc $HOME/.cabsnap/ghc;+ cp -a $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin installplan.txt $HOME/.cabsnap/;+ fi++# Here starts the actual work to be performed for the package under test;+# any command which exits with a non-zero exit code causes the build to fail.+script:+ - if [ -f configure.ac ]; then autoreconf -i; fi+ - cabal configure --enable-tests --enable-benchmarks -v2 # -v2 provides useful information for debugging+ - cabal build # this builds all libraries and executables (including tests/benchmarks)+ - cabal test+ - cabal check+ - cabal sdist # tests that a source-distribution can be generated++# Check that the resulting source distribution can be built & installed.+# If there are no other `.tar.gz` files in `dist`, this can be even simpler:+# `cabal install --force-reinstalls dist/*-*.tar.gz`+ - SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&+ (cd dist && cabal install --force-reinstalls "$SRC_TGZ")++# EOF
+ CHANGELOG.markdown view
+ Data/DotNet/TimeSpan.hs view
@@ -0,0 +1,37 @@+--------------------------------------------------------------------------------+-- |+-- Module : Data.DotNet.TimeSpan+-- Copyright : (C) 2016 Yorick Laupa+-- License : (see the file LICENSE)+--+-- Maintainer : Yorick Laupa <yo.eight@gmail.com>+-- Stability : provisional+-- Portability : non-portable+--+-- .NET TimeSpan implemented in Haskell.+--------------------------------------------------------------------------------+module Data.DotNet.TimeSpan+ ( TimeSpan+ , timeSpanTicks+ , timeSpanHoursMinsSecs+ , timeSpanDaysHoursMinsSecs+ , timeSpanDaysHoursMinsSecsMillis+ , ticks+ , days+ , hours+ , minutes+ , seconds+ , millis+ , fromSeconds+ , fromMinutes+ , fromHours+ , fromDays+ , totalDays+ , totalHours+ , totalMinutes+ , totalSeconds+ , totalMillis+ ) where++--------------------------------------------------------------------------------+import Data.DotNet.TimeSpan.Internal
+ Data/DotNet/TimeSpan/Internal.hs view
@@ -0,0 +1,312 @@+--------------------------------------------------------------------------------+-- |+-- Module : Data.DotNet.TimeSpan.Internal+-- Copyright : (C) 2016 Yorick Laupa+-- License : (see the file LICENSE)+--+-- Maintainer : Yorick Laupa <yo.eight@gmail.com>+-- Stability : provisional+-- Portability : non-portable+--+-- .NET TimeSpan implemented in Haskell.+--------------------------------------------------------------------------------+module Data.DotNet.TimeSpan.Internal where++--------------------------------------------------------------------------------+import Data.Int+import Data.Monoid+import Prelude++--------------------------------------------------------------------------------+-- | .NET TimeSpan: Represents a time interval.+newtype TimeSpan = TimeSpan Int64 deriving (Eq, Ord)++--------------------------------------------------------------------------------+instance Show TimeSpan where+ show = timeSpanString++--------------------------------------------------------------------------------+millisPerSecond :: Int64+millisPerSecond = 1000++--------------------------------------------------------------------------------+millisPerMinute :: Int64+millisPerMinute = millisPerSecond * 60++--------------------------------------------------------------------------------+millisPerHour :: Int64+millisPerHour = millisPerMinute * 60++--------------------------------------------------------------------------------+millisPerDay :: Int64+millisPerDay = millisPerHour * 24++--------------------------------------------------------------------------------+ticksPerMillisecond :: Int64+ticksPerMillisecond = 10000++--------------------------------------------------------------------------------+ticksPerSecond :: Int64+ticksPerSecond = ticksPerMillisecond * 1000++--------------------------------------------------------------------------------+ticksPerMinute :: Int64+ticksPerMinute = ticksPerSecond * 60++--------------------------------------------------------------------------------+ticksPerHour :: Int64+ticksPerHour = ticksPerMinute * 60++--------------------------------------------------------------------------------+ticksPerDay :: Int64+ticksPerDay = ticksPerHour * 24++--------------------------------------------------------------------------------+daysPerTick :: Double+daysPerTick = 1 / (realToFrac ticksPerDay)++--------------------------------------------------------------------------------+hoursPerTick :: Double+hoursPerTick = 1 / (realToFrac ticksPerHour)++--------------------------------------------------------------------------------+minutesPerTick :: Double+minutesPerTick = 1 / (realToFrac ticksPerMinute)++--------------------------------------------------------------------------------+secondsPerTick :: Double+secondsPerTick = 1 / (realToFrac ticksPerSecond)++--------------------------------------------------------------------------------+millisPerTick :: Double+millisPerTick = 1 / (realToFrac ticksPerMillisecond)++--------------------------------------------------------------------------------+maxMillis :: Int64+maxMillis =+ truncate+ (((realToFrac (maxBound :: Int64) :: Double)+ / realToFrac ticksPerMillisecond) :: Double)++--------------------------------------------------------------------------------+minMillis :: Int64+minMillis =+ truncate+ (((realToFrac (minBound :: Int64) :: Double)+ / realToFrac ticksPerMillisecond) :: Double)++--------------------------------------------------------------------------------+-- | Initializes a new instance of the TimeSpan structure to the specified+-- number of ticks.+timeSpanTicks :: Int64 -> TimeSpan+timeSpanTicks = TimeSpan++--------------------------------------------------------------------------------+-- | Initializes a new instance of the TimeSpan structure to a specified number+-- of hours, minutes, and seconds.+timeSpanHoursMinsSecs :: Int64 -> Int64 -> Int64 -> TimeSpan+timeSpanHoursMinsSecs hh mm ss = TimeSpan $ totalSecs * ticksPerSecond+ where+ totalSecs = (hh * 3600) + (mm * 60) + ss++--------------------------------------------------------------------------------+-- | Initializes a new instance of the TimeSpan structure to a specified number+-- of days, hours, minutes, and seconds.+timeSpanDaysHoursMinsSecs :: Int64 -> Int64 -> Int64 -> Int64 -> TimeSpan+timeSpanDaysHoursMinsSecs dd hh mm ss =+ timeSpanDaysHoursMinsSecsMillis dd hh mm ss 0++--------------------------------------------------------------------------------+-- | Initializes a new instance of the TimeSpan structure to a specified number+-- of days, hours, minutes, seconds, and milliseconds.+timeSpanDaysHoursMinsSecsMillis :: Int64+ -> Int64+ -> Int64+ -> Int64+ -> Int64+ -> TimeSpan+timeSpanDaysHoursMinsSecsMillis dd hh mm ss ms =+ TimeSpan $ _totalMillis * ticksPerMillisecond+ where+ _totalMillis = ((dd * 3600 * 24) ++ (hh * 3600) ++ (mm * 60) ++ ss) * 1000 + ms++--------------------------------------------------------------------------------+-- | Gets the number of ticks that represent the value of the current 'TimeSpan'+-- structure.+ticks :: TimeSpan -> Int64+ticks (TimeSpan i) = i++--------------------------------------------------------------------------------+-- | Gets the days component of the time interval represented by the current+-- 'TimeSpan' structure.+days :: TimeSpan -> Int64+days (TimeSpan i) = truncate $ (realToFrac i :: Double) /+ (realToFrac ticksPerDay)++--------------------------------------------------------------------------------+-- | Gets the hours component of the time interval represented by the current+-- 'TimeSpan' structure.+hours :: TimeSpan -> Int64+hours (TimeSpan i) = mod (truncate $+ (realToFrac i :: Double) /+ (realToFrac ticksPerHour)) 24++--------------------------------------------------------------------------------+-- | Gets the minutes component of the time interval represented by the current+-- 'TimeSpan' structure.+minutes :: TimeSpan -> Int64+minutes (TimeSpan i) = mod (truncate $+ (realToFrac i :: Double) /+ (realToFrac ticksPerMinute)) 60++--------------------------------------------------------------------------------+-- | Gets the seconds component of the time interval represented by the current+-- 'TimeSpan' structure.+seconds :: TimeSpan -> Int64+seconds (TimeSpan i) = mod (truncate $+ (realToFrac i :: Double) /+ (realToFrac ticksPerSecond)) 60++--------------------------------------------------------------------------------+-- | Gets the milliseconds component of the time interval represented by the+-- current 'TimeSpan' structure.+millis :: TimeSpan -> Int64+millis (TimeSpan i) = mod (truncate $+ (realToFrac i :: Double) /+ (realToFrac ticksPerMillisecond)) 1000++--------------------------------------------------------------------------------+-- | Returns a 'TimeSpan' that represents a specified number of seconds, where+-- the specification is accurate to the nearest millisecond.+fromSeconds :: Double -> TimeSpan+fromSeconds i = interval i millisPerSecond++--------------------------------------------------------------------------------+-- | Returns a 'TimeSpan' that represents a specified number of minutes, where+-- the specification is accurate to the nearest millisecond.+fromMinutes :: Double -> TimeSpan+fromMinutes i = interval i millisPerMinute++--------------------------------------------------------------------------------+-- | Returns a 'TimeSpan' that represents a specified number of hours, where the+-- specification is accurate to the nearest millisecond.+fromHours :: Double -> TimeSpan+fromHours i = interval i millisPerHour++--------------------------------------------------------------------------------+-- | Returns a 'TimeSpan' that represents a specified number of days, where the+-- specification is accurate to the nearest millisecond.+fromDays :: Double -> TimeSpan+fromDays i = interval i millisPerDay++--------------------------------------------------------------------------------+-- | Gets the value of the current 'TimeSpan' structure expressed in whole and+-- fractional days.+totalDays :: TimeSpan -> Double+totalDays (TimeSpan i) = (realToFrac i) * daysPerTick++--------------------------------------------------------------------------------+-- | Gets the value of the current 'TimeSpan' structure expressed in whole and+-- fractional hours.+totalHours :: TimeSpan -> Double+totalHours (TimeSpan i) = (realToFrac i) * hoursPerTick++--------------------------------------------------------------------------------+-- | Gets the value of the current 'TimeSpan' structure expressed in whole and+-- fractional minutes.+totalMinutes :: TimeSpan -> Double+totalMinutes (TimeSpan i) = (realToFrac i) * minutesPerTick++--------------------------------------------------------------------------------+-- | Gets the value of the current 'TimeSpan' structure expressed in whole and+-- fractional seconds.+totalSeconds :: TimeSpan -> Double+totalSeconds (TimeSpan i) = (realToFrac i) * secondsPerTick++--------------------------------------------------------------------------------+-- | Gets the value of the current 'TimeSpan' structure expressed in whole and+-- fractional milliseconds.+totalMillis :: TimeSpan -> Double+totalMillis (TimeSpan i) =+ let tmp = (realToFrac i) * millisPerTick in+ if tmp > (realToFrac maxMillis) then realToFrac maxMillis+ else if tmp < (realToFrac minMillis) then realToFrac minMillis+ else tmp++--------------------------------------------------------------------------------+data FormatLiteral = Positive | Negative++--------------------------------------------------------------------------------+padded :: Int -> a -> [a] -> [a]+padded n p xs = replicate diff p ++ xs+ where+ len_xs = length xs+ diff = n - len_xs++--------------------------------------------------------------------------------+timeSpanString :: TimeSpan -> String+timeSpanString (TimeSpan _ticks) =+ start <>+ genDay <>+ genHours <>+ genMins <>+ genSecs <>+ genFract++ where+ ticksPerHourD = realToFrac ticksPerHour :: Double+ ticksPerDayD = realToFrac ticksPerDay :: Double+ ticksPerMinuteD = realToFrac ticksPerMinute :: Double+ ticksPerSecondD = realToFrac ticksPerSecond :: Double++ day :: Int64+ day = truncate $ realToFrac _ticks / ticksPerDayD++ time = _ticks `mod` ticksPerDay++ cday = if _ticks < 0 then negate day else day+ ctime = if _ticks < 0 then negate time else time++ _hours :: Int64+ _hours = mod (truncate (realToFrac ctime / ticksPerHourD)) 24++ mins :: Int64+ mins = mod (truncate (realToFrac ctime / ticksPerMinuteD)) 60++ secs :: Int64+ secs = mod (truncate (realToFrac ctime / ticksPerSecondD)) 60++ fraction :: Int64+ fraction = ctime `mod` ticksPerSecond++ literal = if _ticks < 0 then Negative else Positive++ start =+ case literal of+ Positive -> ""+ Negative -> "-"++ genDay =+ if cday /= 0+ then show cday <> "."+ else mempty++ genHours = padded 2 '0' (show _hours) <> ":"+ genMins = padded 2 '0' (show mins) <> ":"+ genSecs = padded 2 '0' (show secs)++ genFract =+ if fraction /= 0+ then "." <> padded 7 '0' (show fraction)+ else mempty++--------------------------------------------------------------------------------+interval :: Double -> Int64 -> TimeSpan+interval value scale =+ let tmp = value * (realToFrac scale)+ _millis = tmp + (if value >= 0 then 0.5 else (-0.5))+ res = truncate (_millis * (realToFrac ticksPerMillisecond)) in+ TimeSpan res
+ LICENSE view
@@ -0,0 +1,27 @@+Copyright (c) 2016, Yorick Laupa+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++* Redistributions of source code must retain the above copyright notice, this+ list of conditions and the following disclaimer.++* Redistributions in binary form must reproduce the above copyright notice,+ this list of conditions and the following disclaimer in the documentation+ and/or other materials provided with the distribution.++* Neither the name of dotnet-timespan nor the names of its+ contributors may be used to endorse or promote products derived from+ this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,13 @@+# dotnet-timespan+[](https://travis-ci.org/YoEight/dotnet-timespan)++.NET TimeSpan in Haskell++Notes+=====++Contributions and bug reports are welcome!++BSD3 License++-Yorick Laupa
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ dotnet-timespan.cabal view
@@ -0,0 +1,79 @@+-- Initial eventstore.cabal generated by cabal init. For further+-- documentation, see http://haskell.org/cabal/users-guide/++-- The name of the package.+name: dotnet-timespan++-- The package version. See the Haskell package versioning policy (PVP)+-- for standards guiding when and how versions should be incremented.+-- http://www.haskell.org/haskellwiki/Package_versioning_policy+-- PVP summary: +-+------- breaking API changes+-- | | +----- non-breaking API additions+-- | | | +--- code changes with no API change+version: 0.0.1.0++tested-with: GHC >= 7.8.3 && < 7.11++-- A short (one-line) description of the package.+synopsis: .NET TimeSpan++-- A longer description of the package.+description: .NET TimeSpan++-- The license under which the package is released.+license: BSD3++-- The file containing the license text.+license-file: LICENSE++-- The package author(s).+author: Yorick Laupa++-- An email address to which users can send suggestions, bug reports, and+-- patches.+maintainer: yo.eight@gmail.com++-- A copyright notice.+-- copyright:++homepage: http://github.com/YoEight/dotnet-timespan+bug-reports: http://github.com/YoEight/dotnet-timespan/issues+category: Data++build-type: Simple++-- Extra files to be distributed with the package, such as examples or a+-- README.+extra-source-files: README.md+ CHANGELOG.markdown+ .gitignore+ .travis.yml++-- Constraint on the version of Cabal needed to build this package.+cabal-version: >=1.10++source-repository head+ type: git+ location: git://github.com/YoEight/dotnet-timespan.git++library+ -- Modules exported by the library.+ exposed-modules: Data.DotNet.TimeSpan+ Data.DotNet.TimeSpan.Internal+ -- Modules included in this library but not exported.+ -- other-modules:++ -- LANGUAGE extensions used by modules in this package.+ -- other-extensions:++ -- Other library packages from which modules are imported.+ build-depends: base >=4.7 && <5+++ -- Directories containing source files.+ -- hs-source-dirs:++ -- Base language which the package is written in.+ ghc-options: -Wall++ default-language: Haskell2010