time.Time Round to Day - go

I have a timestamp coming in, I wonder if there's a way to round it down to the start of a day in PST. For example, ts: 1305861602 corresponds to 2016-04-14, 21:10:27 -0700, but I want to round it to a timestamp that maps to 2016-04-14 00:00:00 -0700. I read through the time.Time doc but didn't find a way to do it.

The simple way to do this is to create new Time using the previous one and only assigning the year month and day. It would look like this;
func truncateToDay(t time.Time) time.Time {
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
}
here's a play example; https://play.golang.org/p/jnFuZxruKm

You can simply use duration 24 * time.Hour to truncate time.
t := time.Date(2015, 4, 2, 0, 15, 30, 918273645, time.UTC)
d := 24 * time.Hour
t.Truncate(d)
https://play.golang.org/p/BTz7wjLTWX

I believe the simplest is to create a new date as shown in this answer.
However, if you wanna use time.Truncate, there is two distinct cases.
If you are working in UTC:
var testUtcTime = time.Date(2016, 4, 14, 21, 10, 27, 0, time.UTC)
// outputs 2016-04-14T00:00:00Z
fmt.Println(testUtcTime.Truncate(time.Hour * 24).Format(time.RFC3339))
If you are not, you need to convert back and forth to UTC
var testTime = time.Date(2016, 4, 14, 21, 10, 27, 0, time.FixedZone("my zone", -7*3600))
// this is wrong (outputs 2016-04-14T17:00:00-07:00)
fmt.Println(testTime.Truncate(time.Hour * 24).Format(time.RFC3339))
// this is correct (outputs 2016-04-14T00:00:00-07:00)
fmt.Println(testTime.Add(-7 * 3600 * time.Second).Truncate(time.Hour * 24).Add(7 * 3600 * time.Second).Format(time.RFC3339))

in addition to sticky's answer to get the local Truncate do like this
t := time.Date(2015, 4, 2, 0, 15, 30, 918273645, time.Local)
d := 24 * time.Hour

fmt.Println("in UTC", t.Truncate(d))
_, dif := t.Zone()
fmt.Println("in Local", t.Truncate(24 * time.Hour).Add(time.Second * time.Duration(-dif)))

func truncateToDay(t time.Time) {
nt, _ := time.Parse("2006-01-02", t.Format("2006-01-02"))
fmt.Println(nt)
}
This is not elegant but works.

I using theses functions on all my projects:
package time_utils
import "time"
func TruncateToStartOfDay(t time.Time) time.Time {
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
}
func TruncateToEndOfDay(t time.Time) time.Time {
return time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, t.Location())
}

Related

How to find previous month and year in golang

I just found AddDate() does not always works as expected.
ex:
mayEndDate := time.Date(2021, 5, 31, 12, 00, 00, 00, time.UTC)
finalDate := endOfMay.AddDate(0, -1, 0)
here
output:
myEndDate = 2021-05-31 12:00:00 +0000 UTC
finalDate = 2021-05-01 12:00:00 +0000 UTC
I was expecting finalDate to be in April.
After reading the documentation, I found out the reason.
AddDate normalizes its result in the same way that Date does, so, for example, adding one month to October 31 yields December 1, the normalized form for November 31.
My question: how to now correctly find out the last month's date from today's date?
Get the current month using Month(), then from there it’s pretty simple to get the previous one:
currentMonth := mayEndDate.Month()
previousMonth := currentMonth - 1
if currentMonth == time.January {
previousMonth = time.December
}
if date is 2021-05-31 then previous month is April 2021.
package main
import (
"fmt"
"time"
)
func prevMonth(t time.Time) (int, time.Month) {
y, m, _ := t.Date()
y, m, _ = time.Date(y, m-1, 1, 0, 0, 0, 0, time.UTC).Date()
return y, m
}
func main() {
endOfMay := time.Date(2021, 5, 31, 12, 00, 00, 00, time.UTC)
fmt.Println(endOfMay)
fmt.Println(prevMonth(endOfMay))
}
https://go.dev/play/p/rP25ramRrZ3
2021-05-31 12:00:00 +0000 UTC
2021 April

Is it possible to sort a slice of structs by time in Golang?

I am trying to sort the structs Session in the slice Session by each Session's start time and hall_id. Here is the code:
Sessions := []Session{
Session{
name: "superman",
hall_id: 1,
startTime: time.Date(2022, time.August, 15, 17, 35, 0, 0, time.UTC),
endTime: time.Date(2022, time.August, 15, 18, 35, 0, 0, time.UTC),
},
Session{
name: "thor",
hall_id: 2,
startTime: time.Date(2022, time.August, 15, 16, 30, 0, 0, time.UTC),
endTime: time.Date(2022, time.August, 15, 17, 30, 0, 0, time.UTC),
},
Session{
name: "joker",
hall_id: 3,
startTime: time.Date(2022, time.August, 15, 19, 40, 0, 0, time.UTC),
endTime: time.Date(2022, time.August, 15, 20, 30, 0, 0, time.UTC),
},
Session{
name: "batman",
hall_id: 1,
startTime: time.Date(2022, time.August, 15, 17, 40, 0, 0, time.UTC),
endTime: time.Date(2022, time.August, 15, 18, 20, 0, 0, time.UTC),
},
}
The point is that I am using "time" package, and in order to create a date, you need to use Date() function, which requires multiple stuff like: year int, month, day int, hour int, minute int, etc.
I have tried the AndreKR's answer which is:
slice.Sort(planets[:], func(i, j int) bool {
return planets[i].Axis < planets[j].Axis
})
but it seems that it does not work with multiple "parameters" of a struct. I tried this:
sort.Slice(Sessions[:], func(i, j int) bool {
return Sessions[i].startTime.Year() < Sessions[j].startTime.Year(),
int(Sessions[i].startTime.Month()) < int(Sessions[j].startTime.Month()),
Sessions[i].startTime.Day() < Sessions[j].startTime.Day(),
Sessions[i].startTime.Hour() < Sessions[j].startTime.Hour(),
Sessions[i].startTime.Minute() < Sessions[j].startTime.Minute()
})
I am new to the Golang, so if I have made an obvious mistake I am sorry ;(
Alright, I have got the answer:
sort.Slice(Sessions[:], func(i, j int) bool {
return Sessions[i].startTime.Before(Sessions[j].startTime)
})
this code will solve this problem

How to get one month in seconds

Failing to do something fairly simple and can't find an answer
nor from uncle Google nor from here
I'm trying to get one full month in seconds (an int)
Something more elegant then this:
s := 3600 * 24 * 30
also tried :
m := time.Hour * 24 * 30
but that returns type 'time.Duration' which I also can't convert to an int
NOTE: Don't really care for the pressie days of each month (28-31)
but if it's possible to use specific month as input it will be super.
I'm not a Goxpert so Go (see what I did there?) easy on me..
Thanks in advance.
Use time.Duration Seconds() :
package main
import (
"fmt"
"time"
)
func main() {
m := time.Hour * 24 * 30
fmt.Println("In float: ", m.Seconds())
fmt.Println("In int: ", int(m.Seconds()))
}
Example on playground
If you do care about the different days in months, you can use time.Sub to get the duration:
package main
import (
"fmt"
"time"
)
func secondsInMonth(y int, m time.Month) int {
start := time.Date(y, m, 0, 0, 0, 0, 0, time.UTC)
end := time.Date(y, m+1, 0, 0, 0, 0, 0, time.UTC)
return int(end.Sub(start).Seconds())
}
func main() {
month := time.February
year := 2016
fmt.Printf("Days in %s %d: %d\n", month, year, secondsInMonth(year, month))
}
If you dont care just do 30*24*60*60. Thats as elegant as it gets.
Agree with the previous answers, but if you really want to remove the 24 * 30 it is possible.
Just goofing around; time.Time has some nice comparison features so this is another option:
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
// the current month in seconds - can vary
duration := now.AddDate(0, 1, 0).Sub(now)
fmt.Println("In int: ", int(duration.Seconds()))
// similar, but exactly 30 days
duration := now.AddDate(0, 0, 30).Sub(now)
fmt.Println("In int: ", int(duration.Seconds()))
}
Example on playground
The number of days in a month depends on the month and the year (leap or non-leap year). The number of seconds in a day varies when there is a transition to or from daylight savings time. Therefore, the number of seconds in a month will vary by month, year, and time zone.
For example, Los Angeles is in the Pacific Time Zone. January and March both have 31 days. Because of the daylight savings time transition in March, there is one hour less (3600 = 60*60 seconds) in March than January.
For example,
package main
import (
"fmt"
"time"
)
func secondsInMonth(month time.Month, year int, loc *time.Location) int {
u := time.Date(year, month, 1, 0, 0, 0, 0, loc)
v := time.Date(year, month+1, 1, 0, 0, 0, 0, loc)
return int(v.Sub(u).Seconds())
}
func main() {
loc, err := time.LoadLocation("America/Los_Angeles")
if err != nil {
fmt.Println(err)
return
}
year := 2016
jan := secondsInMonth(time.January, year, loc)
feb := secondsInMonth(time.February, year, loc)
mar := secondsInMonth(time.March, year, loc)
apr := secondsInMonth(time.April, year, loc)
fmt.Println(jan, feb, mar, apr)
fmt.Println(jan - mar)
}
Output:
2678400 2505600 2674800 2592000
3600
Since you are only having 30 day months, we have a constant here and there is absolutely no need for any calculation. Using basic maths, we simplify
30*24*60*60
to
const secsInMonth = 2592000

