beginningOfDay() used local timezone methods (getFullYear, getMonth,
getDate) to snap timestamps to midnight. Since the server sends UTC
timestamps, this caused day boundary calculations to be off by one
for users in UTC-negative timezones — cards created after UTC midnight
but before local midnight showed as "yesterday" instead of "today".
Switch to UTC methods (getUTCFullYear, getUTCMonth, getUTCDate) so day
boundaries are calculated consistently with the server's UTC timestamps.
Affects DaysAgoFormatter, DaysAgoOrWeekdayFormatter, TimeOrDateFormatter,
InDaysFormatter, and bubble controller stalled/entropy calculations.
The "closing soon" bubbles were introduced in #406, and the "falling
back" bubbles in #500. However, these bubbles are part of the cached
card and so as time passes, the relative time doesn't change unless
the card is touched.
This PR introduces a stimulus controller for bubbles, which takes care
of:
- making the bubble visible during the reminder period
- calculating the relative number of days until entropy kicks in
- rendering appropriate text around the day count
ref: https://37s.fizzy.37signals.com/collections/693169850/cards/999009091