Created
August 15, 2018 21:52
-
-
Save infinisil/f740489b94917edfbaf0050cb455fcc3 to your computer and use it in GitHub Desktop.
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
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