Freecodecamp: Streak is still inaccurate for many campers

Created on 6 Apr 2016  ·  39Comments  ·  Source: freeCodeCamp/freeCodeCamp

One of the most common complaints I get (as person in charge of support emails) is that the streak isn't accurate. This may be due to timezones.

We probably need to go ahead and write some test cases and really tighten up this code. Any volunteers?

help wanted bug

All 39 comments

My first time with open source contributions, but I'd love to see if I'm up for the task.

This is still an issue that we get a lot of complaints about.

@QuincyLarson I am interested in helping out

@sorlovsky Awesome! We're interested in your help! See whether you can write some tests around this that cover various edge cases. It seems to work 99.9% of the time, but there are some situations where it doesn't and I'm not quite sure why.

I looked into this a bit and it may possibly caused by the fact that it is counting current streaks of Challenges and not the other activities (Projects or Algorithms). It's also possible that it's timezones as stated above. I'm going to look into the issue and see if I can PR if no one else get's to it.

Can someone please let me know if I'm missing something here.

const daysBetween = 1.5; can be updated to const daysBetween = 2; because the logic in the following functions always says less than daysBetween and not less than or equal to daysBetween. This means there will be coverage from 12:00:00AM one day all the way to 11:59:59PM the next. The timezone logic should all stay the same as well.

Changing daysBetween to 2 means that two tests break, which can be fixed but I'd have to learn a little bit how the tests work first.

The alternative option would be to set daysBetween to 1.99 so all tests pass, but you would have a possibility of missing the streak by 7 mins and 12 seconds.

@donofriov please go for it I was not able to figure why it didn't work

@donofriov thanks a lot for the analysis, and great to hear that you are interested to look into this. Here is another related issue https://github.com/freeCodeCamp/freeCodeCamp/issues/7468 (has to do with log in state of the user)

If you need any assistance hit us up on the chat room.

I'd have to learn a little bit how the tests work first.

The tests are at
https://github.com/freeCodeCamp/freeCodeCamp/blob/staging/server/utils/user-stats.test.js

Well this is a bit complicated structuring than usual. I'll be around if you need figuring out things.

Happy fixing!

@donofriov Yes - if you think that will fix it, great. Bump daysBetween to 2 and update the tests so they will pass.

If you're able to, please see if you can add some additional test coverage to make sure this is addressing the various corner cases that have cropped up (there are several issues related to streaks).

Thank you for your time and attention to this. This has been a major issue for months and is a source of many complaints, so fixing this will be huge :)

The problem is that the calculation of a streak is dependent on the timezone. In one timezone, say my three submissions are [Aug 5, Aug 6, Aug 7]. In another timezone, those same submissions might be on [Aug 5, Aug 5, Aug 6]. The calendar heatmap is likewise dependent on the timezone, and the heatmap always uses the timezone of the client viewing the page in the browser. So if we want the streaks to match the heatmap, we need to use the client's timezone in the calculation. That is basically what @LenaBarinova did when this issue was fixed back in January 2016 with #6333. The solution was to have the browser send the user's timezone whenever a challenge was submitted. The server would store the timezone and use it to calculate the streaks. But then in January 2017, there was a big refactoring that changed how challenges are submitted, and the fix got removed. The server side logic is still there, it's just the browser isn't sending the timezone anymore.

@Motardo Thanks for investigating this. Would you be interested in and fixing this to get @LenaBarinova's fix working again?

@QuincyLarson After having another look and sleeping on it, here are my thoughts:

Plan A
I think that the old solution was not ideal. It required a user to be logged in to view their own profile correctly and would still show inconsistencies when viewing other users profiles in other timezones.

Plan B (simple and straightforward, good temporary fix)
I believe that a simpler and more robust solution is to send the clients timezone with any request to view any user's profile, and the server could calculate the streaks based on that timezone. Then it wouldn't matter if the client was logged in, or whose profile was viewed. The streaks and the calendar would always be in sync.

Plan C (complicated refactor, possible future roadmap)
Probably the best solution would be to not calculate streaks on the server at all. The server should send the raw timestamps to the client and let the client decide which day each timestamp belongs to and how long the streaks are based on the local timezone. This is exactly what we do with the calendar heatmap data so it would always be consistent.

I am completely new to react and rxjs, and I think Plan C is out of my depth, but I would be happy to make a patch for Plan B, and I would love to hear other ideas and suggestions.

@Motardo I definitely agree that Plan C makes the most sense.

Given that it's been 15 days since you posted this, have you improved much with React and RXJS? This might be a good challenge to push the limits of your client side scripting abilities to the next level 😉

Hi. I just submitted a PR with possible fix. #16071

What I did:
I first changed the streak calculation to use 24 hoursBetween instead of 1.5 daysBetween. Then I took the difference in hours of startOf('day') of the previous timestamp and current timestamp and compared it to hoursBetween to account for works that has been done the past 24 hours instead of the past day. (Sounds the same but probably worth a try)

Probably a better fix would be is if you allow the user to set their own timezone in settings and everything is calculated/set using that timezone.

