This is more or less the same as others have suggested, but with an additional step to take the format string as a parameter in the attribute.
The formatter:
public class DateTimeFormatConverter : JsonConverter<DateTime>
{
private readonly string format;
public DateTimeFormatConverter(string format)
{
this.format = format;
}
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.ParseExact(
reader.GetString(),
this.format,
CultureInfo.InvariantCulture);
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
ArgumentNullException.ThrowIfNull(writer, nameof(writer));
writer.WriteStringValue(value
.ToUniversalTime()
.ToString(
this.format,
CultureInfo.InvariantCulture));
}
}
Since JsonConverterAttribute
is not sealed, we can do something like this:
public sealed class JsonDateTimeFormatAttribute : JsonConverterAttribute
{
private readonly string format;
public JsonDateTimeFormatAttribute(string format)
{
this.format = format;
}
public string Format => this.format;
public override JsonConverter? CreateConverter(Type typeToConvert)
{
return new DateTimeFormatConverter(this.format);
}
}