Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: time: Add functions for finding greatest or least time.Time supplied #65679

Open
kevinxmorales opened this issue Feb 12, 2024 · 4 comments
Labels
Milestone

Comments

@kevinxmorales
Copy link

Proposal Details

While attempting to port over from Ruby code to Go, I ran into an issue where I needed to set a variable of type time.Time to the maximum of three different times. The maximum here would apply to the farthest in the future time. In Ruby this involves putting the three times in an array and calling the max method on the array.

my_time = [someTime, someTime2, DateTime.now].max

This doesn't work in Go currently because the slices.Max method only works on slices where of type cmp.Ordered which time.Time is not.
All time.Time's can be converted to an int64 Unix representation which would satisfy the cmp.Ordered requirement for using slices.Max and slices.Min. However, this wouldn't work for times before 0 Unix time.

I'd instead purpose adding Min and Max functions for the time package. They'd work by just using the Before and After methods that already exist in the package

func Max(x Time, y ...Time) Time {
	maxTime := x
	for _, val := range y {
		if val.After(maxTime) {
			maxTime = val
		}
	}
	return maxTime
}

func Min(x Time, y ...Time) Time {
	minTime := x
	for _, val := range y {
		if val.Before(minTime) {
			minTime = val
		}
	}
	return minTime
}
// Usage
thatTime := time.Max(someTime, someTime2, time.Now())

The function signature is just like the min and max built-in functions where at least one parameter is required, that way we can just return that value if no others are passed in. The first parameter would also just get used as our base for finding the min or max of the times. This also prevents us from unintentionally returning the time.Time zero value in the Min function

@gopherbot gopherbot added this to the Proposal milestone Feb 12, 2024
@seankhliao
Copy link
Member

This sounds quite specialized, how often is this operation used outside of your specific example?

https://go.dev/doc/faq#x_in_std

@earthboundkid
Copy link
Contributor

oldest := slices.MinFunc([]time.Time{now, someTime, someTime2}, time.Time.Compare)

https://go.dev/play/p/rVGx_3me6NQ

@ianlancetaylor ianlancetaylor moved this to Incoming in Proposals Feb 13, 2024
@jflambert
Copy link

jflambert commented Dec 16, 2024

Thanks @earthboundkid, I ended up here while looking for golang equivalents to greatest and least functions in PostgreSQL which accept any data type.

@apparentlymart
Copy link

Note that the conversion from a time.Time to an offset from the Unix epoch can return a negative number, so Unix timestamp zero is not the lower bound.

The documentation for each of the methods that return Unix-epoch-relative offsets says, at the time of writing:

  • Time.Unix "is valid for billions of years into the past or future" [relative to zero]
  • Time.UnixMicro: Year -290307 through 294246
  • Time.UnixMilli: "292 million years before or after 1970"
  • Time.UnixNano: Year 1678 through 2262

The nanosecond-grain result does have a somewhat constrained range if you want to talk about all years where humans might have done something, but the others seem like they ought to be sufficient for most cases unless you actually need to be able to distinguish timestamps that differ only in nanoseconds.

Does the ability for these functions to represent timestamps before Unix epoch make that a viable solution after all, or do you need to compare timestamps even outside of these wide ranges? 🤔

(I personally don't feel opposed to having comparison functions that are valid for all time.Time values, FWIW, but the argument for it in the proposal suggested that these Unix timestamp functions can only return positive timestamps, which doesn't seem to be true.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Incoming
Development

No branches or pull requests

6 participants