简体   繁体   中英

How to create a time duration in a for loop - (mismatched types int and time.Duration)

I have a loop where I start by a time.Time and I what to add a minute.

 for idx := range keys {
    var a = idx * time.Minute
    var t = tInit.Add(time.Minute * a)
    fmt.Println(t, idx)


 }

Here is my error

invalid operation: idx * time.Minute (mismatched types int and time.Duration)

The operands to numeric operations must have the same type. Convert the int value idx to a time.Duration : var a = time.Duration(idx) * time.Minute

As a developer in other programing languages I found this the most counterintuitive and illogical way of doing it. I worked in Scala in the last 10 years, and it could be as simple as this:

val a = idx minutes

compared that, the Go way:

var a = time.Duration(idx) * time.Minute

is more verbose, but that wouldn't be the end of the world.

The problem is that multiplying a Duration with another Duration doesn't make any sense if what you want is to obtain another Duration as a result, because from a physical point of view that would be measured in something like seconds squared.

According to the documentation time.Minute is a constant:

const (
    Nanosecond  Duration = 1
    Microsecond          = 1000 * Nanosecond
    Millisecond          = 1000 * Microsecond
    Second               = 1000 * Millisecond
    Minute               = 60 * Second
    Hour                 = 60 * Minute
)

And all those are defined in terms of the Duration type which is an alias for int64:

type Duration int64

From what I see is perfectly fine to multiply an integer literal with each one of these constants, after all that's how each one is defined in relation to the others.

So, to recap why is 60 * time.Second valid syntax (and makes perfect sense), but:

var secondsInAMinute := 60

var oneMinute = secondsInAMinute * time.Second

is invalid. This doesn't make any sense.

All those constants are of type Duration. That means they are measured in units of time (multiples of one nanosecond to be precise).

So, it seems the "correct" way to do it (correct in the sense that it compiles and works) doesn't make any physical sense. Let's look at this again:

var a = time.Duration(idx) * time.Minute

So, we are multiplying time.Duration(idx) with time.Minute.

The type for time.Minute is Duration which should be measured with a time unit. In physics it the accepted unit for time is the second. It seems Go uses integer nanoseconds instead, so time.Minute represents a Duration, represented internally in nanoseconds. That's fine.

The problem is that time.Duration(idx) also "converts" the integer idx to a Duration, so in physics it would also be represented as a unit of time, like seconds. So, accordingly, time.Duration(idx), in my opinion, represents idx nanoseconds in Go.

So, basically, when we write time.Duration(idx) * time.Minute we are muliplying idx nanoseconds (idx * 0.0000000001 seconds) with one minute (60 seconds).

So, from a physical point of view time.Duration(idx) * time.Minute would represent idx * 0.000000001 seconds * 60 seconds . Or, simplified, idx * 0.00000006 seconds squared .

Now, in what world is idx * 0.00000006 seconds squared equal to idx * 1 minute ?

So, now I know, in Go, if you want to apply a multiplier to a duration, you have to multiply that Duration to another Duration, and divide that in your mind with one millisecond so that all this mess can still makes any kind of physical sense.

I understand that all these unit inconsistencies are the result of the "The operands to numeric operations must have the same type." constraint. But that doesn't make it more logical or less annoying. In my opinion that restriction of the Go language should be removed.

But, for anyone that was lost in my explanations, let's see how illogical all this is with a concrete code example:

package main

import (
    "fmt"
    "time"
)

func main() {
    var oneMinute = 1 * time.Minute
    var oneNanosecond = 1 * time.Nanosecond

    var oneMinuteTimesOneNanoSecond = oneMinute * oneNanosecond
    
    fmt.Println(oneMinuteTimesOneNanoSecond)
}

The result is exactly what I expected from this nonsensical way of doing time calculations:

1m0s

I'll learn to live with this, but I will never like it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM