• (disco)

    Whoah, one of those code snippets is disingenious:

    public void Remove(Calendar calendar)
            {
                // Preconditions
                Calendar c = new Calendar();
                if (c.GetType() != calendar.GetType())
                {
                    throw new InvalidOperationException("calendar param has wrong type.");
                }
                ...
            }
    

    It might not happen soon, but if you ever want to extend Calendar this little nugget will start spitting exceptions in your face… I can only hope that idiom was used sparingly.

  • (disco) in reply to JBert
    public void Remove(Calendar calendar)
    {
        // Preconditions
        Calendar c = new Calendar();
        if (c.GetType() != calendar.GetType())
        {
            throw new InvalidOperationException("calendar param has wrong type.");
        }
        ...
    }
    

    I can't even make a funny comment about this. I'm just speechless. It's like he's never heard of type safety.

  • (disco) in reply to Masaaki_Hosoi
    Masaaki_Hosoi:
    It's like he's never heard of type safety.

    reads to me more like he has and doesn't trust it. of course if he was coding in C# and didn't want anyone to inherit from his classes he could always create them as sealed and then the type system would take care of his paranoia for him.

  • (disco) in reply to Masaaki_Hosoi

    You don't want to know how often similar things appear in the C# code a former coworker left behind.

  • (disco)

    Wow... the level of :wtf: is so high it nearly blew the meter! Good thing it didn't; those things are expensive...

    <!-- Emoji'd by MobileEmoji 0.2.0-->
  • (disco)
      if ( $month =~ /^\d{1}$/ )
      {
        $month = '0' . $month;
      }
    

    I wonder why someone would type “{1}“ instead of typing “”. Paid by the character? Also, regex abuse. Perl has a function to get the length of a string; it’s called length. It also has a sprintf function to avoid having to manually prepend zeros.

  • (disco) in reply to VinDuv

    Yep. I'm the submitter of that little bit - we have had some date WTFs in our code (Why did this invoice upload for January 1, 1900?!) thanks to Perl's... idiosyncratic date implementation combined with the Not Invented Here syndrome some of our previous devs had. I've been using sprintf to replace a lot of iffy string builders as well.

    Nearly every time I go in to fix something in the older areas of our application, I end up carving out some useless crap. We've actually set it up to crash on unused variables on the devel server just so we get rid of the huge pile of legacy variables, db queries that are made then never paid attention to, etc...

  • (disco)

    Sigh,

    Date handling is hard. Its not supposed to be hard for you though. Why developers can't just internalize the lesson use whatever epoch your platform likes and store the date as integer, than use the provided formatting and conversion functions; do not write your own.

    Honestly most date time handling WTFs come down to someone could not be bothered to RTFM. These are all solved problems if you are working with any modern language from plain old C onward.

    The two real exceptions are when you have to deal with dates that may be a mix of Julian and Gregorian and when you have to move data between systems using different epocs; which is generally easy except when there are conditional rules you need to be aware of about which epoc is used, (looks disapprovingly at Excel).

  • (disco) in reply to geoff
    geoff:
    use the provided formatting and conversion functions

    Everyone who uses any .NET language - even if just during 5 minutes of their life - should have these two articles bookmarked:

    https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx

  • (disco) in reply to Masaaki_Hosoi
    Masaaki_Hosoi:
    public void Remove(Calendar calendar)
    {
        // Preconditions
        Calendar c = new Calendar();
        if (c.GetType() != calendar.GetType())
        {
            throw new InvalidOperationException("calendar param has wrong type.");
        }
        ...
    }
    

    It seems like a poor man's check whether you haven't been passed a ChineseLunisolarCalendar by accident. I don't vouch for it actually working though...

    if (date.Date == new DateTime(9999, 12, 31))
    {
       date.Date = DateTime.MaxValue;
    }
    

    on the other hand, I see nothing wrong with - maybe they interface with a system that uses 9999-12-31 as a placeholder of sorts, and want to bring it to the common denominator? Or does

    Maybe next time, someone should just spend ten seconds Googling what DateTime.MaxValue is...

    mean there's some weird MaxValue quirk I'm not aware of?

  • (disco) in reply to Maciejasjmj
    Maciejasjmj:
    if (date.Date == new DateTime(9999, 12, 31))
    {
       date.Date = DateTime.MaxValue;
    }
    

    on the other hand, I see nothing wrong with - maybe they interface with a system that uses 9999-12-31 as a placeholder of sorts, and want to bring it to the common denominator? Or does

    Maybe next time, someone should just spend ten seconds Googling what DateTime.MaxValue is...

    mean there's some weird MaxValue quirk I'm not aware of?

    Given `DateTime.MaxValue` ≡ `23:59:59.9999999 UTC, December 31, 9999`, I think the article writer should have Googled the info themselves :laughing: <!-- Emoji'd by MobileEmoji 0.2.0-->
  • (disco)

    This article feels a bit dated...

  • (disco) in reply to nobulate
    nobulate:
    This article feels a bit dated...

    :rimshot:

  • (disco) in reply to RaceProUK
    RaceProUK:
    Given `DateTime.MaxValue` ≡ `23:59:59.9999999 UTC, December 31, 9999`, I think the article writer should have Googled the info themselves :laughing:

    However, if I'm reading that right (I'm not a .NET guy), only the Date part of that is being used; the 23:59:59.9999999 UTC part is being ignored in the comparison and discarded in the assignment. So the code snippet is, indeed, a NOP. (Alternatively, if the time component is not ignored in the comparison, the comparison will always fail. Again a NOP.)

  • (disco) in reply to Maciejasjmj
    Maciejasjmj:
    It seems like a poor man's check whether you haven't been passed a `ChineseLunisolarCalendar` by accident. I don't vouch for it actually working though...

    Why does the code care at this point though? :facepalm:

  • (disco) in reply to HardwareGeek

    Obligatory Joke:

    Q: Why do programmers confuse Halloween and XMas? A: Because DEC 25 == OCT 31

    :rimshot:

  • (disco) in reply to Maciejasjmj
    Maciejasjmj:
    if (date.Date == new DateTime(9999, 12, 31))
    {
       date.Date = DateTime.MaxValue;
    }
    

    on the other hand, I see nothing wrong with - maybe they interface with a system that uses 9999-12-31 as a placeholder of sorts, and want to bring it to the common denominator?

    I think this qualifies as bogus anyway. Certainly it would in Java (without some sort of boxing going on), because this pre-existing Date object would not have the same object-reference pointer as the one the code creates on the fly to do the comparison.

    But the business-day function makes me despair. Deciding if a particular day is a business day without a database - that is, 100% algorithmically - is a difficult problem, and is best solved using a database. (Even if the problem is specified as "without a database", the best solution is to use a database. In this context, "best" is usefully translated as "only viable".) For starters, once you go beyond one particular group of countries, testing for weekends as "Saturday and Sunday" fails - the weekend in Israel is "Friday and Saturday", for example. Public holidays can only sanely be handled by a database because of the number of exceptions, changes, and so on.

    Like much in the business world, naive generalisations will let you down. Consider currencies. Quick, which of these statements is true?

    • All currencies have 100 sub-units (e.g. dollars and cents, pounds and pence).
    • All currencies have sub-units.
    • All currencies with sub-units have an integer-power-of-ten number of sub-units.
    • All stock exchanges list share prices in the local major unit.
    • All Sterling-listed share prices in London are listed in pence.

    The answer, of course, is "none of them." Some currencies don't have sub-units at all. Some of the ones that do have sub-units have 1000 sub-units per major unit rather than the more common 100. Two very, very minor currencies have 5 sub-units per major unit. Share prices in London are usually listed in pence, not pounds, but in some cases, the listing currency is pounds, not pence.

    EDIT: Fixed the quote. Discourse is bogus. Or maybe bugus.

  • (disco) in reply to Steve_The_Cynic
    Steve_The_Cynic:
    I think this qualifies as bogus anyway. Certainly it would in Java (without some sort of boxing going on), because this pre-existing Date object would not have the same object-reference pointer as the one the code creates on the fly to do the comparison.

    Yeah, DateTimes in .NET are sane (as in, compare by value).

  • (disco) in reply to Steve_The_Cynic
    Steve_The_Cynic:
    Discourse is bogus. Or maybe bugus.

    :+1:

  • (disco) in reply to tarunik
    tarunik:
    Why does the code care at this point though?

    One thing I've always admired about Java's date-handling library is that if you used it correctly, you could switch to a wildly different calendar without changing any of the other date code. Sure, having to type in "new GregorianCalendar()" was a pain, but that they didn't assume anything about it was nifty. So, for example, creating something that would switch from looking at the Jewish month of Adar to the more conventional month of March is really not that difficult.

  • (disco) in reply to HardwareGeek

    It looks like they had DateTime.MaxValue in their database already in a column that allowed DateTime values, but their UI only allowed users to enter dates. So if a user entered 12/31/9999 this code changed it to DateTime.MaxValue to keep their database consistent.

    They probably had some more WTFy business logic that selected the rows containing DateTime.MaxValue for some particular reason, and they didn't want to try to change that in five dozen different locations to ignore the time component of the DateTime so it would also select rows that contained 12/31/9999 00:00:00.

  • (disco)

    The real WTF with the perl example is that it is definitely not "clever".

    if you really want to do what the programmer was doing & avoid standard date functions, you would:

    my($se,$mi,$ho,$da,$mo,$ye)= localtime();
    printf("%04d_%02d_%02d_%02d%02d\n\n", $ye+1900, $mo+1, $da, $ho, $mi, $se);
    

    a 'clever' perl programmer would be succinct, invoke a deep meaning of hashes & perl parameter passing, use map & eval and the code would be completely opaque.

    f (2=>0, 2=>0, 2=>0, 2=>0, 2=>1, 4=>1900);
    sub f {   print join('_', reverse(map { eval("sprintf ('%0".shift(@_)."d',". ($_+shift(@_)).")") } (localtime())[0..5] )); }
    

    the only let-down from a perl point-of-view is that there in no 1000 character regex involved.

  • (disco) in reply to Steve_The_Cynic
    Steve_The_Cynic:
    Like much in the business world, naive generalisations will let you down. Consider currencies. Quick, which of these statements is true?

    All currencies have 100 sub-units (e.g. dollars and cents, pounds and pence). All currencies have sub-units. All currencies with sub-units have an integer-power-of-ten number of sub-units. All stock exchanges list share prices in the local major unit. All Sterling-listed share prices in London are listed in pence.

    The answer, of course, is "none of them." Some currencies don't have sub-units at all. Some of the ones that do have sub-units have 1000 sub-units per major unit rather than the more common 100. Two very, very minor currencies have 5 sub-units per major unit. Share prices in London are usually listed in pence, not pounds, but in some cases, the listing currency is pounds, not pence.

    Never mind that fractional United States cents do exist in some parts of the finance world (such as credit/debit card payments)...

  • (disco) in reply to bc3_au
    bc3_au:
    the only let-down from a perl point-of-view is that there in no 1000 character regex involved.

    I think I'll manage to survive somehow…

  • (disco) in reply to tarunik
    tarunik:
    Never mind that fractional United States cents do exist in some parts of the finance world (such as credit/debit card payments)...

    And gas station signs! :wtf:

  • (disco) in reply to geoff
    geoff:
    Why developers can't just internalize the lesson use whatever epoch your platform likes and store the date as integer,
    Integer? Why not store a date as a date type. That's what it's for. Any sane language has a date type (or more than one, which makes it less sane). The developer shouldn't have to care that the compiler converts dates to an offset of an epoch.
  • (disco) in reply to anotherusername
    anotherusername:
    So if a user entered 12/31/9999 this code changed it to DateTime.MaxValue to keep their database consistent.
    HardwareGeek:
    the 23:59:59.9999999 UTC part is being ignored in the comparison and discarded in the assignment

    Referring StackOverflow: http://stackoverflow.com/questions/6127123/net-datetime-maxvalue-is-different-once-it-is-stored-in-database

  • (disco) in reply to nerd4sale
    nerd4sale:
    The developer shouldn't have to care that the compiler converts dates to an offset of an epoch.

    Until they do have to care, which is when the problems start (or rather they started a bit before). Dates aren't as simple as they look. For example, it matters a lot whether you're talking about a genuine date or a timestamp when it comes to things like the calculation of differences between two dates, and many calculations are not meaningful at all without knowing about the calendar as well.

    7 days ago != 7×24 hours ago.

  • (disco) in reply to boomzilla
    boomzilla:
    And gas station signs! :wtf:
    Yes, but just the signs. The meters themselves round up to the nearest penny. So the signs are wrong, but are tolerated by Weights and Measures because it falls within their margin of error.
  • (disco) in reply to Steve_The_Cynic
    Steve_The_Cynic:
    Share prices in London are usually listed in pence

    100th's of a penny.

    http://www.londonstockexchange.com/exchange/prices-and-markets/stocks/summary/company-summary.html?fourWayKey=GB00B09LQS34GBGBXAIM

    [image]
  • (disco) in reply to tharpa
    tharpa:
    The meters themselves round up to the nearest penny.

    Nope, they round to the nearest penny.

  • (disco)

    That Perl "date function" has a lovely gem:

    localtime() is called multiple times for each of year, month, day, hour, minute, and second. That leaves for a nasty ticking landmine when the function inevitably gets called on a date roll-over.

    Call the function on 2015-12-31 11:59.9998? It could very well return 2015_01_01_12_00.

    Calling the function on 2015-01-31 11:59.9990? Hope the rest of the program has sanity checks for the new 31st of February...


    (This is not OT, but sweet baby Cthulu on a flaming unicycle this forum feels like the most ADHD mashup of Tumblr, Twitter, and Facebook. Sooo many gewgaws, gubbins, and gadgets expanding, sliding, contracting, popping up, scrolling... I feel like I should be at least 3 decades younger to properly appreciate it...)

  • (disco) in reply to groz
    groz:
    the most ADHD mashup of Tumblr, Twitter, and Facebook. Sooo many gewgaws, gubbins, and gadgets expanding, sliding, contracting, popping up, scrolling.
    Welcome to Discourse. :open_mouth:

    Edit: BTW, the link next to your post means that somebody (me) replied to it in that other topic. Well done, to post a quote-worthy comment in your first post here. :)

  • (disco) in reply to RaceProUK

    Correct.. its checking for 12-31-9999 @ any time of day, and forcing it to 12-31-9999 @ 23:59:59.9999999.. I would guess so that they can compare against DateTime.MaxValue elsewhere in the code rather than having to come up with their own constant (or worse, hardcoding the comparison all over the place.)

    Chances are its coming from a date-only field somewhere that has 12-31-9999 as a sentinel and using .Date is just a safety precaution in case a non-midnight time somehow gets added in.

  • (disco) in reply to groz

    On of the few things I like about SQL is that this always displays now()

    select if (now() - now(), 'Black hole', now())

    as the value returned by now() is calculated at the start of the query and remains constant throughout the query.

  • (disco) in reply to groz
    groz:
    localtime() is called multiple times for each of year, month, day, hour, minute, and second. That leaves for a nasty ticking landmine when the function inevitably gets called on a date roll-over.

    Really? I don't mean to doubt what you say, but that would be the sort of fuckup that you don't usually see in Perl, due to its widespread use by pedantic asshole sysadmins…

  • (disco)

    Calendar c = new Calendar(); So they actually managed to create the instance of an abstract class?

  • (disco) in reply to PJH
    PJH:
    [100th's of a penny][1].

    http://www.londonstockexchange.com/exchange/prices-and-markets/stocks/summary/company-summary.html?fourWayKey=GB00B09LQS34GBGBXAIM

    <img src="/uploads/default/16254/9718c9e98e089ac4.png" width="668" height="351">

    Sigh. No. The price is listed, or, perhaps a better term, quoted, in pence, but those pence might have decimal places. The 5.38 in the graph is 5.38 **pence**, not 5.38 *hundredths of a penny*.

    Geez, why do I have to explain this? Are you ... No, I won't say it. But please stand over there. Don't worry about the machine with the long tubes pointing at you, it won't hurt (for long) if it starts up.

  • (disco) in reply to Steve_The_Cynic
    Steve_The_Cynic:
    The 5.38 in the graph is 5.38 pence, not 5.38 hundredths of a penny.

    That's a rendering of 538 hundredths of a penny, of course.

  • (disco) in reply to dkf
    dkf:
    That's a rendering of 538 hundredths of a penny, of course.
    You're angling for another KPDotMHOotB(ov), I take it...
  • (disco) in reply to Steve_The_Cynic
    Steve_The_Cynic:
    You're angling for another KPDotMHOotB(ov), I take it...

    As the tag line says, Better living through pedantry

  • (disco) in reply to anonymous_coder
    anonymous_coder:
    (Why did this invoice upload for January 1, 1900?!) thanks to Perl's... idiosyncratic date implementation

    Perl's date functions are well documented so you can't blame perl for that one. Besides, wouldn't it have been the year 19100?

    anonymous_coder:
    he Not Invented Here syndrome

    You should have seen the bugs when someone decided they didn't want to see 24 hour time in the UI. It actually made it to production where it went 11am, 12am, 1pm. That's right, they didn't test for midnight and midday properly. I also replaced hundreds of lines of manual date flinging with a series of one-liners.

    I shudder to think what is going to happen when we try and expand into markets with different expectations for date formats.

  • (disco)

    TSQL smalldatetime also has this irregularity:

    DECLARE @SqlDateFoo TABLE (id int, bar smalldatetime)
    INSERT INTO @SqlDateFoo ([id], [bar]) VALUES
    (1, '1 jan 2000 23:59:00'),
    (2, '1 jan 2000 23:59:30'),
    (3, '1 jan 2000 23:59:40'),
    (4, '1 jan 2000 23:59:50'),
    (5, '1 jan 2000 23:59:55'),
    (6, '1 jan 2000 23:59:56'),
    (7, '1 jan 2000 23:59:57'),
    (8, '1 jan 2000 23:59:58'),
    (9, '1 jan 2000 23:59:59'),
    (10, '2 jan 2000 00:00:00'),
    (11, '2 jan 2000 00:00:01'),
    (12, '2 jan 2000 00:00:02')
    
    SELECT * FROM @SqlDateFoof
    
    |id|bar                    |
    |1 |2000/01/01 23:59:00.000|
    |2 |2000/01/02 00:00:00.000|
    |3 |2000/01/02 00:00:00.000|
    |4 |2000/01/02 00:00:00.000|
    |5 |2000/01/02 00:00:00.000|
    |6 |2000/01/02 00:00:00.000|
    |7 |2000/01/02 00:00:00.000|
    |8 |2000/01/02 00:00:00.000|
    |9 |2000/01/02 00:00:00.000|
    |10|2000/01/02 00:00:00.000|
    |11|2000/01/02 00:00:00.000|
    |12|2000/01/02 00:00:00.000|
    

    The system I work on now has 173 smalldatetime columns because they are "optimized for reduced space usage", while causing many, many missing results due to this value resolution misinterpretation. :wtf:

  • (disco) in reply to groz

    nasty ticking landmine when the function inevitably gets called on a date roll-over.

    We handle it by not scheduling any batch jobs between 11 PM and 12:15 AM. Seriously.

    Certain advantages to doing accounting and billing software...

  • (disco) in reply to John_Imrie
    John_Imrie:
    select if (now() - now(), 'Black hole', now())
    Msg 156, Level 15, State 1, Line 1
    Incorrect syntax near the keyword 'if'.
    Msg 195, Level 15, State 10, Line 1
    'now' is not a recognized built-in function name.
    
  • (disco) in reply to groz
    groz:
    localtime() is called multiple times for each of year, month, day, hour, minute, and second.

    Efficient!

    groz:
    That leaves for a nasty ticking landmine when the function inevitably gets called on a date roll-over.

    Efficient and effective!

    ANOTHER GREAT OPEN SOURCE PROGRAMMING LANGUAGE!

  • (disco) in reply to geoff
    geoff:
    Why developers can't just internalize the lesson use whatever epoch your platform likes and store the date as integer

    Doesn't always work. For example, if you're storing the date and time of a future appointment, you pretty much have to do that in local datetime component form, complete with tz; store it as epoch+offset and you risk being screwed over by a change in Daylight Saving rules.

  • (disco) in reply to flabdablet
    flabdablet:
    For example, if you're storing the date and time of a future appointment, you pretty much have to do that in local datetime component form, complete with tz; store it as epoch+offset and you risk being screwed over by a change in Daylight Saving rules.

    that's what Julian Dates were invented for. Store as Year+day index in year+decimal pecentage of day elapsed (or HH:MM if you insist)

    well ok they weren't invented for that but they do neatly sidestep the issue (until someone fucks up their handling of Feb29)

  • (disco) in reply to accalia

    So, to cut this short, our calendars are TRWTF.

    The sooner[1] we move to a stardate equivalent, the happier I'll be.

    [1] - See also: never

  • (disco) in reply to Onyx

    you just had to defuse a perfectly good flame war, didn't you?!

Leave a comment on “Dating Woes”

Log In or post as a guest

Replying to comment #:

« Return to Article