为仅限日期的 DateTime 处理客户端和服务器之间的时区

Handling time-zone between client and server for date-only DateTime

我的 ASP.NET Web API 应用程序中有一个自定义验证属性,用于检查日期是否在未来(不允许未来的日期)。这是代码:

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
    if (value != null)
    {
        var date = (DateTime)value;
        if (date != null)
        {
            if(date.Date > DateTime.UtcNow.Date)
            {
                return new ValidationResult(FormatErrorMessage(validationContext.DisplayName), new[] { validationContext.MemberName });
            }
        }
    }

    return ValidationResult.Success;
}

我不知道如何进行比较,因此它适用于所有时区。使用 DateTime.UtcNow 不是解决方案,因为如果客户端和服务器处于同一时区,则在接近午夜的时间,日期将是后一天。而且,当然 DateTime.Now 不适用于其他时区。那么,解决方案是什么?

更新:

在我的 WebApiConfig.cs 文件中,我有这段代码可以将 DateTimeZoneHandling 设置为 Utc:

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

这会将 JSON 响应中的日期格式化为:“2018-03-02T00:00:00Z”。

并且,所有来自客户端的 DateTime 值都将其 Kind 属性 设置为 Utc。然后,我可以将日期与 UtcNow 进行比较,但现在问题是日期“2018-03-02T00:00:00Z”在我的浏览器中显示为 2018 年 3 月 1 日,因为它已转换为本地时间(UTC -5).

试试这个:

var date = (DateTime)value;
var utcDate = date.ToUniversalTime();

比主持人这样:

if(utcDate .Date > DateTime.UtcNow.Date)

只有两种可行的方法。

  1. 在将值发送到服务器进行比较之前,在 客户端 上转换为 UTC。
  2. 尝试确定客户端的时区 ID(如果只是单个时间点,则为偏移量),并将其从客户端传递到服务器。然后服务器可以使用该信息在比较之前转换为 UTC。

如果您不采用这些选项,仅将 client-local-time 值传递给服务器而没有任何偏移量或时区信息,则无法实现您的目标。服务器对客户端的时区可能没有任何魔力。

此外,如果您要比较整个日期(例如 2018-03-02,而不是 2018-03-02T00:00:00),那么您将需要确定哪个时区与您的用例相关。例如,如果您与 UTC 日进行比较,这对洛杉矶的企业来说效果不佳,除非他们将业务流程与 UTC 保持一致。

根据我们的聊天更新:

由于您只需要处理整个日期,因此不要进行任何时区转换。确保从日期选择器中选择的日期与发送的日期完全一致 - 而不是通过 Date 对象。如果您的日期选择器不直接提供此值,则从 Date 对象创建它 - 手动或使用像 moment.js 这样的库。不要调用 .toISOString() 因为除了 ISO 格式外,它还会假定您指的是当地时间午夜并进行 UTC 转换。

也不要设置任何 JSON.Net 的日期设置 - 只需使用默认值。

var timezoneOffset = new Date().getTimezoneOffset(); - 您可以从客户端到服务器获取此信息(任何网络 API 调用)

借助 timezoneoffset 详细信息,您可以实现相同的目的。在我的例子中,我在服务器端将 UTC DateTime 转换为我的客户端本地日期时间。

DateTime clientDateTime = DateTime.UtcNow - new TimeSpan(timezoneOffset / 60, timezoneOffset % 60, 0);