Skip to content

Instantly share code, notes, and snippets.

@lrhn
Created September 11, 2016 15:01
Show Gist options
  • Save lrhn/92f0414cf6c97e3a42e2a29a36d3d9c0 to your computer and use it in GitHub Desktop.
Save lrhn/92f0414cf6c97e3a42e2a29a36d3d9c0 to your computer and use it in GitHub Desktop.
List<int> daysToYearMonthDay(int days) {
// Use 1st of March year -99 as base.
// This keeps the leap day of year 0, 400, ... in the first
// century, but place the Feb 29 day of the century at the very end.
days += 306 + 365 * 99 + 24;
const daysIn4Centuries = 365 * 400 + 97;
// Multiply by 4, then divide by days in 400 years. This is basically
// the same as dividing by 365.2425 * 100 - the average number of days
// in a century, but using only integer division.
var daysX4 = days * 4;
var centuries = daysX4 ~/ daysIn4Centuries;
var daysInCenturyX4 = daysX4.remainder(daysIn4Centuries);
if (daysInCenturyX4 < 0) {
daysInCenturyX4 += daysIn4Centuries;
centuries -= 1;
} // Don't have div compatible with %, so this is necessary for negative values.
daysInCenturyX4 &= ~3;
// Add a leap year in front, so the century + 1y starts and ends with a
// leap year (unless the last year is divisible by 100, but all previous
// years always have the same lengths: 366, 365 * 3, repeat).
daysInCenturyX4 += 366 * 4;
const daysIn4Years = 365 * 4 + 1;
var year = (centuries - 1) * 100 + daysInCenturyX4 ~/ daysIn4Years;
daysInCenturyX4 = daysInCenturyX4.remainder(daysIn4Years);
var daysInYear = daysInCenturyX4 ~/ 4;
// The 5-year periods March-July and August-December both have 153 days
// divided as 31-30-31-30-31.
// The third period, January-February, starts with 31-x as well,
// so all three periods can be treated equally.
var fiveMonths = daysInYear ~/ 153;
var daysIn5Months = daysInYear.remainder(153);
var daysIn5MonthsX2 = daysIn5Months * 2;
var month = daysIn5MonthsX2 ~/ 61;
var dayInMonth = daysIn5MonthsX2.remainder(61) ~/ 2;
month += 2 + fiveMonths * 5;
// Correct for having rotated January-February to end of year,
// all the previous months really belong to the preivous year.
// This is 1 if month is January or February, 0 otherwise.
int isJanFeb = fiveMonths >> 1;
month -= isJanFeb * 12;
year -= isJanFeb ^ 1;
return[year, month + 1, dayInMonth + 1];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment