In RetentionReportGenerator, we compare studyStartDate with requestInfo.getSignedInOn() and requestInfo.getUploadedOn(). However, studyStartDate is always in UTC while the requestInfo dates are always in the user's local time zone. This means that, for dates late at night, the user will appear to gave signed in / uploaded the day before they actually signed-in / uploaded.
Example: User's studyStartDate is 2019-09-02T04:00Z (which is actually 2019-09-01 in local time) and their signed-in on is 2019-09-03T21:00-0700. RetentionReportGenerator will see this as day 2, even though it's actually day 3.
In the extreme case, if the user signed-in after signing up and never signed-in again (studyStartDate 2019-09-02T04:00Z and sign-in on 2019-09-01T21:01-0700), RetentionReportGenerator will see this as day -1 and fail with an ArrayOutOfBoundsException.