How to convert UTC+0 Date to PST Date? - c#

I have this UTC+0 Date :
2011-11-28T07:21:41.000Z
and I'd like, on C#, convert it to a PST Date. How can I do it? Tried with :
object.Data.ToLocalTime()
but I can't get the correct value (which should be 2011-11-27)
EDIT
Also tried (after suggesion on another topic) this :
DateTime convertedDate = DateTime.SpecifyKind(
DateTime.Parse(object.Data.ToShortDateString()),
DateTimeKind.Utc);
DateTime dt = convertedDate.ToLocalTime();
string dataVideo = dt.ToShortDateString();
but the date still 28/11/2011, not 27/11/2011

I've changed my clock to use UTC-08:00 Pacific Time.
DateTime timestamp = DateTime.Parse("2011-11-28T07:21:41.000Z");
Console.WriteLine("UTC: " + timestamp.ToUniversalTime());
Console.WriteLine("PST: " + timestamp.ToLocalTime());
Output:
UTC: 28/11/2011 7:21:41
PST: 27/11/2011 23:21:41
Example with TimeZoneInfo
DateTime timestamp = DateTime.Parse("2011-11-28T07:21:41.000Z");
Console.WriteLine("UTC: " + timestamp.ToUniversalTime());
Console.WriteLine("GMT+1: " + timestamp.ToLocalTime());
Console.WriteLine("PST: " + TimeZoneInfo.ConvertTimeBySystemTimeZoneId(timestamp, "Pacific Standard Time"));
Output:
UTC: 28/11/2011 7:21:41
GMT+1: 28/11/2011 8:21:41
PST: 27/11/2011 23:21:41

For a little more color
2011-11-28T07:21:41.000Z
This is a ISO8601 Timestamp, the Z at the end stands for UTC. This represents a specific instance in time.
DateTime.Parse will return to you a local date time structure, there are three types of datetime kinds, UTC, Local, and Unspecified.
If you try displaying this, it will show you this instant in your computers current timezone (I'm eastern time so when I print it I get 11/28/2011 2:21:41 AM).
If I want to switch this DateTime Kind to UTC, I could do something like
DateTime.Parse("2011-11-28T07:21:41.000Z").ToUniversalTime()
Printing this now (since it's kind is now UTC) I get 11/28/2011 7:21:41 AM.
Note that although the time is printed differently both these date times are referring to the same instant in time.
To display this instant in a different timezone, the easiest way imo is the TimeZoneInfo class (though I'm not sure it's 100% accurate).
TimeZoneInfo.ConverTimeBySystemTimeZoneId(dateTime, "Pacific Standard Time").
Printing it now will yield your desired result 11/27/2011 11:21:41 PM
Note that this return DateTime's Kind property is now Unspecified, meaning you won't be able to transfer it back to UTC without more information. You no longer have a specific instant in time, rather you have a unspecified time..we know it's the same instant as the ones previously just in pacific time, but the computer no longer knows that. Keep that in mind if you want to store this time.

Related

C# Manually specify a timezone in DateTime.ParseExact

I have a log file that contains date/time strings formatted like this:
2019/10/01 15:30
As you can see, the strings don't contain any timezone information. However, I do know the timezone that the time is represented within.
If I use this C# code on my own PC, which has its local timezone set correctly, the time is parsed as expected. I'm expecting to convert the local time to UTC for inserting into a database.
Time.ParseExact("2019/10/01 15:30", "yyyy/MM/dd HH:mm", provider, DateTimeStyles.AdjustToUniversal & DateTimeStyles.AssumeLocal);
However, if I run this code on one of my Docker hosts, which has its timezone set to UTC, the times are parsed as UTC. This makes sense, since on a Docker host using UTC AssumeLocal will be the same as UTC.
Simply applying a manual offset isn't sufficient due to daylight saving time. Also, some of these logs are historical and go back to prior to the DST change, so even using an algorithm would be complex and it seems like it's something that should already be solved (i.e. given a date and timezone, determine if it's in DST or not and then adjust to UTC accordingly)
What I want to be able to do is to explicitly specify the timezone for the timestamp and have the framework use both the given timezone and the actual date to properly convert the time to UTC. I've looked at this question and this question but they all seem to depend on the system itself being set to the timezone that you want to assume the date is in.
The second question does seem to start addressing the issue of assuming a known timezone, but then the responses just use GetUtcOffset on the parsed time to determine the amount of time to offset the time. This assumes that the time was already parsed in the desired timezone.
I believe what you're looking for is TimeZoneInfo.
Using TimeZoneInfo, you can get the information you need from TimeZoneInfo.FindSystemTimeZoneById.
Those Ids are based on the operating system, but as long as all of your containers are on Linux (as an example) you will be able to use that to get a UTC time for storage. You mention that you know what timezone your string is in, so you'll likely need something to convert that to Ids readable by TimeZoneInfo.
Code example taken from TimeZoneInfo.FindSystemTimeZoneById
using System;
public class Example
{
public static void Main()
{
// Get time in local time zone
DateTime thisTime = DateTime.Now;
Console.WriteLine("Time in {0} zone: {1}", TimeZoneInfo.Local.IsDaylightSavingTime(thisTime) ?
TimeZoneInfo.Local.DaylightName : TimeZoneInfo.Local.StandardName, thisTime);
Console.WriteLine(" UTC Time: {0}", TimeZoneInfo.ConvertTimeToUtc(thisTime, TimeZoneInfo.Local));
// Get Tokyo Standard Time zone
TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time");
DateTime tstTime = TimeZoneInfo.ConvertTime(thisTime, TimeZoneInfo.Local, tst);
Console.WriteLine("Time in {0} zone: {1}", tst.IsDaylightSavingTime(tstTime) ?
tst.DaylightName : tst.StandardName, tstTime);
Console.WriteLine(" UTC Time: {0}", TimeZoneInfo.ConvertTimeToUtc(tstTime, tst));
}
}
// The example displays output like the following when run on a system in the
// U.S. Pacific Standard Time zone:
// Time in Pacific Standard Time zone: 12/6/2013 10:57:51 AM
// UTC Time: 12/6/2013 6:57:51 PM
// Time in Tokyo Standard Time zone: 12/7/2013 3:57:51 AM
// UTC Time: 12/6/2013 6:57:51 PM

Parse date time c# with correct timezone and kind

I have a datetime in database which I read using SqlDataReader and then cast it to (DateTime). After the cast its Kind property is DateTimeKind.Unspecified.
Then I have another string which I read from some other source. Its format is like this 2016-01-20T22:20:29.055Z. I do DateTime.Parse("2016-01-20T22:20:29.055Z") and its Kind property is DateTimeKind.Local.
How do I properly parse the both date times for comparison? Do I need to use DateTimeOffsets? How should I parse them?
Thanks
Because SQLReader cannot reasonably infer a DateTimeKind, it leaves it as unspecified. You'll want to use DateTime.SpecifyKind to change the DateTimeKind on your output from the SQLReader to the appropriate value. This works ok if you are only dealing with UTC and one consistent local time zone; otherwise, you really should be using DateTimeOffset in both your code and the SQL Database.
The string "2016-01-20T22:20:29.055Z" is ISO 8601 compliant and is a UTC date; however, DateTime.Parse with only 1 argument can end up performing a conversion to local time. Per the documentation:
Generally, the Parse method returns a DateTime object whose Kind
property is DateTimeKind.Unspecified. However, the Parse method may
also perform time zone conversion and set the value of the Kind
property differently, depending on the values of the s and styles
parameters:
If s contains time zone information, the date and time is converted
to the time in the local time zone and the Kind is DateTimeKind.Local.
If s contains time zone information, and styles includes the
AdjustToUniversalflag, the date and time is converted to Coordinated
Universal Time (UTC) and the Kind is DateTimeKind.Utc.
If s contains the Z or GMT time zone designator, and styles includes
the RoundtripKind flag, the date and time are interpreted as UTC and
the Kind is DateTimeKind.Utc.
Also see UTC gotchas in .NET and SQL Server in Derek Fowler's blog for additional coverage on the topic.
In your second example, 2016-01-20T22:20:29.055Z has timezone information provided with it; the 'Z' at the end indicates that the timestamp is intended for Coordinated Universal Time (UTC). However, DateTime.Parse() will default its conversion using DateTimeKind.Local unless a specific timezone is specified. You can use DateTime.ParseExact to be more specific.
As to why the datetime values in your database are coming out as Unspecified, that's likely because they contain no timezone indication at all. Check to see if your database values specify timezone information, either by using 'Z' at the end or specifying an exact timezone, such as 2016-01-20T22:20:29.055-07:00 (UTC-7).
You can use something like this:
string format = "ddd dd MMM h:mm tt yyyy";
DateTime dateTime = DateTime.ParseExact(dateString, format,
CultureInfo.InvariantCulture);
In format variable, you can put the format you want, and pass it to ParseExact function.
Hope it helps.
You are missing the datetime context (offset) in your database. You should persist it either in a datetimeoffset column or in a datetime column but persisting utc datetimes.
And always better compare two utc datetimes.
I coded a quick C# console app that I pasted in below. This converts a UTC date and time to a string (format similar to the ISO 8601 format described in another post with some extra digits of precision), writes it to a file, reads it from the file (as a string) and then converts it back to a UTC date and time.
It then compares the two UTC Date Time objects, which are both of UTC kind, and they match.
class Program
{
// "2016-01-20T22:20:29.055Z" is ISO 8601 compliant and is a UTC date
const string dtf = "yyyy-MM-ddTHH:mm:ss.fffffffZ";
static void Main(string[] args)
{
string file = #"c:\temp\file.txt";
DateTime dt = DateTime.UtcNow;
using (var sw = new System.IO.StreamWriter(file))
{
sw.WriteLine(dt.ToString(dtf, System.Globalization.CultureInfo.InvariantCulture));
}
DateTime dtin;
using (var sr = new System.IO.StreamReader(file))
{
dtin = DateTime.ParseExact(sr.ReadLine(), dtf, System.Globalization.CultureInfo.InvariantCulture);
}
Console.WriteLine(dt.ToString(dtf) + "\r\n" + dtin.ToString(dtf) + "\r\nEquality:" + (dt == dtin));
Console.ReadLine();
}
}

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.

How to convert string to local Date Time?

I am trying to convert a string of this format:
MM/dd/yyyy HH:mm
The input is from a US database, so, i.e.:
09/20/2010 14:30
I know that my string is always US time but when I display it, I need to translate that into the local time, so that string should be turned into:
09/20/2010 19:30 (for UK for instance)
I tried a few things but nothing seems to give me the correct solution when I run on a US machine vs a UK or Ge machine
I tried:
CompletedDttm = DateTime.ParseExact(value, "MM/dd/yyyy HH:mm", CultureInfo.CurrentCulture);
CompletedDttm = DateTime.ParseExact(value, "MM/dd/yyyy HH:mm", new CultureInfo("en-US"));
They all work locally (US machine) but they don't convert the time to local time on a European machine.
Thanks
Tony
Try this - it converts local time (input in US format) to GMT and then prints in GB/DE format.
var zones = TimeZoneInfo.GetSystemTimeZones(); // retrieve timezone info
string value = "09/20/2010 14:30";
DateTime CompletedDttm = DateTime.ParseExact(value, "MM/dd/yyyy HH:mm",
new CultureInfo("en-US"));
DateTime FinalDttm = TimeZoneInfo.ConvertTime(CompletedDttm,
TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"),
TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time"));
string output = FinalDttm.ToString(new CultureInfo("en-GB"));
FinalDttm = TimeZoneInfo.ConvertTime(CompletedDttm, TimeZoneInfo.Local,
TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time"));
output = FinalDttm.ToString(new CultureInfo("de-DE"));
Output is, in turn:
20/09/2010 19:30:00
20.09.2010 20:30:00
UPDATE: You have to know the timezone of the data (not just that it is "US") as well as the interpreting machine if you want to reliably convert it to anything else. You're not only looking at hours offset, but DST also which varies by location (not all locales abide by it). Eastern is either -4 or -5 depending on the time of year. And if the date is old enough you run into the issue that "summer" dates were changed recently.
Your best course is to ALWAYS store timestamps in UTC. Aside from that, you can just make guesses about the offset.
You should be working with UTC times (the new, slightly different, version of GMT) if you want to be converting to other time zones.
DateTime dt = new DateTime(DateTime.Parse('2010-10-06 19:40').Ticks, DateTimeKind.Local);
dt.AddHours(5);
dt.ToLocalTime();
You could also make use of TimeZoneInfo which will have DST information also.
Unless you specify otherwise, the parse will assume you mean to parse the string into your current timezone. US culture just means the expected format of the string, and has nothing to do with the timezone (for example, in the US it could be EST or it could be PST).
Your string contains no timezone information, so naturally you're going to get your value in whatever the local timezone is. You can either:
Add the timezone info
Change the timezone afterwards
I think it's a display problem, but need more info to be sure. Try displaying the dates in yyyy-MM-dd format in both cases to check if the problem is on parse or display. You can create a custom format info object if you know exactly what you want to accept or display:
public static DateTimeFormatInfo GetISOFormatInfo()
{
DateTimeFormatInfo dtFormat = new DateTimeFormatInfo();
dtFormat.DateSeparator = "-";
dtFormat.TimeSeparator = ":";
dtFormat.ShortDatePattern = "yyyy-MM-dd";
dtFormat.ShortTimePattern = "HH:mm:ss";
return dtFormat;
}
Using a Date without TimeZone information, you will not be able to know the UK time / Canada time etc... since you do not know who (which part of the world) instered that time. Since you specifically said that the time is US time, you can add the time difference for the different parts of the world to display the local time.
You could use string.Split. first with the '/' separator on the whole string. You will get "09" "20" and "2010 14:30" then apply the split 2 more times with ' ' and ':'

Converting UK times (both BST and GMT) represented as strings to UTC (in C#)

I have to use some dates and times from a legacy database. They are represented as strings. Dates are dd/MM/yy. Times are HH:mm.
I'd like to convert these to UTC as soon as I pull them from the database. I'm working on US systems, so need a common time.
The problem I'm facing is how to convert them to UTC DateTime values. I can do the parsing, etc. The real problem I have concerns the timezone.
I'm trying to use the following approach:
DateTime ukTime = // Parse the strings in a DateTime value.
TimeZoneInfo timeZoneInformation = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTimeOffset utcTime = new DateTimeOffset(ukTime, timeZoneInformation.BaseUtcOffset);
However, this gives incorrect values if the date is in the British Summer Time period.
I can use "GMT Daylight Time" on those dates, but that requires me to know when the switchover is. I'm sure there must be a less laborious way.
As I'm not using a machine with UK time settings I can't rely on local time.
Basically, I need something like:
// Works for both GMT (UTC+0) and BST (UTC+1) regardless of the regional settings of the system it runs on.
DateTime ParseUkTimeAsUtcTime(string date, string time)
{
...
}
I've scoured the posts, but couldn't find anything that addressed this directly. Surely this is also an issue with EST, EDT, etc?
Try using the GetUtcOffset() method on your TimeZoneInfo instance, which takes "adjustment rules" into consideration.
Using this should work basically the same as your original example, but you'll use that method instead of the BaseUtcOffset property.
DateTime ukTime = // Parse the strings in a DateTime value.
TimeZoneInfo timeZoneInformation = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTimeOffset utcTime = new DateTimeOffset(ukTime, timeZoneInformation.GetUtcOffset(ukTime));
How about:
DateTime.Parse(dateTimeString).ToUniversalTime();
Assuming that the database server stores its datetimes in the same timezone as your application server.

Categories

Resources