Finding newer, better ways to mess up DateTime comparisons



  • I realize it's common enough for someone not to understand how DateTime values work and think that just writing something like this (in C#) works:

    DateTime rightNow = DateTime.Now;
    DateTime today = DateTime.Parse("2/27/2012");
    if (rightNow == today)
    {
        // it doesn't, so we don't get here
    }
    

    (Sorry for the bad example, but the point is that disregarding the time portion of the original DateTime value is really common, though inexcusable.)

    I thought that might have been the issue when I got a bug report saying that entering a date to search in the web UI of our application returned no results. I think I would have preferred that to what I actually found:

    if (input.Filter.ServicerOpenDate.HasValue)
    {
        DateTime startDate = DateTime.Parse(input.Filter.ServicerOpenDate.Value.ToShortDateString());
        DateTime endDate = DateTime.Parse(input.Filter.ServicerOpenDate.Value.AddDays(1).Subtract(new TimeSpan(0, 0, 1)).ToShortDateString());
    
    result = result.Where(b => b.CreatedDate >= startDate && b.CreatedDate <= endDate);
    

    }


    Note that the CreatedDate property was just a timestamp (usually created with getutcdate() on SQL Server in a stored procedure).

    This code was brought to us by the same group of idiot contractors long-past that brought us Entity Framework object queries with obscene numbers of unnecessary includes. It would have been really nice if the contractors had bothered checking whether the construct above worked before littering their entire code with copy-pasted versions of it. Or, you know, they could have been smarter and realized that this wouldn't work.


  • Trolleybus Mechanic

    Our system doesn't need datetime libraries...

     ... unless we want to wish anyone Happy Birthday who was born on Feb 29th.



  • Are they adding a day, and then subtracting a day... therefore converting it to the same value as the startDate?



  • @Sutherlands said:

    Are they adding a day, and then subtracting a day... therefore converting it to the same value as the startDate?

    Also, ToShortDateString() doesn't print out times. So it queries for values between midnight and midnight on the same day.



  • @Sutherlands said:

    Are they adding a day, and then subtracting a day... therefore converting it to the same value as the startDate?

    They add a day, subtract a second, then truncate the time. Since input.Filter.ServicerOpenDate.Value is always just a date, with a time of midnight, the result is that the start date and end date are the same down to the second, and no records match. Even without the ToShortDateString(), the approach is still wrong because there are possibly DateTime values between 23:59:59 and 00:00:00 of the next day.

    One solution, though there are likely other, better ones:

    if (input.Filter.ServicerOpenDate.HasValue)
    {
        DateTime startDate = input.Filter.ServiceOpenDate.Value.Date;
        DateTime endDate = startDate.AddDays(1);
    
    result = result.Where(b => b.CreatedDate >= startDate && b.CreatedDate < endDate);
    

    }


    It's amazing how often people forget that the bare less-than and greater-than operators exist.



  • I've had my share of stupidity when dealing with DateTime objects too:



  • @Renan said:

    I've had my share of stupidity when dealing with DateTime objects too:

    Good read, though it doesn't appear that your WTF was DateTime-specific; more to the point, someone who had no business anywhere near a compiler, IDE, or any other programming tool needlessly rewrote your code because they couldn't understand what the hell a for loop does.

    Sometimes, it's a good thing when your boss is non-technical and doesn't pretend to know how to do your job.



  • I had a small one to clean up a couple of years ago (I was just reminded of it yesterday while clearing out some old email) left to me by a former coworker. The idea was to get customers who had birthdays between two dates, typically between the 6th of the current month and the 5th of the following month. His solution?

    to_char(birth_dt, 'MMDD') between to_char(sysdate, 'MM') || '06' and to_char(add_months(sysdate, 1), 'MM') || '05'

    Fortunately I was making other changes to this code and saw this before we did the December run; you're not going to find many birthdays that are between '1206' and '0105' in string comparison order. (In case you're wondering, I used months_between to calculate whether the number of whole years since the birth date increased between the two dates.)



  • @corgimonster said:

    I realize it's common enough for someone not to understand how DateTime values work and think that just writing something like this (in C#) works:

    ...
    DateTime today = DateTime.Parse("2/27/2012");
    ...

    IMAO methods like DateTime.Parse(string) shouldn't exist. Force people to specify which locale they want to use. It alerts people like your predecessor to their existence, and gives the maintenance programmer a bit more confidence that the original programmer actually made a decision.


  • ♿ (Parody)

    @pjt33 said:

    IMAO methods like DateTime.Parse(string) shouldn't exist. Force people to specify which locale they want to use. It alerts people like your predecessor to their existence, and gives the maintenance programmer a bit more confidence that the original programmer actually made a decision.

    Probably easier to simply conquer the world and establish a date format hegemony.



  • @boomzilla said:

    @pjt33 said:
    IMAO methods like DateTime.Parse(string) shouldn't exist. Force people to specify which locale they want to use. It alerts people like your predecessor to their existence, and gives the maintenance programmer a bit more confidence that the original programmer actually made a decision.
    Probably easier to simply conquer the world and establish a date format hegemony.
    World destruction is easier and far more affective, since there wont be anyone to challenge your super special awesome chocolaty fudge covered ultra mega uber date format.



  • @Lorne Kates said:

    Our system doesn't need datetime libraries...

     ... unless we want to wish anyone Happy Birthday who was born on Feb 29th.

    In the news today major problems with various systems (like ATMs and private health claim machines) blamed on the "edge case" of feb 29. Of course denied by the institutions.


Log in to reply