feat(datasync): add ParameterFormatConverter with JDE date/time support
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
namespace JdeScoping.DataSync.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Converts parameter values to JDE-specific formats with timezone support.
|
||||
/// </summary>
|
||||
public class ParameterFormatConverter
|
||||
{
|
||||
private readonly TimeZoneInfo _timezone;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ParameterFormatConverter"/> class.
|
||||
/// </summary>
|
||||
/// <param name="timezone">
|
||||
/// The timezone to use for conversions.
|
||||
/// Accepts "UTC", "LOCAL", or a valid timezone ID (e.g., "Eastern Standard Time").
|
||||
/// </param>
|
||||
public ParameterFormatConverter(string timezone)
|
||||
{
|
||||
_timezone = timezone.ToUpperInvariant() switch
|
||||
{
|
||||
"UTC" => TimeZoneInfo.Utc,
|
||||
"LOCAL" => TimeZoneInfo.Local,
|
||||
_ => TimeZoneInfo.FindSystemTimeZoneById(timezone)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a DateTime value to the specified format.
|
||||
/// </summary>
|
||||
/// <param name="value">The DateTime value to convert.</param>
|
||||
/// <param name="format">
|
||||
/// 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
|
||||
/// </param>
|
||||
/// <returns>The converted value.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when an unknown format is specified.</exception>
|
||||
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}")
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a DateTime to JDE Julian date format (CYYDDD).
|
||||
/// </summary>
|
||||
/// <param name="date">The date to convert.</param>
|
||||
/// <returns>
|
||||
/// 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)
|
||||
/// </returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a DateTime to JDE time format (HHMMSS).
|
||||
/// </summary>
|
||||
/// <param name="time">The time to convert.</param>
|
||||
/// <returns>The JDE time as an integer in HHMMSS format.</returns>
|
||||
public static int ToJdeTime(DateTime time)
|
||||
{
|
||||
return time.Hour * 10000 + time.Minute * 100 + time.Second;
|
||||
}
|
||||
}
|
||||
@@ -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>();
|
||||
((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<ArgumentException>(() => 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user