fix: sync sadhna calendar with local timezone
This commit is contained in:
@@ -79,10 +79,33 @@ func NewSadhnaService(
|
||||
|
||||
const dayFmt = "2006-01-02"
|
||||
|
||||
// utcToday returns today's UTC calendar date truncated to midnight, the
|
||||
// anchor every day-bucket comparison uses.
|
||||
func utcToday() time.Time {
|
||||
now := time.Now().UTC()
|
||||
// fallbackTZ is used when the user has no stored timezone — the sādhana day
|
||||
// boundary (and thus the nightly chant reset) defaults to India time.
|
||||
const fallbackTZ = "Asia/Kolkata"
|
||||
|
||||
// resolveTZ returns the user's IANA timezone name + loaded location, falling
|
||||
// back to Asia/Kolkata (then UTC) so the day boundary is always defined.
|
||||
func (s *SadhnaService) resolveTZ(ctx context.Context, userID string) (string, *time.Location) {
|
||||
tz, _ := s.logs.UserTimezone(ctx, userID)
|
||||
if tz == "" {
|
||||
tz = fallbackTZ
|
||||
}
|
||||
loc, err := time.LoadLocation(tz)
|
||||
if err != nil {
|
||||
tz = fallbackTZ
|
||||
if loc, err = time.LoadLocation(fallbackTZ); err != nil {
|
||||
return "UTC", time.UTC
|
||||
}
|
||||
}
|
||||
return tz, loc
|
||||
}
|
||||
|
||||
// todayIn returns the current calendar date in loc, anchored at UTC midnight
|
||||
// so it round-trips cleanly through Postgres DATE columns and dayFmt. This is
|
||||
// the anchor every day-bucket comparison uses — the day rolls over at the
|
||||
// user's local midnight.
|
||||
func todayIn(loc *time.Location) time.Time {
|
||||
now := time.Now().In(loc)
|
||||
return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.UTC)
|
||||
}
|
||||
|
||||
@@ -99,7 +122,10 @@ func (s *SadhnaService) SaveChant(ctx context.Context, userID string, rounds int
|
||||
target := s.targetFor(ctx, userID)
|
||||
chantDone := rounds >= target
|
||||
|
||||
if _, err := s.logs.UpsertToday(ctx, userID, utcToday(), rounds, chantDone); err != nil {
|
||||
// Bucket against the user's local "today" so progress resets at their
|
||||
// local midnight (fallback Asia/Kolkata), not UTC midnight.
|
||||
_, loc := s.resolveTZ(ctx, userID)
|
||||
if _, err := s.logs.UpsertToday(ctx, userID, todayIn(loc), rounds, chantDone); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.Dashboard(ctx, userID)
|
||||
@@ -109,14 +135,15 @@ func (s *SadhnaService) SaveChant(ctx context.Context, userID string, rounds int
|
||||
// logs and quote posts over the trailing window.
|
||||
func (s *SadhnaService) Dashboard(ctx context.Context, userID string) (*model.SadhnaDashboard, error) {
|
||||
target := s.targetFor(ctx, userID)
|
||||
today := utcToday()
|
||||
tz, loc := s.resolveTZ(ctx, userID)
|
||||
today := todayIn(loc)
|
||||
since := today.AddDate(0, 0, -(streakWindowDays - 1))
|
||||
|
||||
logs, err := s.logs.ListSince(ctx, userID, since)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postsByDay, err := s.posts.PostCountsByDate(ctx, userID, since)
|
||||
postsByDay, err := s.posts.PostCountsByDate(ctx, userID, since, tz)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -361,11 +388,12 @@ func (s *SadhnaService) AckRewards(ctx context.Context, userID string) error {
|
||||
// arbitrary week or month. Days with no activity (including future days)
|
||||
// come back as all-false. The caller is expected to bound the range.
|
||||
func (s *SadhnaService) History(ctx context.Context, userID string, from, to time.Time) ([]model.SadhnaDay, error) {
|
||||
tz, _ := s.resolveTZ(ctx, userID)
|
||||
logs, err := s.logs.ListSince(ctx, userID, from)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
postsByDay, err := s.posts.PostCountsByDate(ctx, userID, from)
|
||||
postsByDay, err := s.posts.PostCountsByDate(ctx, userID, from, tz)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user