Sunday, March 25, 2012

MSCRM 2011 using whole number time zone format for parsing date time sting C#

MSCRM 2011 using whole number time zone format for parsing date time sting


Multi-international companies, often needs to take care of time zone in date time fields coming from outer systems. It gets complicated when the time zone isn't part of the date time string.
In this example I've create new whole number attribute in time zone format named new_timezone.
I've used it for translating the date time string to the right UTC date time with taking care of the day light saving.


The Idea.
1) Getting the time zone code (int) from the time zone attribute (whole number - time zone format)
2) Getting the MSCRM TimeZoneDefinition entity matching the time zone code
3) Using the MSCRM TimeZoneDefinition for getting .net TimeZoneInfo (by comparing the standard name).
4) Parse the Date Time string to DateTimeOffset.
(Thanks http://stackoverflow.com/questions/5615538/parse-a-date-string-into-a-certain-timezone-supporting-daylight-saving-time for the method)
5) Update the relevant attribute with UTC date time.


The code (C# - originally used in plugin):

//accTemp = Is account entity with time zone attribute
//GetEntityByName = is function getting the matching entity by comparing attribute to a value


//Get timezone info from account
TimeZoneDefinition timeZoneTemp;
//accTemp.new_timezone
if (accTemp.new_timezone != null)
{
        Entity timeZoneEntityTemp = GetEntityByName(localContext.OrganizationService, TimeZoneDefinition.EntityLogicalName, "timezonecode", accTemp.new_timezone.Value.ToString());
         if (timeZoneEntityTemp != null)
        {
              timeZoneTemp = timeZoneEntityTemp.ToEntity<TimeZoneDefinition>();
         }
}


//parse the datetime by account timezone
TimeZoneInfo tz = GetTimeZoneInfoByStandardName(timeZoneTemp);
string dateString = String.Format("{0} {1}",  anyEntity.new_dateString,  anyEntity.new_timeString);
DateTimeOffset dtOffset = ReadStringWithTimeZone(dateString, tz);
DateTime  dt =  dtOffset  .UtcDateTime;

anyEntity.new_datetime= dt;


public TimeZoneInfo GetTimeZoneInfoByStandardName(TimeZoneDefinition timeZoneTemp)
        {
            var timezonesInfo = TimeZoneInfo.GetSystemTimeZones();
            foreach (var timezone in timezonesInfo)
            {
                if (timezone.StandardName == timeZoneTemp.StandardName)
                {
                    return timezone;
                }
            }
            throw new Exception(String.Format("Internal Exception: Fail to get TimezoneInfo: Standard Name = {0}, TimeZone Code = {1}", timeZoneTemp.StandardName, timeZoneTemp.TimeZoneCode));
        }

public DateTimeOffset ReadStringWithTimeZone(string EnteredDate, TimeZoneInfo tzi)
{
      try
     {
            DateTimeOffset cvUTCToTZI = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, tzi);
            DateTimeOffset cvParsedDate = DateTimeOffset.MinValue;
            DateTimeOffset.TryParse(EnteredDate + " " + cvUTCToTZI.ToString("zzz"), out cvParsedDate);
                if (tzi.SupportsDaylightSavingTime)
                {
                    TimeSpan getDiff = tzi.GetUtcOffset(cvParsedDate);
                    string MakeFinalOffset = (getDiff.Hours < 0 ? "-" : "+") + (getDiff.Hours > 9 ? "" : "0") + getDiff.Hours + ":" + (getDiff.Minutes > 9 ? "" : "0") + getDiff.Minutes;
                 DateTimeOffset.TryParse(EnteredDate + " " + MakeFinalOffset, out cvParsedDate);
                  return cvParsedDate;
                }
                else
                {
                    return cvParsedDate;
                }
       }
       catch(Exception ex)
       {
             throw new Exception(String.Format("Fail to parse date time: {0}", EnteredDate), ex);
       }
}

Hope it helps.


Any other ideas? Have better solution for the problem? Please share them...



Wednesday, March 21, 2012

Upgrade ISV folde code from mscrm 4.0 to mscrm 2011

This is the MSDN article "Upgrade Code in the ISV folder to Microsoft Dynamics CRM 2011"
It gives almost everything one needs for making sure his code runs on mscrm 2011.
But the one thing it doesn't mention, gave me hell today.
In multi organization deployment you need to include the organization name in the path to the isv folder.
for example:
in mscrm 4.0 the path was:
http://crm2011/isv/...
In 2011 the path needed is
http://crm2011/organization name/isv...
otherwise it tries to authenticate the user with the user's default organization which might be different then the one needed.

Thanks for
http://nishantrana.wordpress.com/2011/03/17/showing-a-custom-aspx-deployed-in-isv-in-iframe-of-crm-form-crm-2011/. Without it I would have kept struggling with the code upgrade for quite some time.

One last thing:
It is better to really upgrade the code in ISV folder into something that stands by its own like WebResource(HTML, Silverlight) or separate asp.net application with it's own application pool. The ISV folder is officially deprecated.