74

What is the most convenient way to create a specific instance of Microsoft.SharePoint.SPTimeZone as the following one:

SPTimeZone utc = SPRegionalSettings.GlobalTimeZones
                                   .OfType<SPTimeZone>()
                                   .FirstOrDefault(tz => tz.Information.Bias == 0
                                                   && tz.Information.DaylightBias == 0);

Is this hack the best one I can get...

This is in particular a problem for me, since I would like to mock this part of code for unit testing and to force it to always return UTC. The property GlobalTimeZones seems to depend on HttpContext.Current or an actual request - a prerequisite I don't have in my Unit Tests...

N.B: I know that there is System.TimeZoneInfo but a third party assembly forces me into using SPTimeZone ...

brainless coder
  • 6,310
  • 1
  • 20
  • 36
Markus
  • 3,225
  • 6
  • 35
  • 47
  • *Why* do you want to create an instance? `SPTimeZone` is supposed to be the site's timezone, not as a generic timezone class. Settings gives you the list of available *ie installed* timezones and is probably loaded from settings in the database. The lack of a constructor is there for a reason - you are *not* supposed to create this on your own. Just pass the `SPWeb.RegionalSettings.TimeZone` property of the current web to the library – Panagiotis Kanavos May 22 '15 at 08:09
  • You are right there - however, I am handling data that was retrieved in an elevated context and is therefor in the timezone of the user that was used to retrieve it. This information is merged on the fly with search results that are stored in UTC. So I have a result set with different Timezones - the elevation context however allows me to pass a TimeZone; so for me this would be the easiest way to get all data in UTC and then I can convert it to the timezone of the web (or the user) where I want to show it ... – Markus May 22 '15 at 08:15
  • @Markus i belive you can use msfakes to override `SPRegionalSettings.GlobalTimeZones` behaviour and then return `IEnumarable` of `SPTimeZone`. i don't have sharepoint server to verify it.... – Old Fox Jun 02 '15 at 07:16
  • @OldFox yes of course but one can't instanciate SPTimeZone so it is pretty nasty to fake it - the only way I could think of is using reflection ... – Markus Jun 02 '15 at 07:18
  • @OldFox Ok - I could fake the whole 3rd party call and fake all properties of all SPTimeZone instances, that I read within the tested method. That seems to work but I would prefer injecting a specific SPTimeZone object ... – Markus Jun 02 '15 at 07:59
  • 2
    @Markus I believe you can stub the `SPTimeZone` so that you'll have a specific time zone. by the way, if money is not an issue I offer you to use [TypeMock Isolator](http://www.typemock.com/isolator) and then you can do almost any thing... – Old Fox Jun 02 '15 at 09:44
  • 9
    If you run into trouble with a dependency like this SPTimeZone while unit-testing your code, consider introducing an [adapter](https://en.wikipedia.org/wiki/Adapter_pattern) for it and create a fake implementation that you use in your test. – wigy Aug 10 '15 at 19:56
  • You can also create HttpContext using "FakeHttpContext" package from nuget. I believe that is what you required. – CreativeManix Sep 08 '15 at 10:03
  • If you look at SPTimeZone class with ILMerge you'll see that it has some internal constructors, so you can probably create an instance using reflection. But if you look at the time conversion methods exposed by SPTimeZone class (which your 3rd party DLL will probably call), you'll see they use SPWeb.Request and SPFarm, so you will probably get a runtime exception from that DLL anyway. So I would go with MS fakes/shims or TypeMock Isolator as suggested above, these libraries allow you to override any method of SPTimeZone class. – johnnyjob Sep 08 '15 at 21:46

1 Answers1

5

To stop the discussion I decided to finally answer this question on my own.

There are several really helpful solutions in the comments which I want to gather in this short answer:

  • Introducing a facade / adapter
  • MS Fakes or other frameworks to
    • fake access to SPTimeZone
    • create a fake HttpContext
  • go with the hack described in the question above ...

I for my part decided to go with MSFakes to shim the whole 3rd party call (since I didn't wan't to test its behavior anyways) and to shim all properties of SPTimeZone that I use in my method. Introducing an adapter unfortunately wasn't an option for me, since I had to preserve the (internal) API.

Markus
  • 3,225
  • 6
  • 35
  • 47