2013-06-03 11 views
9

Ho un'implementazione Mongo C# che memorizza datetime come UTC.Memorizzazione di Utc e data/ora locale in Mongo

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); 

Ho anche bisogno di memorizzare il fuso orario locale dell'utente insieme all'ora UTC. Per spiegare, ho due proprietà che va come

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

mi piacerebbe memorizzare i tempi indiani/Altro australiani/americano/nella proprietà locale e il rispettivo valore UTC nell'altro. Poiché ho a che fare con dozzine di fusi orari, ho un codice che converte l'UTC nel fuso orario desiderato e lo memorizza nella proprietà WorkItemToCompleteByLocal. Vorrei che Mongo conservasse questo valore "così com'è" e me lo restituisse. Il problema è che Mongo lo memorizza sempre come ISODate e converte il valore nella versione di Utc. Per spiegare. Se UTC è 0730 ore ed io calcolare Brisbane Tempo di 1730Hours e impostarlo per WorkitemToCompleteByLocal, essi vengono salvati come

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

Mongo interpreta il tempo previsto come locali, server essendo in India e ripari a l'UTC equivalente di 1200 ore. Mentre recupera i valori indietro come 1730 (IST anche se) Elimina il mio scopo e mi impedisce di eseguire qualsiasi query basata su ora locale su Mongo. Sono senza idee. Qualsiasi aiuto è apprezzato per aiutare a memorizzare WorkItemToCompleteByLocal data 'As-Is' senza modifiche

+1

Ho trovato un lavoro ingannando il sistema rifondendo il fuso orario "Locale" come un UTC idratando un nuovo DateTime (Local.Year, Local.Month ......., Kind.Utc) e poi usando quel valore. Ora, i dati vengono archiviati così come sono e la mia logica sa che la colonna locale memorizza il valore locale indipendentemente da ciò che dice il genere (si dice UTC a causa del lavoro adottato). Lo userò fino a trovare una risposta migliore. –

+0

Ho aggiunto un articolo a JIRA di MongoDB su come gestire le ore locali, che si riferisce anche a questa voce SO (richiede un'iscrizione): https://jira.mongodb.org/browse/DOCS-4086 – akauppi

+0

Vedere http: //stackoverflow.com/a/38934986/194717 – Tony

risposta

2

Nuova versione del C# conducente =>

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); 
    } 
} 
21

Questo è il modo in cui impongo a MongoDB di memorizzare il valore non elaborato e di ignorare l'attributo DateTimeKind nell'oggetto DateTime.

Questo potrebbe non essere applicabile alla logica aziendale, ma ha senso per noi per le nostre particolari ragioni.

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); 
    } 
} 
+3

Non sembra trovare MongoDB.Bson.Serialization.IBsonSerializationOptions in 2.0.1 – Vaibhav

+1

Ottimo approccio. Anche se il driver C# rispetterebbe [BsonDateTimeOptions (Kind = DateTimeKind.Utc)], questa soluzione sarà migliore nella maggior parte dei casi di utilizzo dello sviluppo perché si applicherà globalmente e automaticamente a tutte le proprietà DateTime, piuttosto che dover specificare ciascuna e quindi avere bug quando inevitabilmente ne dimentichi uno. –

0

In conducente .NET versione 2.4, utilizzare questo: valori datetime

using MongoDB.Bson.Serialization; 
using MongoDB.Bson.Serialization.Serializers; 

BsonSerializer.RegisterSerializer(DateTimeSerializer.LocalInstance); 

questo modo verranno memorizzate con il genere = UTC in db, ma deserializzato in tipo locale.