【问题标题】:Store DateTime according to Current CultureInfo ASP.NET Core根据当前 CultureInfo ASP.NET Core 存储 DateTime
【发布时间】:2021-04-04 00:47:30
【问题描述】:

我的应用程序服务器与我的大多数应用程序用户当前所在的位置不同。

在存储日期时间值时,我意识到如果我只是这样做

`TimeAdded=DateTime.Now`, 

无论我在Startup.cs 课程中是否执行了以下操作,都会根据服务器位置时间存储时间

 var cultureInfo = new CultureInfo("en-NG");
 cultureInfo.NumberFormat.CurrencySymbol = "NGN";

 CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
 CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;

我的用户的位置在 UTC+1,而服务器当前位于 UTC-8 的位置

有没有办法根据startup.cs 类中设置的CurrentCultureInfo 将我的日期时间值存储在数据库(SQL Server)中?

我目前仅将日期时间值存储为 UTC,并在从数据库中检索值后将其转换为等效的 UTC+1 值。

所以,我愿意

TimeAdded=DateTime.UtcNow;

在检索到显示给用户的值后,我将其转换为

TimeAdded=TimeAdded.AddHours(1)

我希望找到更好的方法来解决这个问题。

谢谢

【问题讨论】:

  • 没有。在机器之间传输 DateTime 时,标准是使用 UTC 保存。 Datetime 是一个使用 UTC 的数字。当您将字符串转换为/从 DateTime 转换时,本地计算机使用文化(时区)自动转换为 UTC。所以你看到的是使用机器时区显示的日期。使用当前机器时区自动存储日期。如果您要存储来自另一个时区的日期,则字符串必须包含时区,或者您必须指定时区。
  • 您可以更改整个服务器的时区,使其与用户之一一致。这是唯一的方法。您无法更改单个应用的时区(例如,请参阅 stackoverflow.com/questions/8589014/…
  • 不是将 DateTime 数据存储为 UTC,另一种方法是在 .NET 和 T-SQL 中使用 DateTimeOffset 类型。这样,您就不必担心文化或日期数学(例如DateTimeOffset.Now)。
  • @jdweng,我目前将日期存储为 UTC。但是您提到我可以在存储日期时包含或指定日期,您能否提供一个指向资源的链接,我可以在其中找到如何执行此操作?
  • @Josh 不,我从未使用过它。我知道它的存在,但这只是因为我读了很多书。我认为使用起来并不复杂。例如:DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(-8)) 将生成一个偏移量为 -8 的Now...您应该将 DateTime 的生成集中在某个方法中(public static DateTimeOffset Now() { return DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(-8)); },这样就不会有人忘记使用它。取决于您的程序如何是写的(如果你有所有页面的基本页面),你可以把它放在那里

标签: c# sql-server asp.net-core-mvc cultureinfo currentuiculture


【解决方案1】:

有没有办法让我的日期时间值存储在数据库中 (SQL Server) 是否符合 CurrentCultureInfo?

日期时间在 SQL Server 中以二进制格式存储,没有任何文化信息。但是 SQL Server 可以存储带有时间偏移的日期和时间信息。 SQL Server 具有datetimeoffset 类型。我认为用文化信息存储日期并不能解决在用户本地时区显示日期和时间的问题,因为文化信息可以对应多个时区。例如,在西班牙,我们有两个时区,而美国有多个时区。

在检索到显示给用户的值后,我将其转换为

TimeAdded=TimeAdded.AddHours(1)

我希望有更好的方式去 这是那里。

不要那样做,因为夏令时会发生什么?而且您假设您的所有用户都在同一个时区。

我建议您将日期时间存储为 UTC,因为它没有歧义,它只有一种解释。然后您必须将该日期时间转换为用户时区的本地日期时间以进行显示。如果您知道用户的时区,您可以执行以下操作:

var usertimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(userTimeZoneId);
var userLocalDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, usertimeZoneInfo);

可以使用一些 JavaScript 计算出用户的 IANA 时区。这个answer 向您展示了如何做到这一点。

并且 IANA 时区可以转换为 windows 时区 id。请看这个answer。它向您展示了如何做到这一点。

另一方面,如果您通过从浏览器调用某些 Web API 来获取数据。你真的不需要做太多。您只需要确保数据按照 UTC 日期进行序列化。是的,您将 UTC 日期存储在数据库中,但是当您从数据库中检索它们时,您会得到 DateTimeKind.Unspecified 日期,然后这些日期未正确序列化为 JSON。如果使用Newtosoft.Json进行序列化,可以指定SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc

如果您使用 System.Text.Json,那么您必须为 DateTime 编写自定义 JsonConverter

这里有一个 JsonConverter 用于序列化 DateTimeKind.Unspecified 日期,因为它们是 UTC:

public class JsonDateConverter : JsonConverter<DateTime>
{
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var d = reader.GetDateTime();
        return d;
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        if (value.Kind == DateTimeKind.Unspecified)
        {
            value = new DateTime(value.Ticks, DateTimeKind.Utc);
        }
        writer.WriteStringValue(value);
    }
}

然后在从 Web API 检索到数据之后,编写一些 Javascript 来解析日期:

obj.theDate = obj.TheDate && new Date(obj.TheDate);

您需要这样做,因为DateTime 在序列化为 JSON 时被序列化为字符串。并且您希望 theDate 成为 JavaScript 日期。

之后,theDate 为用户时区本地时间日期。要检查它,请编写以下内容:

console.log(obj.theDate);

【讨论】:

    猜你喜欢
    • 2020-09-02
    • 2020-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多