MongoDB C# 驱动程序和 ISODate

7

我有一个通过的测试:

namespace MongoDateTest
{

    [TestFixture]
    public class DateTesting
    {
        public class TestEntity
        {
            public string Id { get; set; }
            public string StringTest { get; set; }
            public DateTime DateTest { get; set; }

        }
        [Test]
        public void MongoDateConversion()
        {
            const string connectionString = "mongodb://localhost";
            var client = new MongoClient(connectionString);
            var server = client.GetServer();
            var database = server.GetDatabase("test");
            var collection = database.GetCollection<TestEntity>("entities");
            var entity = new TestEntity { 
                   Id = "1", 
                   StringTest = "Test",
                   DateTest = new DateTime(2013, 10, 13) //this is the date
            };
            collection.Save(entity);
            var id = entity.Id;
            var query = Query<TestEntity>.EQ(e => e.Id, id);
            var entityNew = collection.FindOne(query);
            Assert.AreEqual(entityNew.Id, entity.Id);
            Assert.AreEqual(entity.StringTest, entityNew.StringTest);

            //Assert.AreEqual(entity.DateTest,entityNew.DateTest);
            // This gives one day error:
            //  Expected: 2013-10-13 00:00:00.000
            //  But was:  2013-10-12 22:00:00.000
            //Assert.AreEqual(entity.DateTest.ToLocalTime(),entityNew.DateTest.ToLocalTime());
            // This gives a 2 hours error.
            //   Expected: 2013-10-13 02:00:00.000
            //   But was:  2013-10-13 00:00:00.000
            Assert.AreEqual(entity.DateTest, entityNew.DateTest.ToLocalTime());
        }
    }
 }

如果我取消注释任何一个Asserts.AreEqual,我会得到一个错误(在下面已经注释)。

保存的实体是:

{
"_id" : "1",
"StringTest" : "Test",
"DateTest" : ISODate("2013-10-12T22:00:00Z")
 }

我知道这可能与ISODate和UTC有关(我在UTC+1时区),但我很烦恼我的日期保存在集合中的天数会少一天,这要求我每次获取带有日期数据的数据时都进行本地时间转换。请问这种行为的原因是什么,是否有方法可以避免?
2个回答

9

大多数情况下,您希望将UTC日期时间存储在数据库中,因此应构造DateTime:-

DateTest = new DateTime(2013, 10, 13, 0, 0, 0, DateTimeKind.Utc) //this is the date

你的第一个已经被注释的单元测试现在通过了。

如果不指定DateTimeKind,则会随机选择。 MongoDB似乎默认为本地时间并将其转换为UTC存储在数据库中。

请注意,MongoDB DateTime值比.NET DateTime值精度低。 如果您想存储任意的DateTime值,并以这样的方式获取它们以使它们仍然匹配,则需要在存储它们之前将它们四舍五入到最近的毫秒。

如果您确实想存储本地时间,我建议您从DateTime切换到DateTimeOffset,并将其序列化为UTC DateTime的长刻度值和偏移量的值。

请注意,除非您存储了获取DateTime值时计算出的偏移量,否则.NET方法转换为LocalTime基本上是无用的,因为它们不知道夏令时何时开始,也不知道DateTime值来自哪个区域。总体而言,.NET DateTime处理还有许多误导性的方法声称能帮助但实际上并没有。


谢谢!更大的问题已经解决。我尝试了这段代码,即使在两个小时的时间差中第一和第二个断言仍然无法通过,至少我得到了相同的日期...我知道 .Net 处理 DateTime 时会变得复杂,但在这种情况下,它似乎更像是 Mongodb 驱动程序的问题。对于基本的 CRUD 操作,我希望能够像在任何其他解决方案中一样获得我插入的内容。在这种情况下,我只想存储日期(不包括时间),将 ticks 存储为 long 类型会使直接在 mogodb shell 中查询集合变得复杂。 - Ronnie

3
您也可以在您的模型中执行此操作。 public class TestEntity
{
    public string Id { get; set; }

    public string StringTest { get; set; }

    [BsonDateTimeOptions(Kind = DateTimeKind.Utc)]
    public DateTime DateTest { get; set; }
}

1
这对我来说可以正确保存UTC日期。当执行查询时,[BsonDateTimeOptions(Kind = DateTimeKind.Local)]有助于将UTC日期转换为本地时间。无需额外的代码。 - Jipo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接