Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions src/repositories/powerBoostingRepository.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -988,12 +988,23 @@ function powerBoostingSnapshotTests() {
const firstGivbackRoundTimeStamp = Number(
process.env.FIRST_GIVBACK_ROUND_TIME_STAMP,
);
const givbackRoundLength = Number(process.env.GIVPOWER_ROUND_DURATION);

const startBoundary =
firstGivbackRoundTimeStamp + (round - 1) * givbackRoundLength;
const endBoundary = startBoundary + givbackRoundLength;
const snapshotTime = (snapshot.time.getTime() as number) / 1000;
// Calculate month-based boundaries (new logic)
const startDate = new Date(firstGivbackRoundTimeStamp * 1000);

// Round boundaries: 1st of the round's month to 1st of next month
const roundStartDate = new Date(startDate);
roundStartDate.setUTCMonth(startDate.getUTCMonth() + (round - 1));
roundStartDate.setUTCDate(1);
roundStartDate.setUTCHours(0, 0, 0, 0);

const roundEndDate = new Date(roundStartDate);
roundEndDate.setUTCMonth(roundEndDate.getUTCMonth() + 1);

const startBoundary = Math.floor(roundStartDate.getTime() / 1000);
const endBoundary = Math.floor(roundEndDate.getTime() / 1000);
const snapshotTime = Math.floor(snapshot.time.getTime() / 1000);

assert.isAtLeast(snapshotTime, startBoundary);
assert.isBelow(snapshotTime, endBoundary);

Expand Down
45 changes: 38 additions & 7 deletions src/utils/powerBoostingUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,54 @@ const firstGivbackRoundTimeStamp = Number(
process.env.FIRST_GIVBACK_ROUND_TIME_STAMP,
);

const givbackRoundLength = Number(process.env.GIVPOWER_ROUND_DURATION);
// Not used for month-based calculation, kept for backwards compatibility
// const givbackRoundLength = Number(process.env.GIVPOWER_ROUND_DURATION);

/**
* Get the round number for a given date
*
* @description
* The round number is calculated based on the date. Each month is a new round.
*
* @example
* getRoundNumberByDate(new Date('2026-02-10')) // 1778 // 1st of February 2026 is the 1778th round
*
* @param date - The date to get the round number for
* @returns {
* round: number;
* fromTimestamp: number;
* toTimestamp: number;
* }
*/
export const getRoundNumberByDate = (
date: Date,
): {
round: number;
fromTimestamp: number;
toTimestamp: number;
} => {
const now = getTimestampInSeconds(date);
// Calendar month-based calculation for perfect 1st-of-month alignment
const startDate = new Date(firstGivbackRoundTimeStamp * 1000);
const currentDate = new Date(date);

const round =
Math.floor((now - firstGivbackRoundTimeStamp) / givbackRoundLength) + 1;
// Calculate months elapsed since start date
const monthsElapsed =
(currentDate.getFullYear() - startDate.getFullYear()) * 12 +
(currentDate.getMonth() - startDate.getMonth());

const round = monthsElapsed + 1;

// Round boundaries: 1st of current month to 1st of next month
const roundStartDate = new Date(
Date.UTC(currentDate.getFullYear(), currentDate.getMonth(), 1, 0, 0, 0),
);

const roundEndDate = new Date(roundStartDate);
roundEndDate.setUTCMonth(roundEndDate.getUTCMonth() + 1);

const fromTimestamp = getTimestampInSeconds(roundStartDate);
const toTimestamp = getTimestampInSeconds(roundEndDate);

const fromTimestamp =
(round - 1) * givbackRoundLength + firstGivbackRoundTimeStamp;
const toTimestamp = round * givbackRoundLength + firstGivbackRoundTimeStamp;
return {
round,
fromTimestamp,
Expand Down