[CSHARP-80] Return Local DateTime by default Created: 22/Oct/10 Updated: 20/Mar/14 Resolved: 30/Oct/10 |
|
| Status: | Closed |
| Project: | C# Driver |
| Component/s: | None |
| Affects Version/s: | 0.5 |
| Fix Version/s: | 0.7 |
| Type: | New Feature | Priority: | Major - P3 |
| Reporter: | Robert Stam | Assignee: | Robert Stam |
| Resolution: | Done | Votes: | 1 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Description |
|
Moved from: http://github.com/mongodb/mongo-csharp-driver/issues#issue/4 What the most .Net developers expect is that they can save a DateTime.Now to database, load it and get back the correct value. Currently the driver returns UTC. Which forces the developers do always convert it to local date by hand which is very uncomfortable. MongoDB-CSharp solves that by automatically convert the date to a local date (means the timezone where i am in currently). But the developer is able to deactivate this by configuration. I think 95% of all developers are developing apps where they store dates only for the current timezone. |
| Comments |
| Comment by Robert Schooley [ 04/Dec/10 ] |
|
Not to put words into Testo's mouth, but I don't believe either of us were looking to change how the data is stored. Robert added the functionality to default to local time in the serialization process, however I am using the raw BsonDocuments, which doesn't support this feature. Not a big deal really. PS: Thanks Robert for walking me through the above. |
| Comment by Ian Mercer [ 04/Dec/10 ] |
|
Not that it affects the solution since the solution defaults to UTC but the original premise of this issue is at odds with database best practices. Most DateTimes can and should be stored in UTC and not local time because of the many issues that local time has (e.g. it goes backwards and repeats during DST changes) making it impossible to sort correctly for all times within a year. |
| Comment by Robert Stam [ 25/Nov/10 ] |
|
It's no problem to have an Id property of type string. You just have to assign the unique values yourself. I've modified the sample program at: https://gist.github.com/714723 to use a string Id. I also made the following changes: 1. Replaced AutoMap with explicit mapping (useful when you want total control) The "Unexpected element _id" issue should only show up in v0.7. Are you using the latest code from github? For the model you describe (Model has Bar which has a Baz) it will be serialized using embedded documents, where the embedded Bar has ALL the properties of Bar (and in turn the embedded Baz has all the properties of Baz). That's just how serialization of embedded objects is supposed to work. If that's now what you want, then you have to do something different. You could either: 1. Change your Model so that instead of having a Bar property you only have an Id for the Bar In the second case it will be rather challenging to read a Model back in because you will only have the Id and somehow you have to rehydrate the entire Bar object, so this may not even be possible. It's fine to use BsonDocument directly if that's what you want. But currently there is no control over how DateTime timezones are handled in a BsonDocument. That only applies to serialization of POCOs. Regarding timezones, I highly recommend that you store all your values in UTC. If your application ever has to run in multiple timezones you pretty much have to go with UTC as a common denominator. Even in a single timezone going with UTC in your database can save you from daylight saving time issues. |
| Comment by Robert Schooley [ 25/Nov/10 ] |
|
Thanks for the sample code. I have previously tried to go this route but ran into some issues: 1) My Id property does not know about the implementation type of ObjectId, it is a string. Is the proper setting: cm.MapIdProperty(c => c.Id); 2) Allowing automatic parsing and populating of objects has me a little concerned. I have added in more model classes, where Model has a Bar, and Bar can have a Baz, etc. When I save the Model class I get all of the Bar properties, even though they don't apply. For example take saving a Blog Post. I could have all the Posts be a nested collection inside of the User document, but let's say I don't and I have them as top level collections due to other design factors. When I save the Post, I want to add the User.Id property. I don't want the entire User object saved into the Post. There are properties for Roles, Password, Email, etc. These won't be populated in the case of saving the Post, but they would be sent to the database and be just hanging out in there effectively creating noise, or worse potentially stale data if the fields were populated. Using the BsonDocument directly has given me a lot of flexibility at the cost of a little development overhead. Am I misusing the library or just leaving a little convenience on the table? Back to the DateTime challenge, is it possible to have the date time default to local using the BsonDocument approach? I can't think of a use case where I want UTC so I can probably go into the source and modify the default there but I would prefer a way to just globally change this setting and not have to customize it for each DateTime property in every Model. Thanks. |
| Comment by Robert Stam [ 25/Nov/10 ] |
|
There is no need to convert your Model instances to and from BsonDocument. You can save and read instances of Model directly to the collection. I've modified your sample a bit to show what I mean: https://gist.github.com/714723 I made some other minor changes to get everything to work:
|
| Comment by Robert Schooley [ 24/Nov/10 ] |
|
Thanks for the reply. I tried this out and did not seem to get it to work. I forked your gist with an example of what I am trying to accomplish: |
| Comment by Robert Stam [ 21/Nov/10 ] |
|
Sure. For anything that can be done with attributes there should be an equivalent way to do it using initialization code alone for those who wish to keep persistence details out of their model. Here's a link to a gist of a sample program: https://gist.github.com/708380 The relevant lines are: public class Model { } var localTime = new DateTimeSerializationOptions { Kind = DateTimeKind.Local }; |
| Comment by Robert Schooley [ 21/Nov/10 ] |
|
Is there a way to do this without using an attribute on the model? My model is separate from my implementation. It does not have a reference to the persistence implementation at all. |
| Comment by Robert Stam [ 30/Oct/10 ] |
|
Added BsonDateTimeOptions attribute. Samples include: [BsonDateTimeOptions(Kind = DateTimeKind.Utc)] // the default // the following are for DateTime values intended to store only a Date value (so TimeOfDay component is zero) // the following specify that DateTime values should be stored as BsonType.String instead of BsonType.DateTime |
| Comment by Testo [ 28/Oct/10 ] |
|
would be nice if I can decorate DateTime property field with an attribute to specify the DateTimeKind i need |