-5

How to get seconds of day (1 - 86400) in Go?

Just like http://joda-time.sourceforge.net/apidocs/org/joda/time/base/AbstractDateTime.html#getSecondOfDay()

Update/Clarifications

  • Wanted equivalent of the joda/SecondOfDay in golang
  • Expected to start at 0 and 86400 at end of the day
  • Required when rewriting in golang a java opensource function which in turn is using joda/secondOfDay
  • Googled '24 hour to seconds' to get 86400
  • While asking question I could only think of now.Unix()-yesterdayMidnight.Unix() and the simple accepted answer didn't come to my mind
  • Obviously didn't think about Daylight Saving
  • Wanted to see if there is some built in function or popular/standard library
yodhevauhe
  • 765
  • 3
  • 11
  • 33

2 Answers2

4

If we define "seconds of day" as the "elapsed seconds since midnight", then to get correct result even on days when daylight saving time happens we should subtract the time representing midnight from the given time. For that, we may use Time.Sub().

func daySeconds(t time.Time) int {
    year, month, day := t.Date()
    t2 := time.Date(year, month, day, 0, 0, 0, 0, t.Location())
    return int(t.Sub(t2).Seconds())
}

Testing it:

for _, t := range []time.Time{
    time.Date(2019, 1, 1, 0, 0, 30, 0, time.UTC),
    time.Date(2019, 1, 1, 0, 1, 30, 0, time.UTC),
    time.Date(2019, 1, 1, 0, 12, 30, 0, time.UTC),
    time.Date(2019, 1, 1, 12, 12, 30, 0, time.UTC),
} {
    fmt.Println(daySeconds(t))
}

Output (try it on the Go Playground):

30
90
750
43950

Let's see how this function gives correct result when daylight saving time happens. In Hungary, 25 March 2018 is a day when the clock was turned forward 1 hour at 02:00:00, from 2 am to 3 am.

loc, err := time.LoadLocation("CET")
if err != nil {
    fmt.Println(err)
    return
}

t := time.Date(2018, 3, 25, 0, 0, 30, 0, loc)
fmt.Println(t)
fmt.Println(daySeconds(t))

t = t.Add(2 * time.Hour)
fmt.Println(t)
fmt.Println(daySeconds(t))

This outputs (try it on the Go Playground):

2018-03-25 00:00:30 +0100 CET
30
2018-03-25 03:00:30 +0200 CEST
7230

We print the daySeconds of a time being 30 seconds after midnight, which is 30 of course. Then we add 2 hours to the time (2 hours = 2*3600 seconds = 7200), and the daySeconds of this new time will be properly 7200 + 30 = 7230, even though the time changed 3 hours.

icza
  • 389,944
  • 63
  • 907
  • 827
1

Note: This function returns the nominal number of seconds of day in the (0 - 86399) range. If you're looking for the "number of seconds elapsed since midnight", which may not be in (0 - 86399) range due to daylight saving time, please see @icza's answer.

Update: Please note also that the question refers to Joda Time implementation, which, according to Joda Time getSecondOfDay on DST switch day, seems to correspond to the nominal number of seconds implementation (as in my answer below) as opposed to the "number of seconds elapsed since midnight" (as in @icza's answer).

package main 

import (
    "fmt"
    "time"
)

func getSecondOfDay(t time.Time) int {
    return 60*60*t.Hour() + 60*t.Minute() + t.Second()
}

func main() {
    t := time.Now()
    fmt.Println(getSecondOfDay(t))
}
perl
  • 9,826
  • 1
  • 10
  • 22
  • I was thinking of more complex way time.Now().Unix() - yesterdayMidNight.Unix() – yodhevauhe Mar 06 '19 at 13:22
  • 2
    This doesn't work on days when daylight saving happens. Also, `Time.Truncate()` operates on time as an absolute duration since the zero time, so it may also return incorrect result. – icza Mar 06 '19 at 13:31
  • @icza: interesting point, can you share some examples when it fails? – perl Mar 06 '19 at 13:39
  • 1
    Read the doc of [`Time.Truncate()`](https://golang.org/pkg/time/#Time.Truncate). Here's an example: https://play.golang.org/p/hAfBrYWNeZ – icza Mar 06 '19 at 13:40
  • Thanks, that's interesting, I removed that option from my answer – perl Mar 06 '19 at 13:53
  • 1
    The one option you have still gives invalid results on days when daylight saving time happens. – icza Mar 06 '19 at 13:54
  • I suppose it depends on the definition. @yodhevauhe asked for a function that returns (1 - 86400), so that seems to be just (60*60*h + 60*m + s) [technically, +1 also, but I'll skip that]. Your function is correct if we need "seconds since midnight", but that's not necessarily within the (1 - 86400) range, e.g. in your example with Central European time t := time.Date(2018, 10, 28, 23, 59, 59, 0, loc) would return 89999 – perl Mar 06 '19 at 14:19
  • 1
    @perl Exactly my point. If the clock is turned back, on that day there is more than 86400 seconds. So reporting more is the correct answer. – icza Mar 06 '19 at 14:27
  • Yes, if you define it as "seconds since midnight", while the question was "How to get seconds of day (1 - 86400) in Go?" – perl Mar 06 '19 at 14:28
  • 1
    @icza: I have added a comment to my answer to clarify the point, and referred to your answer for the "seconds since midnight" version – perl Mar 06 '19 at 14:39