diff --git a/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiDate.cs b/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiDate.cs index 2d2a2ad9..956ffbb3 100644 --- a/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiDate.cs +++ b/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiDate.cs @@ -106,8 +106,8 @@ private DateOnly GetFromBinary(long value) case eTargetProjectPlatform.SIMATICAX: var valAx = value / 100; - return DateOnly.FromDateTime(DateTime.FromBinary(valAx).AddYears(1969)); - + return valAx.AdjustForLeapDate(); + default: var valdef = value / 100; return DateOnly.FromDateTime(DateTime.FromBinary(valdef).AddYears(1969)); @@ -128,8 +128,7 @@ private string GetFromDate(DateOnly date) { if (date <= MinValue) date = MinValue; - - var retval = date.ToDateTime(TimeOnly.MinValue) - MinValue.ToDateTime(TimeOnly.MinValue); + var retval = date.ToDateTime(TimeOnly.MinValue) - MinValue.ToDateTime(TimeOnly.MinValue); return (new DateTime().AddDays(retval.TotalDays).ToBinary() * 100).ToString(); } diff --git a/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiDateTime.cs b/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiDateTime.cs index b2466cc1..4d53a77e 100644 --- a/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiDateTime.cs +++ b/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiDateTime.cs @@ -138,7 +138,7 @@ private DateTime GetFromBinary(string value) private DateTime GetFromBinary(long val) { var dt = val / 100; - return DateTime.FromBinary(dt).AddYears(1969); + return dt.AdjustForLeapDateTime(); // DateTime.FromBinary(dt).AddYears(1969); } private string GetFromDate(DateTime dateTime) diff --git a/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiLDate.cs b/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiLDate.cs index 5333aa38..e4b18fe0 100644 --- a/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiLDate.cs +++ b/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiLDate.cs @@ -84,7 +84,7 @@ private DateOnly GetFromBinary(string value) private DateOnly GetFromBinary(long value) { var val = value / 100; - return DateOnly.FromDateTime(DateTime.FromBinary(val).AddYears(1969)); + return val.AdjustForLeapDate(); // DateOnly.FromDateTime(DateTime.FromBinary(val).AddYears(1969)); } private string GetFromDate(DateOnly date) diff --git a/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiLDateTime.cs b/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiLDateTime.cs index 426605ca..913f4115 100644 --- a/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiLDateTime.cs +++ b/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/BuiltInWrappers/WebApiLDateTime.cs @@ -84,7 +84,7 @@ private DateTime GetFromBinary(string value) private DateTime GetFromBinary(long val) { var dt = val / 100; - return DateTime.FromBinary(dt).AddYears(1969); + return dt.AdjustForLeapDateTime(); // DateTime.FromBinary(dt).AddYears(1969); } diff --git a/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/WebApiConnectorExtensions.cs b/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/WebApiConnectorExtensions.cs index d4ea6817..a58f9f66 100644 --- a/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/WebApiConnectorExtensions.cs +++ b/src/AXSharp.connectors/src/AXSharp.Connector.S71500.WebAPI/WebApiConnectorExtensions.cs @@ -54,4 +54,18 @@ public static ConnectorAdapter CreateWebApi(this ConnectorAdapterBuilder adapter return new ConnectorAdapter(typeof(WebApiConnectorFactory)) { Parameters = new object[] { ipAddress, userName, password, customServerCertHandler, platform, dbName } }; } + + public static DateOnly AdjustForLeapDate(this long value) + { + var noLeap = DateOnly.FromDateTime(DateTime.FromBinary(value).AddYears(1969)); + var leapDays = DateTime.IsLeapYear(noLeap.Year) && ((noLeap.Month == 2 && noLeap.Day == 29) || noLeap.Month >= 3) ? -1 : 0; + return noLeap.AddDays(leapDays); + } + + public static DateTime AdjustForLeapDateTime(this long value) + { + var noLeap = DateTime.FromBinary(value).AddYears(1969); + var leapDays = DateTime.IsLeapYear(noLeap.Year) && ((noLeap.Month == 2 && noLeap.Day == 29) || noLeap.Month >= 3) ? -1 : 0; + return noLeap.AddDays(leapDays); + } } \ No newline at end of file diff --git a/src/AXSharp.connectors/tests/AXSharp.Connector.Sax.WebAPITests/WebApiConnector/WebApiPrimitiveTests.cs b/src/AXSharp.connectors/tests/AXSharp.Connector.Sax.WebAPITests/WebApiConnector/WebApiPrimitiveTests.cs index 66013413..cfcbf2a0 100644 --- a/src/AXSharp.connectors/tests/AXSharp.Connector.Sax.WebAPITests/WebApiConnector/WebApiPrimitiveTests.cs +++ b/src/AXSharp.connectors/tests/AXSharp.Connector.Sax.WebAPITests/WebApiConnector/WebApiPrimitiveTests.cs @@ -167,6 +167,80 @@ public class WebApiDateTests : WebApiPrimitiveTests protected override DateOnly Max { get; } = WebApiDate.MaxValue; protected override DateOnly Mid { get; } = DateOnly.FromDateTime(DateTime.Today); protected override DateOnly Min { get; } = WebApiDate.MinValue; + + [Fact] + public virtual async void should_synchron_write_leap_value() + { + var expected = new DateOnly(2024, 3, 4); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive!.SetAsync(expected); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + [Fact] + public virtual async void should_synchron_write_no_leap_value() + { + var expected = new DateOnly(2023, 3, 4); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive!.SetAsync(expected); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + [Fact] + public virtual async void should_synchron_write_first_leap_day_value() + { + var expected = new DateOnly(2024, 2, 29); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive!.SetAsync(expected); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + [Fact] + public virtual async void should_write_cyclic_leap_value() + { + var expected = new DateOnly(2024, 3, 4); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive.SetAsync(Max); + webApiPrimitive!.Cyclic = expected; + webApiPrimitive!.AddToPeriodicQueue(); + await Task.Delay(WaitTimeForCyclicOperations); + Assert.Equal(expected, webApiPrimitive.Cyclic); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + + [Fact] + public virtual async void should_write_cyclic_no_leap_value() + { + var expected = new DateOnly(2023, 3, 4); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive.SetAsync(Max); + webApiPrimitive!.Cyclic = expected; + webApiPrimitive!.AddToPeriodicQueue(); + await Task.Delay(WaitTimeForCyclicOperations); + Assert.Equal(expected, webApiPrimitive.Cyclic); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + [Fact] + public virtual async void should_synchron_read_first_leap_day_value() + { + var primitive = Activator.CreateInstance(typeof(WebApiDate), Connector, "", "myDATE_leap_febr") as WebApiDate; + var expected = new DateOnly(2024, 2, 29); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + + Assert.Equal(expected, await primitive.GetAsync()); + } + + [Fact] + public virtual async void should_synchron_read_leap_day_value() + { + var primitive = Activator.CreateInstance(typeof(WebApiDate), Connector, "", "myDATE_leap_late") as WebApiDate; + var expected = new DateOnly(2024, 3, 5); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + + Assert.Equal(expected, await primitive.GetAsync()); + } } public class WebApiDateTimeTest : WebApiPrimitiveTests @@ -175,6 +249,80 @@ public class WebApiDateTimeTest : WebApiPrimitiveTests protected override DateTime Max { get; } = WebApiDateTime.MaxValue; protected override DateTime Mid { get; } = DateTime.Today; protected override DateTime Min { get; } = WebApiDateTime.MinValue; + + [Fact] + public virtual async void should_synchron_write_leap_value() + { + var expected = new DateTime(2024, 3, 4); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive!.SetAsync(expected); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + [Fact] + public virtual async void should_synchron_write_no_leap_value() + { + var expected = new DateTime(2023, 3, 4); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive!.SetAsync(expected); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + [Fact] + public virtual async void should_synchron_write_first_leap_day_value() + { + var expected = new DateTime(2024, 2, 29); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive!.SetAsync(expected); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + [Fact] + public virtual async void should_write_cyclic_leap_value() + { + var expected = new DateTime(2024, 3, 4); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive.SetAsync(Max); + webApiPrimitive!.Cyclic = expected; + webApiPrimitive!.AddToPeriodicQueue(); + await Task.Delay(WaitTimeForCyclicOperations); + Assert.Equal(expected, webApiPrimitive.Cyclic); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + + [Fact] + public virtual async void should_write_cyclic_no_leap_value() + { + var expected = new DateTime(2023, 3, 4); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive.SetAsync(Max); + webApiPrimitive!.Cyclic = expected; + webApiPrimitive!.AddToPeriodicQueue(); + await Task.Delay(WaitTimeForCyclicOperations); + Assert.Equal(expected, webApiPrimitive.Cyclic); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + [Fact] + public virtual async void should_synchron_read_first_leap_day_value() + { + var primitive = Activator.CreateInstance(typeof(WebApiDateTime), Connector, "", "myDATE_AND_TIME_leap_febr") as WebApiDateTime; + var expected = new DateTime(2024, 2, 29); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + + Assert.Equal(expected, await primitive.GetAsync()); + } + + [Fact] + public virtual async void should_synchron_read_leap_day_value() + { + var primitive = Activator.CreateInstance(typeof(WebApiDateTime), Connector, "", "myDATE_AND_TIME_leap_late") as WebApiDateTime; + var expected = new DateTime(2024, 3, 5); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + + Assert.Equal(expected, await primitive.GetAsync()); + } } public class WebApiDIntTest : WebApiPrimitiveTests @@ -489,6 +637,83 @@ public class WebApiLDateTests : WebApiPrimitiveTests protected override DateOnly Max { get; } = WebApiLDate.MaxValue; protected override DateOnly Mid { get; } = DateOnly.FromDateTime(DateTime.Today); protected override DateOnly Min { get; } = WebApiLDate.MinValue; + + [Fact] + public virtual async void should_synchron_write_leap_value() + { + var expected = new DateOnly(2024, 3, 4); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive!.SetAsync(expected); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + [Fact] + public virtual async void should_synchron_write_no_leap_value() + { + var expected = new DateOnly(2023, 3, 4); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive!.SetAsync(expected); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + [Fact] + public virtual async void should_synchron_write_first_leap_day_value() + { + var expected = new DateOnly(2024, 2, 29); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive!.SetAsync(expected); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + [Fact] + public virtual async void should_write_cyclic_leap_value() + { + var expected = new DateOnly(2024, 3, 4); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive.SetAsync(Max); + webApiPrimitive!.Cyclic = expected; + webApiPrimitive!.AddToPeriodicQueue(); + await Task.Delay(WaitTimeForCyclicOperations); + Assert.Equal(expected, webApiPrimitive.Cyclic); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + + [Fact] + public virtual async void should_write_cyclic_no_leap_value() + { + var expected = new DateOnly(2023, 3, 4); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + await webApiPrimitive.SetAsync(Max); + webApiPrimitive!.Cyclic = expected; + webApiPrimitive!.AddToPeriodicQueue(); + await Task.Delay(WaitTimeForCyclicOperations); + Assert.Equal(expected, webApiPrimitive.Cyclic); + Assert.Equal(expected, await webApiPrimitive.GetAsync()); + } + + [Fact] + public virtual async void should_synchron_read_first_leap_day_value() + { + var primitive = Activator.CreateInstance(typeof(WebApiDate), Connector, "", "myLDATE_leap_febr") as WebApiDate; + var expected = new DateOnly(2024, 2, 29); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + + Assert.Equal(expected, await primitive.GetAsync()); + } + + [Fact] + public virtual async void should_synchron_read_leap_day_value() + { + var primitive = Activator.CreateInstance(typeof(WebApiDate), Connector, "", "myLDATE_leap_late") as WebApiDate; + var expected = new DateOnly(2024, 3, 5); + TestConnector.TestApiConnector.ClearPeriodicReadSet(); + + Assert.Equal(expected, await primitive.GetAsync()); + } + + + } public class WebApiLDateTimeTest : WebApiPrimitiveTests @@ -497,6 +722,81 @@ public class WebApiLDateTimeTest : WebApiPrimitiveTests