getting hour part and time-zone part from datetime - c#

I had a string in config file, defining date time with time zone.
I am not able to get this value, while reading values from config file.
In config file:
Setting name="abcdefgh" value="2012-08-10T22:00:00-08:00"
In C#, I am reading this as follows:
DateTime StartDate;
StartDate = DateTime.ParseExact(RoleEnvironment.GetConfigurationSettingValue("abcdefgh"), "yyyy-MM-dd HH:mm:ss", null);
Configuration.Instance.abcdefgh= StartDate;
In start date, i am getting 11 Aug, 2012 11:30:00, with no time zone.
I want to read it as it is. also tell, if my format of writing datetime in config file is correct

MSDN link to DateTimeOffset.
Use DateTimeOffset whenever you are referring to an exact point in
time. For example, use it to calculate "now", transaction times, file
change times, logging event times, etc. If the time zone is not
known, use it with UTC. These uses are much more common than the
scenarios where DateTime is preferred, so this should be considered
the default.
var date = DateTimeOffset.Parse("2012-08-10T22:00:00-08:00");
date.Offset // -08:00:00, offset from Coordinated Universal Time (UTC)
date.DateTime // 10/08/2012 22:00:00,

DateTime doesn't keep information about timezone. To parse the string and keep information about timezone - you should use DateTimeOffset structure.

Use the DateTimeOffset structure (and DateTimeOffset.ParseExact) if you want to store timezone information.
Your ParseExact format also doesn't quite match the setting value: it should have a zz at the end for the timezone information. You can also use DateTimeOffset.Parse since your setting string is in a standard format.

It's a standard format, so the ParseExact isn't needed, try:
StartDate = DateTime.Parse(RoleEnvironment.GetConfigurationSettingValue("abcdefgh"));
I substituted the hard-coded value you provided and got the correct result for my timezone (GMT-4) as
8/11/2012 2:00 AM
Note: as others mentioned, the timezone is not retained, so you will get the correct localized time corresponding to whatever timezone information was in the string, but you won't be able to find out what timezone that was. The DateTime.Kind property will reflect that it's a local time.

Related

Is there functionality to convert from UTC time to local time using country name? [duplicate]

We are developing a C# application for a web-service client. This will run on Windows XP PC's.
One of the fields returned by the web service is a DateTime field. The server returns a field in GMT format i.e. with a "Z" at the end.
However, we found that .NET seems to do some kind of implicit conversion and the time was always 12 hours out.
The following code sample resolves this to some extent in that the 12 hour difference has gone but it makes no allowance for NZ daylight saving.
CultureInfo ci = new CultureInfo("en-NZ");
string date = "Web service date".ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);
As per this date site:
UTC/GMT Offset
Standard time zone: UTC/GMT +12 hours
Daylight saving time: +1 hour
Current time zone offset: UTC/GMT +13 hours
How do we adjust for the extra hour? Can this be done programmatically or is this some kind of setting on the PC's?
For strings such as 2012-09-19 01:27:30.000, DateTime.Parse cannot tell what time zone the date and time are from.
DateTime has a Kind property, which can have one of three time zone options:
Unspecified
Local
Utc
NOTE If you are wishing to represent a date/time other than UTC or your local time zone, then you should use DateTimeOffset.
So for the code in your question:
DateTime convertedDate = DateTime.Parse(dateStr);
var kind = convertedDate.Kind; // will equal DateTimeKind.Unspecified
You say you know what kind it is, so tell it.
DateTime convertedDate = DateTime.SpecifyKind(
DateTime.Parse(dateStr),
DateTimeKind.Utc);
var kind = convertedDate.Kind; // will equal DateTimeKind.Utc
Now, once the system knows its in UTC time, you can just call ToLocalTime:
DateTime dt = convertedDate.ToLocalTime();
This will give you the result you require.
I'd look into using the System.TimeZoneInfo class if you are in .NET 3.5. See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx. This should take into account the daylight savings changes correctly.
// Coordinated Universal Time string from
// DateTime.Now.ToUniversalTime().ToString("u");
string date = "2009-02-25 16:13:00Z";
// Local .NET timeZone.
DateTime localDateTime = DateTime.Parse(date);
DateTime utcDateTime = localDateTime.ToUniversalTime();
// ID from:
// "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zone"
// See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.id.aspx
string nzTimeZoneKey = "New Zealand Standard Time";
TimeZoneInfo nzTimeZone = TimeZoneInfo.FindSystemTimeZoneById(nzTimeZoneKey);
DateTime nzDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, nzTimeZone);
TimeZone.CurrentTimeZone.ToLocalTime(date);
DateTime objects have the Kind of Unspecified by default, which for the purposes of ToLocalTime is assumed to be UTC.
To get the local time of an Unspecified DateTime object, you therefore just need to do this:
convertedDate.ToLocalTime();
The step of changing the Kind of the DateTime from Unspecified to UTC is unnecessary. Unspecified is assumed to be UTC for the purposes of ToLocalTime: http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx
I know this is an older question, but I ran into a similar situation, and I wanted to share what I had found for future searchers, possibly including myself :).
DateTime.Parse() can be tricky -- see here for example.
If the DateTime is coming from a Web service or some other source with a known format, you might want to consider something like
DateTime.ParseExact(dateString,
"MM/dd/yyyy HH:mm:ss",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)
or, even better,
DateTime.TryParseExact(...)
The AssumeUniversal flag tells the parser that the date/time is already UTC; the combination of AssumeUniversal and AdjustToUniversal tells it not to convert the result to "local" time, which it will try to do by default. (I personally try to deal exclusively with UTC in the business / application / service layer(s) anyway. But bypassing the conversion to local time also speeds things up -- by 50% or more in my tests, see below.)
Here's what we were doing before:
DateTime.Parse(dateString, new CultureInfo("en-US"))
We had profiled the app and found that the DateTime.Parse represented a significant percentage of CPU usage. (Incidentally, the CultureInfo constructor was not a significant contributor to CPU usage.)
So I set up a console app to parse a date/time string 10000 times in a variety of ways. Bottom line:
Parse() 10 sec
ParseExact() (converting to local) 20-45 ms
ParseExact() (not converting to local) 10-15 ms
... and yes, the results for Parse() are in seconds, whereas the others are in milliseconds.
I'd just like to add a general note of caution.
If all you are doing is getting the current time from the computer's internal clock to put a date/time on the display or a report, then all is well. But if you are saving the date/time information for later reference or are computing date/times, beware!
Let's say you determine that a cruise ship arrived in Honolulu on 20 Dec 2007 at 15:00 UTC. And you want to know what local time that was.
1. There are probably at least three 'locals' involved. Local may mean Honolulu, or it may mean where your computer is located, or it may mean the location where your customer is located.
2. If you use the built-in functions to do the conversion, it will probably be wrong. This is because daylight savings time is (probably) currently in effect on your computer, but was NOT in effect in December. But Windows does not know this... all it has is one flag to determine if daylight savings time is currently in effect. And if it is currently in effect, then it will happily add an hour even to a date in December.
3. Daylight savings time is implemented differently (or not at all) in various political subdivisions. Don't think that just because your country changes on a specific date, that other countries will too.
#TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local)
Don't forget if you already have a DateTime object and are not sure if it's UTC or Local, it's easy enough to use the methods on the object directly:
DateTime convertedDate = DateTime.Parse(date);
DateTime localDate = convertedDate.ToLocalTime();
How do we adjust for the extra hour?
Unless specified .net will use the local pc settings. I'd have a read of: http://msdn.microsoft.com/en-us/library/system.globalization.daylighttime.aspx
By the looks the code might look something like:
DaylightTime daylight = TimeZone.CurrentTimeZone.GetDaylightChanges( year );
And as mentioned above double check what timezone setting your server is on. There are articles on the net for how to safely affect the changes in IIS.
In answer to Dana's suggestion:
The code sample now looks like:
string date = "Web service date"..ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);
DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(convertedDate);
The original date was 20/08/08; the kind was UTC.
Both "convertedDate" and "dt" are the same:
21/08/08 10:00:26; the kind was local
I had the problem with it being in a data set being pushed across the wire (webservice to client) that it would automatically change because the DataColumn's DateType field was set to local. Make sure you check what the DateType is if your pushing DataSets across.
If you don't want it to change, set it to Unspecified
I came across this question as I was having a problem with the UTC dates you get back through the twitter API (created_at field on a status); I need to convert them to DateTime. None of the answers/ code samples in the answers on this page were sufficient to stop me getting a "String was not recognized as a valid DateTime" error (but it's the closest I have got to finding the correct answer on SO)
Posting this link here in case this helps someone else - the answer I needed was found on this blog post: http://www.wduffy.co.uk/blog/parsing-dates-when-aspnets-datetimeparse-doesnt-work/ - basically use DateTime.ParseExact with a format string instead of DateTime.Parse
This code block uses universal time to convert current DateTime object then converts it back to local DateTime. Works perfect for me I hope it helps!
CreatedDate.ToUniversalTime().ToLocalTime();

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();
}
}

How to combine date time and Timezone offset in an ASP.net application?

My web service call to a third party applications returns the date,time zone and timezone_offset values. I need to add this to a calendar in Asp.net application. What is the best way to combine this together so that my date object understands that its from Eastern time zone?
<start_date>2014-11-17 19:00:00</start_date>
<timezone>America/New_York</timezone>
<timezone_offset>GMT-0500</timezone_offset>
Since you have the offset too, you can use DateTimeOffset.Parse() to get the DateTimeOffset. From there, you can read the DateTime property. The output dt variable will have 2014-11-17 7:00:00 PM with DateTimeKind property set to "Unspecified"
var dtOffset = DateTimeOffset.Parse("2014-11-17 19:00:00-0500", CultureInfo.InvariantCulture);
var dt = dtOffset.DateTime;
A DateTimeOffset represents a point in time. Usually, its relative to UTC. So, it is a natural structure to initially parse the fields that you have.
If you want a reference to the same datetime in UTC, you can use this. Here the output dt variable will have 2014-11-18 12:00:00 AM with DateTimeKind property set to "Utc"
var dt = DateTime.Parse("2014-11-17 19:00:00-0500", CultureInfo.InvariantCulture).ToUniversalTime();
If you don't have the offset but just have the timeZoneId, you can still do it but you need NodaTime for that.
I'll focus on this part of the question:
What is the best way to combine this together so that my date object understands that its from Eastern time zone?
There is no data type built in to .NET that can sufficiently do that. The DateTimeOffset type associates with a particular offset, such as the -05:00 or -04:00 that might be in use by the Eastern time zone (depending on the date). But those same offsets might also be sourced from some other time zone entirely. A time zone has one or more offsets, but an offset isn't a time zone itself.
Fortunately there are solutions. There are two options to consider:
You could pair a DateTimeOffset with a TimeZoneInfo object. When storing or transmitting these, you would only send the full DateTimeOffset along with the Id of the time zone.
The Noda Time library is a much more effective way to work with date and time, especially when it comes to time zone concerns. It contains a type called ZonedDateTime that already combines a date, time, offset, and time zone. It can also be used to work with IANA time zone identifiers, such as the "America/New_York" time zone you specified in the question.

Parse String DateTime containing TimeZone Info

I am trying to convert a string value to a datetime value but am getting a System.FormatException error. This is because of the timezone info which is part of the date string. Is there any method which will be able to handle this conversion?
string date = "Wed, 04 Jan 2012 20:18:00 EST";
DateTime dt = Convert.ToDateTime(date);
Console.WriteLine(dt.ToString());
I don't believe there's any custom date and time format string which will parse or format a time zone abbreviation. You'll have to strip it out, parse the local part, work out which time zone is meant from the abbreviation (good luck with that - they're ambiguous) and then apply that time zone to the local time to get a UTC value (again, this can be ambiguous).
If you're in control of the format at all, I would try to avoid including time zone information if you can, or include an offset rather than a time zone if that's all that's important (an offset doesn't give the same information of course), or an unambiguous time zone identifier if you really need the time zone. Note that .NET uses the Windows system time zone identifiers; my own Noda Time project uses the more widespread Olson / zoneinfo / tz identifiers, if that's helpful to you.

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