Converting Local Time To UTC - c#

I'm up against an issue storing datetimes as UTC and confused why this does not yield the same result when changing timezones:
var dt = DateTime.Parse("1/1/2013");
MessageBox.Show(TimeZoneInfo.ConvertTimeToUtc(dt, TimeZoneInfo.Local).ToString());
I am manually switching my local time zone on the machine between eastern and central.
Central yields 1/1/2013 6:00:00 AM, and Eastern yields 1/1/2013 5:00:00 AM. What am I missing here? They should be the same regardless of the time zone, correct?
Thanks so much in advance!

I think what you are missing is that the DateTime returned by your DateTime.Parse() statement doesn't come with a time zone. It's just a date and time that can be in any time zone. When you call TimeZoneInfo.ConvertTimeToUtc(dt, TimeZoneInfo.Local), you are telling it which time zone it starts in. So if you start in Central, you will get one answer, whereas if you start in Eastern, you will get an answer that is an hour earlier, UTC. Indeed, this is what your code shows.

There is a .ToUniversalTime() method for DateTime class

This is midnight
var dt = DateTime.Parse("1/1/2013");
Midnight in eastern and central is not the same absolute time.
That is the whole purpose of time zones.

You can use NodaTime :
static string LocalTimeToUTC(string timeZone, string localDateTime)
{
var pattern = LocalDateTimePattern.CreateWithInvariantCulture("dd/MM/yyyy HH:mm:ss");
LocalDateTime ldt = pattern.Parse(localDateTime).Value;
ZonedDateTime zdt = ldt.InZoneLeniently(DateTimeZoneProviders.Tzdb[timeZone]);
Instant instant = zdt.ToInstant();
ZonedDateTime utc = instant.InUtc();
string output = utc.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture);
return output;
}

When you have trouble with converting to local time to UTC then just remove the last keyword of index and then convert to UtcDateTime
NewsDate = DateTimeOffset.Parse(data.NewsDate.Remove(data.NewsDate.LastIndexOf("IST"))).UtcDateTime;

Related

Parse String into DateTimeOffset While Assuming TimeZone

Probably a super simple solution but I'm clearly missing something.
I have a string object with value "2020/07/29 13:30:00".
How can I parse that into a DateTimeOffset object and make the assumption that the time zone of that parsed time is "GMT Standard Time" for example, or any TimeZoneInfo I wish to specify preferably?
How can I then take that DateTimeOffset, and return its Utc time but to any specified time zone of my choice?
Many thanks
The easiest I could find is something like this.
I couldn't find any methods to parse a DateTimeOffset in a particular given timezone, but you can parse your string as a DateTime (with a Kind of Unspecified, which just acts as a container for the bits of information in the string, without trying to apply timezone knowledge to it).
Then you can ask a TimeZoneInfo for the UTC offset in a given timezone at the given local time, and apply this to the DateTime to create a DateTimeOffset.
Once you've got your DateTimeOffset, you can work with it using its ToOffset method, and TimeZoneInfo.ConvertTime.
string input = "2020/07/29 13:30:00";
var timezone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
// DateTime.Parse creates a DateTime with Kind == Unspecified
var dateTime = DateTime.Parse(input);
Console.WriteLine(dateTime); // 7/29/2020 1:30:00 PM
// Since Kind == Unspecified, timezone.GetUtcOffset will give us the UTC offset in effect at
// the given local time in timezone
var dateTimeOffset = new DateTimeOffset(dateTime, timezone.GetUtcOffset(dateTime));
Console.WriteLine(dateTimeOffset); // 7/29/2020 1:30:00 PM +01:00
// Convert to UTC
Console.WriteLine(dateTimeOffset.UtcDateTime); // 7/29/2020 12:30:00 PM
Console.WriteLine(dateTimeOffset.ToOffset(TimeSpan.Zero)); // 7/29/2020 12:30:00 PM +00:00
// Convert to another timezone
var cst = TimeZoneInfo.FindSystemTimeZoneById("Central America Standard Time");
Console.WriteLine(TimeZoneInfo.ConvertTime(dateTimeOffset, cst)); // 7/29/2020 6:30:00 AM -06:00
Try the DateTimeOffset.ParseExact overload that accepts a DateTimeStyles parameter.
This code:
var dt=DateTimeOffset.ParseExact("2020/07/29 13:30:00","yyyy/MM/dd HH:mm:ss",
CultureInfo.InvariantCulture,DateTimeStyles.AssumeUniversal);
Returns 2020-07-29T13:30:00.0000000+00:00
There's no GMT Standard Time, that's a very unfortunate name used in Windows that somehow manages to mix up British and UTC time to the point that no-one knows what it means without looking at the docs. This was thoroughly discussed and explained in this question: Difference between UTC and GMT Standard Time in .NET. As one of the answers explains :
The names GMT Standard Time and GMT Daylight Time are unknown outside of Redmond. They are mythical animals that appear only in the bestiary called the Windows Registry.
If you wanted to assume British time and your machine uses a British timezone, you can use DateTimeStyles.AssumeLocal
This function should convert your date time string (with assumption this is GMT Standard Time) to any other timezone:
public static DateTime? ToUTCTimeZone(string sDate, string timeZone)
{
DateTime utcDate = DateTime.Parse(sDate);
DateTimeOffset localServerTime = DateTimeOffset.Now;
utcDate = DateTime.SpecifyKind(utcDate, DateTimeKind.Utc);
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById(timeZone);
if (cstZone == null)
return null;
return TimeZoneInfo.ConvertTimeFromUtc(utcDate, cstZone);
}//ToUTCTimeZone

