【问题标题】:STOP Auto Localization of DateTime when Serializing/Deserializing with WCF Service and DataTable使用 WCF 服务和 DataTable 进行序列化/反序列化时停止 DateTime 的自动本地化
【发布时间】:2014-12-22 17:30:43
【问题描述】:

我无法弄清楚这一点,这让我发疯了。为什么数据类型对象会这样做,这超出了我的理解。我觉得处理时区的指定类型就足够了。无论如何,这是我的设置。我有一个向我的应用程序提供序列化 DataTable 的 WCF 服务。数据通过网络界面输入。如果我将 12/12/2014 11:00 AM 放入数据库,它将通过 Web 服务将数据表中的 12/12/2014 12:00 PM 严格返回到我的应用程序。

我该如何阻止它!?

事件链:

  1. 登录到 Web 界面,选择现在执行任务(通过 DateTime.Now)或稍后执行任务(解析用户选择的日期时间常数的字符串表示)。我将时区存储在单独的列中。 注意:DateTime.Now 不会由序列化程序自动本地化,另一个会。
  2. 任务设置正确。所有日期都正确反映在数据库中。目前还没有差异。
  3. 任务在正确的时间执行。因为我正在处理这些任务设置执行的时区差异。这很顺利。任务在应有的时候执行。
  4. 看看手机。时间不对。我断了点,来自已序列化和反序列化的数据表中的 Web 服务的数据不正确。休息一小时(CMT 到 EST)。

我已经尝试在不同的地方更改类型,但没有任何效果。

我想要我放入数据库中的内容与显示的内容完全相同。我通过简单的算术处理数据库逻辑中的时区转换。不需要这种自动化。

对于这样一个老问题,我已经厌倦了挖掘大量的变通方法,其中没有一个工作或解决方案足以很好地解释该做什么以及如何处理这个问题。

