Click here to Skip to main content
15,879,095 members
Articles / Database Development / SQL Server

Serializing System.DateTime for SQL Server

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
28 Aug 2010CPOL2 min read 16.8K   6  
Learn how to serialize System.DateTime for use in SQL Server stored procedures

If you need to pass an entire object to a SQL Server stored procedure, one of the ways is to serialize it to XML and parse it in the SP then. I’ve used this approach several times for saving hierarchical data objects (let’s say an Order with a list of OrderLine objects) into the database. I’m not going to talk about pros and cons of this method, but rather share a solution to passing System.DateTime values.

So, what’s the problem with DateTimes, you might ask? Let’s suppose we have a class that looks like that:

C#
public class MyClass
{
	public DateTime LocalDateTime
	{
		get;
		set;
	}
}

This class only exposes a single property that holds the local date and time. If we set it to DateTime.Now and serialize the whole object, the LocalDateTime value would look something like this:

2010-01-17T12:29:23.5561314+02:00

Now if you wanted to cast that string to DATETIME type in SQL Server (that’s what you do when you parse the serialized object’s XML inside a stored procedure), you would get an error message:

Conversion failed when converting datetime from character string.

After some playing, I found out that the string you try to cast must not have timezone information and only supports milliseconds. If you try to execute this statement:

SQL
select cast('2010-01-17T12:29:23.556' as DateTime)

... it will cast just fine. So, we need to get rid of the timezone information and cut the numbers to only milliseconds. The first one is easy. In you DateTime setter, use this code:

C#
localDateTime = DateTime.SpecifyKind(value, DateTimeKind.Utc);

This just makes the DateTime value a UTC time and that means that timezone is +00:00 and after serialization, the value will now turn to:

2010-01-17T12:29:23.5561314Z

This gives you the local time without timezone information. Don’t worry about the ‘Z’ at the end. It is perfectly fine for SQL Server. If you want to convert the time to UTC first, you’d use:

C#
utcDateTime = DateTime.SpecifyKind(value.ToUniversalTime(), DateTimeKind.Utc);

DateTime.ToUniversalTime() converts the DateTime value to universal time, the rest is the same.

We’re now left with the milliseconds issue. The numbers that appear after milliseconds are ticks. One tick is 10000 milliseconds, it’s the smallest unit of time. So we need to somehow cut the ticks information.

Since a millisecond is 10000 ticks, to drop the ticks portion of DateTime (to make it equal to 0), we can divide the ticks by 10000 and then multiply the result by 10000. Also, the System.DateTime struct gives us a handy constructor that takes the number of ticks and DateTimeKind value to construct the new DateTime. So we can use it like this:

C#
localDateTime = new DateTime(value.Ticks / 10000 * 10000, DateTimeKind.Utc);

... which, when serialized would make our value look like this:

2010-01-17T12:29:23.556Z

which is now perfect to use in SQL Server.

I’m not sure if it’s the fastest and best way to deal with the ticks part of the serialized output. However, if you need only date, you can use DateTime.Date conbined with DateTimeKind.Utc and the output would be exactly what you need for SQL Server, there would be no need to deal with the ticks.

Here’s the complete source code for test console application:

C#
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml.Serialization;
 
namespace DateTimeSerialization
{
	public class MyClass
	{
		private DateTime localDateTime;
		private DateTime utcDateTime;
 
		public DateTime LocalDateTime
		{
			get { return localDateTime; }
			set
			{
				localDateTime = new DateTime
				(value.Ticks / 10000 * 10000, DateTimeKind.Utc);
			}
		}
 
		public DateTime UtcDateTime
		{
			get { return utcDateTime; }
			set
			{
				long ticks = value.ToUniversalTime().Ticks / 
						10000 * 10000;
				utcDateTime = new DateTime(ticks, DateTimeKind.Utc);
			}
		}
	}
 
	class Program
	{
		static void Main(string[] args)
		{
			MyClass myClass = new MyClass();
 
			DateTime dateTime = DateTime.Now;
 
			myClass.LocalDateTime = dateTime;
			myClass.UtcDateTime = dateTime;
 
			StringBuilder builder = new StringBuilder();
			StringWriter writer = new StringWriter(builder);
 
			XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
			serializer.Serialize(writer, myClass);
 
			Console.WriteLine(builder.ToString());
			Console.Read();
		}
	}
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Lithuania Lithuania
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --