Enterprise integration is its own torturous brand of software development. Imagine all the pain of inheriting someone else's code, but now that code is proprietary, you can't modify it, poorly documented, and exposes an API that might solve somebody's problem, but none of the problems you have, and did I say poorly documented? I meant "the documentation is completely inaccurate and it's possible that this was intentional".
Michael was working on getting SAP integrated to their existing legacy systems. This meant huge piles of bulk data loading, which wasn't so bad- they had a third party module which promised to glue all this stuff together. And in early testing phases, everything went perfectly smooth.
Of course, this was a massive enterprise integration project for a massive company. That guaranteed a few problems that were unavoidable. First, there were little teams within business units who weren't using the documented processes in the first place, but had their own home-grown process, usually implemented in an Excel file on a network drive, to do their work. Tracking these down, prying the Excel sheet out of their hands, and then dealing with the fallout of "corporate coming in and changing our processes for no reason" extended the project timeline.
Well, it extended how much time the project actually needed, which brings us to the second guaranteed problem: the timeline was set based on what management wanted to have happen, not based on what was actually possible or practical. No one on the technical side of things was consulted to give an estimate about required effort. A go-live date of October 8th was set, and everything was going to happen on October 8th- or else.
The project was, against all odds, on track to hit the ridiculous target. Until it went into UAT- and that's when Michael started catching issues from users. Dates were shifting. In the source system, the date might be November 21st, but in SAP it was November 20th. The 23rd turned into the 24th. The 25th also turned into the 24th.
Michael was under a time crunch, and trapped between a rock (the obtuse legacy system), a hard place (SAP), and a hydraulic press (the third-party data import module). There was a pattern to the errors, though, and that pattern pointed to a rounding error.
"Wait, a rounding error?" Michael wondered aloud. Now, they did use numbers to represent dates. The "Japanese" notation, which allowed them to store "November 21st, 2018" as 20181121
. That's a super common approach to encoding a date as a 32-bit integer. As integers, of course, there was no rounding. They were integers on the legacy side, they were integers on the SAP side- but what about in the middle? What was the third party import module doing?
As a test, Michael whipped up a little two-line program to test:
float _date = Integer.parseInt("20181121");
System.out.println((int)_date);
//Outputs: 20181120
Of course. This is a standard feature of IEEE floating point arithmetic. This hadn't been happening in early testing because they safely avoided date/numbers "large" enough. It was only when they moved into UAT and started using real data that the bug became apparent. For some reason, the data import module was passing integer data straight through floats, probably out of a misguided attempt to be "generic".
Michael raised the issue with the vendor, suggested that the vendor should check for casts to float, and pointed out that he was under an extreme time crunch. The vendor, to their credit, tracked down the bug and had a patched version to Michael within two days.
Working in the enterprise space, Michael has seen too many applications which store currency values as floats, leading to all sorts of accounting-related messes. This, however, is the only time he's seen that happen with dates.