Get the first and last day of a year from a timestamp

Given a time object, t := time.Now(), is there a way I could get a timestamp for the first and last days of that year?
I could do something like d := t.YearDay() to get the number of days through the year, and then t.AddDate(0, 0, -d) to get the start of the year, and t.AddDate(0, 0, 365-d) to get the end of the year, but that seems to brittle as it doesn't deal with leap years etc.
You can use your Time struct object and create new Time struct object using time.Date and time.Time.Year() functions. So, if current time is t := time.Now() then last day in this year in UTC will be lt := time.Date(t.Year(), time.December, 31, 0, 0, 0, 0, time.UTC)
Here's an example:
package main
import "fmt"
import "time"
func main() {
t := time.Now()
last := time.Date(t.Year(), time.December,31, 0, 0, 0, 0, time.UTC)
first := time.Date(t.Year(), time.January,1, 0, 0, 0, 0, time.UTC)
fmt.Println("Current: ", t)
fmt.Println("First: ", first)
fmt.Println("Last: ", last)
}
http://play.golang.org/p/jahjd_mi6K

Something like python timedelta in golang

I want to get a datetime, counting weeks from a date, days from a week and seconds from 00:00 time.
With Python I can use this:
BASE_TIME = datetime.datetime(1980,1,6,0,0)
tdelta = datetime.timedelta(weeks = 1722,
days = 1,
seconds = 66355)
mydate = BASE_DATE + tdelta
I'm trying to get it with Go, but I have some problems to reach it:
package main
import (
"fmt"
"time"
)
var base = time.Date(1980, 1, 6, 0, 0, 0, 0, time.UTC)
func main() {
weeks := 1722
days := 1
seconds := 66355
weeksToSecs := 7 * 24 * 60 * 60
daysToSecs := 24 * 60 * 60
totalSecs := (weeks * weeksToSecs) + (days * daysToSecs) + seconds
nanosecs := int64(totalSecs) * 1000000000
//delta := time.Date(0, 0, 0, 0, 0, totalSecs, 0, time.UTC)
date := base.Add(nanosecs)
fmt.Printf("Result: %s", date)
}
prog.go:21: cannot use nanosecs (type int64) as type time.Duration in function argument
http://play.golang.org/p/XWSK_QaXrQ
What I'm missing?Thanks
package main
import (
"fmt"
"time"
)
func main() {
baseTime := time.Date(1980, 1, 6, 0, 0, 0, 0, time.UTC)
date := baseTime.Add(1722*7*24*time.Hour + 24*time.Hour + 66355*time.Second)
fmt.Println(date)
}
Playground
Output
2013-01-07 18:25:55 +0000 UTC
jnml's answer works and is more idiomatic go. But to illustrate why your original code didn't work, all you have to do is change one line.
date := base.Add(time.Duration(nanosecs)) will cast the nanosecs to a time.Duration which is the type that Add expects as opposed to int64. Go will not automatically cast a type for you so it complained about the type being int64.
timeutil supports timedelta and strftime.
package main
import (
"fmt"
"time"
"github.com/leekchan/timeutil"
)
func main() {
base := time.Date(2015, 2, 3, 0, 0, 0, 0, time.UTC)
td := timeutil.Timedelta{Days: 10, Minutes: 17, Seconds: 56}
result := base.Add(td.Duration())
fmt.Println(result) // "2015-02-13 00:17:56 +0000 UTC"
}

Resources