kopia lustrzana https://github.com/peterhinch/micropython-samples
166 wiersze
4.4 KiB
Python
166 wiersze
4.4 KiB
Python
# date.py Minimal Date class for micropython
|
|
|
|
# Released under the MIT License (MIT). See LICENSE.
|
|
# Copyright (c) 2023-2024 Peter Hinch
|
|
|
|
from time import mktime, localtime
|
|
from sys import implementation
|
|
if implementation.name != "micropython":
|
|
const = lambda x : x
|
|
|
|
_SECS_PER_DAY = const(86400)
|
|
def leap(year):
|
|
return bool((not year % 4) ^ (not year % 100))
|
|
|
|
class Date:
|
|
|
|
def __init__(self, lt=None):
|
|
self.callback = lambda : None # No callback until set
|
|
self.now(lt)
|
|
|
|
def now(self, lt=None):
|
|
self._lt = list(localtime()) if lt is None else list(lt)
|
|
self._update()
|
|
|
|
def _update(self, ltmod=True): # If ltmod is False ._cur has been changed
|
|
if ltmod: # Otherwise ._lt has been modified
|
|
self._lt[3] = 6
|
|
self._cur = mktime(tuple(self._lt)) // _SECS_PER_DAY
|
|
self._lt = list(localtime(self._cur * _SECS_PER_DAY))
|
|
self.callback()
|
|
|
|
def _mlen(self, d=bytearray((31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31))):
|
|
days = d[self._lt[1] - 1]
|
|
return days if days else (29 if leap(self._lt[0]) else 28)
|
|
|
|
@property
|
|
def year(self):
|
|
return self._lt[0]
|
|
|
|
@year.setter
|
|
def year(self, v):
|
|
if self.mday == 29 and self.month == 2 and not leap(v):
|
|
self.mday = 28 # Ensure it doesn't skip a month
|
|
self._lt[0] = v
|
|
self._update()
|
|
|
|
@property
|
|
def month(self):
|
|
return self._lt[1]
|
|
|
|
# Can write d.month = 4 or d.month += 15
|
|
@month.setter
|
|
def month(self, v):
|
|
y, m = divmod(v - 1, 12)
|
|
self._lt[0] += y
|
|
self._lt[1] = m + 1
|
|
self._lt[2] = min(self._lt[2], self._mlen())
|
|
self._update()
|
|
|
|
@property
|
|
def mday(self):
|
|
return self._lt[2]
|
|
|
|
@mday.setter
|
|
def mday(self, v):
|
|
if not 0 < v <= self._mlen():
|
|
raise ValueError(f"mday {v} is out of range")
|
|
self._lt[2] = v
|
|
self._update()
|
|
|
|
@property
|
|
def day(self): # Days since epoch.
|
|
return self._cur
|
|
|
|
@day.setter
|
|
def day(self, v): # Usage: d.day += 7 or date_1.day = d.day.
|
|
self._cur = v
|
|
self._update(False) # Flag _cur change
|
|
|
|
# Read-only properties
|
|
|
|
@property
|
|
def wday(self):
|
|
return self._lt[6]
|
|
|
|
# Date comparisons
|
|
|
|
def __lt__(self, other):
|
|
return self.day < other.day
|
|
|
|
def __le__(self, other):
|
|
return self.day <= other.day
|
|
|
|
def __eq__(self, other):
|
|
return self.day == other.day
|
|
|
|
def __ne__(self, other):
|
|
return self.day != other.day
|
|
|
|
def __gt__(self, other):
|
|
return self.day > other.day
|
|
|
|
def __ge__(self, other):
|
|
return self.day >= other.day
|
|
|
|
def __str__(self):
|
|
return f"{self.year}/{self.month}/{self.mday}"
|
|
|
|
|
|
class DateCal(Date):
|
|
days = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
|
|
months = (
|
|
"January",
|
|
"February",
|
|
"March",
|
|
"April",
|
|
"May",
|
|
"June",
|
|
"July",
|
|
"August",
|
|
"September",
|
|
"October",
|
|
"November",
|
|
"December",
|
|
)
|
|
|
|
def __init__(self, lt=None):
|
|
super().__init__(lt)
|
|
|
|
@property
|
|
def month_length(self):
|
|
return self._mlen()
|
|
|
|
@property
|
|
def day_str(self):
|
|
return self.days[self.wday]
|
|
|
|
@property
|
|
def month_str(self):
|
|
return self.months[self.month - 1]
|
|
|
|
def wday_n(self, mday=1):
|
|
return (self._lt[6] - self._lt[2] + mday) % 7
|
|
|
|
def mday_list(self, wday):
|
|
ml = self._mlen() # 1 + ((wday - wday1) % 7)
|
|
d0 = 1 + ((wday - (self._lt[6] - self._lt[2] + 1)) % 7)
|
|
return [d for d in range(d0, ml + 1, 7)]
|
|
|
|
# Optional: return UK DST offset in hours. Can pass hr to ensure that time change occurs
|
|
# at 1am UTC otherwise it occurs on date change (0:0 UTC)
|
|
# offs is offset by month
|
|
def time_offset(self, hr=6, offs=bytearray((0, 0, 3, 1, 1, 1, 1, 1, 1, 10, 0, 0))):
|
|
ml = self._mlen()
|
|
wdayld = self.wday_n(ml) # Weekday of last day of month
|
|
mday_sun = self.mday_list(6)[-1] # Month day of last Sunday
|
|
m = offs[self._lt[1] - 1]
|
|
if m < 3:
|
|
return m # Deduce time offset from month alone
|
|
return int(
|
|
((self._lt[2] < mday_sun) or (self._lt[2] == mday_sun and hr <= 1)) ^ (m == 3)
|
|
) # Months where offset changes
|
|
|
|
def __str__(self):
|
|
return f"{self.day_str} {self.mday} {self.month_str} {self.year}"
|