5 ms·
Fix date-handling bug when today’s date is later than the target month
- torstenvl 3y agoHow is 3+3+2+3+2+3+3+2+3+2+3 equal to 5? The bug exists every time today's date is greater than the lowest total number of days in a month (28). So it's a bug for 3 days in January, (sometimes 1 day in February,) 3 days in March, 2 days in April, etc.
- steanne 3y agoin a SPECIFIC month. it's only 28 for february, and then only sometimes. it's only going to affect months where the month contains more days than the month after it. january, march, may, august, and october. of those, however, there's more than one date in january which would error, so the total is more than 5. 6 or 7 depending on if it's a leap year
- torstenvl 3y agoThe bug occurs when using setMonth() to a month value containing fewer days than the current date. There is no limitation in setMonth() such that you can only set the month to "the month after." I'm sorry, but I think you misunderstand this bug.
- Izkata 3y agoI think you did too, I don't have the slightest clue where your math came from. This bug happens when the month you're setting it to has fewer days than the month in the date object, so it rolls the day forward into the next month. It's the same functionality that lets you just add days and iterate over the whole year.
- torstenvl 3y agoIn non-leap years, there are potential invalid target months when the current date is January 29th, January 30th, January 31st, March 29th, March 30th, March 31st, April 29th, April 30th, May 29th, May 30th, May 31st, June 29th, June 30th, July 29th, July 30th, July 31st, August 29th, August 30th, August 31st, September 29th, September 30th, October 29th, October 30th, October 31st, November 29th, November 30th, December 29th, December 30th, or December 31st. That is, the number of days of a given year where this bug applies are: 3 in January, 3 in March, 2 in April, 3 in May, 2 in June, 3 in July, 3 in August, 2 in September, 3 in October, 2 in November, and 3 in December. 3+3+2+3+2+3+3+2+3+2+3
- avandekleut 3y agoReminder to use something like the date-fns library for immutable operations on dates. The native JS date library can be painful to work on when doing operations like adding or subtracting time.
- wdfx 3y agoI would argue that doing time arithmetic by modifying components of a date individually is wrong in any language.
- djrockstar1 3y agoAnd the right way would be?
- wdfx 3y agoTo have a better understanding of what operations you are trying to do. I can't answer your question specifically because it depends a lot on use case and what date/time standards you want to use.
- joncrocks 3y agoTo expand on this a little, there are operations that have slightly ambiguous meanings/can end up with different answers depending on your assumptions. e.g. If today is the 30th of January 2024. What is the date in 1 months time? Should it be the 29th of February? (as the 30th doesn't exist). The 28th? (the penultimate day of the month, like the 30th of Jan). The 1st of March (a 'standard' month should be considered 30 days, so 30 days from now).
- JR1427 3y agoConvert to unix times, and do the calculation with those?
- pasc1878 3y ago
- wouldbecouldbe 3y agoI make this bug in my taxes every now and then. Most invoices are from EU, but the few US ones have the months in wrong order, I only notice if the days exceed 12
- wheybags 3y agoThis is why I normally use "23/Aug/2023" form. Only breaks down if you don't know the months in English.
- a_gnostic 3y agoMy military friend uses YYYY/MM/DD. Used to tick me off, but makes sense now.
- jayknight 3y agoISO 8601, ftw.
- fragmede 3y agoISO 8601 is yyyy-mm-ddthh:mm:ss.sssZ
- thfuran 3y agoDays in that format even order as proper numbers instead of some kind of little endian disaster.
- bryanlarsen 3y agoI've seen people do YYYY/DD/MM, so your friend's format isn't foolproof. OTOH although I'm sure some insane person somewhere has done YYYY-DD-MM I've never seen it so YYYY-MM-DD should be safe.
- a_gnostic 3y agoYYYY/MM/DD is in order of size. Y > M > D makes some kind of sense.
- RicoElectrico 3y agoApparently, date handling is still causing problems in 2024, as evidenced by the Newag trains' DRM.
- MrHus 3y agoI was just browsing HN because I'm procrastinating solving a date based bug. It is literally this bug! Who said surfing HN is not productive!
- polyterative 3y agono way
- wffurr 3y agoDid I not look closely enough? I didn’t see any tests in the changes.
- candiddevmike 3y agoI had something like this for a while. It wasn't a bug per-say, it was a test flake due to dates and follow on calculations based on them. On the plus side, it prevented you from working on the weekend as the tests/PRs would always fail during that time.
- Pxtl 3y agoI've seen somebody write this exact bug before! Hah. Like, something to the effect of var newDate = new Date(GetDate().Year, GetDate().Month + 1, GetDate().Day); but with extra logic to ensure that the Month component wrapped around.
- Izkata 3y ago> but with extra logic to ensure that the Month component wrapped around Extra unnecessary logic. The functionality that causes this bug is so you don't need to handle wraparound yourself: >> new Date(2023, 12, 1) Date Mon Jan 01 2024 00:00:00 GMT-0600 (Central Standard Time) (Note months are 0-indexed so 12 is one past the last month of the year) It works with negative numbers too, to wrap backwards: >> new Date(2024, -1, 1) Date Thu Dec 01 2023 00:00:00 GMT-0600 (Central Standard Time)
- Pxtl 3y agoDepends on the language/library. C#'s DateTime will throw ArgumentOutOfRangeException.
- oleganza 3y agoUnlike many issues with dates, this one is purely a result of a wrong API design. It does not make sense to "set a component" of a date all by itself (unlike hours/minutes/seconds in a day), so an API that allows you to so is plain broken. Correct API would be to set the components D,M,Y all at once and have them validated on the spot before returning a valid Date value.
- cranium 3y agoI tried to replicate the bug only to find out the months are 0-indexed (jan = 0) so the example should use `setMonth(1)`. I must say I'd prefer getting an exception rather than a silent roll-over any day of the week – pun intended.
- deleted 3y ago[deleted]
- jakub_g 3y agoVery relatedly, there's a potential similar footgun related to hours, due to the fact that dates initialized without hour default to 00:00, and that JS dates are in user's current local timezone. It's possible then that after changing the month programmatically, the time component will jump to 23:00 due to timezone DST changes, and the date will jump back one day as well due to this (and in an unlucky case, the month will jump back as well!) Example bug I had in 2014 when Russian timezone definitions have changed: https://github.com/yui/yui2/pull/15 https://github.com/yui/yui2/pull/15 A workaround is to initialize dates with fake "midday" time component so that you avoid the day jumping back.
- deleted 3y ago[deleted]
- ramses0 3y ago...the comment! The hubris! // Important: Important to set these in order
- chmod775 3y agoYeah, there's multiple variations of that bug possible depending on what you set first, so setting these in that specific order likely avoided one bug they noticed. They just didn't realize they have a different bug now.
- deleted 3y ago[deleted]
- solardev 3y agoYou should never, ever do date math naively like this. There are too many unexpected edge cases, especially between time zones or daylight savings time or leap years, but even without them: https://moment.github.io/luxon/#/math https://moment.github.io/luxon/#/math In fact I would strongly argue you should never use the JS Date built-ins at all because they are terrible. Use a library like Luxon or date-fns. As a frontend dev, this is the most common category of bugs I've dealt with in my career, and I've spent dozens of hours fixing other people's datetime handling because of how poorly implemented the JS Date API is. It's full of minefields and gotchas. The Temporal API is supposed to fix some issues, but that's been in development for like a decade now.
- tzs 3y agoThe fix is to change things like this: targetEndDate = new Date(); targetEndDate.setFullYear( endDate.getFullYear() ); targetEndDate.setMonth( endDate.getMonth() ); targetEndDate.setDate( endDate.getDate() ); to targetEndDate = new Date(); targetEndDate.setFullYear( endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); That works because setFullYear has a three argument form that takes the year, month, and date avoiding the inconsistency that can arise by setting those one at a time. But you know what else has a three argument for that take the year, month, and date? The Date constructor. So why not fix it like this? targetEndDate = new Date( endDate.getFullYear(), endDate.getMonth(), endDate.getDate()); Using the empty constructor would initial the object with the current date and time, but they promptly overwrite those. The Date construction also has a form that takes another Date object, so I wonder if they could have simple used: targetEndDate = new Date(endDate);