We found this one out during testing in different time zones earlier this - if your app is going used in different time zones avoid using DateTime with Observable.Timer. In fact I guess the general message should be avoid DateTime all together in any apps use DateTimeOffset instead...
This code works from here in London but when run in Hong Kong throws an exception:
London time zone shows output as expected:
Where as when run for a time zone set to anything positive of London (offset = 0), e.g. Hong Kong (offset = +8) you get an exception:
If you want to know why this is happening check out @leeoades post here, but simply because DateTime supports an implicit conversation to DateTimeOffset and the value is invalid after conversation this is why we're seeing this happen.
So it can be fixed easily enough by using any of the following alternatives:
I prefer the final alternative, it's better suited for testing because the scheduler can be mocked out and you can control the value of the Scheduler.Now.
This code works from here in London but when run in Hong Kong throws an exception:
1: static void Main(string[] args)
2: {
3: var now = DateTimeOffset.Now;
4: Console.WriteLine("Time zone offset: " + now.Offset);
5:
6: var scheduler = NewThreadScheduler.Default;
7:
8: using(Observable.Timer(DateTime.MinValue, TimeSpan.FromSeconds(1), scheduler)
9: .Subscribe(Console.WriteLine))
10: {
11: Console.ReadLine();
12: }
13: }
London time zone shows output as expected:
Where as when run for a time zone set to anything positive of London (offset = 0), e.g. Hong Kong (offset = +8) you get an exception:
If you want to know why this is happening check out @leeoades post here, but simply because DateTime supports an implicit conversation to DateTimeOffset and the value is invalid after conversation this is why we're seeing this happen.
So it can be fixed easily enough by using any of the following alternatives:
1: Observable.Timer(DateTimeOffset.MinValue, TimeSpan.FromSeconds(1));
2:
3: // or...
4:
5: Observable.Timer(DateTimeOffset.Now, TimeSpan.FromSeconds(1));
6:
7: // or...
8:
9: var scheduler = NewThreadScheduler.Default;
10: Observable.Timer(scheduler.Now, TimeSpan.FromSeconds(1), scheduler);
I prefer the final alternative, it's better suited for testing because the scheduler can be mocked out and you can control the value of the Scheduler.Now.
Comments
Post a Comment