将存储在一个时区的日期/时间转换为用户的本地日期/时间

时间:2015-03-13 03:26:56

标签: c# asp.net date datetime timezone

我正在处理一个数据库,其中使用Web服务器本地日期/时间(在这种情况下,东部时间)错误地存储了所有日期。假设数据库中保留的所有日期/时间都是东部,我该如何转换我把这些数据选入我的C#模型后,这个日期是当地时间的用户吗?

2 个答案:

答案 0 :(得分:3)

您可以在数据库中存储基于UTC的日期时间,也可以使用正确的偏移量存储datetimeoffset。请参阅DateTime vs DateTimeOffset以确定哪个对您的用例有意义。 (我假设其余响应的UTC日期时间)

问题是,由于您只存储datetime,并且它基于美国东部时间,因此您可能已经丢失了信息。让我解释一下:

  • 由于daylight saving time,美国东部时区在两个不同的偏移之间交替。在一年中的大部分时间里,它都在UTC-5,但在夏天它会切换到UTC-4。
  • 您需要考虑日期和时间来计算要使用的正确偏移量。
  • 在秋季,当时钟"后退"时,本地时间从1:59:59.999跳回到1:00。这意味着1:00小时on that particular date中的任何值都是不明确的。如果您没有存储任何其他内容以帮助您关联它们,则可能会丢失数据。

现在也许你会很幸运,发现在那个小窗口里没有记录交易,但也许没有。您可以使用一种方式消除歧义。

  • 许多数据库都有一个自动递增的整数主键,或者有一些其他增量字段。您可以将其用于消除歧义。

  • 例如:

    ID  | ... | TransactionDate
    ----+-----+--------------------
    101 | ... | 2014-11-02 00:55:00
    102 | ... | 2014-11-02 01:00:00
    103 | ... | 2014-11-02 01:30:00
    104 | ... | 2014-11-02 01:55:00
    105 | ... | 2014-11-02 01:15:00  <--- transition!
    106 | ... | 2014-11-02 01:59:00
    107 | ... | 2014-11-02 02:00:00
    

在上表中,因为我们在1:00时有一些不按顺序的记录,所以在东部夏令时(UTC-4)期间记录101-104是合理的假设,并且记录在东部标准时间(UTC-5)期间发生了105-107。

这种方法不是你可以轻松自动化的方法。有时您会在模糊的时间内进行交易,但不会出现任何不按顺序的交易。这意味着要么所有这些都在过渡之前出现,要么全部都在过渡之后。没有办法说出来。

您需要编写一些C#代码或SQL脚本来查询表并转换数据。我建议为输出创建第二个表,或在现有表中创建第二个列。不要尝试更新适当的值,否则如果出现问题,您将很难解开它。

关于转换本身,如果您在.NET代码中执行此操作,则可以使用TimeZoneInfo类,"Eastern Standard Time"时区ID。不要对命名感到困惑,该标识符代表两者 EST和EDT - 尽管单词&#34;标准&#34;以它的名字命名。

DateTime dt = (DateTime) yourSqlDataReader["TransactionDate"];
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
if (tz.IsAmbiguousTime(dt))
{
    // record this item in some way, so you can review it manually later
}
else
{
    DateTime utc = TimeZoneInfo.ConvertTimeToUtc(dt, tz);
    // save this field to a new table or a new column in the current table
}

完成转换后,请手动填写模糊期间的任何空白。如果您满意,请将值复制回原位,或将代码移至指向新的UTC列等。

从现在开始,始终以UTC的形式存储交易时间。在.NET中,使用DateTime.UtcNow,或在SQL中,使用GETUTCDATE()SYSUTCDATETIME()

现在问题的最后一部分是 - 你将如何转换到用户的时区进行展示?那么你当然可以再次使用TimeZoneInfo,或者你可以使用更全面的库,例如Noda Time。但无论你走哪条路,你都可能需要知道用户的时区是什么!最简单的方法是通过用户个人资料页面中的下拉设置(例如)从应用程序的用户收集此信息。

另一种方法,如果您熟悉JavaScript,可以将UTC时间一直传递给客户端,然后将其加载到JavaScript Date对象中,或者您可以使用像{{ {3}}。其中任何一个的好处是客户端将自动将值转换为用户计算机设置的任何时区。如果您使用的是现代应用程序开发风格,例如通过WebAPI发送数据并使用像Angular这样的JavaScript框架显示数据,这种方法效果特别好。

答案 1 :(得分:1)

您可以使用TimeZoneInfo类进行此类操作(来自客户端)

TimeZoneInfo.ConvertTime

  

将时间从一个时区转换为另一个时区。

  String dbTime = "2015.02.21 1:00 AM"; // <= A sample time

  DateTime time = DateTime.Parse(dbTime); // <= Convert it to a datetime

  TimeZoneInfo eastern = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");  // <= TimeZoneInfo for Eastern
  TimeZoneInfo local = TimeZoneInfo.Local; // <=TimeZoneInfor for local

  Console.WriteLine(TimeZoneInfo.ConvertTime(time, estern, local)); // Will return the Local time related to provided to Eastern Time

附加:正如Matt Johnson所说,是local将是服务器的时区。所以要使用这种方法,因为Matt Johnson解释说你需要从之前设置的设置中识别用户时区,或者从他们的IP(如果可能)或通过传递给服务器的字段(可能是通过URL)识别用户时区