1

What is the real difference between the following d,e,f values? What the 'ToUniversalTime()' really do?

  var d = DateTime.Now;
  var e = d.ToUniversalTime();
  var f = e;

Does somebody knows? Thanks.

Remark: we detected differences on an EF query, when the 'Created' field is a datetime sql field, and contains UTC time:

var itemsD = ctx.Log.Where(p => p.Created > d);
var itemsE = ctx.Log.Where(p => p.Created > e);
Zoltan Hernyak
  • 989
  • 1
  • 14
  • 35
  • 1
    Looks like the actual question is "How can I perform a query on dates that are stored as UTC?". Not about `ToUniversalTime()`. Use `DateTime.UtcNow` or `DateTime.Now.ToUniversalTime()` to get the value, not `DateTime.Now` – Panagiotis Kanavos Jun 27 '19 at 12:04
  • The implementation should tell you whats happening: https://referencesource.microsoft.com/#mscorlib/system/datetime.cs,fddce8be2da82dfc – thehennyy Jun 27 '19 at 12:04
  • I think a date is a date, ToUniversalTime() should not change it. So 'd' and 'e' should represent the same date. The EF only marked the fact that a difference exists... I wonder why? SQL should have known how to compare 2 datetime ... I am wrong, but I don't know why and where. – Zoltan Hernyak Jun 27 '19 at 12:18
  • 2
    @ZoltanHernyak: There is no `Date` data type in .NET. There is only `DateTime`. If a datetime contains `2019-01-02 00:00`, your local timezone is UTC+2 and you execute ToUniveralTime, the result will be `2019-01-01 22:00`. – Heinzi Jun 27 '19 at 12:24
  • I really still do not understand. The "2019-01-02 00:00" in local time represents a definit moment in "time" - knowing I am in Hungary, in summer, it is shifted by +2 hours. Converting it to UTC I really hope still represents the very same moment in our universe's timeline. Does it? Then "d==e" should be equal. Is it right? Then what is the difference between d and e? – Zoltan Hernyak Jun 27 '19 at 18:07
  • In addition: if d==e, then p.Created>d and p.Created>e should have been the same thing :( – Zoltan Hernyak Jun 27 '19 at 18:30
  • 1
    @ZoltanHernyak: I see your point, and `var d = DateTimeOffset.Now; return d == d.ToUniversalTime()` actually returns true. Unfortunately, that's not the case for the old `DateTime` data type, which does *not* store time zone offset information but only some vague "kind". – Heinzi Jul 01 '19 at 17:39
  • Thanks, @heinzi seems you are the 1st who understands my problem :) So .ToUniversalTime() doest nothing (does not change the meaning) to the datetime value, the problem is on the SQL side and the EF implementation. So EF won't convert the datetime value to UTC automatically, I have to give the datetime value properly. – Zoltan Hernyak Jul 02 '19 at 05:09
  • 1
    @ZoltanHernyak: "*So .ToUniversalTime() doest nothing (does not change the meaning) to the datetime value*" -- only for `DateTimeOffset`, not for `DateTime`! Note that there are different data types: .NET's `DateTimeOffset` and SQL Server's `datetimeoffset` are time-zone-aware, store an "absolute point in time" and behave as you would expect them to: Converting them to UTC does *not* change the underlying point in time. However, .NET's `DateTime` and SQL's `datetime`/`datetime2` are different: They don't store "absolute points in time", they store "calendar time". – Heinzi Jul 02 '19 at 06:54
  • 1
    @ZoltanHernyak: If you haven't seen it yet, check out this question for more details: https://stackoverflow.com/q/4331189/87698 – Heinzi Jul 02 '19 at 06:54
  • Thanks for the link! – Zoltan Hernyak Jul 02 '19 at 16:48

2 Answers2

6

The value returned by the "ToUniversalTime" method is determined by the "Kind" property of the current DateTime object. The following describes the possible results:

Kind: Utc 

Results: No conversion is performed.

Kind: Local. 

Results: The current DateTime object is converted to UTC.

Kind: Unspecified. 

Results: The current DateTime object is assumed to be local time, and the conversion is performed as if Kind were Local.

The default is Unspecified.

The ToUniversalTime method converts a DateTime value from local time to UTC. To convert the time in a non-local time zone to UTC, use the TimeZoneInfo.ConvertTimeToUtc(DateTime, TimeZoneInfo) method. To convert a time whose offset from UTC is known, use the ToUniversalTime method.

Tomse
  • 179
  • 5
  • If I understand it well, d.Kind is local, and e.Kind is utc. As a datetime can be resresented by the elapsed "ticks" from a base moment, the values should be change as the kind changes, but the d==e equality (in a very strict way) is still true, is it? Then why I need to convert 'd' to utc representation 'e'? – Zoltan Hernyak Jun 27 '19 at 18:12
  • If you are in Hungary then your timezone is (UTC +2), that means your "d" = (UTC +2). Because "e" is the conversion of "d" to (UTC), "e" = (UTC). Since "f" = "e", both "f" and "e" = (UTC). My timezone = CEST, so my "e" and "f" = (28/06/2019 06.12.56), but my d = (28/06/2019 08.12.56). – Tomse Jun 28 '19 at 06:24
0

The method ToUniversalTime converts a DateTime value of the local hour to a UTC hour. If you want to convert a time value wich UTC value is known you can use this method

Synapsis
  • 667
  • 1
  • 5
  • 19