template Asset
with
issuer : Party
owner : Party
name : Text
timeOfCreation: Time
timeOfCreationText: Text
where
ensure name /= ""
signatory issuer
observer owner
choice Give : ContractId Asset
with newOwner : Party
controller owner
do
now <- getTime
let newTime = addRelTime now (convertMicrosecondsToRelTime 23123)
create this with owner = newOwner; timeOfCreation = newTime; timeOfCreationText = show newTime
timeOfCreationText shows microsecond resolution on the Navigator when I add the 23123 microseconds to now , whereas it shows millisecond resolution without this line.
Am I correct in my understanding that Time in Daml can support upto microsecond resolution?
How do we extract in Daml the day, hour, minute, second, millisecond and microsecond values from a Time value?
There is a convertRelTimeToMicroseconds function you can use to convert the time to microseconds. You could then use mod microseconds 1000 to get the microseconds part. The number of hours, minutes, seconds in a time can be calculated by dividing the microseconds respectively by 3.600.000.000, 60.000.000, 1.000.000. The number of days by dividing by 86.400.000.000. (I’m not aware of easy helper functions for this, please correct me if there are)
If you want a separate milliseconds part and microseconds part, you should mod 1000 for just the microseconds remainder. (the remainder of microseconds separately from the number of milliseconds). I might have assumed incorrectly that you wanted to separate milliseconds and microseconds parts.
There is DA.Time.wholeDays, but there doesn’t seem to be an equivalent for other units.
1 000 000.
This is a bit sad but it does look like the only possible approach at the moment given that Time is opaque.
You could replace (date 1970 Jan 1) with (DA.Date.toDateUTC now) to avoid a magic number.
Alternatively, you could go through show, but that’s definitely not better:
toMs : Time -> Int
toMs time =
case DA.Text.splitOn "." (show time) of
[] -> error "can't happen, splitOn always returns at least 1 element"
[_] -> 0 -- No ms part printed
[_, ms] -> foldl f 0 $ zip [100000, 10000, 1000, 100, 10, 1] (DA.List.dropSuffix ["Z"] $ DA.Text.explode ms)
_ -> error "can't happen, no more than one . in a date"
where f acc (m, c) = acc + m * case c of
"0" -> 0
"1" -> 1
"2" -> 2
"3" -> 3
"4" -> 4
"5" -> 5
"6" -> 6
"7" -> 7
"8" -> 8
"9" -> 9
_ -> error "can't happen"
I don’t think this is safe. Don’t you need to account for leap seconds and such?
Again I don’t think this is a good idea - I haven’t looked at the implementation, but there can be a danger of overflow here. I.e. x number of microseconds in a 32 or 64 bit value max. I’m not certain what guarantees there are that this won’t change.
RelTime is a duration, not a time, so leap seconds don’t apply. It quite literally is a number of milliseconds.
Whether the conversion from Time to RelTime is safe is a different matter, which is partly why I suggested converting after removing the same date, which would leave you with just the “time of day” and thus a maximum of 8.6e10 which very comfortably fits in 64 bits. This also avoids leap years and leap seconds. Plus, bear in mind that the question was how to get the milliseconds, so seconds, leap or not, are basically ignored.
I’m not sure what the internal representation of Time is, but on the JSON conversion side we limit the range to 0000-01-01T00:00:00Z to 9999-12-31T23:59:59.999999Z, which, assuming we start at 0, still only reaches ~3.2e17, compared to 9.22e18 for a signed, 64-bits integer, so I wouldn’t worry about overflow.