-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for AT TIME ZONE #26199
Comments
/cc @maumar |
Problem here is with using Note to triage: As a solution, we could extend the usage of |
We may simply want to add an AtTimeZone SqlExpression, and it may even make sense in relational (IIRC it's part of the SQL standard, and at least PG supports it too). This could be used in translating DateTime.ToUniversalTime and similar. |
@maumar, thanks, that explains why it wasn't working. Is there any documentation on which expressions are supported in All I could find was here and here, however, neither seems to indicate that Am I right in thinking that solving this using my own custom expression (subclassing I came up with two workarounds; one involves wrapping
Both seem to work, but I'm unsure what the impact on performance (if any) will be. I'd appreciate any suggestions on a different way to approach this. @roji, I agree having an |
Not really - HasDbFunction is mostly used to map CLR functions to a simple SQL function call, it's rather rare for users to have to map to other SQL expression types. The relational (database-independent) SQL expressions can be found here, while the SQL Server-specific ones go here (though we currently have very few).
Note that SqlFragmentExpression is supported, just not for this kind of usage (which requires a type mapping). We can add docs for this, though this seems like a very rare edge case.
No - you are free to replace the SqlNullabilityProcessor and add support for your custom expressions. However, creating your own SQL expression type is complex and goes beyond just implementing support in SqlNullabilityProcessor; it's simply not something that users are supposed to do, only providers (it has always been this way). See the recent discussion in #26147 for more on this (especially this comment by @smitpatel). Your workarounds may very well work OK - I'd need to see actual SQL to comment on the performance. But the right way to fix this is for us to add AT TIME ZONE support in EF Core, either in the SQL Server provider or in relational.
I don't think these are very similar... Both simply modify the statement they're in and wouldn't require a type mapping (they're more similar to query hints in this sense). |
I don't think "AT TIME ZONE" belongs to relational layer. |
@smitpatel The point here was less whether this belongs in relational or not, and more to introduce it (could be a provider-specific expression). We should also consider an EF.Functions.AtTimeZone, again either in relational or provider-specific. |
@roji, thanks for the feedback.
Right, it's just that the document here refers to "Mapping a method to a custom SQL" and uses the following example:
Which isn't so simple, and implies support of more complex SQL where specific use-cases haven't been covered by other expressions. I accept that the example given can be expressed as an expression tree, however, given my use-case doesn't seem possible to do with the provided SQL expression types, a first guess might be that In this case, the use of "fragment" rather than "token" causes confusion around its intent, in the absence of documentation suggesting otherwise.
Right, but I can't return one from
The solutions I found online suggested that prior to If replacing
Using the
I agree that they were bad examples; it seems (for now) that |
That's true, but complex SQL is very different from implementing custom expressions. Users can translate to arbitrary complex SQL constructs, as long as their basic building blocks (the expression types) are supported by the provider.
SqlFragmentExpression simply isn't like these other expressions, and wasn't meant for doing this kind of thing. I'm not sure "token" describes it better than "fragment", but that's a naming decision that is not longer very relevant.
Some notes to put this in context:
@smitpatel can confirm, but the way I see it, there's no recommended way for end users to do function translation to SQL with unsupported expression types. Either use raw SQL queries or wait for the expression to be implemented on the EF Core side (which is what I think this issue should be about). |
Info on SQL Server-- Convert datetime2 to datetimeoffset (no conversion, just specify time zone):
SELECT CAST('2020-01-01' AS datetime2) AT TIME ZONE 'Central European Standard Time'; -- 2020-01-01 00:00:00.0000000 +01:00
-- Convert datetimeoffset from one time zone to another:
SELECT CAST('2020-01-01 00:00:00+02:00' AS datetimeoffset) AT TIME ZONE 'Central European Standard Time'; -- 2019-12-31 23:00:00.0000000 +01:00
-- Nullability propagation:
SELECT CAST('2020-01-01 00:00:00+02:00' AS datetimeoffset) AT TIME ZONE NULL -- null
SELECT NULL AT TIME ZONE N'UTC' -- null PostgreSQL-- Convert UTC timestamp to local Berlin timestamp (timestamptz -> timestamptz)
SELECT CAST('2020-01-01 00:00:00Z' AS timestamptz) AT TIME ZONE 'Europe/Berlin'; -- 2020-01-01 01:00:00.000000
-- Convert local Berlin timestamp to UTC (timestamp -> timestamptz)
SELECT CAST('2020-01-01 00:00:00' AS timestamp) AT TIME ZONE 'Europe/Berlin'; -- 2019-12-31 23:00:00.000000 +00:00
-- Nullability propagation:
SELECT '2020-01-01'::timestamp AT TIME ZONE NULL -- null
SELECT NULL AT TIME ZONE 'UTC' - null OracleFirebirdSQLiteNot supported MySQL/MariaDBNot supported |
Hiya just wanted to share some usage info quickly, I often have to make reports grouped by day, week, month or year - quite commin in all kinds of BI applications. SELECT
DATEADD(DAY, DATEDIFF(DAY, 0, [Orders].[OrderDateTime] AT TIME ZONE 'W. Europe Standard Time'), 0) as [Day],
SUM([TotalInclVat]) as [TotalInclVat],
-- etc...
FROM [Orders]
GROUP BY DATEADD(DAY, DATEDIFF(DAY, 0, [Orders].[OrderDateTime] AT TIME ZONE 'W. Europe Standard Time'), 0) The query above groups orders daily in the right timezone, rather than the group by grouping daily based on UTC. |
I'm trying to use
HasDbFunction
andHasTranslation
to make use of the SQLAT TIME ZONE
clause.I have the following in
OnModelCreating
:Which is intended to translate calls to the following extension method:
If I try to query using this extension method like this:
Instead of the
ToTimeZone
method being translated, the method itself seems to be called and I get the following exception:Even though the call to
ToTimeZone
isn't translated, the translation itself is being called (twice) and is generating the correct SQL fragment, however, the fragment is not included in the query and the exception from the extension method is thrown.There is a minimal reproducible example here.
Technical Details
EF Core version: 5.0.10
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 5.0
Operating system: Windows 10
IDE: Visual Studio 2019 16.11.3
The text was updated successfully, but these errors were encountered: