| 545 | |
| 546 | |
| 547 | class _CalendarOffset: |
| 548 | __slots__ = ["m", "w", "d", "hour", "minute", "second"] |
| 549 | |
| 550 | _DAYS_BEFORE_MONTH = ( |
| 551 | -1, |
| 552 | 0, |
| 553 | 31, |
| 554 | 59, |
| 555 | 90, |
| 556 | 120, |
| 557 | 151, |
| 558 | 181, |
| 559 | 212, |
| 560 | 243, |
| 561 | 273, |
| 562 | 304, |
| 563 | 334, |
| 564 | ) |
| 565 | |
| 566 | def __init__(self, m, w, d, hour=2, minute=0, second=0): |
| 567 | if not 1 <= m <= 12: |
| 568 | raise ValueError("m must be in [1, 12]") |
| 569 | |
| 570 | if not 1 <= w <= 5: |
| 571 | raise ValueError("w must be in [1, 5]") |
| 572 | |
| 573 | if not 0 <= d <= 6: |
| 574 | raise ValueError("d must be in [0, 6]") |
| 575 | |
| 576 | self.m = m |
| 577 | self.w = w |
| 578 | self.d = d |
| 579 | self.hour = hour |
| 580 | self.minute = minute |
| 581 | self.second = second |
| 582 | |
| 583 | @classmethod |
| 584 | def _ymd2ord(cls, year, month, day): |
| 585 | return ( |
| 586 | _post_epoch_days_before_year(year) |
| 587 | + cls._DAYS_BEFORE_MONTH[month] |
| 588 | + (month > 2 and calendar.isleap(year)) |
| 589 | + day |
| 590 | ) |
| 591 | |
| 592 | # TODO: These are not actually epoch dates as they are expressed in local time |
| 593 | def year_to_epoch(self, year): |
| 594 | """Calculates the datetime of the occurrence from the year""" |
| 595 | # We know year and month, we need to convert w, d into day of month |
| 596 | # |
| 597 | # Week 1 is the first week in which day `d` (where 0 = Sunday) appears. |
| 598 | # Week 5 represents the last occurrence of day `d`, so we need to know |
| 599 | # the range of the month. |
| 600 | first_day, days_in_month = calendar.monthrange(year, self.m) |
| 601 | |
| 602 | # This equation seems magical, so I'll break it down: |
| 603 | # 1. calendar says 0 = Monday, POSIX says 0 = Sunday |
| 604 | # so we need first_day + 1 to get 1 = Monday -> 7 = Sunday, |
no outgoing calls
no test coverage detected
searching dependent graphs…