json 将 UTC DateTime 传递给 Web API HttpGet 方法导致本地时间
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22581138/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Passing UTC DateTime to Web API HttpGet Method results in local time
提问by Ryan
I'm trying to pass a UTC date as a query string parameter to a Web API method. The URL looks like
我正在尝试将 UTC 日期作为查询字符串参数传递给 Web API 方法。网址看起来像
/api/order?endDate=2014-04-01T00:00:00Z&zoneId=4
The signature of the method looks like
该方法的签名看起来像
[HttpGet]
public object Index(int zoneId, DateTime? endDate = null)
The date is coming in as 31/03/2014 8:00:00 PMbut I'd like it to come in as 01/04/2014 12:00:00 AM
日期即将到来,31/03/2014 8:00:00 PM但我希望它以01/04/2014 12:00:00 AM
My JsonFormatter.SerializerSettingslooks like this
我的JsonFormatter.SerializerSettings看起来像这样
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
DateFormatHandling = DateFormatHandling.IsoDateFormat
};
EDIT #1:
I've noticed when I POST 2014-04-01T00:00:00Zit will serialize to the UTC DateTime kind in C#. However I've found a work around of doing endDate.Value.ToUniversalTime()to convert it although I find it odd how it works for a POST but not a GET.
编辑#1:我注意到当我发布2014-04-01T00:00:00Z它时,它会序列化为 C# 中的 UTC DateTime 类型。但是,我找到了一种解决方法endDate.Value.ToUniversalTime()来转换它,尽管我发现它对 POST 而不是 GET 的工作方式很奇怪。
采纳答案by Badri
The query string parameter value you are sending 2014-04-01T00:00:00Zis UTC time. So, the same gets translated to a time based on your local clock and if you call ToUniversalTime(), it gets converted back to UTC.
您发送的查询字符串参数值为2014-04-01T00:00:00ZUTC 时间。因此,它会根据您的本地时钟转换为时间,如果您调用ToUniversalTime(),它会转换回 UTC。
So, what exactly is the question? If the question is why is this happening if sent in as query string but not when posted in request body, the answer to that question is that ASP.NET Web API binds the URI path, query string, etc using model bindingand the body using parameter binding. For latter, it uses a media formatter. If you send JSON, the JSON media formatter is used and it is based on JSON.NET.
那么,问题究竟是什么?如果问题是如果作为查询字符串发送而不是在请求正文中发布时为什么会发生这种情况,那么该问题的答案是 ASP.NET Web API 使用模型绑定和正文绑定 URI 路径、查询字符串等参数绑定。对于后者,它使用媒体格式化程序。如果您发送 JSON,则使用 JSON 媒体格式化程序,它基于 JSON.NET。
Since you have specified DateTimeZoneHandling.Utc, it uses that setting and you get the date time kind you want. BTW, if you change this setting to DateTimeZoneHandling.Local, then you will see the same behavior as model binding.
由于您已指定DateTimeZoneHandling.Utc,它使用该设置并获得您想要的日期时间类型。顺便说一句,如果您将此设置更改为DateTimeZoneHandling.Local,那么您将看到与模型绑定相同的行为。
回答by Sean Fausett
If you want the conversion to be transparent, then you could use a custom TypeConverter:
如果您希望转换是透明的,那么您可以使用自定义TypeConverter:
public sealed class UtcDateTimeConverter : DateTimeConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return ((DateTime)base.ConvertFrom(context, culture, value)).ToUniversalTime();
}
}
and wire it up using:
并使用以下方法将其连接起来:
TypeDescriptor.AddAttributes(typeof(DateTime), new TypeConverterAttribute(typeof(UtcDateTimeConverter)));
Then the query string parameter will be instantiated as DateTimeKind.Utc.
然后查询字符串参数将被实例化为DateTimeKind.Utc.
回答by Ryan
I ended up just using the ToUniversalTime()method as parameters come in.
我最终只是在ToUniversalTime()参数传入时使用该方法。
回答by Reginald Blue
So, for those of you who do not wish to override string-to-date conversion in your entire application, and also don't want to have to remember to modify every method that takes a date parameter, here's how you do it for a Web API project.
因此,对于那些不想在整个应用程序中覆盖字符串到日期转换的人,也不想记住修改每个接受日期参数的方法,以下是您如何为Web API 项目。
Ultimately, the general instructions come from here:
最终,一般说明来自这里:
Here's the specialized instructions for this case:
以下是此案例的专门说明:
In your "WebApiConfig" class, add the following:
var provider = new SimpleModelBinderProvider(typeof(DateTime),new UtcDateTimeModelBinder()); config.Services.Insert(typeof(ModelBinderProvider), 0, provider);Create a new class called 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; } }
在您的“WebApiConfig”类中,添加以下内容:
var provider = new SimpleModelBinderProvider(typeof(DateTime),new UtcDateTimeModelBinder()); config.Services.Insert(typeof(ModelBinderProvider), 0, provider);创建一个名为 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; } }
回答by mhKarami
I finally find this code , it's not the main answer but it can be used in some cases :
我终于找到了这段代码,它不是主要答案,但可以在某些情况下使用:
var dateUtc = TimeZoneInfo.ConvertTimeToUtc(date);

