Friday, March 27, 2015

Get local DateTime from UTC DateTime in CRM

Hello All,
Few days back I was writing a CRM 2013 plugin for an integration project in CRM. Requirement involved passage of some DateTime fields from CRM to another system. The other system was expecting the local date and time values for its DateTime fields in a string format. In my plugin code, I was pulling some DateTime fields from different entities using LINQ and OrganizationServiceContext. As we all know that CRM SDK web services always return the DateTime fields in UTC format only, I was retrieving it using LINQ (directly into the REST request object) converting the UTC date time into a string format (because the REST request object had string data type). Now since I have the string UTC DateTime value, I needed the same to be converted into the local time of the user under which the plugin is executed.

Below are the simple steps for converting any DateTime fields in CRM from UTC to user’s local time:
  1. Retrieve the “timezonecode” from user’s settings for the user under whose context the plugin is executed.
  2. Use the “timezonecode” as well as the UTC DateTime you want to convert to create LocalTimeFromUtcTimeRequest request.
  3. Pass the request object created in Step 3 above to “Execute” method of CRM Service.
  4. Response object of type LocalTimeFromUtcTimeResponse will contain the local time within its “LocalTime” property.

Okay! I hear you, enough of the stories and theories. Let’s dive directly inside the code below to perform the desired action above.

Below two functions will help you convert the UTC DateTime to Local DateTime. I have added code comments as much as I can to make it quite self-explanatory. Still if you need any help feel free to drop your comment below and I will try my best to address it.

In Order to perform vice-a-versa operation use UtcTimeFromLocalTimeRequest/UtcTimeFromLocalTimeResponse instead of LocalTimeFromUtcTimeRequest/LocalTimeFromUtcTimeResponse with some simple substitutions.

/// <summary>
/// Convert UTC DateTime to Local DateTime
/// </summary>
/// <param name="utcDateTime">DateTime in UTC Format</param>
/// <param name="service">CRM Organization Service</param>
/// <returns>Local DateTime</returns>
public DateTime ConvertUtcDateToLocal(DateTime utcDateTime, IOrganizationService service)
{
   // Get the TimezoneCode for the user
   int? _timeZoneCode = RetrieveCurrentUsersTimezone(_serviceProxy);

   // Some quick error checking
   if (_timeZoneCode != -1 && !_timeZoneCode.HasValue)
       throw new InvalidPluginExecutionException("Retrieve TimeZoneCode Failed!");

   // Below line is required only if you have a DateTime value as a String.
   // Uncomment below line if required
   //DateTime utcCreatedOnDate = DateTime.SpecifyKind(Convert.ToDateTime(stringUtcDateTime), DateTimeKind.Utc);

   // Create the LocalTimeFromUtcTimeRequest object using TimeZoneCode
   var request = new LocalTimeFromUtcTimeRequest
   {
       TimeZoneCode = _timeZoneCode.Value,
       UtcTime = utcDateTime
   };

   // Execute the above request created and get the Response back
   var responseLocalDateTime = (LocalTimeFromUtcTimeResponse)_serviceProxy.Execute(request);

   // Some null checking for the response object
   if (null != responseLocalDateTime)
       throw new InvalidPluginExecutionException("LocalTimeFromUtcTimeRequest Failed!");

   // Retrieve LocalTime from the Response
   DateTime localDateTimeValue = responseLocalDateTime.LocalTime;

   // Return Local DateTime value
   return localDateTimeValue;
}

/// <summary>
/// Retreive Current User's Timezonecode
/// </summary>
/// <param name="service">OrganizationService</param>
/// <returns>TimeZoneCode or -1</returns>
public int RetrieveCurrentUsersTimezone(IOrganizationService service)
{
   // Create RetrieveMultiple Request for UserSettings
   var currentUserSettings = service.RetrieveMultiple(
       new QueryExpression("usersettings")
       {
           ColumnSet = new ColumnSet("localeid", "timezonecode"),
           Criteria = new FilterExpression
           {
               Conditions =
{
new ConditionExpression("systemuserid", ConditionOperator.EqualUserId)
}
           }
       }).Entities[0].ToEntity<Entity>();

   // Some (old school) null and error checking
   if (null != currentUserSettings && currentUserSettings.Attributes.Contains("timezonecode"))
   {
       // Convert timezonecode into Integer type
       return Convert.ToInt32(currentUserSettings.Attributes["timezonecode"]);
   }
   else
       return -1;
}

Hope you find this post helpful. Feel free to post your comments/suggestions.

Thank You! ☺