DateTimeOffset: Is the DateTime the local time, or UTC time?

I got pretty much confused today when talking to a colleague, so please excuse me. I have this:
date: 2020-04-01 (yyyy-MM-dd)
time: 10:00:00
timezone: +2
When I return this to my colleague, I do it through an API that returns json, it returns something on the line
{
...
"dateTimeOffset": "2020-04-01T10:00:00+02:00"
...
}
I build my DateTimeOffset like this:
var utc = DateTime.UtcNow;
string time = "10:00:00";
string timezoneIdentifier = "Romance Standard Time";
var date = DateTime.Now.Date;
var zone = TimeZoneInfo.FindSystemTimeZoneById(timezoneIdentifier);
var timespanOffset = zone.GetUtcOffset(utc);
var baseDateTime = date + TimeSpan.Parse(time);
baseDateTime= DateTime.SpecifyKind(baseDateTime, DateTimeKind.Unspecified);
var dateTimeOffset = new DateTimeOffset(baseDateTime, timespanOffset);
When he pulls it in, his part converts the time to "12:00:00", that is: it adds the timezone, and it really got me, because I got so confused, because, he wanted me to send him "08:00:00 +2", so it was showing correctly to the end user, but i refused, because my understanding is: the time part is the local time and the +2, describes the offset from UTC, and it isn't the other way around: that the time part is UTC and you have to add the offset to get the local time. I can't find it anywhere in the docs: https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset?view=netcore-2.2 other than
The DateTimeOffset structure includes a DateTime value, together with an Offset property that defines the difference between the current DateTimeOffset instance's date and time and Coordinated Universal Time (UTC). Because it exactly defines a date and time relative to UTC, the DateTimeOffset structure does not include a Kind member, as the DateTime structure does
But that is not good enough for me. My brain will not accept it. So:
1. is the time in a DateTimeOffset the local time of a given zone, or
2. is the time the UTC time, and you have to add/substract the offset to get the local time
I know this should be basic stuff, but we have discussed it so much that I dont know what to think anymore.
Hope someone can help.

How to get "today's local midnight expressed in UTC" using .NET core?

