haskell / time

A time library
http://hackage.haskell.org/package/time
Other
118 stars 78 forks source link

Supporting decimal fractions on values other than seconds #213

Closed giulioforesto closed 1 year ago

giulioforesto commented 2 years ago

Expected behavior

The standard says: "If necessary for a particular application, the lowest order components may have a decimal fraction." (§4.4.3.2) The plural suggests that it's not the lowest order component in absolute (if so, why wouldn't they have written just "seconds"?), but rather the lowest that is used in the time interval representation we're talking about. This is also what the definition of "decimal representation" stands (§2.3.6): "decimal representation: expansion of a representation by addition of a decimal fraction to the lowest order component of the expression"

So the following should be valid:

But the following shouldn't:

Current behavior

Currently, it seems that decimal representation is allowed only on seconds:

ghci> import Data.Time.Format.ISO8601
ghci> iso8601ParseM "PT1H" :: Maybe CalendarDiffTime 
Just P0MT3600S
ghci> iso8601ParseM "PT1.5H" :: Maybe CalendarDiffTime 
Nothing
ghci> iso8601ParseM "PT1S" :: Maybe CalendarDiffTime 
Just P0MT1S
ghci> iso8601ParseM "PT1.5S" :: Maybe CalendarDiffTime 
Just P0MT1.5S
ghci> iso8601ParseM "P1Y" :: Maybe CalendarDiffTime 
Just P12MT0S
ghci> iso8601ParseM "PT1.5Y" :: Maybe CalendarDiffTime 
Nothing
AshleyYakeley commented 2 years ago

Fractional hours and minutes should be OK. But we run into problems with fractional years and months, as they can't be directly represented in CalendarDiffTime. Also, if I fix #210, fractional days become tricky.

AshleyYakeley commented 2 years ago

How long is half a month?

dcastro commented 2 years ago

For what it's worth, java.time and joda-time don't seem to handle this either: https://scastie.scala-lang.org/dcastro/vB4apOIwQdOEl6rORycOWA/89

giulioforesto commented 2 years ago

How long is half a month?

I don't know exactly how it works, but I suppose that with integral diffs it's easy to get a time interval by simply incrementing the corresponding value in the start date:

However, if we want to manage fractions, then we will necessary need to convert the decimal fraction of the time interval to a duration and add it to the date to get the result. To compute the end date of 2022-06-30T14:27:00/P1.5M, which is 2022-07-30T14:27:00/P0.5M, we need to convert 2022-07-30T14:27:00/P1M to a duration x (let's say in seconds) and do 2022-07-30T14:27:00/PTyS where y = x * 0.5.

However, it could be too much work for what it's worth and this could be a won't fix :) (maybe we should simply mention it in the doc).

Does this make sense?

AshleyYakeley commented 1 year ago

I think this handling of half a month is counter-intuitive, and it's better not to support it.