Created
February 19, 2015 18:13
-
-
Save socantre/c9dfcc5bd106a601d395 to your computer and use it in GitHub Desktop.
days_from_civil implemented in Lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
http://howardhinnant.github.io/date_algorithms.html | |
Returns number of days since civil 1970-01-01. Negative values indicate | |
days prior to 1970-01-01. | |
Preconditions: y-m-d represents a date in the civil (Gregorian) calendar | |
m is in [1, 12] | |
d is in [1, last_day_of_month(y, m)] | |
y is "approximately" in | |
[numeric_limits<Int>::min()/366, numeric_limits<Int>::max()/366] | |
Exact range of validity is: | |
[civil_from_days(numeric_limits<Int>::min()), | |
civil_from_days(numeric_limits<Int>::max()-719468)] | |
]] | |
function days_from_civil(y, m, d) | |
if m <= 2 then -- adjust so that leap days are at the end of leap years | |
y = y - 1 | |
m = m + 9 | |
else | |
m = m - 3 | |
end | |
local era = math.floor(y / 400) | |
local yoe = y - era * 400 -- [0, 399] | |
local doy = math.modf((153*m + 2)/5) + d-1 -- [0, 365] | |
local doe = yoe * 365 + math.modf(yoe/4) - math.modf(yoe/100) + doy -- [0, 146096] | |
return era * 146097 + doe - 719468 | |
end | |
local reference_date = {year=2001, month = 1, day = 1} | |
local date = os.date("*t") | |
local reference_days = days_from_civil(reference_date.year, reference_date.month, reference_date.day) | |
local days = days_from_civil(date.year, date.month, date.day) | |
print(string.format("Today is %d days into the 21st century.",days-reference_days)) | |
-- Returns: true if y is a leap year in the civil calendar, else false | |
function is_leap(y) | |
return math.fmod(y, 4) == 0 and (math.fmod(y, 100) ~= 0 or math.fmod(y, 400) == 0) | |
end | |
--[[ | |
Preconditions: m is in [1, 12] | |
Returns: The number of days in the month m of common year | |
The result is always in the range [28, 31]. | |
]] | |
function last_day_of_month_common_year(m) | |
local a = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} | |
return a[m] | |
end | |
--[[ | |
Preconditions: m is in [1, 12] | |
Returns: The number of days in the month m of year y | |
The result is always in the range [28, 31]. | |
]] | |
function last_day_of_month(y, m) | |
return (m ~= 2 or not is_leap(y)) and last_day_of_month_common_year(m) or 29 | |
end | |
local previous_days = days_from_civil(-1001, 12, 31) | |
for year = -1000, 3000 do | |
for month = 1, 12 do | |
for day = 1, last_day_of_month(year, month) do | |
local days = days_from_civil(year, month, day) | |
if previous_days + 1 ~= days then | |
print("Error", year, month, day) | |
end | |
previous_days = days | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment