I am trying to find a way to check if the current time is in a given interval, where start and end are given (eventually) by a user.
I have been trying by using the After and Before from the Time package after making sure all times are in UTC, but clearly I am doing something wrong.
The code looks similar to this example:
func inTimeSpan(start, end, check time.Time) bool {
return check.After(start) && check.Before(end)
}
func main() {
now := time.Now()
newLayout := "15:04"
ns, _ := time.Parse(newLayout, strconv.Itoa(now.Hour())+":"+strconv.Itoa(now.Minute()))
srt, _ := time.Parse(newLayout, "23:00")
end, _ := time.Parse(newLayout, "05:00")
fmt.Println("1 : ", inTimeSpan(srt, end, ns))
}
Any help is appreciated.
Now() function, we can get the current time in Golang by importing time module. Return: Return current date and time. Example #1: In this example, we can see that by using time. Now() function, we are able to get the current date and time.
The Now() function in Go language is used to find the current local time. Moreover, this function is defined under the time package. Here, you need to import the “time” package in order to use these functions. Return Value: It returns the current local time.
For example, a 4-digit year might be represented by %Y . In Go, though, these parts of a date or time are represented by characters that represent a specific date. To include a 4-digit year in a Go date format, you would actually include 2006 in the string itself.
EDIT: It was wrong initially, sorry about that. Fixed version, and also the range now is inclusive. Check also Mickael V. answer as adding time make sense too.
func inTimeSpan(start, end, check time.Time) bool {
if start.Before(end) {
return !check.Before(start) && !check.After(end)
}
if start.Equal(end) {
return check.Equal(start)
}
return !start.After(check) || !end.Before(check)
}
Check it on playground https://play.golang.org/p/CGWqY2AQ-Th
package main
import (
"fmt"
"time"
)
func inTimeSpan(start, end, check time.Time) bool {
if start.Before(end) {
return !check.Before(start) && !check.After(end)
}
if start.Equal(end) {
return check.Equal(start)
}
return !start.After(check) || !end.Before(check)
}
func main() {
test := []struct {
start string
end string
check string
}{
{"23:00", "05:00", "04:00"},
{"23:00", "05:00", "23:30"},
{"23:00", "05:00", "20:00"},
{"10:00", "21:00", "11:00"},
{"10:00", "21:00", "22:00"},
{"10:00", "21:00", "03:00"},
// Additional checks.
{"22:00", "02:00", "00:00"},
{"10:00", "21:00", "10:00"},
{"10:00", "21:00", "21:00"},
{"23:00", "05:00", "06:00"},
{"23:00", "05:00", "23:00"},
{"23:00", "05:00", "05:00"},
{"10:00", "21:00", "10:00"},
{"10:00", "21:00", "21:00"},
{"10:00", "10:00", "09:00"},
{"10:00", "10:00", "11:00"},
{"10:00", "10:00", "10:00"},
}
newLayout := "15:04"
for _, t := range test {
check, _ := time.Parse(newLayout, t.check)
start, _ := time.Parse(newLayout, t.start)
end, _ := time.Parse(newLayout, t.end)
fmt.Println(t.start+"-"+t.end, t.check, inTimeSpan(start, end, check))
}
}
Result:
23:00-05:00 04:00 true
23:00-05:00 23:30 true
23:00-05:00 20:00 false
10:00-21:00 11:00 true
10:00-21:00 22:00 false
10:00-21:00 03:00 false
22:00-02:00 00:00 true
10:00-21:00 10:00 true
10:00-21:00 21:00 true
23:00-05:00 06:00 false
23:00-05:00 23:00 true
23:00-05:00 05:00 true
10:00-21:00 10:00 true
10:00-21:00 21:00 true
10:00-10:00 09:00 false
10:00-10:00 11:00 false
10:00-10:00 10:00 true
For example,
package main
import (
"fmt"
"strconv"
"time"
)
func inTimeSpan(start, end, check time.Time) bool {
start, end = start.UTC(), end.UTC()
if start.After(end) {
start, end = end, start
}
check = check.UTC()
return !check.Before(start) && !check.After(end)
}
func main() {
now := time.Now()
newLayout := "15:04"
ns, _ := time.Parse(newLayout, strconv.Itoa(now.Hour())+":"+strconv.Itoa(now.Minute()))
srt, _ := time.Parse(newLayout, "23:00")
end, _ := time.Parse(newLayout, "05:00")
fmt.Println(srt, end)
fmt.Println(ns)
fmt.Println("1 : ", inTimeSpan(srt, end, ns))
}
Output:
0000-01-01 23:00:00 +0000 UTC 0000-01-01 05:00:00 +0000 UTC
0000-01-01 20:37:00 +0000 UTC
1 : true
Building on Kamil's answer, which is ultimately wrong as its own tests show, here is a solution that makes use only of Go's time interface.
The trick, knowing that Go will make Before
and After
comparison using time AND date, is to just push the end time to the next day if its time component is "smaller" than the start one. Then the time to check needs to be done the same if it's before the start time.
I took the same test cases and added some significant ones like midnight.
package main
import (
"fmt"
"time"
)
func inTimeSpan(start, end, check time.Time) bool {
_end := end
_check := check
if end.Before(start) {
_end = end.Add(24 * time.Hour)
if check.Before(start) {
_check = check.Add(24 * time.Hour)
}
}
return _check.After(start) && _check.Before(_end)
}
func main() {
test := []struct {
start string
end string
check string
}{
{"23:00", "05:00", "04:00"},
{"23:00", "05:00", "23:30"},
{"23:00", "05:00", "20:00"},
{"10:00", "21:00", "11:00"},
{"10:00", "21:00", "22:00"},
{"10:00", "21:00", "03:00"},
{"22:00", "02:00", "00:00"},
{"10:00", "21:00", "10:00"},
{"10:00", "21:00", "21:00"},
}
newLayout := "15:04"
for _, t := range test {
check, _ := time.Parse(newLayout, t.check)
start, _ := time.Parse(newLayout, t.start)
end, _ := time.Parse(newLayout, t.end)
fmt.Println(t.start+"-"+t.end, t.check, inTimeSpan(start, end, check))
}
}
Output :
23:00-05:00 04:00 true
23:00-05:00 23:30 true
23:00-05:00 20:00 false
10:00-21:00 11:00 true
10:00-21:00 22:00 false
10:00-21:00 03:00 false
22:00-02:00 00:00 true
10:00-21:00 10:00 false
10:00-21:00 21:00 false
You will notice on the two last cases that the check is not inclusive for the start time, nor the end time. If you need to change that behavior, you can remediate this by changing the function a little :
func inTimeSpanEx(start, end, check time.Time, includeStart, includeEnd bool) bool {
_start := start
_end := end
_check := check
if end.Before(start) {
_end = end.Add(24 * time.Hour)
if check.Before(start) {
_check = check.Add(24 * time.Hour)
}
}
if includeStart {
_start = _start.Add(-1 * time.Nanosecond)
}
if includeEnd {
_end = _end.Add(1 * time.Nanosecond)
}
return _check.After(_start) && _check.Before(_end)
}
Extract of the output when calling with true
for inclusion of start and end :
10:00-21:00 10:00 true
10:00-21:00 21:00 true
Complete playground here : https://play.golang.org/p/8ig34gmHl71
Here is a clean solution which is immune from time zone issues. In my context, I run a function in a concurrent timer thread and it calls this function every 5 minutes to check the time against the given range.
Note that you should use whole minutes only for this to work. While I haven't tested it, I think the time.Kitchen
layout will strip seconds during the time conversions. There is no need to specify seconds as the selector will take every time in the range except the exact end time.
There is no accounting for midnight but I didn't need that functionality. If you wanted that you could test
if end.Before(start) {
if timeNow.After(start) {
return false
}
if timeNow.After(end) {
return true
}
return false
} else {
....
}
Here is my function as it is.
func stringToTime(str string) time.Time {
tm, err := time.Parse(time.Kitchen, str)
if err != nil {
fmt.Println("Failed to decode time:", err)
}
fmt.Println("Time decoded:", tm)
return tm
}
func isInTimeRange() bool {
startTimeString := "06:00AM" // "01:00PM"
endTimeString := "06:05AM"
t := time.Now()
zone, offset := t.Zone()
fmt.Println(t.Format(time.Kitchen), "Zone:", zone, "Offset UTC:", offset)
timeNowString := t.Format(time.Kitchen)
fmt.Println("String Time Now: ", timeNowString)
timeNow := stringToTime(timeNowString)
start := stringToTime(startTimeString)
end := stringToTime(endTimeString)
fmt.Println("Local Time Now: ", timeNow)
if timeNow.Before(start) {
return false
}
if timeNow.Before(end) {
return true
}
return false
}
Output
What's the time, Mr Wolf?
10:58AM Zone: ACST Offset UTC: 34200
String Time Now: 10:58AM
Time decoded: 0000-01-01 10:58:00 +0000 UTC
Time decoded: 0000-01-01 11:00:00 +0000 UTC
Time decoded: 0000-01-01 11:05:00 +0000 UTC
Local Time Now: 0000-01-01 10:58:00 +0000 UTC
What's the time, Mr Wolf?
11:03AM Zone: ACST Offset UTC: 34200
String Time Now: 11:03AM
Time decoded: 0000-01-01 11:03:00 +0000 UTC
Time decoded: 0000-01-01 11:00:00 +0000 UTC
Time decoded: 0000-01-01 11:05:00 +0000 UTC
Local Time Now: 0000-01-01 11:03:00 +0000 UTC
Time to eat you!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With