Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does one use TimeZoneInfo in a SQLCLR assembly in SQL Server 2012

I want to implement time zone conversion within SQL Server 2012. However, TimeZoneInfo is marked with the MayLeakOnAbort attribute. This causes a runtime error when the SQL function I defined (which uses TimeZoneInfo) is invoked.

The error is reported as follows

System.Security.HostProtectionException: Attempted to perform an operation that was forbidden by the CLR host.

The protected resources (only available with full trust) were: All

The demanded resources were: MayLeakOnAbort

Documentation hints that I can use "SafeHandle" to get around this leakage issue but I do not see how.

So, how does one use the class TimeZoneInfo in a SQLCLR context?

Follow Up:

I have found another question here on the site which, though it deals with SQL 2005, prescribes an action which works with 2012. There are aspects of this solution, though, which are unsatisfying.

like image 917
Tevya Avatar asked Mar 24 '23 05:03

Tevya


1 Answers

Updated Answer

I've written the utility I spoke about in the original answer, which you can find here.

Also, as of SQL Server 2016 (and Azure SQL Database), you can now use the AT TIME ZONE keyword to convert between time zones.


Original Answer

Unfortunately, there is no great solution for working with time zones in SQL Server.

I investigated heavily the issue you linked, along with this one also. There are no built-in time zone functions, and any use of TimeZoneInfo in SQLCLR requires the assembly to be registered as "unsafe". This is usually not desired.

I also investigated using Noda Time from SQLCLR. You can read about it in this issue. It also had to be registered as "unsafe" because of the way certain items are cached internally.

Ultimately, with either item, the problem is that there is no way to cache anything in SQLCLR. You can't use static variables in a thread-safe manner, and you cant do any thread synchronization or use classes like ConcurrentDictionary. SQL wants to have full control of the threading model of the assembly. Only single-threaded use-once-and-throw-away style code works in "safe" assemblies. I dug deep into this in this question: Multithreaded caching in SQL CLR

Hopefully, there will eventually be a build of Noda Time that will work in SQLCLR, but it will be a special build that doesn't do any caching. So it won't perform as quickly, but it will get the job done while still being safe.

TimeZoneInfo isn't likely to change. So unless the SQL Server team ever brings time zone functions directly into SQL Server properly (like Oracle and Postgres do), then you've only got a few options:

  • Don't attempt time zone conversions in the data layer. Work with datetime or datetime2 values in UTC, or use datetimeoffset values with any offset. But do all conversions between time zones in the application layer. This is my best recommendation for now.

  • Copy all of the data for the time zones into actual SQL tables, and write functions that work with that data. This isn't the best idea, because the data changes often so table maintenance can be a challenge. Also getting the functions accurate, including all of the rules of daylight saving changes, can be challenging. I am not aware of any project that has this bundled up nice and neat, but if anyone is - then please let me know in comments.

  • Enable xp_regread and work with the timezone data directly from the windows registry keys. Updates would be done for you, but you still have the same challenges in writing these functions. And enabling registry reads might be just as much of a security risk as enabling unsafe CLR assemblies anyway.

Another idea I am considering is to write an IANA/Olson TZDB parser and functions specifically for SQL Server. This would be similar to option 2 above, but done in a maintainable way, and with IANA standard data instead of Windows time zones. Maybe I'll get to this someday, or maybe someone will beat me to it. Again, I am not aware of any current project that does this, but if someone knows of one, please let me know in comments. (done - see update at top)

Regarding SWITCHOFFSET - that only works when you already know the target offset. That's half the battle, and probably why Microsoft still marks datetimeoffset as not "daylight savings aware" in the docs.

like image 142
Matt Johnson-Pint Avatar answered Mar 25 '23 17:03

Matt Johnson-Pint