Skip to content

Commit 69d35cf

Browse files
sotnikov-sswelf19
authored andcommitted
fix local tz usage in MonthlyPaymentSchedule.CurrentMonth
1 parent 187cd41 commit 69d35cf

File tree

2 files changed

+79
-6
lines changed

2 files changed

+79
-6
lines changed

x/revenue/types/payment_schedule.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ type PaymentScheduleI interface {
4646
// ends when the month of the block creation is different from the current month of the payment
4747
// schedule.
4848
func (s *MonthlyPaymentSchedule) PeriodEnded(ctx sdktypes.Context) bool {
49-
return s.currentMonth() != ctx.BlockTime().Month()
49+
return s.CurrentMonth() != ctx.BlockTime().Month()
5050
}
5151

5252
// EffectivePeriodProgress returns the proportion of the current payment period that has elapsed
@@ -55,12 +55,13 @@ func (s *MonthlyPaymentSchedule) PeriodEnded(ctx sdktypes.Context) bool {
5555
// has fully elapsed from the very beginning to the very end. Otherwise the result equals to the
5656
// ratio of time passed since the start of the current period to the whole duration of the month.
5757
func (s *MonthlyPaymentSchedule) EffectivePeriodProgress(ctx sdktypes.Context) math.LegacyDec {
58+
t := s.currentMonthStartBlockTime()
5859
// source: https://www.brandur.org/fragments/go-days-in-month
5960
daysInCurrentMonth := time.Date(
60-
ctx.BlockTime().Year(),
61-
s.currentMonth()+1,
61+
t.Year(),
62+
t.Month()+1,
6263
0, 0, 0, 0, 0,
63-
ctx.BlockTime().Location(),
64+
t.Location(),
6465
).Day()
6566
secondsInCurrentMonth := int64(daysInCurrentMonth * 24 * 60 * 60)
6667
secondsPassed := ctx.BlockTime().Unix() - int64(s.CurrentMonthStartBlockTs) //nolint:gosec
@@ -97,8 +98,14 @@ func (s *MonthlyPaymentSchedule) IntoPaymentSchedule() *PaymentSchedule {
9798
return &PaymentSchedule{PaymentSchedule: &PaymentSchedule_MonthlyPaymentSchedule{MonthlyPaymentSchedule: s}}
9899
}
99100

100-
func (s *MonthlyPaymentSchedule) currentMonth() time.Month {
101-
return time.Unix(int64(s.CurrentMonthStartBlockTs), 0).Month() //nolint:gosec
101+
// CurrentMonth returns the time.Month of the current payment period.
102+
func (s *MonthlyPaymentSchedule) CurrentMonth() time.Month {
103+
return s.currentMonthStartBlockTime().Month()
104+
}
105+
106+
// currentMonthStartBlockTime returns the UTC time.Time of the current month start block.
107+
func (s *MonthlyPaymentSchedule) currentMonthStartBlockTime() time.Time {
108+
return time.Unix(int64(s.CurrentMonthStartBlockTs), 0).UTC() //nolint:gosec
102109
}
103110

104111
// PeriodEnded checks whether the end of the current payment period has come. The current period

x/revenue/types/payment_schedule_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,72 @@ func TestMonthlyPaymentSchedule(t *testing.T) {
9797
assert.NotEqual(t, math.LegacyOneDec(), s.EffectivePeriodProgress(ctx.WithBlockTime(time.Date(2000, time.Month(startMonth), daysInCurrentMonth, 23, 59, 59, 0, time.UTC))))
9898
assert.Equal(t, math.LegacyOneDec(), s.EffectivePeriodProgress(ctx.WithBlockTime(time.Date(2000, time.Month(startMonth)+1, 1, 0, 0, 0, 0, time.UTC))))
9999
}
100+
101+
for _, loc := range []*time.Location{
102+
time.FixedZone("BakerIsland", -12*3600),
103+
time.FixedZone("AzoresIslands", -1*3600),
104+
time.UTC,
105+
time.FixedZone("Berlin", 1*3600),
106+
time.FixedZone("LineIslands", 14*3600),
107+
} {
108+
t.Run("TimezoneOperations"+loc.String(), func(t *testing.T) {
109+
time.Local = loc // set the timezone for the test
110+
111+
t.Run("BeginningOfMonth", func(t *testing.T) {
112+
// timestamp is in the beginning of the month: 2000-01-01 00:00:01
113+
s = &revenuetypes.MonthlyPaymentSchedule{
114+
CurrentMonthStartBlockTs: uint64(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC).Unix()), //nolint:gosec
115+
}
116+
117+
// check that the current month is January regardless of the timezone
118+
assert.Equal(t, time.January, s.CurrentMonth())
119+
120+
// make sure period end edge cases result in the same regardless of the timezone
121+
assert.Equal(t, false, s.PeriodEnded(ctx.WithBlockTime(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC))))
122+
assert.Equal(t, false, s.PeriodEnded(ctx.WithBlockTime(time.Date(2000, time.January, 31, 23, 59, 59, 0, time.UTC))))
123+
assert.Equal(t, true, s.PeriodEnded(ctx.WithBlockTime(time.Date(2000, time.February, 1, 0, 0, 1, 0, time.UTC))))
124+
125+
// make sure effective period progress edge cases result in the same regardless of the timezone
126+
assert.Equal(t, math.LegacyZeroDec(), s.EffectivePeriodProgress(ctx.WithBlockTime(time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC))))
127+
assert.Equal(t, math.LegacyNewDecWithPrec(5, 1), s.EffectivePeriodProgress(ctx.WithBlockTime(time.Date(2000, time.January, 16, 12, 0, 0, 0, time.UTC))))
128+
assert.Equal(t, math.LegacyNewDecWithPrec(1344086021505376, 18), s.EffectivePeriodProgress(ctx.WithBlockTime(time.Date(2000, time.January, 1, 1, 0, 0, 0, time.UTC))))
129+
assert.Equal(t, math.LegacyNewDecWithPrec(999977598566308244, 18), s.EffectivePeriodProgress(ctx.WithBlockTime(time.Date(2000, time.January, 31, 23, 59, 0, 0, time.UTC))))
130+
assert.Equal(t, math.LegacyOneDec(), s.EffectivePeriodProgress(ctx.WithBlockTime(time.Date(2000, time.February, 1, 0, 0, 0, 0, time.UTC))))
131+
132+
// make sure the next period start timestamp and month are the same regardless of the timezone
133+
nextPeriodStartDate := time.Date(2000, time.February, 1, 0, 0, 0, 0, time.UTC)
134+
s.StartNewPeriod(ctx.WithBlockTime(nextPeriodStartDate))
135+
assert.Equal(t, time.February, s.CurrentMonth())
136+
assert.Equal(t, uint64(nextPeriodStartDate.Unix()), s.CurrentMonthStartBlockTs) //nolint:gosec
137+
})
138+
139+
t.Run("EndOfMonth", func(t *testing.T) {
140+
// timestamp is in the end of the month: 2000-01-31 23:59:00
141+
s = &revenuetypes.MonthlyPaymentSchedule{
142+
CurrentMonthStartBlockTs: uint64(time.Date(2000, time.January, 31, 23, 59, 0, 0, time.UTC).Unix()), //nolint:gosec
143+
}
144+
145+
// check that the current month is January regardless of the timezone
146+
assert.Equal(t, time.January, s.CurrentMonth())
147+
148+
// make sure period end edge cases result in the same regardless of the timezone
149+
assert.Equal(t, false, s.PeriodEnded(ctx.WithBlockTime(time.Date(2000, time.January, 31, 23, 59, 0, 0, time.UTC))))
150+
assert.Equal(t, false, s.PeriodEnded(ctx.WithBlockTime(time.Date(2000, time.January, 31, 23, 59, 59, 0, time.UTC))))
151+
assert.Equal(t, true, s.PeriodEnded(ctx.WithBlockTime(time.Date(2000, time.February, 1, 0, 0, 1, 0, time.UTC))))
152+
153+
// make sure effective period progress edge cases result in the same regardless of the timezone
154+
assert.Equal(t, math.LegacyZeroDec(), s.EffectivePeriodProgress(ctx.WithBlockTime(time.Date(2000, time.January, 31, 23, 59, 0, 0, time.UTC))))
155+
assert.Equal(t, math.LegacyNewDecWithPrec(22028076463560, 18), s.EffectivePeriodProgress(ctx.WithBlockTime(time.Date(2000, time.January, 31, 23, 59, 59, 0, time.UTC))))
156+
assert.Equal(t, math.LegacyNewDecWithPrec(22401433691756, 18), s.EffectivePeriodProgress(ctx.WithBlockTime(time.Date(2000, time.February, 1, 0, 0, 0, 0, time.UTC))))
157+
158+
// make sure the next period start timestamp and month are the same regardless of the timezone
159+
nextPeriodStartDate := time.Date(2000, time.February, 1, 0, 0, 0, 0, time.UTC)
160+
s.StartNewPeriod(ctx.WithBlockTime(nextPeriodStartDate))
161+
assert.Equal(t, time.February, s.CurrentMonth())
162+
assert.Equal(t, uint64(nextPeriodStartDate.Unix()), s.CurrentMonthStartBlockTs) //nolint:gosec
163+
})
164+
})
165+
}
100166
}
101167

102168
func TestBlockBasedPaymentSchedule(t *testing.T) {

0 commit comments

Comments
 (0)