Java.util.Timestamp => ElasticSearch long => C# NEST DateTime
Java.util.Timestamp => ElasticSearch long => C# NEST DateTime
我用java.sql.Timestamp
2014-12-27 00:00:00
和 ElasticSearch
将其保存为 long 1419634800000
并映射:
"EventDateLocal" : {
"type" : "long"
}
我想在 System.DateTime
中用 C#(通过 NEST)阅读它
我试过了
[Date(NumericResolution = NumericResolutionUnit.Milliseconds)]
public DateTime? EventDateLocal { get; set; }
但我得到了:
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)...
我应该在注释中输入什么才能自动获得此效果(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();
}
我的 NEST 配置是:
var client = new ElasticClient(new ConnectionSettings(new Uri(url))
.DefaultIndex(index)
.DefaultTypeNameInferrer(t => type)
);
如果没有注释,是否可以通过某种方式告诉 NEST 长?
client.Map<Event>(m => m
.AutoMap()
.Properties(ps => ps
.Date(e => e
.Name("EventDateLocal")
.Format(????)
)
)
);
NEST 使用的默认序列化程序 Json.NET 不会将纪元以来的毫秒数作为日期的序列化形式处理 (System.DateTime
/System.DateTimeOffset
)。然而,我们可以应用我们自己的转换器来处理这个问题,无论是针对这些属性还是全局。
首先,定义转换器
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}");
}
}
现在将其应用于您的 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; }
}
并测试它
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
}
NEST 默认不发送 null
值,但如果您真的想发送 null
.
测试反序列化
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);
请注意,所有 DateTime
和 DateTimeOffset
实例均采用 UTC,因此可能需要修改以转换为本地时间。
我用java.sql.Timestamp
2014-12-27 00:00:00
和 ElasticSearch
将其保存为 long 1419634800000
并映射:
"EventDateLocal" : {
"type" : "long"
}
我想在 System.DateTime
中用 C#(通过 NEST)阅读它我试过了
[Date(NumericResolution = NumericResolutionUnit.Milliseconds)]
public DateTime? EventDateLocal { get; set; }
但我得到了:
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)...
我应该在注释中输入什么才能自动获得此效果(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();
}
我的 NEST 配置是:
var client = new ElasticClient(new ConnectionSettings(new Uri(url))
.DefaultIndex(index)
.DefaultTypeNameInferrer(t => type)
);
如果没有注释,是否可以通过某种方式告诉 NEST 长?
client.Map<Event>(m => m
.AutoMap()
.Properties(ps => ps
.Date(e => e
.Name("EventDateLocal")
.Format(????)
)
)
);
NEST 使用的默认序列化程序 Json.NET 不会将纪元以来的毫秒数作为日期的序列化形式处理 (System.DateTime
/System.DateTimeOffset
)。然而,我们可以应用我们自己的转换器来处理这个问题,无论是针对这些属性还是全局。
首先,定义转换器
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}");
}
}
现在将其应用于您的 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; }
}
并测试它
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
}
NEST 默认不发送 null
值,但如果您真的想发送 null
.
测试反序列化
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);
请注意,所有 DateTime
和 DateTimeOffset
实例均采用 UTC,因此可能需要修改以转换为本地时间。