I would create a custom ICustomFormatter
to allow you to convert the datetime values. Then you can use it with any of the standard formatting methods available in NET.
Here's a simple example that seems to work for your 2 specific cases. Note that it relies on C# switch expressions. If you're using an older version of C# then you'll need to replace that with something equivalent like if
statements.
public class VariantCustomFormatter : IFormatProvider, ICustomFormatter
{
public string Format ( string? format, object? arg, IFormatProvider? formatProvider )
{
if (arg is DateTime dt)
{
switch (String.IsNullOrEmpty(format) ? default(char) : format[0])
{
case 'V': return HandleVariant1(dt);
case 'v': return HandleVariant2(dt);
default: return HandleOtherFormats(format, arg);
};
};
return HandleOtherFormats (format, arg);
}
public object? GetFormat ( Type? formatType )
{
if (formatType == typeof(ICustomFormatter))
return this;
return null;
}
private static string HandleVariant1 ( DateTime dt )
{
//YMD
//Month = A + (Month - 1)
//Day = 1-90A-...
//Year = A + (Year - 2017)
var yearCode = ((char)('A' + (dt.Year - 2017))).ToString();
var monthCode = ((char)('A' + (dt.Month - 1))).ToString();
//Using switch expression, if not supported then use IF
var dayCode = dt.Day switch {
< 10 => dt.Day.ToString(),
> 10 => (dt.Day - 1).ToString("X"),
_ => "0",
};
return yearCode + monthCode + dayCode;
}
private static string HandleVariant2 ( DateTime dt )
{
//YMDD
//Month = 1-9A-C
//Day = 1-31
//Year = -2025 = 1..9, 2026+ = A+
//Using switch expression, if not supported then use IF
var yearCode = dt.Year switch {
> 2025 => ((char)('A' + (dt.Year - 2026))).ToString(),
_ => (dt.Year - 2016).ToString(),
};
var monthCode = dt.Month switch {
<= 9 => dt.Month.ToString(),
_ => ((char)('A' + (dt.Month - 1))).ToString(),
};
var dayCode = dt.Day.ToString("00");
return yearCode + monthCode + dayCode;
}
private static string HandleOtherFormats ( string format, object arg )
{
if (arg is IFormattable)
return ((IFormattable)arg).ToString(format, CultureInfo.CurrentCulture);
return arg?.ToString() ?? "";
}
}
This code is not optimized. You'll need to make it production ready. Usage example.
var items = new [] {
DateTime.Parse("02/05/2025"),
DateTime.Parse("02/11/2025"),
};
foreach (var item in items)
{
var formatProvider = new VariantCustomFormatter();
Console.WriteLine(String.Format(formatProvider, "{0:V}", item));
Console.WriteLine(String.Format(formatProvider, "{0:v}", item));
}