Edit: Does anyone know how to use/produce dummy accounts in localhost that has different sets of streaks?

Edit: Nevermind all these.

Tried to dig deeper, found out the inconsistencies between the heatmap and the streaks is possibly caused by the heatmap. https://github.com/wa0x6e/cal-heatmap/issues/122

@kennethlumalicay I believe we should be letting users store their timezones (with some smart defaults) mostly because we plan to keep the server side logic agnostic of the frontend as we plan to make the frontend more and more statically hosted.

@raisedadead I think there must be a simpler way to handle this rather than relying on users to set their timezones. Many of them use VPNs and travel.

Can we build in enough affordance that the streak doesn't get broken when someone changes time zones? I think currently we sustain the streak as long as it's within a 36 hour window.

@QuincyLarson I could be wrong but I don't think we sustain the streak within 36 hour window. Afaik the prepUniqueDays creates an array of timestamps that are 24, 48 and so on hours between and we compare it with betweenDays which is 1.5 days but the difference between unique days value could only be integers(1,2,...n) so it doesn't really have any decimal that is being used in the calculation of streaks.

How do we get the req.user.timezone? Because the dummy doesn't have timezone as a property so const timezone = user && user.timezone ? user.timezone : 'UTC'; always default to UTC. Do we set it according to user location?

If we have user.timezone the streaks would be consistent with user.timezone but the heatmap would only always be consistent with client's timezone.

Different scenarios with the current setup

if user's timezone matches client's timezone

  • Streaks and heatmap would both be accurate and consistent.

if user's timezone doesn't match client's timezone (e.g. VPN, wrong location/timezone set)

  • Streaks would be accurate with user.timezone but the heatmap probably won't.

if user.timezone is undefined (User isn't logged in or hasn't set their location/timezone)

  • Streaks would be inaccurate but heatmap will still be accurate with client's timezone unless they use a VPN. I think what we could do here is instead of using UTC as a default, we could use the client's timezone as well to match the heatmap.

_PS: I could be wrong so feel free to correct me._

@Kenneth-LJS I was under the impression we allowed an extra 12 hours of leeway, but that may have changed. If you've been looking closely at the code, I would trust your understanding of how it fits together.

Regarding your scenarios, it's OK for the calendar to be slightly offset. Very few campers have noticed this or complained about it. Campers won't mind that much. But it is not OK for the streak to be broken - that is what has caused so many campers to write in complaining about this bug.

So my argument would be rather than trying to figure out the time zones and sync them up, we just normalize the time to EST - which is where most Americans live - and add 12 to 24 hours leeway to reduce the likelihood of someone inadvertently ending their streak when traveling.

Hi, I'm writing because I saw @QuincyLarson comment on this post.

I'm a new camper and I have a "5 day streak" going on with activities recognized on:
Jan18 - 5 items
Jan19 - 24 items
Jan20 - 16 items
Jan21 - 2 items
Jan22 - 7 items
fcc

I see from reading above there is an expectation the "calendar completed" dates to be offset, but my streak shows only 1 day.

===
Side note - thanks for the awesome work. This is my 5th attempt at learning to code but I think this program is the one that will get me through the hump !

@kennethlumalicay Please take a look at this. Any idea what might be causing @ApeCogs's issue?

@ApeCogs do you know the time you did each challenge on jan 21 and 22?(even rough estimates) What is your timezone? Also do you use VPN?

@kennethlumalicay - Jan 21st would have been around 22:30 - 23:30 EST. Jan 22nd would have been 09:00 - 10:00 EST. I do use a VPN sometimes but it's for work and the region don't change (eastern).

I'm having the problem. It usually happens when I do a challenge around 22:00 CST - 24:00 CST. Though I have lost my streak when I have done it on Sunday around 19:00 CST - 20:00 CST. This would also usually happen when I am around a 7 -8 day streak. Not using a VPN. If there is anything I can do more to help please let me know.

screenshot-2018-1-24 learn to code with free online courses programming projects and interview preparation for developer

@ApeCogs I used some dummy data but I can't seem to reproduce it.

timestamps:

Wed Jan 24 2018 22:30:00 GMT-0500 (Eastern Standard Time)
Wed Jan 24 2018 23:30:00 GMT-0500 (Eastern Standard Time)
Thu Jan 25 2018 09:05:00 GMT-0500 (Eastern Standard Time)
Thu Jan 25 2018 09:12:00 GMT-0500 (Eastern Standard Time)
Thu Jan 25 2018 09:20:00 GMT-0500 (Eastern Standard Time)
Thu Jan 25 2018 09:30:00 GMT-0500 (Eastern Standard Time)
Thu Jan 25 2018 09:39:00 GMT-0500 (Eastern Standard Time)
Thu Jan 25 2018 09:40:00 GMT-0500 (Eastern Standard Time)
Thu Jan 25 2018 09:43:00 GMT-0500 (Eastern Standard Time)

I used 24 and 25 instead of 21 and 22 to recreate your "today" and "yesterday".

result:

ape

