25

When a user is able to perform an action only once a day, for example getting a free ticket for a competition, there are two possibilities I came across in my experience.

1) 24 Hours Reset

If he performs the action on day 1 on 11:45 PM, he can only perform the action again on day 2 on or after 11:45. He won't be able to do it 11:44 on day 2.

2) Midnight Reset (or any fixed time)

No matter what time the user performs the action on day 1, as soon as it turns midnight and day 2 starts, he will be able to do it again.


Both limit the user in performing only one action a day, but I most often come across method 1, who I think is pretty inconvenient for two reasons:

  • First I have to wait for the time
  • and second over a long time period, the timestamp of me performing the action will become later and later, since I won't be able to perform the action exactly at that timestamp everyday, only a couple of seconds or minutes later.

Is there any technical reason, that one would prefer method 1, albeit the in my opinion important disadvantage for the user stated beforehand?


Edit, to specify: I'm especially talking about an example, where the actual timegap of 24 hours is not obviously needed, such as in the current free spin event of Theory11, where you get 1 free spin every 24 hours to get a chance at winning prizes.

RUL
  • 361
  • 3
  • 7
  • 5
    There might be a reason to limit the actual time between the actions, which is why they would opt for a 24-hour lockout. For example, with option 2, you could perform the action at 23:59 and at 00:00 again. – Ivo Coumans Dec 18 '18 at 10:32
  • 21
    The answer would be entirely problem-specific, and it isn't hard to come up with problems that suit either. Software is developed to implement business rules, not the other way around. – Blrfl Dec 18 '18 at 11:25
  • Would this question fit better at UX Stack Exchange? – TRiG Dec 18 '18 at 15:46
  • 1
    @Blrfl I think you have to think a little deeper on this one. The question is, is there some architectural advantage to the 24h version which makes it prefered. – Ewan Dec 18 '18 at 15:53
  • 4
    Note that midnight is an arbitrary time. It could just as easily be any time you want. – David Starkey Dec 18 '18 at 16:23
  • How is the second list item at _"over a long time period"_ at the question substantiated? – guest271314 Dec 18 '18 at 16:27
  • 2
    Kind of a sidenote, midnight can be problematic for night owls. To get around that, WoW, for instance, resets "daily" things at 3 or 4 am. – Kevin Dec 18 '18 at 20:19
  • Midnight in which timezone, anyway? – Bergi Dec 18 '18 at 20:37
  • Dusting off my pedantry, I would argue that only option 1 enforces a truly _at most once per day_ restriction, whereas the second option would allow _3 actions_ in a single 24:02 span. – Eric King Dec 18 '18 at 20:46
  • 2
    This isn't a software engineering question. This is a business rules question ... – svidgen Dec 18 '18 at 21:47
  • @Ewan We don't know what the rule is, and I think Eric King's pedantry is well-applied: If it's _one per calendar day_, three events in 24:02 is just fine. If it's _no more frequently than once every 24 hours_, it isn't. – Blrfl Dec 18 '18 at 21:52
  • 1
    @Blrfl its missing the point. The rule stated by a human is once per day. the question is why implement as once per 24h. (which will be twice a day when DST flips over) – Ewan Dec 18 '18 at 22:13
  • 1
    @Ewan I get the point just fine, and there's no need to be snarky. The stated-by-the-human rule is incomplete. Developing it as once per 24 hours when the actual business need was once per calendar day at headquarters would be a failure to meet a requirement and a failure to have nailed the requirement down in the first place. (Edit: I note that in the comments for you answer, you find this to be a communication issue. I agree.) – Blrfl Dec 18 '18 at 22:44
  • @Blrfl im not being snarkey, there are now 3 votes to close because people think this is a business rules question. Its not – Ewan Dec 18 '18 at 23:17
  • 6
    Note: There's a variety of games and such that only allow an Action every 21 hours. Theoretically one could abuse this to get >1 per day, but that means waking up mid-sleep, which is rare enough to usually not be that big of a deal for the servers. It then allows users to log in "every morning" without the timeout slowly advancing throughout the day. – Mooing Duck Dec 18 '18 at 23:22
  • The question _itself_ makes it clear that "the rule stated by a human" is underspecified. That's why you talk to your product manager, or whoever made the statement, and show them the possible interpretations and boundary conditions, to figure out _what they actually want_. – jscs Dec 19 '18 at 03:35
  • Mooing Duck has a good idea here, it could be once per 21 (or 22 or 23) hours. Would this do for your purposes? – user253751 Dec 19 '18 at 04:42
  • @guest271314, if I'm only 10 seconds late for my 24 hour vote every day, after 360 days I will only be delayed 1 hour. It will take 8640 days to lose 1 day. Reality has it, that you're probably late more than 10 seconds every day, but still. – RUL Dec 19 '18 at 08:39
  • @immibis, actuality has it, that mostly the 24 hour reset is chosen over a 23 hours or something approach, as seen in the linked example in the edit. But I'm with you on that. – RUL Dec 19 '18 at 08:47
  • The second inconvenience is easily solved by adding 24hrs to the _original_ threshold even when the user didn't do the task exactly on time. Although if they waited _more than a day_ then make it 24hrs*_n_ ;) That's how you make a repeating timer in software because such timers are generally not exactly accurate due to the nature of a non-real-time OS. – Lightness Races in Orbit Dec 19 '18 at 11:01

8 Answers8

21

I'm am surprised as usually I would expect the midnight reset.

However, It does come with a major disadvantage, in that there is more than one midnight every 24h. You need to choose your timezone.

Maybe this is why the universal once per 24h is chosen, you can imagine the company might not want to accept that users half in different countries might have non midnight local end times, or rather than they might consider that saying "per day" implied midnight and thus they change the marketing to "per 24h" and the software spec to match

Although I think this is fairly common to see "ends at 2pm GMT" or similar these days.

I would have thought the challenge of storing a last action date for every user would be harder than that of assigning a timezone to users or action types.

Edit I think its worth noting the differences between the two methods

24h rule

  • I will get a constant stream of events, rate limited to less than 1 per 24h.
  • When I end the thing, some users will get less events.
  • I need to store every users last event
  • When daylight savings causes a long or short day I wont have 1 event per day
  • Humans wont be able to hit exactly 24h on the dot, so I will naturally get less than 1 per day on average

1 per calendar day rule

  • I get bucketed events over a 50h(? UTC+14 to -12 ?) period assigned to a calendar day
  • realistically I still have to store every users last event as 'days' over lap
  • I do have a definite end of a day where I can say all the events after now are not in the day.
  • I need to know the location of the user to know which day their event applies to
  • Some people are awake far earlier in the 'day' than others

1 per calendar day in UTC rule

  • I get nice uniform 24h long days
  • I can bucket my events
  • I know when the start and end of a day is
  • Daylight savings are going to confuse people.
  • Humans can have 1 event per day
  • Humans not living near Greenwich will have funny start and end times
  • Maybe I can do a clever optimisation and just store a list of users who have entered? (probably I will end up storing every users event and time)

*Bucketing the events is going to be super useful for various reporting purposes. eg. say I have 10 prizes to be won each 24h period and they differ over time. How many students entered on day 10? etc

Ewan
  • 70,664
  • 5
  • 76
  • 161
  • You clearly touch my train of thoughts as I'm equally surprized. I think it would be fairly lazy to go for the 24 hour reset, but as @Richard Ward's answer states, it might be more difficult to respect all the time zones and might even spark communication problems as of when the event starts and ends. – RUL Dec 18 '18 at 11:57
  • hmm i think you got your answers confused. But on reflection I'm thinking that its most likely a business/developer communication issue. I can just imagine the planning meeting... Sales: "So users must only be allowed to take the offer once per day.." Dev: "what if they are flying and cross the international date line? can they place two orders?" Sales: ".....no... lets say 1 per 24h" Dev: "OK, hmm gona need more tables to store all that data!" Sales: "whateves" – Ewan Dec 18 '18 at 12:42
  • I see, you think the 24 hour approach is less complex? Because I don't think so apart from having an additional table it's far more simple to just say 24 hours than checking and calculating in different time zones. But you got a good point there: with leaving the timezone you could actually get more than one spin. – RUL Dec 18 '18 at 12:48
  • 4
    I think it's less complex to _explain_ – Ewan Dec 18 '18 at 13:20
  • @RUL `when the event starts and ends` - something else to consider, if this is for a social thing, is perceived fairness. Why would someone be allowed early access or to do something past when someone else is locked out? – Izkata Dec 18 '18 at 16:01
  • 10
    This. Timezone dependent stuff opens a whole can of worms that you can just leave closed by using the 24h timeout rule. And it's not exactly harder to store when an action happened than to store that it happened on a specific day. – cmaster - reinstate monica Dec 18 '18 at 17:18
  • An additional problem is that it's trivial for a user to fake their timezone. Meaning that you have to take care of people exploiting the idea by changing their timezone appropriately. – Voo Dec 19 '18 at 09:17
  • one day is not always 24 hours. Sometimes it is 23h, sometimes 25h – Thierry Dec 19 '18 at 10:15
14

Off the top of my head:

  • It may be easier to implement the "24-hours since last action" version
  • If the user does not perform the action exactly 24 hours after the last time, then eventually they may miss a whole 24-hour period because the reset must happen when they are asleep, or working. Perhaps they do it at 7 am before leaving for work, and leave for work at 8 pm. The next day they do it at at 7:15, then 7:30, then 7:45, and on the last day stay until until 8:00 to perform the action just before leaving. The next day they are not willing to stay until until 8:15, so just miss that morning and do it after returning home from work at 6 pm, a gap of 34 hours. If the result of the action is expensive for the company the saving might be more important than the inconvenience.
Richard Ward
  • 240
  • 1
  • 7
  • 3
    Good point on the sneaky marketing reason, to get the users to miss one day. – RUL Dec 18 '18 at 11:59
  • 1
    @RUL Or, probably more to the point, a user is more likely to buy a "paid extra spin" (or whatever) if they miss out on a free one. The cost of giving spins away might be trivial, but the occasional extra sales may be worth it. – TripeHound Dec 18 '18 at 14:37
  • I played a game based on Zulu time when I was in the USA. It was not trivial to keep straight when I could or could not do an activitiy. – Cort Ammon Dec 18 '18 at 16:02
  • 2
    Point 2 is why Blizzard (etc) avoid the 24 hour reset timer in WoW and other MMORPGs and instead do a daily reset. – Monica Apologists Get Out Dec 18 '18 at 18:29
  • 8
    It might be worth noting that some companies just use a less strict "daily" - League of Legends uses a 21-hour lockout for the "first win of the day". Sufficient to keep the bonuses roughly daily, while being convenient for players. Might be partially because of the idea that you won't always win your first game and games take ~30-50 minutes, so a strict clock would be really annoying (since you're likely to push back the time by 30 minutes or so a day, at which point it's not enticing because you only have playtime to get the first win every 3 days on a busy schedule). – Delioth Dec 18 '18 at 19:35
  • @Adonalsium They used to do a 20 hour reset for daily crafting. – corsiKa Dec 18 '18 at 22:34
8

As other answers have mentioned, the 24hr method is more friendly to multiple time zones, and is just as easy to code, as you just store the last successful timestamp for each user.

It also has the added "benefit" of actually requiring the user to interact with the app each day to get all of daily actions. If there is say a midnight reset, then a user may do an action at 11:59PM, and then again at 12:00AM. They could do this every other day and still get all the actions. For some apps the purpose of daily actions is to get the user to interact with the app on a daily basis so this is less ideal.

There's a third alternative that avoids the UI pitfalls of both, but is a bit harder to code.

