【问题标题】:Storing Utc and Local datetime in Mongo在 Mongo 中存储 Utc 和本地日期时间
【发布时间】:2013-06-03 16:24:34
【问题描述】:

我有一个将日期时间存储为 UTC 的 Mongo C# 实现。

MongoDB.Bson.Serialization.Options.DateTimeSerializationOptions options = 
    MongoDB.Bson.Serialization.Options.DateTimeSerializationOptions.UtcInstance;

var serializer = 
    new MongoDB.Bson.Serialization.Serializers.DateTimeSerializer(options);

MongoDB.Bson.Serialization.BsonSerializer.RegisterSerializer(
    typeof(DateTime),
    serializer);

我还需要将用户本地时区与 UTC 一起存储。 解释一下,我有两个类似的属性

DateTime WorkItemToCompleteBy{get; set;}
[BsonDateTimeOptions(Kind = DateTimeKind.Unspecified)]
DateTime WorkItemToCompleteByLocal{get; set;}

我想将澳大利亚/美国/印度/其他时间存储在 Local 属性中,并将各自的 UTC 值存储在另一个属性中。由于要处理数十个时区,因此我有将 UTC 转换为所需时区并将其存储在 WorkItemToCompleteByLocal 属性中的代码。 我希望 Mongo 将这个值“原样”存储并返回给我。问题是 Mongo 总是将其存储为 ISODate 并将值转换为 Utc 版本。 解释。 如果 UTC 为 0730 小时,我将布里斯班时间计算为 1730 小时并将其设置为 WorkitemToCompleteByLocal, 他们被保存为

"WorkItemToCompleteBy" : ISODate("2013-06-05T07:30:00Z"),
"WorkItemToCompleteByLocal" : ISODate("2013-06-05T12:00:00Z"),

Mongo 将提供的时间解释为本地时间,服务器位于印度,并将其转换为 1200 小时的等效 UTC。虽然它将值检索为 1730 (IST Albeit),但它违背了我的目的,并阻止我在 Mongo 上运行任何基于本地时间的查询。我没有想法。感谢您提供任何帮助以帮助将 WorkItemToCompleteByLocal 日期“按原样”存储而无需修改

【问题讨论】:

  • 我找到了一种解决方法,方法是通过水合新的 DateTime(Local.Year,Local.Month......., Kind. Utc) 然后使用该值。现在,数据按原样存储,我的逻辑知道 Local 列存储本地值,而不管类型如何(它说 UTC,因为采用了解决方法)。在找到更好的答案之前,我会一直使用它。
  • 我在 MongoDB 的 JIRA 中添加了一个关于处理当地时间的项目,这也指的是这个 SO 条目(需要注册):jira.mongodb.org/browse/DOCS-4086

标签: c# mongodb datetime isodate


【解决方案1】:

这是我强制 MongoDB 存储原始值并忽略 DateTime 对象中的 DateTimeKind 属性的方式。

这可能不适用于您的业务逻辑,但由于我们的特殊原因对我们有意义。

BsonSerializer.RegisterSerializer(typeof(DateTime), new MyMongoDBDateTimeSerializer());


public class MyMongoDBDateTimeSerializer : DateTimeSerializer
{
    //  MongoDB returns datetime as DateTimeKind.Utc, which cann't be used in our timezone conversion logic
    //  We overwrite it to be DateTimeKind.Unspecified
    public override object Deserialize(MongoDB.Bson.IO.BsonReader bsonReader, System.Type nominalType, MongoDB.Bson.Serialization.IBsonSerializationOptions options)
    {
        var obj = base.Deserialize(bsonReader, nominalType, options);
        var dt = (DateTime) obj;
        return new DateTime(dt.Ticks, DateTimeKind.Unspecified);
    }

    //  MongoDB returns datetime as DateTimeKind.Utc, which cann't be used in our timezone conversion logic
    //  We overwrite it to be DateTimeKind.Unspecified
    public override object Deserialize(MongoDB.Bson.IO.BsonReader bsonReader, Type nominalType, Type actualType, MongoDB.Bson.Serialization.IBsonSerializationOptions options)
    {
        var obj = base.Deserialize(bsonReader, nominalType, actualType, options);
        var dt = (DateTime)obj;
        return new DateTime(dt.Ticks, DateTimeKind.Unspecified);
    }

    //  MongoDB stores all datetime as Utc, any datetime value DateTimeKind is not DateTimeKind.Utc, will be converted to Utc first
    //  We overwrite it to be DateTimeKind.Utc, becasue we want to preserve the raw value
    public override void Serialize(MongoDB.Bson.IO.BsonWriter bsonWriter, System.Type nominalType, object value, MongoDB.Bson.Serialization.IBsonSerializationOptions options)
    {
        var dt = (DateTime) value;
        var utcValue = new DateTime(dt.Ticks, DateTimeKind.Utc);
        base.Serialize(bsonWriter, nominalType, utcValue, options);
    }
}

【讨论】:

  • 在 2.0.1 中似乎找不到 MongoDB.Bson.Serialization.IBsonSerializationOptions
  • 很棒的方法。即使 C# 驱动程序会遵守 [BsonDateTimeOptions(Kind = DateTimeKind.Utc)],这种解决方案在大多数开发用例中也会更好,因为它将全局自动应用到所有 DateTime 属性,而不是必须指定每个属性然后再使用当你不可避免地忘记一个错误时。
【解决方案2】:

新版C#驱动=>

    public class MyMongoDBDateTimeSerializer : DateTimeSerializer
{
    //  MongoDB returns datetime as DateTimeKind.Utc, which cann't be used in our timezone conversion logic
    //  We overwrite it to be DateTimeKind.Unspecified
    public override DateTime Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        var obj = base.Deserialize(context, args);
        return new DateTime(obj.Ticks, DateTimeKind.Unspecified);
    }

    //  MongoDB stores all datetime as Utc, any datetime value DateTimeKind is not DateTimeKind.Utc, will be converted to Utc first
    //  We overwrite it to be DateTimeKind.Utc, becasue we want to preserve the raw value
    public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, DateTime value)
    {
        var utcValue = new DateTime(value.Ticks, DateTimeKind.Utc);
        base.Serialize(context, args, utcValue);
    }
}

【讨论】:

    【解决方案3】:

    在 .net 驱动程序 2.4 版中,使用这个:

    using MongoDB.Bson.Serialization;
    using MongoDB.Bson.Serialization.Serializers;
    
    BsonSerializer.RegisterSerializer(DateTimeSerializer.LocalInstance);
    

    这种方式日期时间值将以 kind=utc 形式存储在 db 中,但以本地类型反序列化。

    【讨论】:

    猜你喜欢
    • 2011-06-06
    • 2012-10-29
    • 2016-10-04
    • 1970-01-01
    • 2013-07-09
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多