Last active
September 13, 2021 07:54
-
-
Save swlaschin/0678d18f8a0ed1ed1184 to your computer and use it in GitHub Desktop.
FsCheck properties to use to check a "how many years old" function
This file contains hidden or 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
module PropertiesForDob = | |
let badAge (today:System.DateTime) (dob:System.DateTime) = | |
let dob = dob.Date // ignore time | |
let today = today.Date // ignore time | |
let ts = today.Subtract(dob) | |
ts.Days / 365 // bad implementation | |
let goodAge (today:System.DateTime) (dob:System.DateTime) = | |
let dob = dob.Date // ignore time | |
let today = today.Date // ignore time | |
let age = today.Year - dob.Year | |
let sameDateInBirthYear = today.AddYears(-age) | |
if dob.Date > sameDateInBirthYear then | |
age - 1 | |
else | |
age | |
// sanity check | |
let ``age is near year difference`` fnAge (dob:System.DateTime) = | |
let dob = dob.Date // ignore time | |
let today = System.DateTime.Today // ignore time | |
let todayYear = today.Year | |
let dobYear = dob.Year | |
let age = fnAge today dob | |
(age <= todayYear - dobYear + 1) && (age >= todayYear - dobYear - 1) | |
let ``you are one year older on your birthday`` fnAge (dob:System.DateTime) = | |
let dob = dob.Date // ignore time | |
let today = System.DateTime.Today // ignore time | |
let todaysAge = fnAge today dob | |
[1.0 .. 367.0] | |
|> List.map (today.AddDays) | |
|> List.tryFind (fun date -> (fnAge date dob) = todaysAge + 1 ) | |
|> Option.map (fun cutoverDate -> | |
cutoverDate.Day = dob.Day && cutoverDate.Month = dob.Month) | |
|> defaultArg <| false | |
Check.Quick (``age is near year difference`` badAge) | |
Check.Quick (``age is near year difference`` goodAge) | |
Check.Quick (``you are one year older on your birthday`` badAge) | |
Check.Quick (``you are one year older on your birthday`` goodAge) | |
// ----------------------------------------------- | |
// enforce that dates are in past (if needed) | |
// ----------------------------------------------- | |
let dateMustBeInPast (dob:System.DateTime) = | |
dob < System.DateTime.Today | |
let prop1 fnAge dob = (dateMustBeInPast dob ==> ``age is near year difference`` fnAge dob ) | |
let prop2 fnAge dob = (dateMustBeInPast dob ==> ``you are one year older on your birthday`` fnAge dob ) | |
Check.Quick (prop1 badAge) | |
Check.Quick (prop1 goodAge) | |
Check.Quick (prop2 badAge) | |
Check.Quick (prop2 goodAge) |
Fixed bugs in gist!
goodAge
fails for some dates!
Falsifiable, after 84 tests (2 shrinks) (StdGen (1781193483,295947640)):
29/02/1972 02:00:00
This could be a good start for a kata or something :-)
I got it working in the end for leap years - the actual impl was fine, it is the property that needed changing for when someone's DOB is on feb 29 and the current year is not a leap year, it expected March 1st.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How about a function like
person born one year later is one year younger
which takes a single DOB, adds a year onto it and confirms that the results are 1 apart?