Apr 12 2010

Take a byte out of time

Category: Tips and TricksJoeGeeky @ 00:01

Recently I was working on a custom transport and at some point I realized my payload had grown to an unacceptable size. After some analysis I discovered that DateTime structures represented the bulk of the problem. On reflection this was completely obvious since the default binary representation of a DateTime is a long (e.g. 8 bytes). This allows us to store date representations across just over 10,000 years.

Normal 8-Byte DateTime: ~10005 Years

In my case; and probably many of yours; I don't need to work with such a wide range of dates. This means I can shrink my dates by half and still have a sufficient range of dates to meet the needs of most applications. 

4-Byte DateTime: ~136 Years

To do this, we can take a lesson from the POSIX community which has been converting Unix Time to and from other formats for a long time. This is a simple pattern that allows us to reuse the built-in DateTime structures. What we need are methods to convert to and from our offset 4 byte representation.   

public static class TimeOffsetExtensions
{
    static readonly DateTime _timeReference = new DateTime(2010, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
 
    public static DateTime ToDateTime(this int timestamp)
    {
        return _timeReference.AddSeconds(timestamp);
    }
 
    public static uint ToOffsetTimestamp(this DateTime instance)
    {
        TimeSpan diff = instance - _timeReference;
        return (uint)Math.Floor(diff.TotalSeconds);
    }
}

One of the keys to this is setting a common time offset. Above you will see that I set my offset to start at 01/01/2010. As long as this never changes, then you can adjust this as needed to meet your particular requirements. With these methods in place we can apply them in reading/writing to transports, stores, or whatever. Here is an example of writing a DateTime in its short form:

DateTime time = DateTime.UtcNow;
 
byte[] offsetDateBytes;
 
using (var stream = new MemoryStream())
{
    using (var writer = new BinaryWriter(stream))
    {
        writer.Write(time.ToOffsetTimestamp());
    }
 
    offsetDateBytes = stream.ToArray();
}

Here is an example of reading the offset bytes back into a normal DateTime object:

DateTime recoveredDateTime;
 
using (var stream = new MemoryStream(offsetDateBytes))
{
    using (var reader = new BinaryReader(stream))
    {
        recoveredDateTime = reader.ReadInt32().ToDateTime();
    }
}

That's all there is to it... Apply this in good health. 

Tags: ,

Comments

1.
trackback DotNetKicks.com says:

Take a byte out of time

You've been kicked (a good thing) - Trackback from DotNetKicks.com

2.
Colon Cleanse Diet Colon Cleanse Diet United States says:

Stumbled into this site by chance but I’m sure glad I clicked on that link. You definitely answered all the questions I’ve been dying to answer for some time now.  Will definitely come back for more of this. Thank you so much

Comments are closed