I'm contacting an API that returns a series of information. One of these, should be what I suppose to be a time unit and is expressed in a weird way:
{
"arrivalTime": 0.22916666666666746,
"stopTimeDelta": 0.0138888888888889,
"startTime": 0.24305555555555636
}
Has anybody ever seen something like this? I don't really need to use these dates for my project so that's why I don't bother contacting them, it's another company without straightforward channels to the dev team. But I'm really curious about this.
As suggested by #phuzi in the comments, it was fractional days. So, 1 is 24 hours, 0.25 is 6AM and so on.
This is a little function that will generate a Go time instance given the fractional unit.
Go Playground
func calculateTime(number float64) time.Time {
today := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 0, 0, 0, 0, time.UTC)
hour := number * 24
minutes := (hour * 1440) / 24
tm := today.Add(time.Duration(minutes) * time.Minute)
return tm
}
Related
I have two times, t1 and t2.
To calculate the difference, I use,
diff := t2.sub(t1)
The above code returns the difference like 10m30s, 1h3m59s etc.
I need to create some conditions for the difference.
For example,
if diff <= 5m {
do this
}
if diff > 20m {
do that
}
My question is if there is any built-in way to compare the time difference.
My other option would be to parse returned diff with regex and then compare. But I was looking for some efficient ways like the sub which the time package offers.
t2.Sub(t1) returns a duration, and you can simply use the comparison operators, for example:
d, _ := time.ParseDuration("4m4s")
if d <= 5 * time.Second {
fmt.Println("<= than limit")
} else {
fmt.Println("> than limit")
}
Way 1: When we use sub to get the duration
A very simple alternative is to directly use the output of the sub function. The func sub returns time.Duration type. So just adding .Minutes() method with it would serve the purpose in my case.
t1 := time.Now()
time.Sleep(60011 * time.Millisecond)
t2 := time.Now()
timeDiff := t2.Sub(t1)
fmt.Println(timeDiff)
fmt.Printf("\nIn just minites: %.f\n", timeDiff.Minutes())
Playground
Way 2: When we have the duration in string
If we would have the "difference" as a string ("10m2s") type then I believe we need to use the ParseDuration function. From the godocs ParseDuration
From the doc,
ParseDuration parses a duration string. A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
I am thinking of using it like the following,
t = "10h10m6s"
timeDiff, _ := time.ParseDuration(t)
numberOfHours := timeDiff.Hours()
numberOfMinutes := timeDiff.Minutes()
numberOfSeconds := timeDiff.Seconds()
numberofNanosec := timeDiff.Nanoseconds()
Find the example snippet on the playground
So in any of the above cases, we can use time.Minutes() to compare the duration.. As #gopher pointed out that to compare with any time range we do not need to convert it to any period of time (e,g Mintues(), Seconds()) but we can just compare with a required time period. As #Haris Osmanagić pointed out that this works for both of the output of ParseDuration and time.Sub() as they both returns time.Duration type. So we can do something like the following,
if timeDiff < 5 * time.Minutes() {
do something
} else if timeDiff > 5 * time.Minutes(){
do something else
} else {
do nothing
}
An example is on the playground.
I have a float64 containing a duration in seconds. I'm looking for a way to convert this value to a time.Duration. I'm able to perform this conversion, but I'm wondering if there is not a more elegant way.
The approach I have is this:
var timeout float64 // input value of float type
var res time.Duration // result value of time.Duration type
res += time.Duration(math.Round(timeout)) * time.Second
timeout -= math.Round(timeout)
timeout *= 1000
res += time.Duration(math.Round(timeout)) * time.Millisecond
timeout -= math.Round(timeout)
timeout *= 1000
res += time.Duration(math.Round(timeout)) * time.Microsecond
timeout -= math.Round(timeout)
timeout *= 1000
res += time.Duration(math.Round(timeout)) * time.Nanosecond
return res
What I dislike about this is that it is cumbersome and not reliable. I'd expect Go to supply something like this out of the box and to perform these conversions in a way that detects overflows and similar range violations. It seems that Go is not there yet, but maybe I missed something obvious, hence my question.
Notes:
This question doesn't address my needs, because it is rather related to the opposite way of conversion. That conversion is actually pretty painless, which makes the it even more surprising that the one I need isn't there.
Why don't I use milliseconds instead? Simple reason: Consistency, KISS principle, principle of least surprise. The SI unit for time is the second. Everything else is only derived from this, so I use this as a default.
Nitpick concerning the previous statement: Go itself says "There is no definition for units of Day or larger to avoid confusion across daylight savings time zone transitions.". They missed the point, because they still have minutes and hours, even though there are minutes with 58..61 seconds. Not a big deal, just mentioning it for completeness.
As JimB's comment shows, multiply the number of seconds by the number of duration units per second. Durations are measured in nanoseconds, but your code does not need to know that detail.
return time.Duration(timeout * float64(time.Second))
Convert to floating point for the multiplication and convert to duration to get the result.
I'm not sure what the issue is here. Your request is very simple to implement:
package main
import (
"fmt"
"time"
)
func duration(f float64) time.Duration {
return time.Duration(f * 1e9)
}
func main() {
t := duration(9)
fmt.Println(t) // 9s
}
It's literally one line of code, what is not elegant about that? The only way it could be more elegant, is if time.Duration was float64 natively. And that just doesn't make sense, as Go doesn't track anything smaller than a nanosecond.
https://golang.org/pkg/time#Duration
Go has methods to extract almost every component of a timestamp, eg time.Second(), time.Nano(), but none to extract the millisecond portion of a timestamp.
How does one extract the millisecond value of a timestamp.
eg, in the case of a timestamp like:
2021-01-07 10:33:06.511
i want to extract 511
To access the fraction seconds, you may use time.Nanosecond(). And if we convert it to time.Duration (time.Duration is exactly the nanoseconds count), we can take advantage of its Duration.Milliseconds() method (which of course does no magic but code will be clearer and easier to read):
func extractMs(t time.Time) int64 {
return time.Duration(t.Nanosecond()).Milliseconds()
}
Try it on the Go Playground.
there is an answer in the comments, but i want to post here to be cannonical:
func extractMillisecond(t time.Time) int {
ms := time.Duration(t.Nanosecond()) / time.Millisecond
return int(ms)
}
I have been trying to work with some go, and have found some weird behavior on windows. If I construct a time object from parsing a time string in a particular format, and then use functions like time.Since(), I get negative durations.
Code sample:
package main
import (
"fmt"
"time"
"strconv"
)
func convertToTimeObject(dateStr string) time.Time {
layout := "2006-01-02T15:04:05.000Z"
t, _:= time.Parse(layout, dateStr)
return t
}
func main() {
timeOlder := convertToTimeObject(time.Now().Add(-30*time.Second).Format("2006-01-02T15:04:05.000Z"))
duration := time.Since(timeOlder)
fmt.Println("Duration in seconds: " + strconv.Itoa(int(duration.Seconds())))
}
If you run it on Linux or the Go Playground link, you get the result as Duration in seconds: 30 which is expected.
However, on Windows, running the same piece of code with Go 1.10.3 gives Duration in seconds: -19769.
I've banged my head on this for hours. Any help on what I might be missing?
The only leads I've had since now are that when go's time package goes to calculate the seconds for both time objects (time.Now() and my parsed time object), one of them has the property hasMonotonic and one doesn't, which results in go calculating vastly different seconds for both.
I'm not the expert in time, so would appreciate some help. I was going to file a bug for Go, but thought to ask here from the experts if there's something obvious I might be missing.
I think I figured out what the reason for the weird behavior of your code snippet is and can provide a solution. The relevant docs read as follows:
since returns the time elapsed since t. It is shorthand for time.Now().Sub(t).
But:
now returns the current local time.
That means you are formatting timeOlder and subtract it from an unformatted local time. That of course causes unexpected behavior. A simple solution is to parse the local time according to your format before subtracting timeOlder from it.
A solution that works on my machine (it probably does not make a lot of sense to give a playground example, though):
func convertToTimeObject(dateStr string) time.Time {
layout := "2006-01-02T15:04:05.000Z"
t, err := time.Parse(layout, dateStr)
// check the error!
if err != nil {
log.Fatalf("error while parsing time: %s\n", err)
}
return t
}
func main() {
timeOlder := convertToTimeObject(time.Now().Add(-30 * time.Second).Format("2006-01-02T15:04:05.000Z"))
duration := time.Since(timeOlder)
// replace time.Since() with a correctly parsed time.Now(), because
// time.Since() returns the time elapsed since the current LOCAL time.
t := time.Now().Format("2006-01-02T15:04:05.000Z")
timeNow := convertToTimeObject(t)
// print the different results
fmt.Println("duration in seconds:", strconv.Itoa(int(duration.Seconds())))
fmt.Printf("duration: %v\n", timeNow.Sub(timeOlder))
}
Outputs:
duration in seconds: 14430
duration: 30s
I am learning how to code in Go and trying to create a simple reminder function.
I want to display the current time as a regular 24 hour clock, XX.XX (hours, minutes).
I have saved the current time in a variable t and when I print it I find out that the time is 23.00 early November 2009. Fine, but when I print t.Hour and t.Minute the result is 132288.132480.
It is something similar when I print t.Seconds. I have not been able to figure out why this happens.
Roughly 2000 days have passed since but that is only 48k hours and 2880k minutes so the small difference between the hours and minutes in my result hints that the issue is something else.
I am running the code in the go playground.
My code:
package main
import (
"fmt"
"time"
)
func main() {
Remind("It's time to eat")
}
func Remind(text string) {
t := time.Now()
fmt.Println(t)
fmt.Printf("The time is %d.%d: ", t.Hour, t.Minute)
fmt.Printf(text)
fmt.Println()
}
You need to call t.Hour() instead of using it as a value.
Check out the source of time package here: https://golang.org/src/time/time.go?s=12994:13018#L390
399 // Hour returns the hour within the day specified by t, in the range [0, 23].
400 func (t Time) Hour() int {
401 return int(t.abs()%secondsPerDay) / secondsPerHour
402 }
403
When in doubt, you can quickly find an explanation by reading specific package source from official go packages page.