My colleague and I are at an impasse in a debate and other's input would be greatly appreciated.

We utilize the Service Locator Pattern and a common interface to abstract all of our data access so we can easily swap between different data sources as our needs change. Our calling code has no indication of where the data is being stored or how. It simply accesses the data via the service it is fed from the service registry.

The issue we are debating occurs when we have DateTime fields on an object and store it to a MongoDB datasource.

What I have noticed is that when we have an object in C# with a DateTime it appears as the correct time. When we log into our MongoDB server with MongoVUE to inspect the object it shows the correct time. But when we retrieve the object the DateTime is now in UTC. This obviously creates issues when comparing a DateTime in memory to one in an object that has been retrieved from the MongoDB data source.

I understand that Mongo stores DateTime internally as UTC time. I even understand why it might be returning UTC when you call it.

Here is where the debate begins.

It's been suggested that this is simply a cosmetic issue and only a problem when displaying dates. Thus we should simply call .ToLocalTime within the interface layer. I disagree and assert that this dangerously breaks the layers of abstraction we have created in implementing the Service Locator Pattern. It also raises questions regarding interaction with those date times as it pertains to triggering other events.

What I have read else where is that we should be storing our times as string, specifically as some standard of UTC format. In this manner the interface layer doesn't know or care how the DateTime is stored and neither does our object since every data source would store that string in the same manner.

I've had success with doing this using the ISO 1806 format but my colleague feels this is a 'hacky' fix and that using the .toLocalTime is the appropriate way to deal with this situation.

1 Answer
1

Why aren't you storing UTC in the DB in the first place? In most cases, DateTime should be stored in UTC, because it usually refers to a point in time. This is true for anything that refers to time in a physical sense, and anything that assumes that time is monotonic, increasing and unique, none of which are true for most local times.

Occasionally, using local times does make sense: suppose a bus leaves every day at 9am. This means that 24 hours pass between two consecutive events. However, if the time zone has a DST, it will be a 23h, respectively 25h interval once a year.

However, if you need to wrangle this kind of data, a simple DateTime doesn't do the trick; DST rules can change, timezones can change, etc. In C#, the DST rules that will be applied are the ones that are currently valid, even if the date is 'historic'. Date arithmetic with historic dates can thus wreak havoc. If you really need to cope with this, at the very least, you should store which timezone the time is in (not only the offset, or even just a isLocal flag).

Storing textual information in the database that can be stored binary doesn't seem very elegant to me, neither does changing the value in some middle layer. The former is inefficient and suffers from the previously mentioned peculiarities of local time, the latter only has the 2nd problem.

BTW, to accomplish the latter, you could decorate the property with [BsonDateTimeOptions(Kind=DateTimeKind.Local)], which will do the conversion for you, but suffers from the same problems, of course.

We discussed the further. It is not practical at the current time re-factor all DateTimes to be stored in UTC time. What we decided to do was mark fields with the prefix UTC which are critical in being explicit to a specific time zone. We ensure that the datetime object going in is UTC and mongo doesn't convert it since its already UTC. Then we know UTC is coming out as well. We've agreed to go back later if we refactor all our code and remove the UTC prefix. The prefixing is not pretty but it lets resolves our current problem and doesn't break abstraction.
–
TGardnerDec 9 '11 at 3:26

Why not run your server on UTC? No markers required. Business logic works more clearly and consistently with UTC times, and you can convert to local times where applicable. If your service is supposed to deliver information including local date formats, then convert them in the service layer logic. Sometimes you may want to operate on local times within your model layer also (if, for example, you need solve daylight savings problems). It is just like any other data transformation. It is necessary to have a point of reference and it does not have to break your design pattern.
–
Jordan MorrisJun 16 '13 at 9:00