3) No streaks of more than n actions in (n-0.75)*24 hours

It does require two variables to store, but it allows someone who's not trying to abuse the system to use their one action at anytime during their day without having to worry about timezones and resets.

It also prevents anyone from using more than 1 "extra" action.

So actually implement the algorithm you'd need to store the start time of the streak, the last play time, and the number of actions in your streak.

Keeping track of the last action time allows you to reject two actions that are too close together. You can make this limit less than 24 hours though because the streak prevents creeping earlier in the day.

A streak keeps going as long as you take your action every day. If taking an action would mean you'd have more actions than days in your streak then it gets rejected. This prevents slowly creeping forward, packing in "extra" actions because the start time of your streak doesn't change.

some pseudo code to implement the check and track the times:

//precondition: streakStart and  lastAction are initialized as in the far past
//              streakCount is initialized as 0
graceHours=18;
checkAllowed(currentTime,&streakStart,&streakCount, &lastAction){
    diffhours=hoursDifferent(lastAction,currentTime);
    if(diffhours< 24 - graceHours){
        return false;
    }
    diffhours=hoursDifferent(streakStart,currentTime);
    if(diffhours <= 24*streakCount - graceHours){
        return false;
    }
    if(diffhours > 24*(streakCount+2)-graceHours){
        streakStart=currentTime;
        streakCount=0;
    }
    streakCount++;
    lastActionTime=currentTime;
    return true;
}

As an added bonus, you get a streak counter, if you want one.

Rick
  • 199
  • 4
  • I think this is probably the best answer since it "just works" for the user. The only downside is that it might be hard to understand, but that should only ever affect people trying to game the system. The 18 graceHours could be explained in the text, since I think it is important to making this work (I think it should be lower though) – rtpax Dec 18 '18 at 21:45
  • Interesting approach, alltough, could you elaborate more in words, how this one works? – RUL Dec 19 '18 at 08:24
  • @RUL The fundamental idea is that the reset time for a user is locked in once they take their first action. It's not locked in at the exact time they take their action, but a bit before then (18 hours before, in this case) to provide a better user experience. This lets a user get *slightly* ahead (they can perform their first two actions in just 6 hours), but there is no cumulative error since the start is still locked in - if they have maxed out the grace period, they will have to wait at least 24 hours for the next action. – Jacob Raihle Dec 19 '18 at 16:43
5

About your problem with the 24h duration between actions, some companies instead use a 22h duration, this way the users get a bit of leeway on the exact moment of the day where the action is required and still get to encourage users to actually perform the action once per day -no 23:59 - 00:00 loophole.

Not an answer but I don't have enough points to comment.

  • I think this website does this with expendable things like votes. They don't reset every 24 hours but every 16 or so (not sure on the exact number). I guess it makes sense - let's say you start your day at 8 AM and start voting up/down - you run out of votes in 6 hours at 2PM. With a strict 24-hours-from-action reset, if you pick the reset time on the *last* vote, you'd need to wait until 2PM again to start voting instead of your usual time and you might not have time then. If you pick the *first* vote, then you have a problem if one day you start voting at 10 AM but 8AM the next one. – VLAZ Dec 19 '18 at 08:57
  • Although now that I think about it - I'm not sure if it's really 16 hours reset time keyed off the actions. It might be 24 hours and I happen to have caught it 8 hours after the daily reset. But I guess the logic holds - if you have a 24 individual timers, then it might not be convenient for a user. – VLAZ Dec 19 '18 at 08:58
  • This does have the opposite problem of the 34 hour reset, of users being able to pack in extra actions if they always act as soon as they can (of course that would require an awful sleep schedule...) – Rick Dec 19 '18 at 13:06
3
tl/dr: 24 hour resets are the lazy man's way of minimizing load spikes

In addition to the above answers, the midnight-reset encourages surges of traffic. If the action becomes available to all participators at a particular time, then there is going to be an incentive for many people to attempt the action at the same time. This is the same reason why most states have your drivers license expire on your birthday instead of on a fixed date (USA): the DMV wouldn't be able to keep up if everyone had their driver's license expire on January 1st.

