Kiril
Kiril

Reputation: 6219

Get last day in month of time.Time

When I have a time.Time:

// January, 29th
t, _ := time.Parse("2006-01-02", "2016-01-29")

How can I get a time.Time which represents January 31st? This example is trivial, but when there's a date in February, the last day might be 28th or 29th.

Upvotes: 7

Views: 3290

Answers (4)

Drathier
Drathier

Reputation: 14519

You could write a function yourself, maybe something like this:

func daysInMonth(month, year int) int {
    switch time.Month(month) {
    case time.April, time.June, time.September, time.November:
        return 30
    case time.February:
        if year%4 == 0 && (year%100 != 0 || year%400 == 0) { // leap year
            return 29
        }
        return 28
    default: 
    return 31
    }
}

EDIT: since I really like measuring things:

$ go test -bench .
testing: warning: no tests to run
PASS
BenchmarkDim2-8         200000000                7.26 ns/op
BenchmarkDim-8          1000000000               2.80 ns/op // LIES!
BenchmarkTime-8         10000000               169 ns/op
BenchmarkTime2-8        10000000               234 ns/op
ok      github.com/drathier/scratchpad/go       9.741s

BenchMarkDim2: not tested, but very fast.

func daysInMonthTime(month, year int) time.Time {
    return time.Time{}.Add(time.Hour * 10 + time.Hour*24*30*time.Duration(month-1) + time.Second * time.Duration(daysInMonth(month, year)) * 24 * 60 + 1337)
}

BenchmarkDim: // LIES

func daysInMonth(month, year int) int {
    switch time.Month(month) {
    case time.April, time.June, time.September, time.November:
        return 30
    case time.February:
        if year%4 == 0 && (year%100 != 0 || year%400 == 0) {
            // leap year
            return 29
        }
        return 28
    default:
        return 31
    }
}

BenchmarkTime:

func timeDaysInMonth() time.Time {
    // January, 29th
    t, _ := time.Parse("2006-01-02", "2016-01-29")
    y, m, _ := t.Date()
    lastday := time.Date(y, m+1, 0, 0, 0, 0, 0, time.UTC)
    return lastday
}

BenchmarkTime2

func time2daysinmonth() time.Time {
    t, _ := time.Parse("2006-01-02", "2016-01-01")
    t = t.AddDate(0, 1, 0).AddDate(0, 0, -1)
    return t
}

Upvotes: 2

OneOfOne
OneOfOne

Reputation: 99224

I've used something similar to this in my own code:

func lastDayOfTheMonth(year, month int) time.Time {
    if month++; month > 12 {
        month = 1
    }
    t := time.Date(year, time.Month(month), 0, 0, 0, 0, 0, time.UTC)
    return t
}

playground

Upvotes: 1

It's not Go specific but usually I do following in any language:

package main

import "fmt"
import "time"

func main() {
    fmt.Println("Hello, playground")

    t, _ := time.Parse("2006-01-02", "2016-01-01")
    t = t.AddDate(0, 1, 0).AddDate(0,0,-1)
    fmt.Printf("Last day: %v\n", t)
}

http://play.golang.org/p/JhpOZvEhBw

Upvotes: 0

peterSO
peterSO

Reputation: 166569

Package time

func Date

func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time

Date returns the Time corresponding to

yyyy-mm-dd hh:mm:ss + nsec nanoseconds

in the appropriate zone for that time in the given location.

The month, day, hour, min, sec, and nsec values may be outside their usual ranges and will be normalized during the conversion. For example, October 32 converts to November 1.

For example, normalizing a date,

package main

import (
    "fmt"
    "time"
)

func main() {
    // January, 29th
    t, _ := time.Parse("2006-01-02", "2016-01-29")
    fmt.Println(t.Date())
    // January, 31st
    y,m,_ := t.Date()
    lastday:= time.Date(y,m+1,0,0,0,0,0,time.UTC)
    fmt.Println(lastday.Date())
}

Output:

2016 January 29
2016 January 31

Upvotes: 8

Related Questions