Skip to content

Commit

Permalink
Don't use exponential notation in PreciseDuration toString (#30)
Browse files Browse the repository at this point in the history
* Move dropWhileEnd to Internal, use Array.foldr

* Add tests for PrecistDuration toString

* Update PreciseDuration toString
  • Loading branch information
paulyoung authored Jul 5, 2018
1 parent 282ce5a commit 0e862a7
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 19 deletions.
11 changes: 11 additions & 0 deletions src/Data/PreciseDateTime/Internal.purs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ module Data.PreciseDateTime.Internal where

import Prelude

import Data.Array as Array
import Data.Formatter.DateTime (FormatterCommand(..))
import Data.List (List, fromFoldable)
import Data.String.CodeUnits as String
import Data.Tuple (Tuple(..), snd)

dateFormat :: List FormatterCommand
dateFormat = fromFoldable
Expand All @@ -25,3 +28,11 @@ timeFormat = fromFoldable

dateTimeFormatISO :: List FormatterCommand
dateTimeFormatISO = dateFormat <> pure (Placeholder "T") <> timeFormat

-- | Returns the prefix remaining after dropping characters that satisfy the
-- | predicate from the end of the string.
dropWhileEnd :: (Char -> Boolean) -> String -> String
dropWhileEnd p s = snd $ Array.foldr check (Tuple false "") (String.toCharArray s)
where
check c state@(Tuple false _) = if p c then state else Tuple true (String.singleton c)
check c state@(Tuple true string) = Tuple true (String.singleton c <> string)
12 changes: 1 addition & 11 deletions src/Data/RFC3339String.purs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ module Data.RFC3339String where
import Prelude

import Data.DateTime (DateTime)
import Data.Foldable (foldr)
import Data.Formatter.DateTime (format)
import Data.JSDate (JSDate)
import Data.JSDate as JSDate
import Data.Maybe (Maybe)
import Data.Newtype (class Newtype, unwrap)
import Data.PreciseDateTime.Internal (dropWhileEnd)
import Data.RFC3339String.Format (iso8601Format)
import Data.String.CodeUnits as String
import Data.Tuple (Tuple(..), snd)
import Effect.Unsafe (unsafePerformEffect)

newtype RFC3339String = RFC3339String String
Expand Down Expand Up @@ -50,11 +48,3 @@ toDateTime = JSDate.toDateTime <<< unsafeParse <<< unwrap
-- | for why this is "unsafe".
unsafeParse :: String -> JSDate
unsafeParse = unsafePerformEffect <<< JSDate.parse

-- | Returns the prefix remaining after dropping characters that satisfy the
-- | predicate from the end of the string.
dropWhileEnd :: (Char -> Boolean) -> String -> String
dropWhileEnd p s = snd $ foldr check (Tuple false "") (String.toCharArray s)
where
check c state@(Tuple false _) = if p c then state else Tuple true (String.singleton c)
check c state@(Tuple true string) = Tuple true (String.singleton c <> string)
25 changes: 17 additions & 8 deletions src/Data/Time/PreciseDuration.purs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import Prelude

import Data.Decimal (Decimal)
import Data.Decimal as Decimal
import Data.PreciseDateTime.Internal (dropWhileEnd)

data PreciseDuration
= Nanoseconds Decimal
Expand Down Expand Up @@ -59,14 +60,22 @@ instance showPreciseDuration :: Show PreciseDuration where

toString :: PreciseDuration -> String
toString = case _ of
Nanoseconds d -> Decimal.toString d <> "ns"
Microseconds d -> Decimal.toString d <> "us"
Milliseconds d -> Decimal.toString d <> "ms"
Seconds d -> Decimal.toString d <> "s"
Minutes d -> Decimal.toString d <> "m"
Hours d -> Decimal.toString d <> "h"
Days d -> Decimal.toString d <> "d"
Weeks d -> Decimal.toString d <> "w"
Nanoseconds d -> format d <> "ns"
Microseconds d -> format d <> "us"
Milliseconds d -> format d <> "ms"
Seconds d -> format d <> "s"
Minutes d -> format d <> "m"
Hours d -> format d <> "h"
Days d -> format d <> "d"
Weeks d -> format d <> "w"

where

format :: Decimal -> String
format = trim <<< Decimal.toFixed 20

trim :: String -> String
trim = dropWhileEnd (_ == '.') <<< dropWhileEnd (_ == '0')

negatePreciseDuration :: PreciseDuration -> PreciseDuration
negatePreciseDuration = case _ of
Expand Down
19 changes: 19 additions & 0 deletions test/Data/Time/PreciseDuration.purs
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,22 @@ spec =
it "toHours" $ test toHours PD.hours hour inputs
it "toDays" $ test toDays PD.days day inputs
it "toWeeks" $ test toWeeks PD.weeks week inputs

it "toString" do
PD.toString (PD.nanoseconds 1) `shouldEqual` "1ns"
PD.toString (PD.microseconds $ Decimal.fromNumber 1.0) `shouldEqual` "1us"
PD.toString (PD.milliseconds $ Decimal.fromNumber 1.0) `shouldEqual` "1ms"
PD.toString (PD.seconds $ Decimal.fromNumber 1.0) `shouldEqual` "1s"
PD.toString (PD.minutes $ Decimal.fromNumber 1.0) `shouldEqual` "1m"
PD.toString (PD.hours $ Decimal.fromNumber 1.0) `shouldEqual` "1h"
PD.toString (PD.days $ Decimal.fromNumber 1.0) `shouldEqual` "1d"
PD.toString (PD.weeks $ Decimal.fromNumber 1.0) `shouldEqual` "1w"

-- Test that exponential notation is not used
PD.toString (PD.toMicroseconds $ PD.nanoseconds 1) `shouldEqual` "0.001us"
PD.toString (PD.toMilliseconds $ PD.nanoseconds 1) `shouldEqual` "0.000001ms"
PD.toString (PD.toSeconds $ PD.nanoseconds 1) `shouldEqual` "0.000000001s"
PD.toString (PD.toMinutes $ PD.nanoseconds 1) `shouldEqual` "0.00000000001666666667m"
PD.toString (PD.toHours $ PD.nanoseconds 1) `shouldEqual` "0.00000000000027777778h"
PD.toString (PD.toDays $ PD.nanoseconds 1) `shouldEqual` "0.00000000000001157407d"
PD.toString (PD.toWeeks $ PD.nanoseconds 1) `shouldEqual` "0.00000000000000165344w"

0 comments on commit 0e862a7

Please sign in to comment.