C# read timezone from string and convert to local - c#

I've looked and looked and can't seem to come up with the perfect solution. So, since stack overflow is perfect, this will cure my problem.
I'm getting System.String datetimes from a server (Microsoft CRM if you care). They're in SQL format ("2010-07-23T17:14:40-04:00"). I want to read that in as a .net System.DateTime type with the timezone information preserved, then convert it to local time. This process happens in various timezones, and I'm having trouble staying in synch. Basically, I get lots of CRM records from CRM server (which seems to stamp all the timezones with this Brazilian time (-4)), and I want to write down in my config file the latest one I saw (so I don't go back and pick up values that I already have). I would like to write it down in local time, though. Here's a distillation
I want to take the string "2010-07-23T17:14:40-04:00" and, run some code:
System.Datetime Get_Local_DT(string val);
that will return "2010-07-23 15:14:40" in Central time (-6) and "2010-07-23 16:14:40" in Eastern Time (-5). Let me know what you think.

The reason your times are stamped with the Brazilian time is that is the timezone attached to the user performing the query. CRM stores universal in the database and the filtered views generate that string based on the current user. This way whenever you open up a record in CRM you get a date with a time for your timezone.
If all you are doing is saving the date/time so you can check against it later, I agree with storing as UTC and doing UTC comparisons.
Note that if you're using any ToLocalTime methods, you are showing Local Time on the server and NOT the actual users local time (unless they're in the same timezone as the server). I guess how important this is to you depends on how many timezones you support (1 or many) and where your server is located.

