Open vrom911 opened 6 years ago
Yeah, we've been going back and forth on this for a while in the F# version and ended up generating a 64-bit integer in the form of a 64-bit FILETIME structure, called tick
:
A date and time expressed in the number of 100-nanosecond intervals that have elapsed since January 1, 0001 at 00:00:00.000 in the Gregorian calendar.
let dateTime : Gen<System.DateTime> =
let minTicks =
System.DateTime.MinValue.Ticks
let maxTicks =
System.DateTime.MaxValue.Ticks
gen {
let! ticks =
Range.constantFrom
(System.DateTime (2000, 1, 1)).Ticks minTicks maxTicks
|> integral
return System.DateTime ticks
}
(The above generator shrinks towards year 2000, and is responsible for generating the instants in time. This way, I hope, you don't have to worry about getting the number of days per month correct.)
Now, under UNIX platforms, file times are maintained in the form of a ANSI C runtime arithmetic type named time_t
1, which represents seconds since midnight January 1, 1970 UTC (coordinated universal time).
Perhaps we can do similar here using EpochTime
, convert to POSIXTime
and then UTCTime
, something I've never tried actually. However, the equivalent in F# works pretty well (so far).
--
1. How To Convert a UNIX time_t to a Win32 FILETIME or SYSTEMTIME
@vrom911 Thanks, I'm giving this generator a go. I think there is one issue:
The seconds generated atm is [0, 86401] (where '[' is inclusive) but the UTC diffTime requires seconds in the range [0, 86401) (where ')' is exclusive): "the time from midnight, 0 <= t < 86401s (because of leap-seconds)".
So I think that line needs to be updated to:
secs <- toInteger <$> Gen.int (Range.constant 0 86400)
Thanks again.
The main concern I have with a time generator, isn't so much the implementation, but that there isn't really an agreed time data type in Haskell.
There are at lease three choices that I'm aware of when it comes to time packages (time, thyme and chronos) and it's not obvious to me which one to support, or if we should support them all. If the choice was obvious I would have had it from the start.
They all have pros and cons, with the vulnerable time
library probably being the worst choice for production code given it uses Integer
to represent everything! In the past I have defaulted to thyme
, but it has a pretty heavy dependency stack. This is much better since they dropped lens
as a required dependency, but it's pretty wild that it has a dependency on QuickCheck
!
I haven't tried chronos
but looks like it might be a happy medium, I especially like that it has nanosecond resolution while using a single Int64
instead of a big Integer
. thyme
also uses a single Int64
but only has microsecond resolution, so it's kind of useless for a whole class of applications (e.g. HFT or other high performance networking, etc)
It is tempting to include UTCTime
from the time
package on the basis that it comes with GHC out of the box. I just wouldn't want to encourage people to actually use it as it's usually the wrong choice.
Fwiw, I would generate a posix time and convert it to UTCTime
so you don't need to worry about seconds and months, etc. I think something like what F# is doing is the right approach.
@jystic Thanks for shedding some light on that situation, I'm not super familiar with the time libraries in Haskell. I might give the POSIX time a go.
It's such a nightmare, hard to believe that of all platforms (at least that I'm familiar with), the one from Microsoft probably has the best built in dates / times. The only thing I would improve about the .NET DateTime
(assuming we don't worry about timezones) is nanosecond resolution. Also some of their conversion functions truncate to milliseconds but I guess that's the same issue.
I think maybe a good way for us to solve this is to have a few small packages hedgehog-time
, hedgehog-thyme
, hedgehog-chrono
, etc.
have a few small packages
hedgehog-time
,hedgehog-thyme
,hedgehog-chrono
, etc.
This looks like a good idea :+1: Those packages should be so small and focused that could even go under https://github.com/hedgehogqa.
Yeah I would be happy to have them in the haskell-hedgehog repo
Here are the imports for the given example in issue description:
import Hedgehog (MonadGen)
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import Data.Time (UTCTime(..), fromGregorian, secondsToDiffTime)
As for merging this function, what's the harm to have it in hedgehog package given that time
is part of GHC and no extra dependencies are needed?
I know that this could be very difficult to implement, but it's very handy to have one.
Currently, I use very simple implementation like this: