Skip to content

Instantly share code, notes, and snippets.

@infinisil
Created August 15, 2018 21:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save infinisil/f740489b94917edfbaf0050cb455fcc3 to your computer and use it in GitHub Desktop.
Save infinisil/f740489b94917edfbaf0050cb455fcc3 to your computer and use it in GitHub Desktop.
with import <nixpkgs/lib>;
rec {
# Deprecate foo with a warning at 1 month after the given date, throw at 2 months after the given date
foo = deprecate "2018-08-15" "foo is deprecated, use fooo instead" "foo";
bar = deprecate "2018-07-10" "bar is deprecated, use barr instead" "bar";
baz = deprecate "2018-05-01" "baz is deprecated, use bazz instead" "baz";
# 1 month
halflife = 30 * 24 * 60 * 60;
deprecate = time: message: value: let
epoch = iso8601ToEpoch time;
now = builtins.currentTime;
diff = now - epoch.value;
in assert epoch.success;
if diff > 2 * halflife then throw message
else if diff > halflife then builtins.trace message value
else value;
iso8601ToEpoch = input: let
parsed = builtins.match "([0-9]{4})-([0-9]{2})-([0-9]{2})" input;
year = toInt (elemAt parsed 0);
month = toInt (elemAt parsed 1);
day = toInt (elemAt parsed 2);
# To not have to recompute everything from 1970 to 2018, we just store the
# precomputed epoch for 2018-01-01
fixedYear = {
year = 2018;
epoch = 1514764800;
};
years = range fixedYear.year (year - 1);
fullYearDays = foldl (acc: year: acc + date.daysForYear year) 0 years;
months = range 1 (month - 1);
fullMonthDays = foldl (acc: month: acc + date.daysForMonth year month) 0 months;
days = fullYearDays + fullMonthDays + (day - 1);
seconds = days * 24 * 60 * 60;
result = fixedYear.epoch + seconds;
error = if parsed == null then "${input} is not of the form YYYY-MM-DD"
else if year < fixedYear.year then "Years below ${toString fixedYear.year} are not supported"
else if month < 1 || month > 12 then "${toString month} is not a valid month"
else if day < 1 || day > date.daysForMonth year month then "${toString day} is not a valid day, this month only has ${toString (daysForMonth year month)} days"
else null;
in if error == null then {
success = true;
value = result;
} else {
success = false;
value = error;
};
# Date utilities
date = rec {
isLeapYear = year:
if mod year 4 != 0 then false
else if mod year 100 != 0 then true
else if mod year 400 != 0 then false
else true;
daysForYear = year: if isLeapYear year then 366 else 365;
daysForMonth = year: month:
if month == 2 then
if isLeapYear year then 29 else 28
else
if elem month [4 6 9 11] then 30 else 31;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment