F# How to Compare Two DateTime Values

Viewed 1266

I have been researching this question, but the answers I am finding are for C#, not F#. It looks like I need to use DateTime.Compare, but I was hoping for a native solution.

The purpose of the function (below) is to determine if the access time of one file is >= to a threshold value. The threshold value is the last access time with a number of days subtracted from the last access time.

days_old is passed into the function isFileStale along with the file name fn.

I am just puzzled as to why this function always returns false.

let isFileStale fn days_old  =
    let rc =
        let currentTime = ((System.DateTime.Now).ToLocalTime())
        let lastFileUsed = File.GetLastAccessTime(fn)
        let timeSpan = new TimeSpan(days_old, 0, 0, 0, 0)
        let fileDeleteThreshhold = lastFileUsed.Subtract(timeSpan)

        if fileDeleteThreshhold >= lastFileUsed then
            true
        else
            false
    rc
2 Answers

I'm not sure to understand what you're trying to do but you always get false because lastFileUsed.Subtract(timeSpan) (which is your fileDeleteThreshhold value) the will always be lower than lastFileUsed (or equal when days_old = 0)

Maybe this is what you're looking for:

let isFileStale fn days_old  =
    let currentTime = DateTime.Now
    let lastFileUsed = File.GetLastAccessTime(fn)
    (currentTime - lastFileUsed).Days >= days_old

BTW, as a general rule of thumb, any time you use DateTime.Now inside a function, I'd recommend turning it into a pure function by moving currentTime into a parameter. This makes your unit testing much simpler because you don't have to mock DateTime.Now, you just have to pass in the time that you want to be the "current" time for that unit test. E.g., to test isFileStale with your current function, your unit test would have to check the current time, create a file with a timestamp of (current time - N days), then call isFileStale on that file. But with a version of isFileStale that takes currentTime as a parameter, your test would be:

  • Create a file with timestamp 2010-01-01
  • Is it 7 days old on 2010-01-07? Answer should be "no".
  • Is it 7 days old on 2010-01-08? Answer should be "yes".

This also allows you to test things like February 29th easily, without needing to run your unit tests precisely at the right time every four years.

Now, for such a simple function as isFileStale, this may not be necessary. But it's a good rule of thumb to remember. I'd recommend writing the following pair of functions (starting with gileCAD's code since it's excellent):

let isFileStale currentTime days_old fn  =
    let lastFileUsed = File.GetLastAccessTime(fn)
    (currentTime - lastFileUsed).Days >= days_old

let isFileOlderThanNDays days_old fn =
    isFileStale DateTime.Now days_old fn

Note that I swapped the order of the days_old and fn parameters, because that allows you to write code that makes sense in a pipeline:

if "/path/to/file" |> isFileOlderThanNDays 7 then
    printfn "File is at least a week old"
else
    printfn "File is relatively fresh"
Related