Skip to content

Commit

Permalink
Improve NYE countdown ready for next year!
Browse files Browse the repository at this point in the history
  • Loading branch information
rtitmuss committed Jan 1, 2025
1 parent 689f8a8 commit a97ba95
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 13 deletions.
5 changes: 5 additions & 0 deletions micropython/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

To run tests locally use:

`MICROPYPATH=.frozen:. micropython test/test_ProviderClock.py`

46 changes: 34 additions & 12 deletions micropython/provider/ProviderNewYearCountdown.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,47 @@
from typing import Union, Tuple
from typing import Callable, Union, Tuple

from provider.Clock import Clock
from provider.Provider import Provider

# Number of days in each month for a common year (non-leap year)
DAYS_IN_MONTHS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
DAYS_IN_MONTHS_LEAP_YEAR = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]


def _days_to_new_year(year: int, month: int, day: int) -> int:
is_leap_year = (year % 4 == 0 and (year % 100 != 0 or year % 400 == 0))
days_in_months = DAYS_IN_MONTHS_LEAP_YEAR if is_leap_year else DAYS_IN_MONTHS

days_passed = sum(days_in_months[:month - 1]) + day
total_days_in_year = 366 if is_leap_year else 365

return total_days_in_year - days_passed


class ProviderNewYearCountdown(Provider):
def __init__(self, timezone: str):
self.timezone = timezone
def __init__(self, timezone: str, clock_now: Callable = None):
self.clock_now = clock_now if clock_now else lambda: Clock.now(timezone)

def get_word(self, word: str, display: Display) -> Tuple[str, Union[int, None]]:
now = Clock.now(self.timezone)
now = self.clock_now()

if now.month == 1 and now.day == 1: # Jan 1st
return now.strftime("!HAPPY NEWYEAR %Y!"), None
return now.strftime("!HAPPY NEW" "YEAR %Y!"), None

next_interval_ms = (60 - now.second) * 1000
if now.month == 12 and now.day == 31 and now.hour == 23 and now.minute == 59: # last minute
return f"BYE {now.year:04}: {now.hour:02}:{now.minute:02}:{now.second:02}", 1

delta_hours = 23 - now.hour
delta_minutes = 59 - now.minute
if now.month == 12 and now.day == 31: # last day
next_interval_ms = (60 - now.second) * 1000
delta_hours = 23 - now.hour
delta_minutes = 59 - now.minute

if delta_minutes % 2 == 0:
return f"{now.year+1:04} IN {delta_hours:02}:{delta_minutes:02} ", next_interval_ms
else:
return f"COUNT DOWN {delta_hours:02}:{delta_minutes:02} ", next_interval_ms
if delta_minutes % 2 == 0:
return f"{now.year+1:04} SOON: {delta_hours:2}H {delta_minutes:02}M", next_interval_ms
else:
return f" NEW YEAR IN {delta_hours:2}H {delta_minutes:02}M", next_interval_ms

next_interval_ms = ((59 - now.minute) * 60 + (60 - now.second)) * 1000
delta_days = _days_to_new_year(now.year, now.month, now.day)
delta_hours = 23 - now.hour
return f" {now.year+1:04} IN {delta_days:3}D {delta_hours:02}H", next_interval_ms
61 changes: 61 additions & 0 deletions micropython/test/test_ProviderNewYearCountdown.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import unittest

from provider.Clock import Clock
from provider.ProviderNewYearCountdown import ProviderNewYearCountdown


class DisplayMock:
def display_length(self) -> int:
return 20


class PythonNewYearCountdownTest(unittest.TestCase):
def setUp(self):
self.display = DisplayMock()
self.provider = ProviderNewYearCountdown("Europe/Stockholm", lambda: self.mock_now)

def test_dec31_even_minute(self):
self.mock_now = Clock(2024, 12, 31, 22, 0)
word, interval_ms = self.provider.get_word(None, self.display)
self.assertEqual(word, " NEW YEAR " "IN 1H 59M")
self.assertEqual(interval_ms, 60000)

def test_dec31_odd_minute(self):
self.mock_now = Clock(2024, 12, 31, 22, 1)
word, interval_ms = self.provider.get_word(None, self.display)
self.assertEqual(word, "2025 SOON:" " 1H 58M")
self.assertEqual(interval_ms, 60000)

def test_last_minute(self):
self.mock_now = Clock(2024, 12, 31, 23, 59, 30)
word, interval_ms = self.provider.get_word(None, self.display)
self.assertEqual(word, "BYE 2024: " " 23:59:30")
self.assertEqual(interval_ms, 1)

def test_new_year(self):
self.mock_now = Clock(2025, 1, 1, 1, 1)
word, interval_ms = self.provider.get_word(None, self.display)
self.assertEqual(word, "!HAPPY NEW" "YEAR 2025!")
self.assertIsNone(interval_ms)

def test_jan2(self):
self.mock_now = Clock(2025, 1, 2, 1, 1)
word, interval_ms = self.provider.get_word(None, self.display)
self.assertEqual(word, " 2026 IN " " 363D 22H")
self.assertEqual(interval_ms, 3540000)

def test_jan2_leap(self):
self.mock_now = Clock(2028, 1, 2, 1, 1)
word, interval_ms = self.provider.get_word(None, self.display)
self.assertEqual(word, " 2029 IN " " 364D 22H")
self.assertEqual(interval_ms, 3540000)

def test_dec30(self):
self.mock_now = Clock(2025, 12, 30, 1, 1)
word, interval_ms = self.provider.get_word(None, self.display)
self.assertEqual(word, " 2026 IN " " 1D 22H")
self.assertEqual(interval_ms, 3540000)


if __name__ == '__main__':
unittest.main()
2 changes: 1 addition & 1 deletion micropython/www/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
<a href="#" onclick="preset('{clock_adl}', 'start_in_sync')">ADL</a>
<a href="#" onclick="preset('{clock_nyc}', 'start_in_sync')">NYC</a>
<br/>
<a href="#" onclick="preset('{new_year_sto}', 'end_in_sync')">New Year Countdown</a>
<a href="#" onclick="preset('{new_year_sto}', 'start_in_sync')">NYE Countdown</a>
<br/>
<a href="#" onclick="preset('{art}', 'end_in_sync')">Art</a>
<br/>
Expand Down

0 comments on commit a97ba95

Please sign in to comment.