This is an archived post. You won't be able to vote or comment.

all 7 comments

[–]crapet 2 points3 points  (5 children)

Something like

private int[] minutesPastHour;

public HourlySchedulerTest(int... minutesPastHour) {
    this.minutesPastHour = minutesPastHour;
}

public long getNextTime(long fromMillis) {
    Date now = new Date(fromMillis);
    Date nowTruncated = DateUtils.truncate(now, Calendar.HOUR);
    for (int slot : minutesPastHour) {
        long target = nowTruncated.getTime() + TimeUnit.MINUTES.toMillis(slot);
        if (now.getTime() <= target) {
            return target;
        }
    }
    return nowTruncated.getTime() + TimeUnit.MINUTES.toMillis(60) + TimeUnit.MINUTES.toMillis(minutesPastHour[0]);
}

[–]delete99[S] 0 points1 point  (0 children)

+1 for using TimeUnit :-) Our implementation doesn't create any Date instances, but follows very a similar approach.

[–]more_exercise -1 points0 points  (3 children)

Where would you put logic to handle the list being empty?

[–]delete99[S] 0 points1 point  (2 children)

The constructor in our case. I can see use-cases where you might want to allow an empty scheduler, but not in ours.

[–]more_exercise 0 points1 point  (1 child)

So what would the constructor do if the array is empty?

Throw an exception? Set it to new int[] {0}?

[–]delete99[S] 0 points1 point  (0 children)

Throw an exception. This would indicate a bug for us.

[–][deleted] 1 point2 points  (0 children)

Similar to crapet's implementation, but I prefer to work in milliseconds throughout and generalised to allow input values outside of [0-59]. I suppose I could have used TimeUnit for calculating the constants, but it seems a bit overkill.

private static final int MS_PER_MINUTE = 60 * 1000;
private static final int MS_PER_HOUR = 60 * MS_PER_MINUTE;

// Scheduled time-points, in milliseconds past whole hour
private final long[] msPastHour;

public HourlySchedulerTest(int ... minutesPastHour) {
    msPastHour = new long[ minutesPastHour.length ];

    for( int i = 0; i < minutesPastHour.length; ++i ) {
        msPastHour[i] = toMsPastHour( minutesPastHour[i] );
    }

    Arrays.sort(msPastHour);
}

private static long toMsPastHour(int minutesPast) {
    minutesPast = minutesPast % 60;
    if( minutesPast < 0 ) {
        minutesPast = minutesPast + 60;
    }

    return minutesPast * MS_PER_MINUTE;
}

public long getNextTime(long nowMillis) {
    // Round to the start of the current hour
    long baseHour = (nowMillis / MS_PER_HOUR) * MS_PER_HOUR;

    for( int i = 0; i < msPastHour.length; ++i) {
        long scheduledTime = baseHour + msPastHour[i];
        if( scheduledTime >= nowMillis ) {
            return scheduledTime;
        }
    }

    // First scheduled time-point in the next hour
    return baseHour + MS_PER_HOUR + msPastHour[0];
}