1

I have a fairly large code base sprinkled with a bunch of DateTime.UtcNow, many other calls and TimeSpans, etc.

Now we are introducing tasks with timers, etc and I need to run the system at a variable speed to debug, like a day is 5 minutes, etc.

Since there are a lot of things depending on time and I can't change the logic everywhere, I can do two things:

  • Create a fake assembly in Visual Studio so I replace DateTime; Or,
  • I can simply change all the DateTime calls to my own class which would normally just return results from DateTime.

But, ultimately, it boils down to writing a replacement of DateTime and since the code is using more than DateTime.UtcNow, I would like to find a existing solution if possible.

Does anyone know if such a thing exists? I haven't found anything so far

Thomas
  • 10,933
  • 14
  • 65
  • 136
  • 2
    You poor thing. This is going to be nearly impossible. You're dealing with a core class of the framework that has `static` methods. You are going to need to create a facade to `DateTime` - say `NearlyImpossibleDateTime` - and push through all calls to an underlying `DateTime` - and then replace all occurrences of `DateTime` with `NearlyImpossibleDateTime`. Then do a static analysis of your code to ensure there are no more `DateTime` left. Then you can fiddle with `NearlyImpossibleDateTime` to change the passage of time. But all of this is going to be very fragile. Good luck! – Enigmativity Aug 31 '17 at 01:01
  • The strategy I'm looking into right now is to see if I can find the source of Datetime since .net is now opensource; then use the code as a fake assembly; I'm pretty sure that it's all based on ticks and maybe just changing the dividers will allow make to make time run faster.. but it's just an idea so far, no idea if that can work – Thomas Aug 31 '17 at 01:04
  • Definitely don't try to create a "fake" assembly. Not only would that bring the validity of the test into question, but trying to fake a system assembly without screwing up other calls I imagine would be a nightmare. At the most, perhaps you could use a namespace alias (a.k.a. using alias) only used for your DateTime calls, then temporarily change it to a namespace with your custom functions. That's still probably not an ideal solution, but better than faking an assembly I think. – C Perkins Aug 31 '17 at 01:04
  • 2
    It makes me nostalgic thinking about my awesome 286 system were I could just push the Turbo button to make everything run faster. You don't have turbo button do you? :) – C Perkins Aug 31 '17 at 01:07
  • @Thomas - You can't fake out the entire mscorlib assembly. All of your code will break. You could try to recreate `DateTime` if you had the source, but it would contain far more than you'd need to use. That's why I suggested creating a facade - it'll be a million times easier (even though it is still very difficult). – Enigmativity Aug 31 '17 at 01:08
  • @C Perkins: I think it would be on all the time :) I had an amiga with a board that had a faster variant of the 68k and you could toggle on the fly (and hope nothing would crash) – Thomas Aug 31 '17 at 01:09
  • Is [this](https://stackoverflow.com/questions/43711/whats-a-good-way-to-overwrite-datetime-now-during-testing) useful? – ainwood Aug 31 '17 at 01:09
  • @Enigmativity: I found the code (https://github.com/dotnet/coreclr/blob/v1.0.0/src/mscorlib/src/System/DateTime.cs) I can compile it under a different name and get the whole app to use it instead of datetime to see if that works – Thomas Aug 31 '17 at 01:10
  • @ainwood: it wouldn't work; I think I should have clarified: I'm not talking about unit tests, but really testing the whole site (it's a sports gambling system) with days going fast – Thomas Aug 31 '17 at 01:11
  • @Thomas - My approach is much the same as your approach in that you end up with a class that you control. But my approach will be a million times easier. I would just keep implementing methods on `NearlyImpossibleDateTime` until the existing code works again. With yours you have to implement everything - and that's where your problem will exist - any internal dependencies will need to be re-coded and there will be heaps. You might find that you need to spend days or weeks to get your version to work. – Enigmativity Aug 31 '17 at 01:13
  • that will be the way to go: I can't compile datetime, it relies on a bunch of external stuff internal to the core libs; so I'll get all the datetime calls in the code base and make a class that implements them – Thomas Aug 31 '17 at 01:15
  • since the calls that really matter are all the DateTime.UtcNow, I could do a wrapper where I get the ticks from UtcNow, multiply them by my speedup factor and regenerate a datetime from the new ticks; there are all the methods to do that, so I could simply make a class that derive from datetime and override the methods where it matters – Thomas Aug 31 '17 at 01:20
  • of course.. datetime is sealed... – Thomas Aug 31 '17 at 01:21
  • @Thomas - `DateTime` is a `struct` you can't derive from it. That's why I suggested a facade (see https://en.wikipedia.org/wiki/Facade_pattern). – Enigmativity Aug 31 '17 at 01:22
  • yep, I found that through the whole code only 5 methods of DateTime are used: UtcNow, Min, Max, ToString, Parse; so it should be very straightforward since I have to code only one and pass the others straight through – Thomas Aug 31 '17 at 01:25
  • @Thomas - Correct. Hence the facade being much easier. – Enigmativity Aug 31 '17 at 01:32
  • yes, there is almost no code involved; I thought more calls were used through the site, but it's quite trivial! thanks! – Thomas Aug 31 '17 at 01:34
  • If you have VS Enterprise you could use Microsoft Fakes and Shim the value of DateTime.UtcNow to be what you need it to be. This is assuming it's for testing purposes only and not production – pinkfloydx33 Aug 31 '17 at 10:10
  • This would be a good time to refactor the code to use some sort of `IDateTimeProvider` interface everywhere that accesses the date or time. – Bradley Uffner Aug 31 '17 at 15:11
  • I can't use the MS fakes since the testing is done with code deployed and tested at the same time by several people. I ended up creating a small static class that provides the functionality and I modified every since call to DateTime – Thomas Sep 03 '17 at 17:16

1 Answers1

0

Have you tried mocking? I would create an interface that returns the time a task must run. That would let you create two classes one for debug and one for release, that way when you are debugging you can return whatever value you need and you won't need to worry about how core classes work.

I hope it helps!

  • that's eventually how it ended since I make a class implementing all the methods we used from datetime – Thomas Sep 03 '17 at 17:16