From 72df7bd95ce0e340a29d8620706e8d9eca284e59 Mon Sep 17 00:00:00 2001 From: ginokent <29125616+ginokent@users.noreply.github.com> Date: Thu, 24 Aug 2023 21:41:35 +0900 Subject: [PATCH] feat: add timez.Now() func --- time/time.go | 48 +++++++++++++++++++++++++++++++++++++++++++++++ time/time_test.go | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 time/time.go create mode 100644 time/time_test.go diff --git a/time/time.go b/time/time.go new file mode 100644 index 00000000..0a44f584 --- /dev/null +++ b/time/time.go @@ -0,0 +1,48 @@ +package timez + +import ( + "context" + "sync" + "time" +) + +type ctxKeyNow struct{} + +func Now(ctx context.Context) time.Time { + nowFuncRWMu.RLock() + defer nowFuncRWMu.RUnlock() + return nowFunc(ctx) +} + +//nolint:gochecknoglobals +var ( + nowFunc = DefaultNowFunc + nowFuncRWMu sync.RWMutex +) + +type NowFunc = func(ctx context.Context) time.Time + +func DefaultNowFunc(ctx context.Context) time.Time { + if now, ok := FromContext(ctx); ok { + return now + } + + return time.Now() +} + +func SetNowFunc(now NowFunc) (backup NowFunc) { + nowFuncRWMu.Lock() + defer nowFuncRWMu.Unlock() + backup = nowFunc + nowFunc = now + return backup +} + +func WithContext(ctx context.Context, now time.Time) context.Context { + return context.WithValue(ctx, ctxKeyNow{}, now) +} + +func FromContext(ctx context.Context) (time.Time, bool) { + now, ok := ctx.Value(ctxKeyNow{}).(time.Time) + return now, ok +} diff --git a/time/time_test.go b/time/time_test.go new file mode 100644 index 00000000..52d2e370 --- /dev/null +++ b/time/time_test.go @@ -0,0 +1,37 @@ +package timez_test + +import ( + "context" + "testing" + "time" + + timez "github.com/kunitsucom/util.go/time" +) + +func TestNow(t *testing.T) { + t.Parallel() + t.Run("success,", func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + constant := time.Date(2023, 8, 24, 21, 32, 0, 0, time.UTC) + ctx = timez.WithContext(ctx, constant) + + actual := timez.Now(ctx) + if constant != actual { + t.Errorf("❌: constant(%v) != actual(%v)", constant, actual) + } + + backup := timez.SetNowFunc(func(_ context.Context) time.Time { return time.Now() }) + current := timez.Now(context.Background()) + if current.After(constant) { + t.Errorf("❌: current(%v) after constant(%v)", current, constant) + } + + timez.SetNowFunc(backup) + current2 := timez.Now(context.Background()) + if !current2.After(current) { + t.Errorf("❌: current2(%v) after current(%v)", current2, current) + } + }) +}