XML Date, Convert to TimeZone

Dates are complicated no matter which language you use.  To solve some of our problems we save all dates as Universal time, typically using (DateTime.UtcNow).  Then when we display it we convert to a specific timezone.

For this specific project we save the Utc date as an XML string.  When we parse it out for display we read the date, convert to the proper timezone, then put it back in the XML be parsed for display. In this system we show all our dates as Central Standard Time.   We were doing a TryParse but got an error stating that the date was the wrong “Kind”.  Finally I hit on the right syntax and, as with so many other little tidbits, don’t want to lose it.


.......

XElement cElement = data.Element("CreatedDate");

cElement.ReplaceWith(GetDateFormattedCst(cElement, "{0:g} CST"));

.......
 private XElement GetDateFormattedCst(XElement element, string format)
    {
      if(element == null || element.IsEmpty)
         return null;
      XmlReader reader = element.CreateReader();
      reader.MoveToContent();
      string dateValue = reader.ReadInnerXml();

      DateTime dateTime;
      CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
      DateTimeStyles styles = DateTimeStyles.AdjustToUniversal;

      if (DateTime.TryParse(dateValue, culture, styles, out dateTime))
      {
        dateTime = dateTime.ToCentralStandardTime();
      }
      else
      {
        return null;
      }

      dateValue = String.Format(format, dateTime);
      dateValue = string.Format("<{0}>{1}</{0}>", element.Name, dateValue);

      return XElement.Parse(dateValue);
    }

Dynamically generate XML based on Class Properties

I recently came across a problem where I needed to dynamically generate data for a PDF file created using Adobe Livecycle Designer. Here are the main methods that I used to loop through the relevant classes and pull out the data for the file. I created a table in the DB containing a list of all the fields from the 3 main classes that need to be included in the XML data. This is done so that in the future we can add additional fields without needing to do a release to add them.

This method will return properly formed XML data that will then be attached to the PDF file. It generates the XML by looping through the PDF, Student, and Security object and retrieving the relevant data.

internal static string GetPDFDocXMLData(int pdfTemplateId, string studentId, SSO sso)
{
   var supportedFields = PDFDocData.GetListSupportedFields();
   using (var sdc = new StudentDataClient())
   using (var db = new DatabaseContainer())
   {
      var pdf = db.PDFForms.Single(f => f.Id == pdfTemplateId);
   
      FillSupportedFields("PDFTemplate", pdf, typeof(PDFForm), supportedFields);
      if (studentId != string.Empty)
      {
         var student = sdc.GetStudentInfo(Int32.Parse(studentId));
         FillSupportedFields("StudentInfo", student, typeof(StudentInfo), supportedFields);
      }
      FillSupportedFields("SSO", sso, typeof(SSO), supportedFields);
      return CreateXML(supportedFields);
   }
}

This method loops through all the properties in the indicated class object and loads any that match the list of valid supported fields. It adds the value of the field to the PDFDocData item.

private static void FillSupportedFields(string cName, object obj, IReflect type, IEnumerable<pdfdocdata> supportedFields)
{
   var props = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);

   foreach (var item in supportedFields.Where(sf => sf.ClassName == cName))
   {
      foreach (var propInfo in props.Where(f => f.Name == item.FieldName).ToList())
      {
         item.Value = propInfo.GetValue(obj, null).ToString();
      }
   }
}

This method generates the properly formed XML string that will be used.

private static string CreateXML(IEnumerable<pdfdocdata> supportedFields)
{
   var doc = new XmlDocument();

   var dec = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
   doc.AppendChild(dec);

   var root = doc.CreateElement("form1");
   doc.AppendChild(root);

   foreach (var item in supportedFields)
   {
      var element = doc.CreateElement(item.ClassName + item.FieldName);
      element.InnerText = item.Value;
      root.AppendChild(element);
   }
   return doc.OuterXml;
}

This class looks at the DataBase and pulls the list of supported fields and populates a list containing all the information about the fields except for the value which is populated in the FillSupportedFields method.

public class PDFDocData
{
   public string ClassName { get; set; }
   public string FieldName { get; set; }
   public string Description { get; set; }
   public string Value { get; set; }
   public static List<pdfdocdata> GetListSupportedFields()
   {
      using (var db = new DatabaseContainer())
      {
         return db.PDFSupportedFields.Select(s => new PDFDocData()
                                             {
                                                ClassName = s.ClassName,
                                                FieldName = s.FieldName,
                                                Description = s.Description
                                             }).ToList();
      }
   }
}