2016-08-26 1 views
0

Ich benutze java.sql.Timestamp 2014-12-27 00:00:00Java.util.Timestamp => Elasticsearch lang => C# NEST Datetime

und ElasticSearch speichert es als lange1419634800000 mit Mapping:

"EventDateLocal" : { 
    "type" : "long" 
} 

und ich möchte es in C# (via NEST) in lesen. System.DateTime

Ich versuchte

[Date(NumericResolution = NumericResolutionUnit.Milliseconds)] 
public DateTime? EventDateLocal { get; set; } 

aber ich habe:

Unhandled Exception: Elasticsearch.Net.UnexpectedElasticsearchClientException: U 
    nexpected token parsing date. Expected String, got Integer. 

....

Path 'hits.hits[0]._ 
     source.EventDateLocal', line 1, position 350. ---> Newtonsoft.Json.JsonSerializa 
     tionException: Unexpected token parsing date. Expected String, got Integer. Path 
     'hits.hits[0]._source.EventDateLocal', line 1, position 350. 
      at Newtonsoft.Json.Converters.IsoDateTimeConverter.ReadJson(JsonReader reader 
     , Type objectType, Object existingValue, JsonSerializer serializer) 
      at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConv 
     ertable(JsonConverter converter, JsonReader reader, Type objectType, Object exis 
     tingValue)... 

Was soll ich in Annotation setzen diesen Effekt automatisch zu erhalten (long + Unix => eventdate):

foreach (var e in request.Documents) 
{ 
    var start = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 
    var date = start.AddMilliseconds(e.EventDateLocal.Value).ToLocalTime(); 
} 

Mein NEST c Konfiguration ist:

var client = new ElasticClient(new ConnectionSettings(new Uri(url)) 
     .DefaultIndex(index) 
     .DefaultTypeNameInferrer(t => type) 
); 

Wenn nicht mit Annotation ist es irgendwie möglich, NEST über die lange zu erzählen?

client.Map<Event>(m => m 
    .AutoMap() 
    .Properties(ps => ps 
     .Date(e => e 
      .Name("EventDateLocal") 
      .Format(????) 
    ) 
) 
); 

Antwort

2

Der Standard Serializer von NEST verwendet, Json.NET, behandelt nicht Millisekunden seit der Epoche als serialisierte Form eines Datums (System.DateTime/System.DateTimeOffset). Wir können jedoch einen eigenen Konverter anwenden, entweder nur für diese Eigenschaften oder global.

Zunächst definieren Sie den Konverter

public class EpochDateTimeConverter : DateTimeConverterBase 
{ 
    private static readonly DateTime Epoch = new DateTime(1970,1,1,0,0,0,DateTimeKind.Utc); 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     if (value == null) 
     { 
      writer.WriteNull(); 
      return; 
     } 

     long millisecondsSinceEpoch; 
     if (value is DateTime) 
     { 
      millisecondsSinceEpoch = Convert.ToInt64((((DateTime)value).ToUniversalTime() - Epoch).TotalMilliseconds); 
     } 
     else 
     { 
      if (!(value is DateTimeOffset)) 
       throw new JsonSerializationException("Expected date object value."); 
      millisecondsSinceEpoch = Convert.ToInt64((((DateTimeOffset)value).ToUniversalTime().UtcDateTime - Epoch).TotalMilliseconds); 
     } 
     writer.WriteValue(millisecondsSinceEpoch); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.Null) 
     { 
      if (objectType != typeof(DateTime?) && objectType != typeof(DateTimeOffset?)) 
       throw new JsonSerializationException($"Cannot convert null value to {objectType}"); 

      return null; 
     } 
     if (reader.TokenType == JsonToken.Integer || reader.TokenType == JsonToken.Float) 
     { 
      var millisecondsSinceEpoch = (long)reader.Value; 
      var dateTime = Epoch.AddMilliseconds(millisecondsSinceEpoch); 
      if (objectType == typeof(DateTime) || objectType == typeof(DateTime?)) 
      { 
       return dateTime; 
      } 
      else 
      { 
       return new DateTimeOffset(dateTime); 
      } 
     } 

     throw new JsonSerializationException($"Cannot convert to DateTime or DateTimeOffset from token type {reader.TokenType}"); 
    } 
} 

Jetzt ist es auf Sie zutrifft Eigenschaften Poco

public class MyDocument 
{ 
    [JsonConverter(typeof(EpochDateTimeConverter))] 
    public DateTime DateTime { get; set;} 

    [JsonConverter(typeof(EpochDateTimeConverter))] 
    public DateTimeOffset DateTimeOffset { get; set; } 

    [JsonConverter(typeof(EpochDateTimeConverter))] 
    public DateTime? NullableDateTime { get; set; } 

    [JsonConverter(typeof(EpochDateTimeConverter))] 
    public DateTimeOffset? NullableDateTimeOffset { get; set; } 
} 

und testen Sie es

var client = new ElasticClient(); 

var document = new MyDocument 
{ 
    DateTime = new DateTime(2016, 8, 29, 9, 46, 0), 
    NullableDateTime = null, 
    DateTimeOffset = new DateTimeOffset(2016, 8, 29, 9, 46, 0, TimeSpan.Zero), 
    NullableDateTimeOffset = new DateTimeOffset(2016, 8, 29, 9, 46, 0, TimeSpan.Zero), 
}; 

client.Index(document); 

{ 
    "dateTime": 1472427960000, 
    "dateTimeOffset": 1472463960000, 
    "nullableDateTimeOffset": 1472463960000 
} 
serialisiert 10

NEST sendet standardmäßig keine null Werte, aber dies kann durch Hinzufügen von [JsonProperty(NullValueHandling = NullValueHandling.Include)] zu der betreffenden POCO-Eigenschaft geändert werden, wenn Sie wirklich senden möchten null.

Um Deserialisierung

var json = @"{ 
    ""dateTime"": 1472427960000, 
    ""dateTimeOffset"": 1472463960000, 
    ""nullableDateTimeOffset"": 1472463960000 
}"; 

MyDocument deserializedDocument = null; 
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) 
    deserializedDocument = client.Serializer.Deserialize<MyDocument>(stream); 

Note zu testen, die alle DateTime und DateTimeOffset Instanzen in UTC sind so wünschen können Ortszeit konvertieren zu ändern.

Verwandte Themen