???
private DateTime Get_Local_DT(string strTimestamp, int iUTCOffset)
{
DateTime _dt = DateTime.MinValue;
try
{
DateTime dt = DateTime.Parse(strTimestamp);
DateTime _returnDateTime = dt.ToUniversalTime().AddHours(iUTCOffset);
return _returnDateTime;
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
return _dt;
}

I think you should use the System.DateTimeOffset type which solves your issue.
String d = "2010-07-23T17:14:40-04:00";
DateTimeOffset dt = DateTimeOffset.Parse(d);
Console.WriteLine(dt.LocalDateTime + " " + dt.ToOffset(TimeSpan.FromHours(-2)));

You could parse the string into a DateTime object using
string sqlDate = "2010-07-23T17:14:40-04:00";
DateTime dt = DateTime.Parse(sqlDate);
Next, you could use the following statement to format it:
dt.ToString("yyyy-MM-dd HH:mm:ss", System.Globalization.DateTimeFormatInfo.InvariantInfo);
I tried this code:
void Main()
{
string sqlDate = "2010-07-23T17:14:40-04:00";
DateTime dt = DateTime.Parse(sqlDate);
Console.WriteLine(dt.ToString("yyyy-MM-dd HH:mm:ss", System.Globalization.DateTimeFormatInfo.InvariantInfo));
}
Output: 2010-07-24 02:44:40
I am in IST. I hope this helps.

Save them as universal time:
DateTime t = DateTime.Parse(str);
t.ToUniversalTime(); // save this
Then show saved time as local:
DateTime t = DateTime.Parse(str);
t.ToLocalTime(); // show this
Always work with universal time, think about local as just a view in mvc.

Related

Dapper return data type DATE with time

I have problem. I have MySQL database and I use DATE type for my date column. I want to save date without time only.
In database date is saved like this 06/02/1999 for example.
But when I try to take it with dapper
var test = connection.QueryFirstAsync<string>(#"SELECT BirthDate FROM Students");
Then it returns 06/02/1999 00:00:00
How can I fix that? I want string without that time that shouldn't even be there in first place.
Thank you very much for answers
Simple (maybe naive) solution is this one:
string date = "06/02/1999 00:00:00";
DateTime dateTime = DateTime.Parse(date);
DateOnly dateOnly = DateOnly.FromDateTime(dateTime);
Note: DateOnly applies to .NET 6, .NET 7 Preview 6

Is it bad to convert c# datetime properties in the get and set to and from utc

In our Entity Framework app we are storing datetimes as UTC. The client uses a reflection utility to convert object graphs to their users timezone, and then back to utc when submitting changes to the server.
The utility works fine, but i'm considering a cleaner approach where I add a unmapped TimeZoneInfo property on the base class with a default value set to UTC, and then for each datetime property i would modify it like so:
private DateTime _endTime;
public DateTime EndTime
{
get
{
return _endTime.ConvertFromUtc(TimeZone);
}
set
{
_endTime = value.ConvertToUtc(TimeZone);
}
}
The idea is that the backing field is always stored as a UTC value. If the TimeZone proeprty is set to UTC, then the ConvertTo/From extension methods will not do any conversion and will simply return the backing fields value. Whereas, if the TimeZone is set to anything else then the conversion will take place, leaving the backing field in UTC.
What i'm wondering is if there are issues i'm not thinking of. For instance, I'm assuming it would serialize with a value based on the current TimeZone property...is that true? Also, would this work for code first entities in EF? My hope is that if the TimeZone is changed it would not trigger a change in the dbcontext. Are there any other considerations that i'm missing that would make this a bad idea, and what would a DDD implementator think?
Edit
To clarify the use case a little more, the service layer will retrieve the values from the db, serialize, and send it to the MVC Controller. The service layer does not know of the users timezone. In my mvc app the web controller cached the user timezone at logon. This controller will then use that value to set the TimeZone property on the object. It will then submit it to the client via JSON. The TimeZone property on the base class represents the current timzone of the object, not the users timezone. The values are always stored as UTC and the controller which sends the data to the client is responsible to make sure it is set to the correct timezone.
The biggest reason i am considering this is for business logic. The object in question is a schedule which has a start and end time. There are three requirements that would be easier to perform if the object were set to the users timezone. For instance, schedules cannot span weeks, so if it starts on Saturday (end of week) and ends on Sunday (start of week) it must be split into two different schedules. For some reason i have a more difficult time when working with datetime logic, and so anything i can do to simplify it is a plus for maintenance.
The thing is that your application's timezone will be the web server's timezone! If the user is visiting your site from another timezone, the conversion will be wrong.
You need to make your page determine via the browser what their timezone is and use that for conversions.
If you need the user's current time, you can use this:
Date.now()
// Or this if you need support for old browsers, like IE8
new Date().getTime()
That will give you UTC time in milliseconds since January 1st 1970. You will have to later convert that to C# time by doing this in your application:
DateTime date = new DateTime(valueFromJS * 10000 + 621355860000000000);
If you don't need the current time but a date+time entered by the user in a date picker, then you should create a date object in the browser from that and send the getTime() of that object. This way your web server always receives UTC time and it's up to the browser do the appropriate conversion.
You can also use new Date().getTimezoneOffset(), which will return the amount of minutes UTC is ahead of the user timezone. So if the user is in GMT -4, that function will return 240. If for some reason you need that in the web server, you can send that value from the browser. Alternatively, if your application has users, you can even store that as a setting and simply use that.
Now, to display the date in the browser's timezone, you have to either know beforehand the user's timezone (from a previous request or a user setting) or just send it in UTC and then convert that via JavaScript in the browser.
There are also useful libraries to deal with timezone problems. For example:
http://momentjs.com/timezone/
http://tzdata-javascript.org
I do not think my question was well worded, nor thought out. I decided to implement the above idea into part of my project and found that it just creates more confusion than it's worth. It's also adds too much risk, especially if used in objects that are persisted to the db, where a programmer may fail to convert the object back to utc.
Instead i am adding a much, much simpler way by adding an extension method to easily calculate based on a specified timezone. The extension method assumes the datetime object is in UTC:
public static DateTime? As(this DateTime? dt, TimeZoneInfo targetTimeZone)
{
if (dt.HasValue)
return dt.Value.As(targetTimeZone);
else
return dt;
}
public static DateTime As(this DateTime dt, TimeZoneInfo targetTimeZone)
{
return TimeZoneInfo.ConvertTimeFromUtc(dt, targetTimeZone);
}
This ensures the underlying object is not mutated unnecessarily.

CRM 2011 Contract ActiveOn Date Issues

I am having an issue with creating a contract from a custom workflow activity. The contract takes it's activeon date from a field in a related entity. The time portion of the date is removed before being set as the activeon date for the contract. This seems to work as expected but the code is creating wonky dates for the contract. Does anyone have any experience with this?
DateTime startDate;
DateTime endDate;
Anh_home home = <<Get record from service>>;
startDate = home.Anh_ActualPossessionDate.GetValueOrDefault().Date;
endDate = startDate.AddYears(contractDuration).Date.AddSeconds(-1);
newContract = new Contract()
{
Title = contractName,
anhwp_Home = home.ToEntityReference(),
CustomerId = home.Anh_CompanyId,
ActiveOn = startDate,
ExpiresOn = endDate,
BillingCustomerId = home.Anh_CompanyId,
BillingStartOn = startDate,
BillingEndOn = endDate,
ContractTemplateId = dataContext.ContractTemplateSet.FirstOrDefault(x => x.Abbreviation == "HWC").ToEntityReference()
};
newContract.Id = service.Create(newContract);
Below is the results of a query on the filtered views. It seems like the activeon date is setting the activeonutc field but my understanding is that CRM handles the conversion to UTC based on the users settings.
Thanks.
So I have stumbled upon the answer to my question on this great blog post https://community.dynamics.com/crm/b/develop1/archive/2011/12/06/dynamics-crm-datetimes-the-last-word.
It seems that when you retrieve data from CRM via the SDK the date is always sent as UTC but you can send data either as local time or UTC. The issue I was having is that I was treating the date retrieved from the other entity as local time when it was really UTC. So when I saved my new contract CRM was correctly taking the UTC time I provided and converting it to local time.
To fix this issue I simply made a call to the .ToLocalTime() method of the DateTime object of the retrieved record.

Casting Error - Converting Strings to Times

In my application I have a datagrid that populates with info from a SQLserver DB. Amongst other things the data which populates the grid includes times. Now I struggled for some time getting the data from the DB to look the way I wanted. In the end my sql comman included the following : -
LEFT(CONVERT(VARCHAR(8), te.StartTime, 8), 5) AS [Start Time],
LEFT(CONVERT(VARCHAR(8), te.FinishTime, 8), 5) AS [Finish Time]
Which nicely shows times in the format of 8:00 & 10:00 etc.
However, this causes a problem later on in my application when I need to use the info in the datagrid to calculate the difference between two times. This is because (I believe) my SQL command (above) has coverted the times to strings. So when I try the following for example:
DateTime startTime = (DateTime)varValue;
DateTime endTime = (DateTime)varFinish;
I get the error message 'invalid cast'. So I'm faced with converting these strings back into DateTime in order to perform any calculations with them. I can't simply add the original time fields to the SQL command, because sometimes the times in the grid will be new times input by the user, so those will be strings anyway.
How should I best convert the user input e.g. "8:00" into a datetime - so that I can perform functions like calucating the difference between two times. Or alternatively, should I be going about the whole timesheet issue a different way.
Any advice will be greatly appreciated. I'm rather new to C# as you may have guessed.
Have you tried this?
DateTime tmp = DateTime.Now;
DateTime startTime = DateTime.Parse(varValue + " " + tmp.ToShortDateString());
DateTime endTime = DateTime.Parse(varFinish + " " + tmp.ToShortDateString());
Think this could solve your Problem?
You got now the current Date with your given times in the two parameters
I advise you to take the date time variables as is without any conversion in SQL, and convert them to the way you want in C#.
you can use the following:
DateTime d = FetchTimeFromDB();
string timeRequired = d.ToString("hh:mm");
It's quite a bad practice to convert your data at the source (database) in a specific format that is dependent on what you need to display in the UI.
In most cases this makes your data virtually not reusable for any other purposes or formats.
You should always try to decouple your application layers and isolate responsibilities.
Your database query should just return the date/time information in the raw format.
Displaying the value in a specific way is a UI-specific requirement that in .NET you can solve using formatting functions (eg ToShortTimeString for a DateTime object).
DateTime t = <date/time form database query>
t.ToShortTimeString(); // or t.ToString("hh:mm");

Read a DateTime object in a different time zone

I have following scenario:
USA: database & application server
Europe: client
The server reads a date time (e.g. 12:00) object from the database and send it to a client in Europe. The problem is now, the client displays this date time in the time zone of the client (e.g. 18:00), but we need the time in the database, independent of the time zone of the server. On the client we don't know from which time zone this value is.
So how can we achieve this?
your tags tell the answer.
use the TimeZone Class.
http://msdn.microsoft.com/en-us/library/system.timezone.touniversaltime.aspx
also: Creating a DateTime in a specific Time Zone in c# fx 3.5
So in your DB, times should be UTC. from there you can do anything what you want.
Can't you simply use DateTime.ToUniversalTime()?
http://msdn.microsoft.com/en-us/library/system.datetime.touniversaltime.aspx
Alternatively, if you don't want UTC, you can find out the timezone of your server and do something like:
DateTime dt;
TimeZoneInfo timezone_EST =
TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime dt_EST = TimeZoneInfo.ConvertTime(dt, timezone_EST);
If you're storing the DateTime data in SQL 2008, take a look at new datetimeoffset type which will store timezone information as well as the date and time themselves

Categories

Resources