[This answer expands on the answer from @SeanFausett]
I wanted to have an ISO 8601 date that could have a "Z" on the and the web api function would receive it as a Utc Kind DateTime. But if there was not a "Z", I did not want the conversion.
I also needed to convert dates from incoming POST JSON payloads. The function below can support converting a string to a DateTime, DateTime?, DateTimeOffset, or DateTimeOffset?
It's handy to have dates parse the same way whether form a JSON post or URL parameter. Feel free to tailor the conversion to suit your needs.
//Register the two converters
var jSettings = new Newtonsoft.Json.JsonSerializerSettings()
jSettings.Converters.Add(new UtcDateTimeConverterJSON());
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = jSettings;
GlobalConfiguration.Configure(config =>
{
    TypeDescriptor.AddAttributes(typeof(DateTime), new TypeConverterAttribute(typeof(UtcDateTimeConverterURI)));
    WebApiConfig.Register(config);
}
//Date converter for URI parameters
public class UtcDateTimeConverterURI : DateTimeConverter
{
    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        if (value?.GetType() == typeof(string))
        {
            return StringToDate(typeof(DateTime), (string)value, Path: "URI parameter");
        }
        else
        {
            return base.ConvertFrom(context, culture, value);
        }
    }
    /// <summary>
    /// Convert String to DateTime, DateTime?, DateTimeOffset, or DateTimeOffset?<br />
    /// Used for incoming JSON objects and URI parameters
    /// </summary>
    /// <param name="targetType">The type (i.e. typeof(DateTime))</param>
    /// <param name="sDate">string representation of date to be converted</param>
    /// <param name="Path">JSON Path in case of error, so the caller knows which parameter to fix</param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public static object StringToDate(Type targetType, string sDate, string Path)
    {
        //if the object is a DateTime, determine if we need to return a UTC or Local date type
        bool returnUTC = false;
        //DateTime or DateTimeOffset return type
        bool isDateTimeOffset;
        if (targetType == typeof(DateTime?) || targetType == typeof(DateTime))
        {
            isDateTimeOffset = false;
        }
        else
        {
            isDateTimeOffset = true;
        }
        DateTimeOffset d;
        if (String.IsNullOrEmpty(sDate))
        {
            //if we have an empty string and the type is a nullable date, then return null... otherwise throw an error
            if (targetType == typeof(DateTime?))
            {
                return null;
            }
            else
            {
                throw new Exception(Path + " cannot be an empty Date");
            }
        }
        if (sDate[0] == '/')
        {
            // /Date(xxxxx)/ format
            sDate = sDate.Substring(6, sDate.Length - 8);
            var index = sDate.LastIndexOf('-');
            if (index == -1) index = sDate.LastIndexOf('+');
            if (index >= 0)
            {
                //lop off timezone offset
                sDate = sDate.Substring(0, index);
            }
            else
            {
                //no timezone offset, return as UTC
                returnUTC = true;
            }
            if (!Int64.TryParse(sDate, out var l))
            {
                //can't parse....
                throw new Exception(Path + " cannot be parsed as a Date");
            }
            else
            {
                d = DateTimeOffset.FromUnixTimeMilliseconds(l);
            }
        }
        else
        {
            //try and parse ISO8601 string
            if (!DateTimeOffset.TryParse(sDate, out d))
            {
                throw new Exception(Path + " cannot be parsed as a Date");
            }
            else
            {
                if (!isDateTimeOffset)
                {
                    //if UTC is specifically requested and we're not returning a DateTimeOffset, then make sure the return is UTC
                    if (d.Offset == TimeSpan.Zero && sDate[sDate.Length - 1] == 'Z') returnUTC = true;
                }
            }
        }
        if (isDateTimeOffset)
        {
            return d;
        }
        else
        {
            if (returnUTC)
            {
                return d.UtcDateTime;
            }
            else
            {
                //return the raw time passed in, forcing it to the "Local" Kind
                //for example:
                //"2020-03-27T12:00:00"       --> use 2020-03-27 12:00:00PM with Kind=Local
                //"2020-03-27T12:00:00-05:00" --> use 2020-03-27 12:00:00PM with Kind=Local
                return DateTime.SpecifyKind(d.DateTime, DateTimeKind.Local); //this will pull the raw time and force the Kind to "Local"
            }
        }
    }
}
//Date converter for JSON payloads
public class UtcDateTimeConverterJSON : DateTimeConverterBase
{
    public override bool CanRead
    {
        get
        {
            return true;
        }
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.Value == null || reader.TokenType == JsonToken.Date) return reader.Value;
        if (reader.TokenType != JsonToken.String) throw new Exception("Cannot parse Date");
    
        return UtcDateTimeConverterURI.StringToDate(objectType, (string)reader.Value, reader.Path);
    }
}