javascript 如何使 ASP.Net MVC 模型绑定器将传入日期视为 UTC?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10293440/
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
How to make ASP.Net MVC model binder treat incoming date as UTC?
提问by C.J.
I'm posting an object to an MVC controller. The object contains a field called StartDt and on the client it is a javascript Date object in local time.
我正在向 MVC 控制器发布一个对象。该对象包含一个名为 StartDt 的字段,在客户端它是本地时间的 javascript Date 对象。
When I call JSON.stringify on the object and POST it to the server using jQuery's ajax method I can see in Firebug that what's being sent to the server is an ISO string like "1900-12-31T13:00:00.000Z" which I believe should be the local time in UTC format.
当我在对象上调用 JSON.stringify 并使用 jQuery 的 ajax 方法将它发布到服务器时,我可以在 Firebug 中看到发送到服务器的内容是一个 ISO 字符串,如“1900-12-31T13:00:00.000Z”,我相信应该是UTC格式的本地时间。
When I look at the DateTime field in my controller though, it looks like its back to local time and not UTC. How can I fix this?
但是,当我查看控制器中的 DateTime 字段时,它看起来像是回到了本地时间而不是 UTC。我怎样才能解决这个问题?
I want to store the UTC version of the Date that came from the client.
我想存储来自客户端的日期的 UTC 版本。
采纳答案by Gautam Jain
You may have to use the DateTime.ToUniversalTime() method to get back the UTC time.
您可能必须使用 DateTime.ToUniversalTime() 方法来获取 UTC 时间。
回答by David Boike
I found a gist on Google with code for an ISO 8601compliant DateTime Model Binder, and then modified it like this:
我在 Google 上找到了符合ISO 8601 的DateTime Model Binder代码的要点,然后像这样修改它:
public class DateTimeBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var name = bindingContext.ModelName;
var value = bindingContext.ValueProvider.GetValue(name);
if (value == null)
return null;
DateTime date;
if (DateTime.TryParse(value.AttemptedValue, null, DateTimeStyles.RoundtripKind, out date))
return date;
else
return base.BindModel(controllerContext, bindingContext);
}
}
I believe the gist code is too restrictive - it wants 6 decimal places on seconds or it will not accept the timestamp. This uses TryParse instead of TryParseExact, so it will technically accept a LOT of timestamp types. The important part is that it uses the DateTimeStyles.RoundtripKind to respect the time zone implied by the Z. So this is no longer technically an ISO 8601 specific implementation.
我相信 gist 代码过于严格——它需要在秒内保留 6 个小数位,否则它不会接受时间戳。这使用 TryParse 而不是 TryParseExact,因此在技术上它将接受很多时间戳类型。重要的部分是它使用 DateTimeStyles.RoundtripKind 来尊重 Z 隐含的时区。所以这在技术上不再是 ISO 8601 特定的实现。
You could then hook this into the MVC pipeline with a model binder attribute or with this snippet in an App_Start:
然后,您可以使用模型绑定器属性或 App_Start 中的此代码段将其连接到 MVC 管道中:
var dateTimeBinder = new DateTimeBinder();
ModelBinders.Binders.Add(typeof(DateTime), dateTimeBinder);
ModelBinders.Binders.Add(typeof(DateTime?), dateTimeBinder);
回答by Matt Johnson-Pint
This problem persists in ASP.NET Core 2.0. The following code will resolve it, supporting ISO 8601 basic and extended formats, properly preserving the value and setting DateTimeKind
correctly. This aligns with the default behavior of JSON.Net's parsing, so it keeps your model binding behavior aligned with the rest of the system.
此问题在 ASP.NET Core 2.0 中仍然存在。以下代码将解决它,支持 ISO 8601 基本和扩展格式,正确保留值并DateTimeKind
正确设置。这与 JSON.Net 解析的默认行为一致,因此它使您的模型绑定行为与系统的其余部分保持一致。
First, add the following model binder:
首先,添加以下模型绑定器:
public class DateTimeModelBinder : IModelBinder
{
private static readonly string[] DateTimeFormats = { "yyyyMMdd'T'HHmmss.FFFFFFFK", "yyyy-MM-dd'T'HH:mm:ss.FFFFFFFK" };
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException(nameof(bindingContext));
var stringValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).FirstValue;
if (bindingContext.ModelType == typeof(DateTime?) && string.IsNullOrEmpty(stringValue))
{
bindingContext.Result = ModelBindingResult.Success(null);
return Task.CompletedTask;
}
bindingContext.Result = DateTime.TryParseExact(stringValue, DateTimeFormats,
CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var result)
? ModelBindingResult.Success(result)
: ModelBindingResult.Failed();
return Task.CompletedTask;
}
}
Then add the following model binder provider:
然后添加以下模型绑定器提供程序:
public class DateTimeModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (context.Metadata.ModelType != typeof(DateTime) &&
context.Metadata.ModelType != typeof(DateTime?))
return null;
return new BinderTypeModelBinder(typeof(DateTimeModelBinder));
}
}
Then register the provider in your Startup.cs
file:
然后在您的Startup.cs
文件中注册提供程序:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
...
options.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider());
...
}
}
回答by Sam
I created this little attribute.
我创建了这个小属性。
public class ConvertDateToUTCAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var dateArgs =
filterContext.ActionParameters.Where(
x => x.Value != null && x.Value.GetType().IsAssignableFrom(typeof(DateTime))).ToList();
foreach (var keyValuePair in dateArgs)
{
var date = (DateTime) keyValuePair.Value;
if (date.Kind == DateTimeKind.Local)
filterContext.ActionParameters[keyValuePair.Key] = date.ToUniversalTime();
}
base.OnActionExecuting(filterContext);
}
}
So this will leave dates that are Unspecified or already Utc alone. You can apply it the whole controller.
所以这将留下未指定或已经是 Utc 的日期。您可以将其应用于整个控制器。
回答by Bryan Johnson
Alternatively, you can specify your bound objects to be DateTimeOffset
rather than DateTime
, and there will be no automatic conversion. As long as the incoming string has the Z
suffix, you should get the original date with an offset of +00:00
.
或者,您可以将绑定对象指定为 ,DateTimeOffset
而不是DateTime
,并且不会自动转换。只要传入的字符串具有Z
后缀,您就应该获得偏移量为 的原始日期+00:00
。