go

How to gracefully iterate a date range in Go


I need to iterate any specified dates range, say 2017-12-21 to 2018-01-05. What is the best way to implement that in Go?

output:
20171221
20171222
20171223
...
20180104
20180105

Solution

  • The Go Programming Language Specification

    Function literals

    A function literal represents an anonymous function.

    FunctionLit = "func" Signature FunctionBody .
    
    func(a, b int, z float64) bool { return a*b < int(z) }
    

    A function literal can be assigned to a variable or invoked directly.

    f := func(x, y int) int { return x + y }
    func(ch chan int) { ch <- ACK }(replyChan)
    

    Function literals are closures: they may refer to variables defined in a surrounding function. Those variables are then shared between the surrounding function and the function literal, and they survive as long as they are accessible.


    In Go, encapsulate complexity in functions. Use a function literal as a closure.

    For example,

    package main
    
    import (
        "fmt"
        "time"
    )
    
    // rangeDate returns a date range function over start date to end date inclusive.
    // After the end of the range, the range function returns a zero date,
    // date.IsZero() is true.
    func rangeDate(start, end time.Time) func() time.Time {
        y, m, d := start.Date()
        start = time.Date(y, m, d, 0, 0, 0, 0, time.UTC)
        y, m, d = end.Date()
        end = time.Date(y, m, d, 0, 0, 0, 0, time.UTC)
    
        return func() time.Time {
            if start.After(end) {
                return time.Time{}
            }
            date := start
            start = start.AddDate(0, 0, 1)
            return date
        }
    }
    
    func main() {
        start := time.Now()
        end := start.AddDate(0, 0, 6)
        fmt.Println(start.Format("2006-01-02"), "-", end.Format("2006-01-02"))
    
        for rd := rangeDate(start, end); ; {
            date := rd()
            if date.IsZero() {
                break
            }
            fmt.Println(date.Format("2006-01-02"))
        }
    }
    

    Playground: https://play.golang.org/p/wmfQC9fEs1S

    Output:

    2018-06-22 - 2018-06-28
    2018-06-22
    2018-06-23
    2018-06-24
    2018-06-25
    2018-06-26
    2018-06-27
    2018-06-28