Go: Proposal: Add time.Until() to the time package

Created on 2 Mar 2016  路  13Comments  路  Source: golang/go

I'd like to propose that a time.Until(t time.Time) time.Duration function be added to the time package to compliment the existing Since() shortcut. This would make writing expressions with an expiration time a bit more readable:

<-After(time.Until(expirationTime))

vs.

<-After(expirationTime.Sub(time.Now()))

While it's still fairly obvious what the second one does, it takes a little longer to recognize "sub" as subtraction than just seeing the symbol. Also keeping time expressions more or less readable as english is a nice benefit of having the until shortcut (as you can do with the existing since function).

If this accepted, I've got a CL here for review.

FrozenDueToAge Proposal Proposal-Accepted

Most helpful comment

There's in total around 2000 repos (counting forks only once) that could benefit from this feature.

SELECT REGEXP_EXTRACT(repo_name, r'.*/(.*)') as project, FLOOR(COUNT(*) / COUNT(DISTINCT repo_name)) as n, FIRST(line) as sample
FROM (
  SELECT id, split(content, '\n') as line
  FROM [campoy-github:go_files.contents]
  HAVING line CONTAINS '.Sub(time.Now())'
) as contents JOIN [campoy-github:go_files.files] as files
ON contents.id = files.id
GROUP BY project
ORDER BY n DESC

The 10 projects that would benefit the most are

Row project                     n           sample   
1   robin                       62.0        time.Sleep(expectedExp.Sub(time.Now()) - 500*time.Millisecond)   
2   contrib                     26.0        deadlineTimeout := dialer.Deadline.Sub(time.Now())   
3   j2                          26.0        time.Sleep(expectedExp.Sub(time.Now()) - 500*time.Millisecond)   
4   gitarchive                  20.0        c.traceInfo.firstLine.deadline = deadline.Sub(time.Now())    
5   megacfs                     20.0        sleep := nextRun.Sub(time.Now())     
6   microcosm                   20.0        d := deadline.Sub(time.Now())    
7   concourse-pipeline-resource 20.0        req.TimeoutSeconds = proto.Float64(cn.readDeadline.Sub(time.Now()).Seconds())    
8   etcd2-bootstrapper          20.0        Timeout: d.Sub(time.Now()),  
9   zypper-docker               18.0        timeout = deadline.Sub(time.Now())   
10  doit                        16.0        Timeout: d.Sub(time.Now()), 

In my opinion there's some projects that could benefit of this, but it's clearly not a high priority addition to the stdlib.

All 13 comments

CL https://golang.org/cl/20118 mentions this issue.

Does it pay for itself?

I see only 7 potential users in the standard library:

$ git grep -E 'Sub\(time.Now'
src/crypto/tls/tls.go:          deadlineTimeout := dialer.Deadline.Sub(time.Now())
src/net/dial_gen.go:    timeout := deadline.Sub(time.Now())
src/net/dial_test.go:           case <-time.After(deadline.Sub(time.Now())):
src/net/fd_poll_runtime.go:     diff := int64(t.Sub(time.Now()))
src/net/http/client.go: timer := time.NewTimer(deadline.Sub(time.Now()))
src/net/http/serve_test.go:                     if remaining := c.rd.Sub(time.Now()); remaining < cue {
src/net/lookup.go:      timeout := deadline.Sub(time.Now())

That's 7 places in the standard library that would be somewhat more readable; however, it's a public API so I'm sure there are many more places where it would be useful outside the standard library too. I'd say it pays for itself in adding simplicity, but maybe I'm alone in that?

We often use the standard library as a proxy for how common a pattern is. Yes, surely there are more than 7 globally. But the question is how often rate-wise this occurs.

I see; I'd suspect a lot (actually, 7 seems like a pretty large number for the handful of packages in the standard library that will use this sort of thing).

For the record, I see 22 uses of Since in the standard library, which is more, but still not a huge number.

I got 22 uses of time.Since in the standard library
vs. 7 that could use the proposed time.Until.

How is this different than -1 * time.Since(expirationTime) or -time.Since(expirationTime) ?

How is this different than -1 * time.Since(expirationTime) or -time.Since(expirationTime)?

It's not, this would be for readability (in the same way that time.Since improves readability over just doing time.Now().Sub(t))

@campoy, can you query the Github corpus in BigQuery and see if this proposal would be worthwhile?

There's in total around 2000 repos (counting forks only once) that could benefit from this feature.

SELECT REGEXP_EXTRACT(repo_name, r'.*/(.*)') as project, FLOOR(COUNT(*) / COUNT(DISTINCT repo_name)) as n, FIRST(line) as sample
FROM (
  SELECT id, split(content, '\n') as line
  FROM [campoy-github:go_files.contents]
  HAVING line CONTAINS '.Sub(time.Now())'
) as contents JOIN [campoy-github:go_files.files] as files
ON contents.id = files.id
GROUP BY project
ORDER BY n DESC

The 10 projects that would benefit the most are

Row project                     n           sample   
1   robin                       62.0        time.Sleep(expectedExp.Sub(time.Now()) - 500*time.Millisecond)   
2   contrib                     26.0        deadlineTimeout := dialer.Deadline.Sub(time.Now())   
3   j2                          26.0        time.Sleep(expectedExp.Sub(time.Now()) - 500*time.Millisecond)   
4   gitarchive                  20.0        c.traceInfo.firstLine.deadline = deadline.Sub(time.Now())    
5   megacfs                     20.0        sleep := nextRun.Sub(time.Now())     
6   microcosm                   20.0        d := deadline.Sub(time.Now())    
7   concourse-pipeline-resource 20.0        req.TimeoutSeconds = proto.Float64(cn.readDeadline.Sub(time.Now()).Seconds())    
8   etcd2-bootstrapper          20.0        Timeout: d.Sub(time.Now()),  
9   zypper-docker               18.0        timeout = deadline.Sub(time.Now())   
10  doit                        16.0        Timeout: d.Sub(time.Now()), 

In my opinion there's some projects that could benefit of this, but it's clearly not a high priority addition to the stdlib.

I'm in favor of this. time.Since is a great API. time.Until is a fitting parallel.

should change milestone to go1.8? or how to set the milestone label?

@s7v7nislands it doesn't matter now. The issue is resolved.

Was this page helpful?
0 / 5 - 0 ratings