121 lines
3.1 KiB
Python
121 lines
3.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
# This file is part of convertdate.
|
|
# http://github.com/fitnr/convertdate
|
|
|
|
# Licensed under the MIT license:
|
|
# http://opensource.org/licenses/MIT
|
|
# Copyright (c) 2016, fitnr <fitnr@fakeisthenewreal>
|
|
import math
|
|
import calendar
|
|
|
|
TROPICALYEAR = 365.24219878 # Mean solar tropical year
|
|
|
|
|
|
def ceil(x):
|
|
return int(math.ceil(x))
|
|
|
|
|
|
def floor(x):
|
|
return int(math.floor(x))
|
|
|
|
|
|
def amod(a, b):
|
|
'''Modulus function which returns numerator if modulus is zero'''
|
|
modded = int(a % b)
|
|
return b if modded == 0 else modded
|
|
|
|
|
|
# Sane people of the world, use calendar.weekday!
|
|
def jwday(j):
|
|
'''Calculate day of week from Julian day'''
|
|
return math.trunc((j + 0.5)) % 7
|
|
|
|
|
|
def weekday_before(weekday, jd):
|
|
return jd - jwday(jd - weekday)
|
|
|
|
|
|
# @param weekday Day of week desired, 0 = Monday
|
|
# @param jd Julian date to begin search
|
|
# @param direction 1 = next weekday, -1 = last weekday
|
|
# @param offset Offset from jd to begin search
|
|
def search_weekday(weekday, jd, direction, offset):
|
|
'''Determine the Julian date for the next or previous weekday'''
|
|
return weekday_before(weekday, jd + (direction * offset))
|
|
|
|
|
|
# Utility weekday functions, just wrappers for search_weekday
|
|
|
|
def nearest_weekday(weekday, jd):
|
|
return search_weekday(weekday, jd, 1, 3)
|
|
|
|
|
|
def next_weekday(weekday, jd):
|
|
return search_weekday(weekday, jd, 1, 7)
|
|
|
|
|
|
def next_or_current_weekday(weekday, jd):
|
|
return search_weekday(weekday, jd, 1, 6)
|
|
|
|
|
|
def previous_weekday(weekday, jd):
|
|
return search_weekday(weekday, jd, -1, 1)
|
|
|
|
|
|
def previous_or_current_weekday(weekday, jd):
|
|
return search_weekday(weekday, jd, 1, 0)
|
|
|
|
|
|
def n_weeks(weekday, jd, nthweek):
|
|
j = 7 * nthweek
|
|
|
|
if nthweek > 0:
|
|
j += previous_weekday(weekday, jd)
|
|
else:
|
|
j += next_weekday(weekday, jd)
|
|
|
|
return j
|
|
|
|
|
|
def monthcalendarhelper(start_weekday, month_length):
|
|
end_weekday = start_weekday + (month_length - 1) % 7
|
|
|
|
lpad = (start_weekday + 1) % 7
|
|
rpad = (5 - end_weekday % 7) % 6
|
|
|
|
days = [None] * lpad + list(range(1, 1 + month_length)) + rpad * [None]
|
|
|
|
return [days[i:i + 7] for i in range(0, len(days), 7)]
|
|
|
|
|
|
def nth_day_of_month(n, weekday, month, year):
|
|
"""
|
|
Return (year, month, day) tuple that represents nth weekday of month in year.
|
|
If n==0, returns last weekday of month. Weekdays: Monday=0
|
|
"""
|
|
if not 0 <= n <= 5:
|
|
raise IndexError("Nth day of month must be 0-5. Received: {}".format(n))
|
|
|
|
if not 0 <= weekday <= 6:
|
|
raise IndexError("Weekday must be 0-6")
|
|
|
|
firstday, daysinmonth = calendar.monthrange(year, month)
|
|
|
|
# Get first WEEKDAY of month
|
|
first_weekday_of_kind = 1 + (weekday - firstday) % 7
|
|
|
|
if n == 0:
|
|
# find last weekday of kind, which is 5 if these conditions are met, else 4
|
|
if first_weekday_of_kind in [1, 2, 3] and first_weekday_of_kind + 28 <= daysinmonth:
|
|
n = 5
|
|
else:
|
|
n = 4
|
|
|
|
day = first_weekday_of_kind + ((n - 1) * 7)
|
|
|
|
if day > daysinmonth:
|
|
raise IndexError("No {}th day of month {}".format(n, month))
|
|
|
|
return (year, month, day)
|