github.com/ethanhsieh/snapd@v0.0.0-20210615102523-3db9b8e4edc5/timeutil/human.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2018 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package timeutil
    21  
    22  import (
    23  	"fmt"
    24  	"time"
    25  
    26  	"github.com/snapcore/snapd/i18n"
    27  )
    28  
    29  // start-of-day
    30  func sod(t time.Time) time.Time {
    31  	y, m, d := t.Date()
    32  	return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
    33  }
    34  
    35  // Human turns the time into a relative expression of time meant for human
    36  // consumption.
    37  // Human(t)  --> "today at 07:47"
    38  func Human(then time.Time) string {
    39  	return humanTimeSince(then.Local(), time.Now().Local(), 60)
    40  }
    41  
    42  func delta(then, now time.Time) int {
    43  	if then.After(now) {
    44  		return -delta(now, then)
    45  	}
    46  
    47  	then = sod(then)
    48  	now = sod(now)
    49  
    50  	n := int(then.Sub(now).Hours() / 24)
    51  	now = now.AddDate(0, 0, n)
    52  	for then.Before(now) {
    53  		then = then.AddDate(0, 0, 1)
    54  		n--
    55  	}
    56  	return n
    57  }
    58  
    59  func humanTimeSince(then, now time.Time, cutoffDays int) string {
    60  	d := delta(then, now)
    61  	switch {
    62  	case d < -cutoffDays || d > cutoffDays:
    63  		return then.Format("2006-01-02")
    64  	case d < -1:
    65  		// TRANSLATORS: %d will be at least 2; the singular is only included to help gettext
    66  		return fmt.Sprintf(then.Format(i18n.NG("%d day ago, at 15:04 MST", "%d days ago, at 15:04 MST", -d)), -d)
    67  	case d == -1:
    68  		return then.Format(i18n.G("yesterday at 15:04 MST"))
    69  	case d == 0:
    70  		return then.Format(i18n.G("today at 15:04 MST"))
    71  	case d == 1:
    72  		return then.Format(i18n.G("tomorrow at 15:04 MST"))
    73  	case d > 1:
    74  		// TRANSLATORS: %d will be at least 2; the singular is only included to help gettext
    75  		return fmt.Sprintf(then.Format(i18n.NG("in %d day, at 15:04 MST", "in %d days, at 15:04 MST", d)), d)
    76  	default:
    77  		// the following message is brought to you by Joel Armando, the self-described awesome and sexy mathematician.
    78  		panic("you have broken the law of trichotomy! ℤ is no longer totally ordered! chaos ensues!")
    79  	}
    80  }