I am trying to get a timestamp for "Local midnight in UTC" using .NET Core.
I wrote this code:
var utcTimeStartLocalDay =
TimeZoneInfo.ConvertTimeToUtc(convertToLocalTimezone(DateTime.UtcNow).Date);
where
public DateTime ConvertToLocalTimezone(DateTime dateTime)
{
return TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.Utc,TimeZoneInfo.FindSystemTimeZoneById("FLE Standard Time"));
}
So, the idea is to get Utc timestamp, convert it to local TZ, then take Date (that is, discard time part and effectively make a midnight timestamp) and convert back to Utc - that should have given me local time.
However, it did not happen, as the result of the first expression is Utc midnight when printed.
Fiddle: https://dotnetfiddle.net/wJIXve
What do I need to correct here to get as the answer the local midnight for the day expressed as UTC (something like 22:00 UTC previous day)?
Edit: just to clarify an unclearness in the question: by "local" TZ I meant known local timezone (found in the code)
To ensure that you are definitely using local time, I would use this code:
DateTime localMidnight = DateTime.SpecifyKind(DateTime.Now.Date, DateTimeKind.Local);
Then simply use .ToUniversalTime() to get the UTC date:
DateTime localMidnightUtc = localMidnight.ToUniversalTime();
Here's a working example:
static async Task Main(string[] args)
{
DateTime localMidnight = DateTime.SpecifyKind(DateTime.Now.Date, DateTimeKind.Local);
DateTime localMidnightUtc = localMidnight.ToUniversalTime();
Console.WriteLine($"localMidnight: {localMidnight}");
Console.WriteLine($"localMidnightUTC: {localMidnightUtc}");
}
// Output:
// localMidnight: 29.01.2020 00:00:00
// localMidnightUTC: 28.01.2020 23:00:00
(And now you know which timezone I'm in ;)
This should work.
var result = DateTime.Now.Date.ToUniversalTime();
This one-liner is the same as .NET Framework:
DateTime.Today.ToUniversalTime();

How to parse the date and time depends upon the time zone?

I want to parse the string to time.
string inputDate = "1970-01-01T00:00:00+0000";
var dt = DateTime.Parse(inputDate, CultureInfo.InvariantCulture);
Console.WriteLine("Date==> " + dt);
It is working fine in india time(UTC +5.30).
But when I change the time zone to UTC -5 in settings in emulator, the out put is showing
12/31/1969 7:00:00 PM
The date should be same when ever i change the time zone in settings. Please help me to resolve my problem.
Let me explain what is going on here..
Usually, DateTime.Parse method returned DateTime's Kind property will be Unspecified.
But since your string has time zone information and you using DateTime.Parse method without DateTimeStyles overload (it uses DateTimeStyles.None by default), your DateTime's Kind property will be Local.
That's why when you use your code in UTC +05.30 time zone system, it will be generate a result like;
01/01/1970 05:00:00 AM
and when you use in UTC -05.00 time zone system, it will generate;
12/31/1969 7:00:00 PM // which is equal 12/31/1969 19:00:00 AM representation
which is too normal.
The date should be same when ever i change the time zone in settings.
Makind your DateTime as UTC is the best choice in such a case. Using ToUniversalTime() method is one way to do that in a Local time.
From documentation;
The Coordinated Universal Time (UTC) is equal to the local time minus
the UTC offset.
Since your code generates Local time, your ToUniversalTime() generated datetime's will be the same in both time zone.
Another way to do it, using DateTimeStyles.AdjustToUniversal as a third parameter in DateTime.Parse method.
From documentation;
Date and time are returned as a Coordinated Universal Time (UTC). If
the input string denotes a local time, through a time zone specifier
or AssumeLocal, the date and time are converted from the local time to
UTC. If the input string denotes a UTC time, through a time zone
specifier or AssumeUniversal, no conversion occurs. If the input
string does not denote a local or UTC time, no conversion occurs and
the resulting Kind property is Unspecified.
string inputDate = "1970-01-01T00:00:00+0000";
var dt = DateTime.Parse(inputDate,
CultureInfo.InvariantCulture,
DateTimeStyles.AdjustToUniversal);
That will generate 01/01/1970 00:00:00 which Kind is Utc.
Final Solution
string givenDate = ("1970-01-01T00:00:00+0000");
DateTime d = DateTime.Parse(givenDate, System.Globalization.CultureInfo.InvariantCulture);
string ouputDate = d.ToUniversalTime().ToString("MMM d, yyyy h:m:s tt", System.Globalization.CultureInfo.InvariantCulture);

Convert US-Style DateTime to local time

How do I convert US-style DateTime such as 5/1/2012 3:38:27 PM returned from the server to user's local time? I am developing for windows phone.
I've tried
DateTime localTime = serverTime.ToLocalTime();
but the result is off a couple of hours. I thought ToLocalTime() will take care of the conversion to any timezone the user are in? Perhaps I need to get the user's timezone info first?
EDIT 1
I think the serverTime is in the PST time zone
EDIT 2
My timezone is GMT +8. I tried the following, but the resulting localTime is 15 hour behind.
TimeZoneInfo localZone = TimeZoneInfo.Local;
DateTime localTime = TimeZoneInfo.ConvertTime(serverTime, localZone);
EDIT 3
This result in 7 hours behind my local time.
TimeZoneInfo localZone = TimeZoneInfo.Local;
DateTime dateTimeKind = DateTime.SpecifyKind(serverTime, DateTimeKind.Utc);
DateTime localTime = TimeZoneInfo.ConvertTime(dateTimeKind, localZone);
EDIT 4
OK I think I am getting there but not sure if this is applicable for all time zones. I think I still have to consider day light saving because the resulting local time is just one hour ahead now.
TimeZoneInfo localZone = TimeZoneInfo.Local;
double offset = localZone.GetUtcOffset(DateTime.Now).TotalHours;
DateTime dateTimeKind = DateTime.SpecifyKind(serverTime, DateTimeKind.Utc);
DateTime localTime = TimeZoneInfo.ConvertTime(dateTimeKind, localZone).AddHours(offset);
But then how do you get DLS is in effect for a particular time zone in Windows Phone? TimeZoneInfo.FindSystemTimeZoneById does not seem to be supported?
For this to work, the DateTime-object serverTime must be of the UTC-form - or at least know what Kindit is. Read all the details around this under the remarks section of this page.
Best of luck!
What does the time represent? If it is a specific moment in time, such as the date and time that something happened, then you should update your server code to return the time in one of the following formats:
// ISO8601 local time with offset.
// get from DateTimeOffset.ToString("o")
2012-05-01T15:38:27-07:00
// ISO8601 UTC time
// get from DateTime.ToString("o") when kind is UTC
2012-05-01T22:38:27Z
It's really important that you do this, because local times can be ambiguous when daylight savings ends. You must either provide the correct offset, (-8 for PST, -7 for PDT), or send as UTC.
There are very few scenarios where sending local time by itself makes sense. If you think you have one, please elaborate about what the time represents.

Categories

Resources