refactor: move FormattableDuration

This commit is contained in:
Fernandez Ludovic 2026-03-09 23:36:10 +01:00
commit f9b6416db4
4 changed files with 113 additions and 96 deletions

View file

@ -141,7 +141,7 @@ func renewForDomains(ctx context.Context, cmd *cli.Command, lazyClient lzSetUp,
// This is just meant to be informal for the user.
log.Info("acme: Trying renewal.",
log.CertNameAttr(certID),
slog.Any("time-remaining", FormattableDuration(cert.NotAfter.Sub(time.Now().UTC()))),
slog.Any("time-remaining", log.FormattableDuration(cert.NotAfter.Sub(time.Now().UTC()))),
)
err = hookManager.Pre(ctx, certID, renewalDomains)
@ -230,7 +230,7 @@ func renewForCSR(ctx context.Context, cmd *cli.Command, lazyClient lzSetUp, cert
// This is just meant to be informal for the user.
log.Info("acme: Trying renewal.",
log.CertNameAttr(certID),
slog.Any("time-remaining", FormattableDuration(cert.NotAfter.Sub(time.Now().UTC()))),
slog.Any("time-remaining", log.FormattableDuration(cert.NotAfter.Sub(time.Now().UTC()))),
)
err = hookManager.Pre(ctx, certID, certcrypto.ExtractDomainsCSR(csr))
@ -286,7 +286,7 @@ func isInRenewalPeriod(cert *x509.Certificate, certID string, days int, now time
log.Infof(
log.LazySprintf("Skip renewal: The certificate expires at %s, the renewal can be performed in %s.",
cert.NotAfter.Format(time.RFC3339),
FormattableDuration(dueDate.Sub(now)),
log.FormattableDuration(dueDate.Sub(now)),
),
log.CertNameAttr(certID),
)
@ -434,43 +434,3 @@ func sameDomains(a, b []string) bool {
return slices.Equal(aClone, bClone)
}
type FormattableDuration time.Duration
func (f FormattableDuration) String() string {
d := time.Duration(f)
days := int(math.Trunc(d.Hours() / 24))
hours := int(d.Hours()) % 24
minutes := int(d.Minutes()) % 60
seconds := int(d.Seconds()) % 60
ns := int(d.Nanoseconds()) % int(time.Second)
s := new(strings.Builder)
if days > 0 {
_, _ = fmt.Fprintf(s, "%dd", days)
}
if hours > 0 {
_, _ = fmt.Fprintf(s, "%dh", hours)
}
if minutes > 0 {
_, _ = fmt.Fprintf(s, "%dm", minutes)
}
if seconds > 0 {
_, _ = fmt.Fprintf(s, "%ds", seconds)
}
if ns > 0 {
_, _ = fmt.Fprintf(s, "%dns", ns)
}
return s.String()
}
func (f FormattableDuration) LogValue() slog.Value {
return slog.StringValue(f.String())
}

View file

@ -169,56 +169,3 @@ func Test_isInRenewalPeriod_dynamic(t *testing.T) {
})
}
}
func TestFormattableDuration(t *testing.T) {
testCases := []struct {
desc string
date time.Time
duration time.Duration
expected string
}{
{
desc: "all",
duration: 47*time.Hour + 3*time.Minute + 8*time.Second + 1234567890*time.Nanosecond,
expected: "1d23h3m9s234567890ns",
},
{
desc: "without nanoseconds",
duration: 47*time.Hour + 3*time.Minute + 8*time.Second,
expected: "1d23h3m8s",
},
{
desc: "without seconds",
duration: 47*time.Hour + 3*time.Minute + 2*time.Nanosecond,
expected: "1d23h3m2ns",
},
{
desc: "without minutes",
duration: 47*time.Hour + 8*time.Second + 2*time.Nanosecond,
expected: "1d23h8s2ns",
},
{
desc: "without hours",
duration: 3*time.Minute + 8*time.Second + 2*time.Nanosecond,
expected: "3m8s2ns",
},
{
desc: "only hours",
duration: 23 * time.Hour,
expected: "23h",
},
{
desc: "only days",
duration: 48 * time.Hour,
expected: "2d",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
assert.Equal(t, test.expected, FormattableDuration(test.duration).String())
})
}
}

49
log/duration.go Normal file
View file

@ -0,0 +1,49 @@
package log
import (
"fmt"
"log/slog"
"math"
"strings"
"time"
)
type FormattableDuration time.Duration
func (f FormattableDuration) String() string {
d := time.Duration(f)
days := int(math.Trunc(d.Hours() / 24))
hours := int(d.Hours()) % 24
minutes := int(d.Minutes()) % 60
seconds := int(d.Seconds()) % 60
ns := int(d.Nanoseconds()) % int(time.Second)
s := new(strings.Builder)
if days > 0 {
_, _ = fmt.Fprintf(s, "%dd", days)
}
if hours > 0 {
_, _ = fmt.Fprintf(s, "%dh", hours)
}
if minutes > 0 {
_, _ = fmt.Fprintf(s, "%dm", minutes)
}
if seconds > 0 {
_, _ = fmt.Fprintf(s, "%ds", seconds)
}
if ns > 0 {
_, _ = fmt.Fprintf(s, "%dns", ns)
}
return s.String()
}
func (f FormattableDuration) LogValue() slog.Value {
return slog.StringValue(f.String())
}

61
log/duration_test.go Normal file
View file

@ -0,0 +1,61 @@
package log
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestFormattableDuration(t *testing.T) {
testCases := []struct {
desc string
date time.Time
duration time.Duration
expected string
}{
{
desc: "all",
duration: 47*time.Hour + 3*time.Minute + 8*time.Second + 1234567890*time.Nanosecond,
expected: "1d23h3m9s234567890ns",
},
{
desc: "without nanoseconds",
duration: 47*time.Hour + 3*time.Minute + 8*time.Second,
expected: "1d23h3m8s",
},
{
desc: "without seconds",
duration: 47*time.Hour + 3*time.Minute + 2*time.Nanosecond,
expected: "1d23h3m2ns",
},
{
desc: "without minutes",
duration: 47*time.Hour + 8*time.Second + 2*time.Nanosecond,
expected: "1d23h8s2ns",
},
{
desc: "without hours",
duration: 3*time.Minute + 8*time.Second + 2*time.Nanosecond,
expected: "3m8s2ns",
},
{
desc: "only hours",
duration: 23 * time.Hour,
expected: "23h",
},
{
desc: "only days",
duration: 48 * time.Hour,
expected: "2d",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
assert.Equal(t, test.expected, FormattableDuration(test.duration).String())
})
}
}