Small Aside: if a computer system needs to take action once a day for a large number of users, you can ask the same question, and I typically design it to be a combination of both. You could imagine two cron tasks:

  1. Run at midnight, find all records, take action
  2. Run every every minute (or some regular frequency), find all records that haven't taken action since 00:00 yesterday, take action, record that action was taken

In practice I have found the former to be brittle. If a cron task breaks while running then some number may not have the action applied, and additional work may be needed for the system to remember where it was and pick up where it left off. It can also cause problems if you get enough records that your cron task can't process them all in a reasonable time limit, and it gets shut down before finishing.

The latter takes care of both of those concerns. It doesn't aim to get everything processed exactly 24 hours apart, but as long as your cron task can easily run through all actions each day, they will be pretty close and you'll guarantee that everyone gets run on each actual day (i.e. you won't have things slowly drifting apart by more than 24 hours). Most importantly though, it will easily pick up where it left off if things break down for some reason.

https://www.youtube.com/watch?v=hoMO1yYC7pQ

Conor Mancone
  • 386
  • 2
  • 11
0

Daily bus/train tickets at TfL (Transport for London) are valid from 4:30am to 4:30am. Do the switch when people are asleep. Plenty of people will want to use a service say from 8:30 to an hour past midnight

gnasher729
  • 42,090
  • 4
  • 59
  • 119
  • 4
    This is fine for strictly local use, but if you are expecting interactions from the internet then you can't pick a reset time that fits everybody. Even locally people have different sleep times - shift workers, etc. Minor objection, not enough for a -1. – Corey Dec 19 '18 at 02:34
  • @Corey Steam does tie most of their timers to 10 AM Pacific time. More specifically, that's changing over any promotions - Daily (10 AM every day), Midweek (10 AM on Tuesday - 10 AM Friday) or Weekend (10AM Friday - 10AM Monday). As an international store, that is applied accross everybody - that would be 19:00 Central European time or 13:00 in New York. Perhaps it's not convenient to every timezone but it's consistent. And, frankly, even were I using PT, then 10 in the morning would not be very convenient - I'm in Europe, so the evening is better for me. – VLAZ Dec 19 '18 at 08:51
0

The midnight reset has a specific condition that could be either desirable or detrimental, depending on what problem you are trying to solve and that is: I can perform the action one day at 11:59:58 and again at 00:00:01. If the problem space is any kind of competition, this could impart an unfair advantage to people choosing to perform their actions close to midnight. The 24-hour reset rule is the only way to ensure a fair distribution of available actions regardless of what time of day someone has available to them.

The consequence of the 24-hour reset becoming later and later can be mitigated by providing for a tolerance, for example accepting an action request within 15 minutes of the reset occurring so long as the action isn't actually recorded (or doesn't take effect) until the reset occurs. This introduces a bit more complexity into the solution, but I can't think of any mitigation strategy for being able to take two daily actions seconds apart as in the midnight reset case.

Jeff Lambert
  • 559
  • 2
  • 9
0

I haven’t seen anyon mention the fact that the 24 hour rule encourages routine regular visits. A lot of games have a once a day login/victory reward that resets after 24 hours because they would rather you check in for a short time every 24 hours rather than for twice as long every 48 hours. I’d imagine it’s similar for websites hosting ticket giveaways.

Carl
  • 21
  • 1
  • 1
    Both methods force a 24 hour revisit, except for few people, who wait the 48 hours and perform the action on 23:59:59 and on 00:00:01, but I think it's fairly unrelevant. – RUL Dec 19 '18 at 08:31
  • @RUL I use the check in twice in a row method for a lot of games that have reset times in a convenient time zone for me. So I don't think this is as irrelevant as you think. I generally won't log on every 48 hours, but I pretty much always get 2 actions every time I log on. – Rick Dec 19 '18 at 13:02