Validating the difference in days between two dates I have some code that is used for validating a condition based on dates, which is always a bit tricky. Here is the code:

package rules

type valueInterval struct {
    min int
    max int
}

func (v valueInterval) containsClosed(x int) bool {
    return x &gt;= v.min &amp;&amp; x &lt;= v.max
}

func permanentExpiryLimit(entityToCheck bla.Entity, intervalInDays valueInterval, compare time.Time) (RuleStatus, string) {
    if entityToCheck.PermanentExpiry == nil {
        return RULE_NOT_APPLICABLE, "... TODO ..."
    }

    diff := beginningOfDay(*entityToCheck.PermanentExpiry).Sub(beginningOfDay(compare))
    diffInDays := int(diff.Hours()) / 24

    if diffInDays &lt; 0 {
        return RULE_NOT_APPLICABLE, "... TODO ..."
    }

    if !intervalInDays.containsClosed(diffInDays) {
        return RULE_FAILED, "... TODO ..."
    }

    return RULE_PASSED, "... TODO ..."
}

func beginningOfDay(datetime time.Time) time.Time {
    oneDay := 24 * time.Hour
    return datetime.Truncate(oneDay)
}


Client code:

   status, msg := permanentExpiry(entity, valueInterval{0, 100}, time.Now())


The idea is that this code check if the PermanentExpiry is at most 100 days in the future from a given compare date.

It can be assumed that both dates are in the same timezone. The dates should be compared only on day basis, that's why the time objects are reset to 00:00:00 time.

Still feels a bit clunky and not sure if it's clear that the comparision is done based on full days only. Any comments appreciated.
Client code:

   status, msg := permanentExpiry(entity, 100, time.Now())

  
  The idea is that this code check if the PermanentExpiry is at most 100
  days in the future from a given compare date.
  
  It can be assumed that both dates are in the same timezone. The dates
  should be compared only on day basis, that's why the time objects are
  reset to 00:00:00 time.
  
  Still feels a bit clunky and not sure if it's clear that the
  comparision is done based on full days only.


In Go, encapsulate that sort of logic in useful functions like isExpired. For example,

expire.go:

package main

import (
    "fmt"
    "time"
)

// isExpired returns true if date is not before the expiration date.
// The expiration date is start date plus expire days.
// Start is in the same time zone as date.
func isExpired(date, start time.Time, expire int) bool {
    loc := date.Location()
    y, m, d := start.In(loc).Date()
    x := time.Date(y, m, d+expire, 0, 0, 0, 0, loc)
    return !date.Before(x)
}

func main() {
    now := time.Now()
    starts := []time.Time{
        time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()),
        now,
        time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location()),
    }
    expire := 10 // 100
    for _, start := range starts {
        for i := expire - 2; i &lt;= expire+1; i++ {
            date := now.AddDate(0, 0, i)
            x := isExpired(date, start, expire)
            fmt.Println(
                x, "\t",
                date.Format("2006-01-02 15:04"),
                start.Format("2006-01-02 15:04"), expire,
            )
        }
        fmt.Println()
    }
}


Output:

false    2017-07-20 11:07 2017-07-12 00:00 10
false    2017-07-21 11:07 2017-07-12 00:00 10
true     2017-07-22 11:07 2017-07-12 00:00 10
true     2017-07-23 11:07 2017-07-12 00:00 10

false    2017-07-20 11:07 2017-07-12 11:07 10
false    2017-07-21 11:07 2017-07-12 11:07 10
true     2017-07-22 11:07 2017-07-12 11:07 10
true     2017-07-23 11:07 2017-07-12 11:07 10

false    2017-07-20 11:07 2017-07-12 23:59 10
false    2017-07-21 11:07 2017-07-12 23:59 10
true     2017-07-22 11:07 2017-07-12 23:59 10
true     2017-07-23 11:07 2017-07-12 23:59 10