@mriel you lost your current streak too? Could you provide a larger screenshot containing the heatmap and streaks?

Re-opening, because of ongoing discussion

@kennethlumalicay here is a my screenshot:

screenshot-2018-1-25 learn to code with free online courses programming projects and interview preparation for developer

Most of the time my previous streaks have been 7-8 days. The next day I will do one lesson at night between 18:00 CST - 22:00 CST. The day after it will say my current streak is 1 day.

I have started to keep a log of current streak, day, time, and what challenge.

In here it says you did something on 20.
mriel

But in here there's nothing on 20.
mriel-2

So I'm assuming your timestamps are being displayed with the wrong timezone.

    // timezone of signed-in account
    // to show all date related components
    // using signed-in account's timezone
    // not of the profile she is viewing
    const timezone = user && user.timezone ?
      user.timezone :
      'EST';

So if you're not signed in, user would be null and timezone would be 'EST'.
Even if you're signed in I'm not really sure if user.timezone actually exist because it doesn't exist on the dummy data on my local db. Idk if fcc's db is different but since you're still getting the wrong timezone then you're still probably getting 'EST'.
I'm assuming this always goes to 'EST' by default.

~So I submitted a possible fix by changing 'EST' to moment.tz.guess().~

I just did a challenge. This is what my status is:
01/25/2018 20:41 PM CST Reverse Arrays with .reverse
screen shot 2018-01-25 at 8 46 08 pm
screen shot 2018-01-25 at 8 44 21 pm

I observed how challenges are recorded during the last week and basically saw challenge dates and streak are going by UTC and the heatmap is using EST. This means I and other people in CST need to do challenges before 6pm to be counted for the same day on all the parts. And if I do challenges in the morning one day and in the evening on the next, goodbye streak.

Just a thought, the language learning programs I use have an hours left countdown visible next to the streak information. Having a note saying "complete lessons by... to maintain streak." would be just as useful. I'd call getting consistent times the first priority for the streak problem, but letting people know their deadline for the day would be more useful than worrying about adjusting TZ for travel or allowing grace hours (as nice as those things sound).

A bug that makes the amazing 100DaysOfCode Challange useless


Here is my profile: https://www.freecodecamp.org/dardandmr

My 69 Days of Streak is broken for no reason

@QuincyLarson please bro, what is this, and can we reverse this?!
I have submitted the work two hours after 24:00, I don't think that it is a Time zone error, even if it is how is it possible that so many people here in FCC have not fixed this error?
image

I am really disappointed, I was so motivated with this 100DaysOfCode Challange, and I have finished all the Front-End Projects and everything else, I have only 4 Advanced Algorithms to solve to claim my Front End Certificate, stayed so many hours without sleep just to keep the streak going...

Screenshot

image
image

100DaysOfCode Challange , if such bug persists , it would just ruin us in morale.

@JohnnyCheung1989 look at my progress since the bug ruined my streak :(
image

It seems the video challenges are not counted toward streaks either, but are counted in heat map.

I'm a beginner especially with production code. Do not know if this algo would create too much overhead... But since heatmap seems to be working fine why can't the algo for streak just check the heatmap for days colored green or go the other way and check for grey gaps and return a value like check if element is '#cccc' etc.. if yes break streak
Remove all the current streak logic timezone and math all together and just check the heatmap in some way for color in element...
If ! grey streak++ if grey stop streak then check if streak longer than longest streak?

Forgive me if this has been brought up before.

I've never seen the heatmap inaccurate but my streaks are well... not so much.

Or someway put a flag in the heatmap code and streak outputs cant check it and update?

@dverdin83
I just briefly looked at the code. Heatmap is a plugin, so editing the heatmap code should not be done as it will break if updated. As for counting the green, it seems the plugin builds the color on the fly, so you would need to add a callback to delay the calculating.

It would be better to check the same thing as the heatmap does, that is what was suggested by Motardo _(see his comment on Sep 2, 2017 - Plan C)_.

Does anyone know which timezone is used by the streak counter and the heatmap? I just lost a 74 day streak even though I finished a challenge by 15:45PM KST (UTC +0900). The streak shows only 1 day but today's square on the heatmap is colored green, and on the timeline the challenge is recorded as being completed today as well. It seems like the streak counter is using one timezone, while the heatmap and timeline are using a second timezone. Can someone please confirm? It's really demoralizing as I was taking pride in watching the number grow every day and being able to share it with friends, family, and potential employers.

I understand that it may not be a high priority to fix, so at least knowing the rules of the streak would really help me understand and adjust my coding accordingly.

Quoted from @sgrayme https://github.com/freeCodeCamp/freeCodeCamp/issues/7925#issuecomment-361716788

I observed how challenges are recorded during the last week and basically saw challenge dates and streak are going by UTC and the heatmap is using EST...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Tzahile picture Tzahile  ·  3Comments

raisedadead picture raisedadead  ·  3Comments

MichaelLeeHobbs picture MichaelLeeHobbs  ·  3Comments

bagrounds picture bagrounds  ·  3Comments

ar5had picture ar5had  ·  3Comments