'How do you deal with wall-clock times without date in Go?
I'd like to know if there is any existing package to deal with datetimes without date in Golang.
The problem is as follows. Imagine I want to store information about shifts in a company, including when this shifts start and end, I would create something like:
import "time"
type Shift struct {
StartTime time.Time
FinishTime time.Time
// More fields
}
The problem is, the field time.Time also stores information about the day, month and year, and that could lead to several problems at the time of comparing shifts.
Is there any alternative like civil.Date (https://pkg.go.dev/cloud.google.com/go/civil) but for just times instead of just dates?
Solution 1:[1]
In order to have just time and omit the other information about the day, month and year you can make use of Format()
method. I have created a sample program for the same as follows:
package main
import (
"fmt"
"time"
)
func main() {
const (
layoutTime = "15:04:05"
)
fmt.Println("Date", time.Now())
fmt.Println("Time", time.Now().Format(layoutTime))
}
Output:
Date 2009-11-10 23:00:00 +0000 UTC m=+0.000000001
Time 23:00:00
Solution 2:[2]
It's kind of hard to answer this question, as you haven't really described what the type would need to do, other than this:
Yeah, but the point is, that time.Time will be prone to bugs in a less-than / more-than comparison if you allow the user to give a date. The goal should be to have a comparable struct and for the user not to give a date in order not to mess it up.
So going off that, you could use something like this:
package wall
import "errors"
type Clock struct { hour, minute, second int }
func NewClock(h, m, s int) (*Clock, error) {
if h > 23 || m > 59 || s > 59 {
return nil, errors.New("invalid input")
}
return &Clock{h, m, s}, nil
}
func (c Clock) Seconds() int {
return c.hour * 60 * 60 + c.minute * 60 + c.second
}
func (c Clock) LessThan(d *Clock) bool {
return c.Seconds() < d.Seconds()
}
Example:
package main
import "wall"
func main() {
c, err := wall.NewClock(9, 59, 59)
if err != nil {
panic(err)
}
d, err := wall.NewClock(10, 59, 59)
if err != nil {
panic(err)
}
println(c.LessThan(d))
}
Solution 3:[3]
Trust me, You still need the Date, not just the Clock.
For example : what if the StartTime = 23:00:00
and FinishTime = 06:00:00
, if you didn't capture the date, the information inside of the Shift
struct is FinishTime < StartTime
, and that goes against the words of start
and finish
itself.
That's where the date works, so if the FinishTime
is more than the StartTime
, the StartTime
needs to be reduced by 1 day OR FinishTime
plus 1 day.
Here's the example solution code that I make to check if the currentTime
is between 2 time(clock)
First of all since I just need the clock information (HH:mm:ss), I prefer to use a string
type for the StartTime
and FinishTime
.
type Shift struct {
StartTime string
FinishTime string
}
and here's what it goes.
type Shift struct {
StartTime string
FinishTime string
}
func main() {
myShift := Shift{
StartTime: "23:00",
FinishTime: "06:00",
}
actualStartTime, actualEndTIme := convertShiftClockToShiftTime(myShift.StartTime, myShift.FinishTime)
fmt.Println(actualStartTime, actualEndTIme)
}
func convertShiftClockToShiftTime(StartTime string, FinishTime string) (startTime time.Time, endTime time.Time) {
// I need to convert the time to a string so I can easily add the clock
timeLayout := "2006-01-02T15:04"
dateOnlyLayout := "2006-01-02"
currentTime := time.Now()
currentDate := currentTime.Format(dateOnlyLayout)
// currentDate = Y-m-d
startDateStr := currentDate + "T" + StartTime
startTime, _ = time.Parse(timeLayout, startDateStr)
endDateStr := currentDate + "T" + FinishTime
endTime, _ = time.Parse(timeLayout, endDateStr)
if startTime.After(endTime) {
// plus 1 day to the endTime if the endTime < startTime
endTime = endTime.AddDate(0, 0, 1)
}
return startTime, endTime
}
I created a function called convertShiftClockToShiftTime
to change the clock into actual time as I mentioned before, what if the StartTime = 23:00
and EndTime = 06:00
.
Basically the program should know if the StartTime is more than FinishTime, FinishTime should be tomorrow.
Hope this helps, I hope my explanation can explain to you what time
itself means.
Solution 4:[4]
time.Duration
can be used for wall-clock time without date. Some examples:
type Shift struct {
StartTime time.Duration
FinishTime time.Duration
}
func main() {
d1, _ := time.ParseDuration("11h") // 11:00
d2, _ := time.ParseDuration("20h") // 20:00
shift := Shift{
StartTime: d1,
FinishTime: d2,
}
// If you want to put them into specific day
today0 := time.Now().UTC().Truncate(24 * time.Hour)
start := today0.Add(shift.StartTime)
finish := today0.Add(shift.FinishTime)
fmt.Printf("Start at: %v\nFinish at: %v\n", start, finish)
}
For times that span two days:
d1, _ := time.ParseDuration("-30m") // 23:30 of previous day
d2, _ := time.ParseDuration("6h30m") // 6:30 of next day
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Gopher |
Solution 2 | Zoe stands with Ukraine |
Solution 3 | Rizlan Nawfal Tamima |
Solution 4 | DDKK |