diff --git a/NEW/src/JdeScoping.DataSync/Services/ParameterFormatConverter.cs b/NEW/src/JdeScoping.DataSync/Services/ParameterFormatConverter.cs new file mode 100644 index 0000000..f40a087 --- /dev/null +++ b/NEW/src/JdeScoping.DataSync/Services/ParameterFormatConverter.cs @@ -0,0 +1,79 @@ +namespace JdeScoping.DataSync.Services; + +/// +/// Converts parameter values to JDE-specific formats with timezone support. +/// +public class ParameterFormatConverter +{ + private readonly TimeZoneInfo _timezone; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The timezone to use for conversions. + /// Accepts "UTC", "LOCAL", or a valid timezone ID (e.g., "Eastern Standard Time"). + /// + public ParameterFormatConverter(string timezone) + { + _timezone = timezone.ToUpperInvariant() switch + { + "UTC" => TimeZoneInfo.Utc, + "LOCAL" => TimeZoneInfo.Local, + _ => TimeZoneInfo.FindSystemTimeZoneById(timezone) + }; + } + + /// + /// Converts a DateTime value to the specified format. + /// + /// The DateTime value to convert. + /// + /// The format to convert to. Supported formats: + /// - "jdejulian": JDE Julian date (CYYDDD format) + /// - "jdetime": JDE time (HHMMSS as integer) + /// - null: Returns the timezone-adjusted DateTime + /// + /// The converted value. + /// Thrown when an unknown format is specified. + public object Convert(DateTime value, string? format) + { + var adjusted = TimeZoneInfo.ConvertTime(value, _timezone); + + return format?.ToLowerInvariant() switch + { + "jdejulian" => ToJdeJulianDate(adjusted), + "jdetime" => ToJdeTime(adjusted), + null => adjusted, + _ => throw new ArgumentException($"Unknown format: {format}") + }; + } + + /// + /// Converts a DateTime to JDE Julian date format (CYYDDD). + /// + /// The date to convert. + /// + /// The JDE Julian date as an integer where: + /// - C is the century bit (0 for 1900s, 1 for 2000s) + /// - YY is the two-digit year + /// - DDD is the day of year (001-366) + /// + public static int ToJdeJulianDate(DateTime date) + { + int century = date.Year >= 2000 ? 1 : 0; + int year = date.Year % 100; + int dayOfYear = date.DayOfYear; + return century * 100000 + year * 1000 + dayOfYear; + } + + /// + /// Converts a DateTime to JDE time format (HHMMSS). + /// + /// The time to convert. + /// The JDE time as an integer in HHMMSS format. + public static int ToJdeTime(DateTime time) + { + return time.Hour * 10000 + time.Minute * 100 + time.Second; + } +} diff --git a/NEW/tests/JdeScoping.DataSync.Tests/Services/ParameterFormatConverterTests.cs b/NEW/tests/JdeScoping.DataSync.Tests/Services/ParameterFormatConverterTests.cs new file mode 100644 index 0000000..049fca9 --- /dev/null +++ b/NEW/tests/JdeScoping.DataSync.Tests/Services/ParameterFormatConverterTests.cs @@ -0,0 +1,148 @@ +using JdeScoping.DataSync.Services; +using Shouldly; + +namespace JdeScoping.DataSync.Tests.Services; + +public class ParameterFormatConverterTests +{ + [Fact] + public void ToJdeJulianDate_Year2024Day100_Returns124100() + { + var date = new DateTime(2024, 4, 9); // Day 100 + var result = ParameterFormatConverter.ToJdeJulianDate(date); + result.ShouldBe(124100); + } + + [Fact] + public void ToJdeJulianDate_Year1999Day365_Returns99365() + { + var date = new DateTime(1999, 12, 31); + var result = ParameterFormatConverter.ToJdeJulianDate(date); + result.ShouldBe(99365); + } + + [Fact] + public void ToJdeJulianDate_Year2000Day1_Returns100001() + { + // Year 2000 should have century bit = 1 + var date = new DateTime(2000, 1, 1); + var result = ParameterFormatConverter.ToJdeJulianDate(date); + result.ShouldBe(100001); + } + + [Fact] + public void ToJdeJulianDate_Year1998Day1_Returns98001() + { + // Year 1998 should have century bit = 0 + var date = new DateTime(1998, 1, 1); + var result = ParameterFormatConverter.ToJdeJulianDate(date); + result.ShouldBe(98001); + } + + [Fact] + public void ToJdeTime_143025_Returns143025() + { + var time = new DateTime(2024, 1, 1, 14, 30, 25); + var result = ParameterFormatConverter.ToJdeTime(time); + result.ShouldBe(143025); + } + + [Fact] + public void ToJdeTime_Midnight_Returns0() + { + var time = new DateTime(2024, 1, 1, 0, 0, 0); + var result = ParameterFormatConverter.ToJdeTime(time); + result.ShouldBe(0); + } + + [Fact] + public void ToJdeTime_235959_Returns235959() + { + var time = new DateTime(2024, 1, 1, 23, 59, 59); + var result = ParameterFormatConverter.ToJdeTime(time); + result.ShouldBe(235959); + } + + [Fact] + public void Convert_WithUtcTimezone_UsesUtc() + { + var converter = new ParameterFormatConverter("UTC"); + var utcTime = DateTime.SpecifyKind(new DateTime(2024, 4, 9, 12, 0, 0), DateTimeKind.Utc); + var result = converter.Convert(utcTime, "jdeJulian"); + result.ShouldBe(124100); + } + + [Fact] + public void Convert_WithJdeTimeFormat_ReturnsInteger() + { + var converter = new ParameterFormatConverter("UTC"); + var utcTime = DateTime.SpecifyKind(new DateTime(2024, 1, 1, 14, 30, 25), DateTimeKind.Utc); + var result = converter.Convert(utcTime, "jdetime"); + result.ShouldBe(143025); + } + + [Fact] + public void Convert_WithNullFormat_ReturnsAdjustedDateTime() + { + var converter = new ParameterFormatConverter("UTC"); + var utcTime = DateTime.SpecifyKind(new DateTime(2024, 4, 9, 12, 0, 0), DateTimeKind.Utc); + var result = converter.Convert(utcTime, null); + result.ShouldBeOfType(); + ((DateTime)result).ShouldBe(new DateTime(2024, 4, 9, 12, 0, 0)); + } + + [Fact] + public void Convert_WithUnknownFormat_ThrowsArgumentException() + { + var converter = new ParameterFormatConverter("UTC"); + var utcTime = DateTime.SpecifyKind(new DateTime(2024, 4, 9, 12, 0, 0), DateTimeKind.Utc); + Should.Throw(() => converter.Convert(utcTime, "unknown")); + } + + [Fact] + public void Constructor_WithLocalTimezone_Succeeds() + { + // Should not throw + var converter = new ParameterFormatConverter("LOCAL"); + converter.ShouldNotBeNull(); + } + + [Fact] + public void Constructor_WithUtcTimezone_Succeeds() + { + // Should not throw + var converter = new ParameterFormatConverter("UTC"); + converter.ShouldNotBeNull(); + } + + [Fact] + public void Convert_CaseInsensitiveFormat_ReturnsCorrectValue() + { + var converter = new ParameterFormatConverter("UTC"); + var utcTime = DateTime.SpecifyKind(new DateTime(2024, 4, 9, 12, 0, 0), DateTimeKind.Utc); + + // Test case insensitivity + var result1 = converter.Convert(utcTime, "JDEJULIAN"); + var result2 = converter.Convert(utcTime, "JdeJulian"); + var result3 = converter.Convert(utcTime, "jdejulian"); + + result1.ShouldBe(124100); + result2.ShouldBe(124100); + result3.ShouldBe(124100); + } + + [Fact] + public void Constructor_CaseInsensitiveTimezone_Succeeds() + { + // All these should work + var converter1 = new ParameterFormatConverter("utc"); + var converter2 = new ParameterFormatConverter("Utc"); + var converter3 = new ParameterFormatConverter("local"); + var converter4 = new ParameterFormatConverter("Local"); + + converter1.ShouldNotBeNull(); + converter2.ShouldNotBeNull(); + converter3.ShouldNotBeNull(); + converter4.ShouldNotBeNull(); + } +}