You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ni...@apache.org on 2020/12/24 12:00:47 UTC
[ignite] branch master updated: IGNITE-12824 .NET: Add
BinaryConfiguration.TimestampConverter (#8568)
This is an automated email from the ASF dual-hosted git repository.
nizhikov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 76eda8d IGNITE-12824 .NET: Add BinaryConfiguration.TimestampConverter (#8568)
76eda8d is described below
commit 76eda8dba406754635599b0cea55bbffb4137efe
Author: Nikolay <ni...@apache.org>
AuthorDate: Thu Dec 24 15:00:16 2020 +0300
IGNITE-12824 .NET: Add BinaryConfiguration.TimestampConverter (#8568)
Co-authored-by: Pavel Tupitsyn <pt...@apache.org>
---
.../ignite/platform/PlatformDeployServiceTask.java | 20 ++
.../Binary/BinaryDateTimeTest.cs | 213 ++++++++++++++++++++-
.../Services/IJavaService.cs | 3 +
.../Services/JavaServiceDynamicProxy.cs | 6 +
.../Services/ServicesTest.cs | 49 +++++
.../Apache.Ignite.Core/Apache.Ignite.Core.csproj | 1 +
.../Binary/BinaryConfiguration.cs | 12 +-
.../Binary/ITimestampConverter.cs | 38 ++++
.../IgniteClientConfigurationSection.xsd | 12 ++
.../IgniteConfigurationSection.xsd | 12 ++
.../Apache.Ignite.Core/Impl/Binary/BinaryReader.cs | 8 +-
.../Impl/Binary/BinarySystemHandlers.cs | 25 ++-
.../Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs | 30 ++-
.../Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs | 8 +-
.../Apache.Ignite.Core/Impl/Binary/Marshaller.cs | 8 +
15 files changed, 412 insertions(+), 33 deletions(-)
diff --git a/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java b/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java
index cb3f8d7..688b3b1 100644
--- a/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java
+++ b/modules/core/src/test/java/org/apache/ignite/platform/PlatformDeployServiceTask.java
@@ -18,6 +18,8 @@
package org.apache.ignite.platform;
import java.sql.Timestamp;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
@@ -531,6 +533,24 @@ public class PlatformDeployServiceTask extends ComputeTaskAdapter<String, Object
}
/** */
+ public void testLocalDateFromCache() {
+ IgniteCache<Integer, Timestamp> cache = ignite.cache("net-dates");
+
+ ZoneId msk = ZoneId.of("Europe/Moscow");
+
+ //This Date in Europe/Moscow have offset +4.
+ Timestamp ts1 = new Timestamp(ZonedDateTime.of(1982, 4, 1, 1, 0, 0, 0, msk).toInstant().toEpochMilli());
+ //This Date in Europe/Moscow have offset +3.
+ Timestamp ts2 = new Timestamp(ZonedDateTime.of(1982, 3, 31, 22, 0, 0, 0, msk).toInstant().toEpochMilli());
+
+ assertEquals(ts1, cache.get(5));
+ assertEquals(ts2, cache.get(6));
+
+ cache.put(7, ts1);
+ cache.put(8, ts2);
+ }
+
+ /** */
public void sleep(long delayMs) {
try {
U.sleep(delayMs);
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDateTimeTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDateTimeTest.cs
index e971eea..9eae893 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDateTimeTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Binary/BinaryDateTimeTest.cs
@@ -21,6 +21,7 @@ namespace Apache.Ignite.Core.Tests.Binary
using System.Linq;
using Apache.Ignite.Core.Binary;
using Apache.Ignite.Core.Cache.Configuration;
+ using Apache.Ignite.Core.Impl.Binary;
using NUnit.Framework;
/// <summary>
@@ -28,6 +29,16 @@ namespace Apache.Ignite.Core.Tests.Binary
/// </summary>
public class BinaryDateTimeTest
{
+ /** */
+ internal const String FromErrMsg = "FromJavaTicks Error!";
+
+ /** */
+ internal const String ToErrMsg = "ToJavaTicks Error!";
+
+ /** */
+ private const String NotUtcDate =
+ "DateTime is not UTC. Only UTC DateTime can be used for interop with other platforms.";
+
/// <summary>
/// Sets up the test fixture.
/// </summary>
@@ -80,7 +91,7 @@ namespace Apache.Ignite.Core.Tests.Binary
.Select(x => x.Serializer)
.OfType<BinaryReflectiveSerializer>()
.Single();
-
+
Assert.IsTrue(ser.ForceTimestamp);
AssertTimestampField<DateTimeObj2>((o, d) => o.Value = d, o => o.Value, "Value");
@@ -111,6 +122,152 @@ namespace Apache.Ignite.Core.Tests.Binary
}
/// <summary>
+ /// Tests custom timestamp converter that modifies the values by adding one year on write and read.
+ /// This test verifies that actual converted values are used by Ignite.
+ /// </summary>
+ [Test]
+ public void TestAddYearTimestampConverter()
+ {
+ var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration())
+ {
+ AutoGenerateIgniteInstanceName = true,
+ BinaryConfiguration = new BinaryConfiguration
+ {
+ ForceTimestamp = true,
+ TimestampConverter = new AddYearTimestampConverter()
+ }
+ };
+
+ var ignite = Ignition.Start(cfg);
+
+ var dt = DateTime.UtcNow;
+ var expected = dt.AddYears(2);
+
+ // Key & value.
+ var cache = ignite.GetOrCreateCache<DateTime, DateTime>(TestUtils.TestName);
+ cache[dt] = dt;
+
+ var resEntry = cache.Single();
+
+ Assert.AreEqual(expected, resEntry.Key);
+ Assert.AreEqual(expected, resEntry.Value);
+
+ // Key & value array.
+
+ // Object field.
+ var cache2 = ignite.GetOrCreateCache<DateTimePropertyAttribute, DateTimePropertyAttribute>(
+ TestUtils.TestName);
+
+ cache2.RemoveAll();
+
+ var obj = new DateTimePropertyAttribute {Value = dt};
+ cache2[obj] = obj;
+
+ var resEntry2 = cache2.Single();
+ Assert.AreEqual(expected, resEntry2.Key.Value);
+ Assert.AreEqual(expected, resEntry2.Value.Value);
+
+ // Object array field.
+ var cache3 = ignite.GetOrCreateCache<DateTimeArr, DateTimeArr>(TestUtils.TestName);
+ cache3.RemoveAll();
+
+ var obj2 = new DateTimeArr {Value = new[]{dt}};
+ cache3[obj2] = obj2;
+ cache3[obj2] = obj2;
+
+ var resEntry3 = cache3.Single();
+ Assert.AreEqual(expected, resEntry3.Key.Value.Single());
+ Assert.AreEqual(expected, resEntry3.Value.Value.Single());
+ }
+
+ /// <summary>
+ /// Tests custom timestamp converter.
+ /// </summary>
+ [Test]
+ public void TestCustomTimestampConverter()
+ {
+ var cfg = new IgniteConfiguration(TestUtils.GetTestConfiguration(name: "ignite-1"))
+ {
+ BinaryConfiguration = new BinaryConfiguration
+ {
+ ForceTimestamp = true,
+ TimestampConverter = new TimestampConverter()
+ }
+ };
+
+ var ignite = Ignition.Start(cfg);
+ var binary = ignite.GetBinary();
+
+ // Check config.
+ Assert.NotNull(ignite.GetConfiguration().BinaryConfiguration.TimestampConverter);
+
+ AssertTimestampField<DateTimeObj2>((o, d) => o.Value = d, o => o.Value, "Value", ignite);
+
+ var dt1 = new DateTime(1997, 8, 29, 0, 0, 0, DateTimeKind.Utc);
+
+ var ex = Assert.Throws<BinaryObjectException>(() => binary.ToBinary<DateTime>(dt1));
+ Assert.AreEqual(ToErrMsg, ex.Message);
+
+ ex = Assert.Throws<BinaryObjectException>(() => binary.ToBinary<DateTime?[]>(new DateTime?[] {dt1}));
+ Assert.AreEqual(ToErrMsg, ex.Message);
+
+ var dt2 = new DateTime(1997, 8, 4, 0, 0, 0, DateTimeKind.Utc);
+
+ ex = Assert.Throws<BinaryObjectException>(() => binary.ToBinary<DateTime>(dt2));
+ Assert.AreEqual(FromErrMsg, ex.Message);
+
+ ex = Assert.Throws<BinaryObjectException>(() => binary.ToBinary<DateTime?[]>(new DateTime?[] {dt2}));
+ Assert.AreEqual(FromErrMsg, ex.Message);
+
+ var datesCache = ignite.CreateCache<DateTime, DateTime>("dates");
+
+ var check = new Action<DateTime, DateTime, String>((date1, date2, errMsg) =>
+ {
+ ex = Assert.Throws<BinaryObjectException>(() => datesCache.Put(date1, date2), "Timestamp fields should throw an error on non-UTC values");
+
+ Assert.AreEqual(errMsg, ex.Message);
+ });
+
+ check.Invoke(DateTime.Now, DateTime.UtcNow, NotUtcDate);
+ check.Invoke(DateTime.UtcNow, DateTime.Now, NotUtcDate);
+ check.Invoke(dt1, DateTime.UtcNow, ToErrMsg);
+ check.Invoke(DateTime.UtcNow, dt1, ToErrMsg);
+
+ var now = DateTime.UtcNow;
+
+ datesCache.Put(now, dt2);
+ ex = Assert.Throws<BinaryObjectException>(() => datesCache.Get(now), "Timestamp fields should throw an error on non-UTC values");
+ Assert.AreEqual(FromErrMsg, ex.Message);
+
+ datesCache.Put(now, now);
+ Assert.AreEqual(now, datesCache.Get(now));
+
+ var datesObjCache = ignite.CreateCache<DateTimeObj, DateTimeObj>("datesObj");
+
+ check = (date1, date2, errMsg) =>
+ {
+ ex = Assert.Throws<BinaryObjectException>(() => datesObjCache.Put(new DateTimeObj {Value = date1}, new DateTimeObj {Value = date2}),
+ "Timestamp fields should throw an error on non-UTC values");
+
+ Assert.AreEqual(errMsg, ex.Message);
+ };
+
+ check.Invoke(DateTime.Now, DateTime.UtcNow, NotUtcDate);
+ check.Invoke(DateTime.UtcNow, DateTime.Now, NotUtcDate);
+ check.Invoke(dt1, DateTime.UtcNow, ToErrMsg);
+ check.Invoke(DateTime.UtcNow, dt1, ToErrMsg);
+
+ var nowObj = new DateTimeObj {Value = now};
+
+ datesObjCache.Put(nowObj, new DateTimeObj {Value = dt2});
+ ex = Assert.Throws<BinaryObjectException>(() => datesObjCache.Get(nowObj), "Timestamp fields should throw an error on non-UTC values");
+ Assert.AreEqual(FromErrMsg, ex.Message);
+
+ datesObjCache.Put(nowObj, nowObj);
+ Assert.AreEqual(nowObj.Value, datesObjCache.Get(nowObj).Value);
+ }
+
+ /// <summary>
/// Asserts that specified field is serialized as DateTime object.
/// </summary>
private static void AssertDateTimeField<T>(Action<T, DateTime> setValue,
@@ -136,10 +293,10 @@ namespace Apache.Ignite.Core.Tests.Binary
/// Asserts that specified field is serialized as Timestamp.
/// </summary>
private static void AssertTimestampField<T>(Action<T, DateTime> setValue,
- Func<T, DateTime> getValue, string fieldName) where T : new()
+ Func<T, DateTime> getValue, string fieldName, IIgnite ignite = null) where T : new()
{
// Non-UTC DateTime throws.
- var binary = Ignition.GetIgnite().GetBinary();
+ var binary = ignite != null ? ignite.GetBinary() : Ignition.GetIgnite().GetBinary();
var obj = new T();
@@ -148,8 +305,7 @@ namespace Apache.Ignite.Core.Tests.Binary
var ex = Assert.Throws<BinaryObjectException>(() => binary.ToBinary<IBinaryObject>(obj),
"Timestamp fields should throw an error on non-UTC values");
- Assert.AreEqual("DateTime is not UTC. Only UTC DateTime can be used for interop with other platforms.",
- ex.Message);
+ Assert.AreEqual(NotUtcDate, ex.Message);
// UTC DateTime works.
setValue(obj, DateTime.UtcNow);
@@ -171,6 +327,11 @@ namespace Apache.Ignite.Core.Tests.Binary
public DateTime Value { get; set; }
}
+ private class DateTimeArr
+ {
+ public DateTime[] Value { get; set; }
+ }
+
private class DateTimePropertyAttribute
{
[Timestamp]
@@ -200,5 +361,47 @@ namespace Apache.Ignite.Core.Tests.Binary
{
public DateTime Value;
}
+
+ private class TimestampConverter : ITimestampConverter
+ {
+ /** <inheritdoc /> */
+ public void ToJavaTicks(DateTime date, out long high, out int low)
+ {
+ if (date.Year == 1997 && date.Month == 8 && date.Day == 29)
+ throw new BinaryObjectException(BinaryDateTimeTest.ToErrMsg);
+
+ BinaryUtils.ToJavaDate(date, out high, out low);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime FromJavaTicks(long high, int low)
+ {
+ var date = new DateTime(BinaryUtils.JavaDateTicks + high * TimeSpan.TicksPerMillisecond + low / 100,
+ DateTimeKind.Utc);
+
+ if (date.Year == 1997 && date.Month == 8 && date.Day == 4)
+ throw new BinaryObjectException(BinaryDateTimeTest.FromErrMsg);
+
+ return date;
+ }
+ }
+
+ private class AddYearTimestampConverter : ITimestampConverter
+ {
+ /** <inheritdoc /> */
+ public void ToJavaTicks(DateTime date, out long high, out int low)
+ {
+ BinaryUtils.ToJavaDate(date.AddYears(1), out high, out low);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime FromJavaTicks(long high, int low)
+ {
+ var date = new DateTime(BinaryUtils.JavaDateTicks + high * TimeSpan.TicksPerMillisecond + low / 100,
+ DateTimeKind.Utc);
+
+ return date.AddYears(1);
+ }
+ }
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs
index dfcaaff..07db779b 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/IJavaService.cs
@@ -187,6 +187,9 @@ namespace Apache.Ignite.Core.Tests.Services
void testUTCDateFromCache();
/** */
+ void testLocalDateFromCache();
+
+ /** */
void sleep(long delayMs);
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs
index 26c0637..4156602 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/JavaServiceDynamicProxy.cs
@@ -350,6 +350,12 @@ namespace Apache.Ignite.Core.Tests.Services
}
/** <inheritDoc /> */
+ public void testLocalDateFromCache()
+ {
+ _svc.testLocalDateFromCache();
+ }
+
+ /** <inheritDoc /> */
public void sleep(long delayMs)
{
_svc.sleep(delayMs);
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs
index b2748ae..682f651 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Services/ServicesTest.cs
@@ -27,6 +27,7 @@ namespace Apache.Ignite.Core.Tests.Services
using Apache.Ignite.Core.Cluster;
using Apache.Ignite.Core.Common;
using Apache.Ignite.Core.Impl;
+ using Apache.Ignite.Core.Impl.Binary;
using Apache.Ignite.Core.Resource;
using Apache.Ignite.Core.Services;
using NUnit.Framework;
@@ -973,6 +974,28 @@ namespace Apache.Ignite.Core.Tests.Services
Assert.AreEqual(dt1, cache.Get(3));
Assert.AreEqual(dt2, cache.Get(4));
+#if NETCOREAPP
+ //This Date in Europe/Moscow have offset +4.
+ DateTime dt3 = new DateTime(1982, 4, 1, 1, 0, 0, 0, DateTimeKind.Local);
+ //This Date in Europe/Moscow have offset +3.
+ DateTime dt4 = new DateTime(1982, 3, 31, 22, 0, 0, 0, DateTimeKind.Local);
+
+ cache.Put(5, dt3);
+ cache.Put(6, dt4);
+
+ Assert.AreEqual(dt3.ToUniversalTime(), cache.Get(5).ToUniversalTime());
+ Assert.AreEqual(dt4.ToUniversalTime(), cache.Get(6).ToUniversalTime());
+
+ svc.testLocalDateFromCache();
+
+ Assert.AreEqual(dt3, cache.Get(7).ToLocalTime());
+ Assert.AreEqual(dt4, cache.Get(8).ToLocalTime());
+
+ var now = DateTime.Now;
+ cache.Put(9, now);
+ Assert.AreEqual(now.ToUniversalTime(), cache.Get(9).ToUniversalTime());
+#endif
+
Services.Cancel(javaSvcName);
}
@@ -1157,6 +1180,9 @@ namespace Apache.Ignite.Core.Tests.Services
{
NameMapper = BinaryBasicNameMapper.SimpleNameInstance,
ForceTimestamp = true
+#if NETCOREAPP
+ , TimestampConverter = new TimestampConverter()
+#endif
}
};
}
@@ -1539,5 +1565,28 @@ namespace Apache.Ignite.Core.Tests.Services
/** */
public int Field { get; set; }
}
+
+#if NETCOREAPP
+ /// <summary>
+ /// Adds support of the local dates to the Ignite timestamp serialization.
+ /// </summary>
+ class TimestampConverter : ITimestampConverter
+ {
+ /** <inheritdoc /> */
+ public void ToJavaTicks(DateTime date, out long high, out int low)
+ {
+ if (date.Kind == DateTimeKind.Local)
+ date = date.ToUniversalTime();
+
+ BinaryUtils.ToJavaDate(date, out high, out low);
+ }
+
+ /** <inheritdoc /> */
+ public DateTime FromJavaTicks(long high, int low)
+ {
+ return new DateTime(BinaryUtils.JavaDateTicks + high * TimeSpan.TicksPerMillisecond + low / 100, DateTimeKind.Utc);
+ }
+ }
+#endif
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
index c315f08..55488ce 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj
@@ -52,6 +52,7 @@
<ItemGroup>
<Compile Include="Binary\BinaryBasicNameMapper.cs" />
<Compile Include="Binary\TimestampAttribute.cs" />
+ <Compile Include="Binary\ITimestampConverter.cs" />
<Compile Include="Cache\Affinity\IAffinityBackupFilter.cs" />
<Compile Include="Cache\Affinity\Rendezvous\ClusterNodeAttributeAffinityBackupFilter.cs" />
<Compile Include="Cache\Configuration\CacheKeyConfiguration.cs" />
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryConfiguration.cs
index 2a2bb95..b25a9f5 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/BinaryConfiguration.cs
@@ -79,6 +79,7 @@ namespace Apache.Ignite.Core.Binary
NameMapper = cfg.NameMapper;
KeepDeserialized = cfg.KeepDeserialized;
ForceTimestamp = cfg.ForceTimestamp;
+ TimestampConverter = cfg.TimestampConverter;
if (cfg.Serializer != null)
{
@@ -137,6 +138,15 @@ namespace Apache.Ignite.Core.Binary
public IBinarySerializer Serializer { get; set; }
/// <summary>
+ /// Gets or sets a converter between <see cref="DateTime"/> and Java Timestamp.
+ /// Called from <see cref="IBinaryWriter.WriteTimestamp"/>, <see cref="IBinaryWriter.WriteTimestampArray"/>,
+ /// <see cref="IBinaryReader.ReadTimestamp"/>, <see cref="IBinaryReader.ReadTimestampArray"/>.
+ /// <para />
+ /// See also <see cref="ForceTimestamp"/>.
+ /// </summary>
+ public ITimestampConverter TimestampConverter { get; set; }
+
+ /// <summary>
/// Default keep deserialized flag.
/// </summary>
[DefaultValue(DefaultKeepDeserialized)]
@@ -164,7 +174,7 @@ namespace Apache.Ignite.Core.Binary
/// should be written as a Timestamp.
/// <para />
/// Timestamp format is required for values used in SQL and for interoperation with other platforms.
- /// Only UTC values are supported in Timestamp format. Other values will cause an exception on write.
+ /// Only UTC values are supported in Timestamp format. Other values will cause an exception on write, unless <see cref="TimestampConverter"/> is provided.
/// <para />
/// Normally Ignite serializer uses <see cref="IBinaryWriter.WriteObject{T}"/> for DateTime fields,
/// keys and values.
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Binary/ITimestampConverter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/ITimestampConverter.cs
new file mode 100644
index 0000000..c760479
--- /dev/null
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Binary/ITimestampConverter.cs
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache.Ignite.Core.Binary
+{
+ using System;
+
+ /// <summary>
+ /// Converts <see cref="DateTime"/> values to Java Timestamp and back.
+ /// </summary>
+ public interface ITimestampConverter
+ {
+ /// <summary>Converts date to Java ticks.</summary>
+ /// <param name="date">Date</param>
+ /// <param name="high">High part (milliseconds).</param>
+ /// <param name="low">Low part (nanoseconds)</param>
+ void ToJavaTicks(DateTime date, out long high, out int low);
+
+ /// <summary>Converts date from Java ticks.</summary>
+ /// <param name="high">High part (milliseconds).</param>
+ /// <param name="low">Low part (nanoseconds)</param>
+ DateTime FromJavaTicks(long high, int low);
+ }
+}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteClientConfigurationSection.xsd b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteClientConfigurationSection.xsd
index 42aa56b..b610318 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteClientConfigurationSection.xsd
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteClientConfigurationSection.xsd
@@ -174,6 +174,18 @@
</xs:attribute>
</xs:complexType>
</xs:element>
+ <xs:element name="timestampConverter" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>Default date time converter.</xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="type" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Assembly-qualified type name.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
</xs:all>
<xs:attribute name="keepDeserialized" type="xs:boolean">
<xs:annotation>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
index 4bb0fef..a840d99 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
@@ -263,6 +263,18 @@
</xs:attribute>
</xs:complexType>
</xs:element>
+ <xs:element name="timestampConverter" minOccurs="0">
+ <xs:annotation>
+ <xs:documentation>Default date time converter.</xs:documentation>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="type" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>Assembly-qualified type name.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
</xs:all>
<xs:attribute name="keepDeserialized" type="xs:boolean">
<xs:annotation>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
index 9153046..c1a6fed 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryReader.cs
@@ -315,25 +315,25 @@ namespace Apache.Ignite.Core.Impl.Binary
/** <inheritdoc /> */
public DateTime? ReadTimestamp(string fieldName)
{
- return ReadField(fieldName, BinaryUtils.ReadTimestamp, BinaryTypeId.Timestamp);
+ return ReadField(fieldName, stream => BinaryUtils.ReadTimestamp(stream, _marsh.TimestampConverter), BinaryTypeId.Timestamp);
}
/** <inheritdoc /> */
public DateTime? ReadTimestamp()
{
- return Read(BinaryUtils.ReadTimestamp, BinaryTypeId.Timestamp);
+ return Read(stream => BinaryUtils.ReadTimestamp(stream, _marsh.TimestampConverter), BinaryTypeId.Timestamp);
}
/** <inheritdoc /> */
public DateTime?[] ReadTimestampArray(string fieldName)
{
- return ReadField(fieldName, BinaryUtils.ReadTimestampArray, BinaryTypeId.ArrayTimestamp);
+ return ReadField(fieldName, stream => BinaryUtils.ReadTimestampArray(stream, _marsh.TimestampConverter), BinaryTypeId.ArrayTimestamp);
}
/** <inheritdoc /> */
public DateTime?[] ReadTimestampArray()
{
- return Read(BinaryUtils.ReadTimestampArray, BinaryTypeId.ArrayTimestamp);
+ return Read(stream => BinaryUtils.ReadTimestampArray(stream, _marsh.TimestampConverter), BinaryTypeId.ArrayTimestamp);
}
/** <inheritdoc /> */
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
index 3ffb1f9..8fdf371 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinarySystemHandlers.cs
@@ -54,9 +54,6 @@ namespace Apache.Ignite.Core.Impl.Binary
ReadHandlers[BinaryTypeId.Double] = new BinarySystemReader<double>(s => s.ReadDouble());
ReadHandlers[BinaryTypeId.Decimal] = new BinarySystemReader<decimal?>(BinaryUtils.ReadDecimal);
- // 2. Date.
- ReadHandlers[BinaryTypeId.Timestamp] = new BinarySystemReader<DateTime?>(BinaryUtils.ReadTimestamp);
-
// 3. String.
ReadHandlers[BinaryTypeId.String] = new BinarySystemReader<string>(BinaryUtils.ReadString);
@@ -92,10 +89,6 @@ namespace Apache.Ignite.Core.Impl.Binary
ReadHandlers[BinaryTypeId.ArrayDecimal] =
new BinarySystemReader<decimal?[]>(BinaryUtils.ReadDecimalArray);
- // 6. Date array.
- ReadHandlers[BinaryTypeId.ArrayTimestamp] =
- new BinarySystemReader<DateTime?[]>(BinaryUtils.ReadTimestampArray);
-
// 7. String array.
ReadHandlers[BinaryTypeId.ArrayString] = new BinarySystemTypedArrayReader<string>();
@@ -258,6 +251,20 @@ namespace Apache.Ignite.Core.Impl.Binary
if (handler == null)
{
+ if (typeId == BinaryTypeId.Timestamp)
+ {
+ // Date.
+ res = TypeCaster<T>.Cast(BinaryUtils.ReadTimestamp(ctx.Stream, ctx.Marshaller.TimestampConverter));
+ return true;
+ }
+
+ if (typeId == BinaryTypeId.ArrayTimestamp)
+ {
+ // Date array.
+ res = TypeCaster<T>.Cast(BinaryUtils.ReadTimestampArray(ctx.Stream, ctx.Marshaller.TimestampConverter));
+ return true;
+ }
+
res = default(T);
return false;
}
@@ -311,7 +318,7 @@ namespace Apache.Ignite.Core.Impl.Binary
{
ctx.Stream.WriteByte(BinaryTypeId.Timestamp);
- BinaryUtils.WriteTimestamp(obj, ctx.Stream);
+ BinaryUtils.WriteTimestamp(obj, ctx.Stream, ctx.Marshaller.TimestampConverter);
}
/// <summary>
@@ -455,7 +462,7 @@ namespace Apache.Ignite.Core.Impl.Binary
{
ctx.Stream.WriteByte(BinaryTypeId.ArrayTimestamp);
- BinaryUtils.WriteTimestampArray(obj, ctx.Stream);
+ BinaryUtils.WriteTimestampArray(obj, ctx.Stream, ctx.Marshaller.TimestampConverter);
}
/// <summary>
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
index 5b30c7e..82e2284 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryUtils.cs
@@ -69,7 +69,7 @@ namespace Apache.Ignite.Core.Impl.Binary
public const int ObjTypeId = -1;
/** Ticks for Java epoch. */
- private static readonly long JavaDateTicks = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).Ticks;
+ public static readonly long JavaDateTicks = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).Ticks;
/** Binding flags for static search. */
private const BindingFlags BindFlagsStatic = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
@@ -388,13 +388,17 @@ namespace Apache.Ignite.Core.Impl.Binary
* <summary>Write date.</summary>
* <param name="val">Date.</param>
* <param name="stream">Stream.</param>
+ * <param name="converter">Timestamp Converter.</param>
*/
- public static void WriteTimestamp(DateTime val, IBinaryStream stream)
+ public static void WriteTimestamp(DateTime val, IBinaryStream stream, ITimestampConverter converter)
{
long high;
int low;
- ToJavaDate(val, out high, out low);
+ if (converter != null)
+ converter.ToJavaTicks(val, out high, out low);
+ else
+ ToJavaDate(val, out high, out low);
stream.WriteLong(high);
stream.WriteInt(low);
@@ -403,14 +407,18 @@ namespace Apache.Ignite.Core.Impl.Binary
/**
* <summary>Read date.</summary>
* <param name="stream">Stream.</param>
+ * <param name="converter">Timestamp Converter.</param>
* <returns>Date</returns>
*/
- public static DateTime? ReadTimestamp(IBinaryStream stream)
+ public static DateTime? ReadTimestamp(IBinaryStream stream, ITimestampConverter converter)
{
long high = stream.ReadLong();
int low = stream.ReadInt();
- return new DateTime(JavaDateTicks + high * TimeSpan.TicksPerMillisecond + low / 100, DateTimeKind.Utc);
+ if (converter != null)
+ return converter.FromJavaTicks(high, low);
+ else
+ return new DateTime(JavaDateTicks + high * TimeSpan.TicksPerMillisecond + low / 100, DateTimeKind.Utc);
}
/// <summary>
@@ -438,7 +446,8 @@ namespace Apache.Ignite.Core.Impl.Binary
/// </summary>
/// <param name="vals">Values.</param>
/// <param name="stream">Stream.</param>
- public static void WriteTimestampArray(DateTime?[] vals, IBinaryStream stream)
+ /// <param name="converter">Timestamp Converter.</param>
+ public static void WriteTimestampArray(DateTime?[] vals, IBinaryStream stream, ITimestampConverter converter)
{
stream.WriteInt(vals.Length);
@@ -448,7 +457,7 @@ namespace Apache.Ignite.Core.Impl.Binary
{
stream.WriteByte(BinaryTypeId.Timestamp);
- WriteTimestamp(val.Value, stream);
+ WriteTimestamp(val.Value, stream, converter);
}
else
stream.WriteByte(HdrNull);
@@ -1165,15 +1174,16 @@ namespace Apache.Ignite.Core.Impl.Binary
/// Read timestamp array.
/// </summary>
/// <param name="stream">Stream.</param>
+ /// <param name="converter">Timestamp Converter.</param>
/// <returns>Timestamp array.</returns>
- public static DateTime?[] ReadTimestampArray(IBinaryStream stream)
+ public static DateTime?[] ReadTimestampArray(IBinaryStream stream, ITimestampConverter converter)
{
int len = stream.ReadInt();
DateTime?[] vals = new DateTime?[len];
for (int i = 0; i < len; i++)
- vals[i] = stream.ReadByte() == HdrNull ? null : ReadTimestamp(stream);
+ vals[i] = stream.ReadByte() == HdrNull ? null : ReadTimestamp(stream, converter);
return vals;
}
@@ -1612,7 +1622,7 @@ namespace Apache.Ignite.Core.Impl.Binary
* <param name="high">High part (milliseconds).</param>
* <param name="low">Low part (nanoseconds)</param>
*/
- private static void ToJavaDate(DateTime date, out long high, out int low)
+ public static void ToJavaDate(DateTime date, out long high, out int low)
{
if (date.Kind != DateTimeKind.Utc)
{
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
index 9025b4d..a39bcd7 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/BinaryWriter.cs
@@ -657,7 +657,7 @@ namespace Apache.Ignite.Core.Impl.Binary
else
{
_stream.WriteByte(BinaryTypeId.Timestamp);
- BinaryUtils.WriteTimestamp(val.Value, _stream);
+ BinaryUtils.WriteTimestamp(val.Value, _stream, _marsh.TimestampConverter);
}
}
@@ -672,7 +672,7 @@ namespace Apache.Ignite.Core.Impl.Binary
else
{
_stream.WriteByte(BinaryTypeId.Timestamp);
- BinaryUtils.WriteTimestamp(val.Value, _stream);
+ BinaryUtils.WriteTimestamp(val.Value, _stream, _marsh.TimestampConverter);
}
}
@@ -690,7 +690,7 @@ namespace Apache.Ignite.Core.Impl.Binary
else
{
_stream.WriteByte(BinaryTypeId.ArrayTimestamp);
- BinaryUtils.WriteTimestampArray(val, _stream);
+ BinaryUtils.WriteTimestampArray(val, _stream, _marsh.TimestampConverter);
}
}
@@ -705,7 +705,7 @@ namespace Apache.Ignite.Core.Impl.Binary
else
{
_stream.WriteByte(BinaryTypeId.ArrayTimestamp);
- BinaryUtils.WriteTimestampArray(val, _stream);
+ BinaryUtils.WriteTimestampArray(val, _stream, _marsh.TimestampConverter);
}
}
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
index cc9aeff..76b9cbc 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Binary/Marshaller.cs
@@ -145,6 +145,14 @@ namespace Apache.Ignite.Core.Impl.Binary
}
/// <summary>
+ /// Gets date time converter.
+ /// </summary>
+ public ITimestampConverter TimestampConverter
+ {
+ get { return _cfg.TimestampConverter; }
+ }
+
+ /// <summary>
/// Marshal object.
/// </summary>
/// <param name="val">Value.</param>