将UTC DateTime传递给Web API HttpGet方法会产生本地时间

时间:2014-03-22 17:36:40

标签: json datetime asp.net-web-api model-binding

我试图将UTC日期作为查询字符串参数传递给Web API方法。 URL看起来像

/api/order?endDate=2014-04-01T00:00:00Z&zoneId=4

该方法的签名类似于

[HttpGet]
public object Index(int zoneId, DateTime? endDate = null)

日期以31/03/2014 8:00:00 PM开头,但我希望它以01/04/2014 12:00:00 AM

的形式进入

我的JsonFormatter.SerializerSettings看起来像这样

new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver(),
    DateTimeZoneHandling = DateTimeZoneHandling.Utc,
    DateFormatHandling = DateFormatHandling.IsoDateFormat
};

编辑#1: 我注意到在POST 2014-04-01T00:00:00Z时它会在C#中序列化为UTC DateTime类型。但是我发现了做endDate.Value.ToUniversalTime()转换它的工作,虽然我觉得奇怪的是它如何用于POST而不是GET。

6 个答案:

答案 0 :(得分:32)

您发送的查询字符串参数值2014-04-01T00:00:00Z是UTC时间。因此,相同的时间会转换为基于本地时钟的时间,如果您调用ToUniversalTime(),它将转换回UTC。

那么,究竟是什么问题?如果问题是为什么发生这种情况如果作为查询字符串发送而不是在请求正文中发布时,该问题的答案是ASP.NET Web API使用模型绑定<绑定URI路径,查询字符串等/ em>和使用参数绑定的正文。对于后者,它使用媒体格式化程序。如果发送JSON,则使用JSON媒体格式化程序,它基于JSON.NET。

由于您已指定DateTimeZoneHandling.Utc,因此它会使用该设置,您可以获得所需的日期时间。顺便说一句,如果您将此设置更改为DateTimeZoneHandling.Local,那么您将看到与模型绑定相同的行为。

答案 1 :(得分:26)

如果您希望转化是透明的,那么您可以使用自定义TypeConverter

public sealed class UtcDateTimeConverter : DateTimeConverter
{
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        return ((DateTime)base.ConvertFrom(context, culture, value)).ToUniversalTime();
    }
}

并使用以下方式将其连线:

TypeDescriptor.AddAttributes(typeof(DateTime), new TypeConverterAttribute(typeof(UtcDateTimeConverter)));

然后查询字符串参数将被实例化为DateTimeKind.Utc

答案 2 :(得分:13)

我最终只是使用ToUniversalTime()方法作为参数。

答案 3 :(得分:2)

因此,对于那些不想在整个应用程序中覆盖字符串到日期的转换并且又不想记住必须修改每个带有date参数的方法的人,这是您的工作方式它用于Web API项目。

最终,一般说明来自此处:

https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api#model-binders

这是此案的专门说明:

  1. 在“ WebApiConfig”类中,添加以下内容:

        var provider = new SimpleModelBinderProvider(typeof(DateTime),new UtcDateTimeModelBinder());
        config.Services.Insert(typeof(ModelBinderProvider), 0, provider);
    
  2. 创建一个名为UtcDateTimeModelBinder的新类:

    public class UtcDateTimeModelBinder : IModelBinder
    {
        public bool BindModel(HttpActionContext actionContext,
            ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType != typeof(DateTime)) return false;
    
            var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            if (val == null)
            {
                return false;
            }
    
            var key = val.RawValue as string;
            if (key == null)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName,
                    "Wrong value type");
                return false;
            }
    
            DateTime result;
            if (DateTime.TryParse(key, out result))
            {
                bindingContext.Model = result.ToUniversalTime();
                return true;
            }
    
            bindingContext.ModelState.AddModelError(bindingContext.ModelName,
                "Cannot convert value to Utc DateTime");
            return false;
        }
    }
    

答案 4 :(得分:0)

我终于找到了这段代码,它不是主要的答案,但是在某些情况下可以使用:

.node {
    background: white;
}

答案 5 :(得分:0)

日期时间偏移
我们的版本化 API 类是 automapped 内部类。在 API 的 URL 参数模型中使用 DateTimeOffset 并添加映射 DateTimeOffset => DateTime 可以有效防止时区转换
。即

API 类:

public DateTimeOffset? SomeDateTime{ get; set; }

内部类:

public DateTime? SomeDateTime{ get; set; }

映射配置文件:

CreateMap<DateTimeOffset, DateTime>();