【问题讨论】:

  • I've tried changing the kind in various places and nothing works DateTime 后立即将 DateTime.Kind 属性设置为 Utc。然后,您需要将 DateTime 转换为您的本地时间,然后再将其显示给客户端。但是,如果服务器和客户端都在 same 时区,您不会期望您正在观察的行为。您的服务器和客户端是否位于不同的时区?
  • 我在将值提交到数据库之前尝试设置 DateTime.Kind。然后我尝试在应用程序上尝试显示消息设置显示多久前的时间跨度。在我看来,我必须将 Kind 设置在两者之间。对我来说,这意味着返回 DataTable 的 WCF Webservice。我没有尝试遍历表并设置列 Kind 然后返回修改后的表。就个人而言,如果这样可以解决问题,这似乎是一项昂贵的工作。也许我错了,应该试一试。
  • 在数据库之前设置肯定不会做任何事情;该字段未保存。问题是在您从数据库中读出它之后,它的DateTime.Kind 将等于Unspecified,并且您希望它是Utc(或者约定如此)。所以是的,你应该试一试(不会很贵)
  • @wal 是这样的吗? Int32 upperBound = (output.Rows.Count - 1); for (Int32 i = upperBound; (i >= 0); i--) { DateTime showAfter = (DateTime)output.Rows[i]["ShowAfter"]; DateTime showBefore = (DateTime)output.Rows[i]["ShowBefore"]; showAfter = DateTime.SpecifyKind(showAfter, DateTimeKind.Utc); showBefore = DateTime.SpecifyKind(showBefore, DateTimeKind.Utc); output.Rows[i]["ShowAfter"] = showAfter; output.Rows[i]["ShowBefore"] = showBefore; }
  • 没有工作 :( 手机上显示的时间仍然提前一个小时。数据库显示上午 9:20,手机显示上午 10:20。数据库位于德克萨斯 (CMT) 和我目前在纽约东部标准时间,所以区别是有道理的。

标签: c# wcf datetime serialization


【解决方案1】:

虽然做了很多调整,但我明白了。这也适用于我的特定设置,可能并不适用于所有人。

我的设置: 日期时间从数据库所在时区的 Web 界面传递到数据库。在同一时区运行的 Windows 服务会根据 show after 字段循环并拉出任务。然后从任何时区的电话应用程序中提取此数据,并以多久前的形式显示该值,例如 1 分钟前、2 小时前等。电话应用程序是唯一与 WCF 服务接口的应用程序。由于 Windows 服务驻留在同一台服务器上,因此不需要任何中间人。

首先在网站上输入这些“任务”时,日期时间通过以下方式获得。

Double selectedTimezone = 0D;
Double offsetTimezone = 0D;

TimeZoneInfo timezoneInfo = TimeZoneInfo.Local;

selectedTimezone = Double.Parse(DDL_EndTimezone.SelectedValue.ToString());

/* Obtain the timezone offset for server to user. 
   For me this is -1: -6 (CST) to -5 (EST) */

offsetTimezone = (timezoneInfo.BaseUtcOffset.TotalHours - selectedTimezone);

/* Parse the date time from the selected user 
   inputs. */

if (!chkSendMessageNow.Checked)
    start = DateTime.Parse(txtBeginDate.Text + " " + cmdBeginHour.SelectedValue.ToString() + ":" + cmdBeginMinute.SelectedValue.ToString() + ":" + "00");
else
    start = DateTime.Parse(DateTime.Now.ToString("MM/dd/yyyy") + " " + DateTime.Now.Hour.ToString() + ":" + DateTime.Now.Minute.ToString() + ":" + "00");
end = DateTime.Parse(txtEndDate.Text + " " + DDL_EndHour.SelectedValue.ToString() + ":" + DDL_EndMin.SelectedValue.ToString() + ":" + "00");

/* Ensure these are "local" kind. I quote because 
   this is local time for user, not where the 
   site is hosted. */

start = DateTime.SpecifyKind(start, DateTimeKind.Local);
end = DateTime.SpecifyKind(end, DateTimeKind.Local);

/* Convert the start and end to UTC from 
   the timezone of the user with the 
   adjusted server to user timezone 
   offset. */

start = start.AddHours(offsetTimezone).AddHours(-1 * selectedTimezone);
end = end.AddHours(offsetTimezone).AddHours(-1 * selectedTimezone);

/* Specify this is UTC. */

start = DateTime.SpecifyKind(start, DateTimeKind.Utc);
end = DateTime.SpecifyKind(end, DateTimeKind.Utc);

现在这些已保存到数据库中。

在我的 WCF 服务的服务器上,我拉出 DataTable,但在返回要序列化的输出之前调整 DateTime 列,如下所示。 此步骤可能不是必需的,并且是先前尝试的残余。但我不会弄乱它,因为它正在工作。

Int32 upperBound = (output.Rows.Count - 1);

DateTime showAfter = DateTime.MinValue;
DateTime showBefore = DateTime.MinValue;

for (Int32 i = upperBound; (i >= 0); i--)
{
    showAfter = (DateTime)output.Rows[i]["ShowAfter"];
    showBefore = (DateTime)output.Rows[i]["ShowBefore"];

    showAfter = DateTime.SpecifyKind(showAfter, DateTimeKind.Utc);
    showBefore = DateTime.SpecifyKind(showBefore, DateTimeKind.Utc);

    output.Rows[i]["ShowAfter"] = showAfter;
    output.Rows[i]["ShowBefore"] = showBefore;
}

最后在应用程序中显示反序列化时正确本地化的时间。我执行以下操作。

DateTime showAfter = DateTime.MinValue;

showAfter = Convert.ToDateTime(_dataTable.Rows[position]["ShowAfter"]);
showAfter = DateTime.SpecifyKind(showAfter, DateTimeKind.Utc);
showAfter = showAfter.ToLocalTime();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-06
    • 1970-01-01
    • 2012-03-10
    • 2021-12-13
    相关资源
    最近更新 更多