X-Git-Url: https://git.madduck.net/etc/awesome.git/blobdiff_plain/32aa8ae47d86e8321ca8b00df394eaeccd160b21..ebcbc1838c17993801dc53fee28a21d05f92aacc:/luatz/timetable.lua diff --git a/luatz/timetable.lua b/luatz/timetable.lua index 879f0a2..fc89fca 100644 --- a/luatz/timetable.lua +++ b/luatz/timetable.lua @@ -56,6 +56,13 @@ local function day_of_week ( day , month , year ) return ( year + leap_years_since ( year ) + sakamoto[month] + day ) % 7 + 1 end +local function borrow ( tens , units , base ) + local frac = tens % 1 + units = units + frac * base + tens = tens - frac + return tens , units +end + local function carry ( tens , units , base ) if units >= base then tens = tens + idiv ( units , base ) @@ -69,34 +76,50 @@ end -- Modify parameters so they all fit within the "normal" range local function normalise ( year , month , day , hour , min , sec ) + -- `month` and `day` start from 1, need -1 and +1 so it works modulo + month , day = month - 1 , day - 1 + + -- Convert everything (except seconds) to an integer + -- by propagating fractional components down. + year , month = borrow ( year , month , 12 ) + -- Carry from month to year first, so we get month length correct in next line around leap years + year , month = carry ( year , month , 12 ) + month , day = borrow ( month , day , month_length ( floor ( month + 1 ) , year ) ) + day , hour = borrow ( day , hour , 24 ) + hour , min = borrow ( hour , min , 60 ) + min , sec = borrow ( min , sec , 60 ) + -- Propagate out of range values up -- e.g. if `min` is 70, `hour` increments by 1 and `min` becomes 10 + -- This has to happen for all columns after borrowing, as lower radixes may be pushed out of range min , sec = carry ( min , sec , 60 ) -- TODO: consider leap seconds? hour , min = carry ( hour , min , 60 ) day , hour = carry ( day , hour , 24 ) - - while day <= 0 do + -- Ensure `day` is not underflowed + -- Add a whole year of days at a time, this is later resolved by adding months + -- TODO[OPTIMIZE]: This could be slow if `day` is far out of range + while day < 0 do year = year - 1 day = day + year_length ( year ) end - - -- Lua months start from 1, need -1 and +1 around this increment - month = month - 1 year , month = carry ( year , month , 12 ) - month = month + 1 - -- This could potentially be slow if `day` is very large + -- TODO[OPTIMIZE]: This could potentially be slow if `day` is very large while true do - local i = month_length ( month , year ) - if day <= i then break end + local i = month_length ( month + 1 , year ) + if day < i then break end day = day - i month = month + 1 - if month > 12 then - month = 1 + if month >= 12 then + month = 0 year = year + 1 end end + -- Now we can place `day` and `month` back in their normal ranges + -- e.g. month as 1-12 instead of 0-11 + month , day = month + 1 , day + 1 + return year , month , day , hour , min , sec end @@ -204,7 +227,7 @@ local function new_from_timestamp ( ts ) if type ( ts ) ~= "number" then error ( "bad argument #1 to 'new_from_timestamp' (number expected, got " .. type ( ts ) .. ")" , 2 ) end - return new_timetable ( 1970 , 1 , 1 , 0 , 0 , ts ) + return new_timetable ( 1970 , 1 , 1 , 0 , 0 , ts ):normalise ( ) end return {