我在sql数据库中有一个日期时间:2020-07-21 13:55:22.990 这个日期时间是UTC,尽管(如果我错了请纠正我),没有办法知道在数据库。作为引用,我在 CST(UTC-6),这个问题是在夏令时期间写的(所以我现在距离 UTC -5)。
我正在向该数据库发送查询并使用以下方法返回 json(我不认为它有任何问题,但为了以防万一,我将其包含在内):
private static string GetJSONFromSQLQuery(string query, string connectionString)
{
var dataTable = new DataTable();
using (var sqlConnection = new SqlConnection(connectionString))
using (var sqlCommand = new SqlCommand(query, sqlConnection))
using (var sqlDataAdapter = new SqlDataAdapter(sqlCommand))
{
sqlConnection.Open();
sqlDataAdapter.Fill(dataTable);
}
var rowsAsDictionaries = new List<Dictionary<string, object>>();
foreach (DataRow row in dataTable.Rows)
{
var rowAsDictionary = new Dictionary<string, object>();
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (DataColumn column in dataTable.Columns)
rowAsDictionary.Add(column.ColumnName, row[column]);
rowsAsDictionaries.Add(rowAsDictionary);
}
return new JavaScriptSerializer().Serialize(rowsAsDictionaries);
}
这是我返回的 json 的片段(在实际调用中,对象中会有更多属性,并且通常会有更多对象):
[
{
"Timestamp":"\\/Date(1595357722990)\\/",
},
]
https://www.freeformatter.com/epoch-timestamp-to-date-converter.html在“将纪元时间戳转换为日期”下显示这是 2020 年 7 月 21 日下午 1:55:22
然后我用 newtonsoft 反序列化 json:
var deserializedJson = JsonConvert.DeserializeObject<List<MyObjectType>>(json)
MyObjectType 有一堆 { get;放; } 属性,其中之一是:
public DateTime Timestamp { get; set; }
根据上面的 json 片段和 newtonsoft 调用,时间戳将设置为 7/21, 6:55:22,Kind 属性将设置为 Utc。这不正确不是我所期望的。
经过一番搜索,我了解了 JsonSerializerSettings 中的 DateTimeZoneHandling 属性,并使用 4 个枚举选项中的每一个进行了以下调用:
var local = JsonConvert.DeserializeObject<List<MyObjectType>>(json, new JsonSerializerSettings
{
DateTimeZoneHandling = DateTimeZoneHandling.Local,
});
var roundtrip = JsonConvert.DeserializeObject<List<MyObjectType>>(json, new JsonSerializerSettings
{
DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind,
});
var unspecified = JsonConvert.DeserializeObject<List<MyObjectType>>(json, new JsonSerializerSettings
{
DateTimeZoneHandling = DateTimeZoneHandling.Unspecified,
});
var utc = JsonConvert.DeserializeObject<List<MyObjectType>>(json, new JsonSerializerSettings
{
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
});
这为我提供了 MyObjectType 中的以下 DateTime 对象(注意这些是 DateTime 对象的片段):
deserializedJson:
Time: 7/21 6:55:22,
Kind: Utc
local:
Time: 7/21 1:55:22,
Kind: Local
roundtripKind:
Time: 7/21 6:55:22,
Kind: Utc
unspecified:
Time: 7/21 6:55:22,
Kind: Unspecified
utc:
Time: 7/21 6:55:22,
Kind: Utc
Kind 属性特别重要,因为我会打电话
TimeZoneInfo.ConvertTimeFromUtc(theDeserializedTimeStamp, TimeZoneInfo.Local);
我想要的输出是:
Time: 7/21 1:55:22,
Kind: Utc
因为这反射(reflect)了数据库中的内容,所以我可以调用 TimeZoneInfo.ConvertTimeFromUtc 将 UTC 时间转换为本地时区。
如何获得该输出?
编辑:
我找到了一个解决方案。我将 GetJSONFromSQLQuery 中的返回语句更改为:
return JsonConvert.SerializeObject(rowsAsDictionaries);
并且所有 DateTimeZoneHandling 选项将时间保留为下午 1:55,并且 Kind 属性的结果有所不同(但符合预期)。不知道为什么 JavaScriptSerializer 中的 json 不能很好地运行,但至少我现在摆脱了困境。
JsonConvert.SerializeObject 的 json 如下所示:
[
{
"Timestamp":"2020-07-21T13:55:22.99"
}
]
最佳答案
一些事情:
1595357722990
是毫秒精度的 Unix 时间戳,等于 2020-07-21 18:55:22.990 UTC。您检查的网站正在将其转换为您的本地时间。 Here's a fiddle showing the conversion with .NET code. ,这是 JavaScript 代码:
const dt = new Date(1595357722990);
console.log(dt.toISOString());
您确实应该避免
JavaScriptSerializer
。 The docs说:ⓘ Important
For .NET Framework 4.7.2 and later versions, the APIs in the
System.Text.Json
namespace should be used for serialization and deserialization. For earlier versions of .NET Framework, useNewtonsoft.Json
.格式
“\\/Date(1595357722990)\\/”
通常被称为“ASP.NET JSON Date”,因为它首先发布到世界上ASP.Net 的早期版本,大约在 JSON 开始变得比 XML 更流行的时候。当时这是一种糟糕的格式,现在也是如此。请参阅On the nightmare that is JSON Dates...来自 Scott Hanselman,早在 2012 年。您应该使用 ISO 8601扩展日期+时间格式(另请参阅 RFC 3339 ),这是大多数现代 JSON 实现的默认格式,包括 Newtosoft JSON.Net 和
System.Text.Json
。你说:
Timestamp would be set to 7/21, 6:55:22 and the Kind property would be set to Utc. This is incorrect.
不,这实际上是正确的 - 假设您指的是 PM。这就是
1595357722990
代表的值。可能您创建该值不正确(请参阅下文)。在大多数情况下,包括您的情况,您不需要更改 JSON.Net 的默认
DateTimeZoneHandling
选项。您说您想要的输出是具有
DateTimeKind.Utc
- 但您的意思似乎是在转换为本地时间之后?这没有道理。如果您要转换为本地时间,则结果类型将为DateTimeKind.Local
。在这种情况下,您只需使用
TimeZoneInfo.ConvertTime
就可以了。由于输入类型已设置为DateTimeKind.Utc
,因此...FromUtc
部分不是必需的。 (只有当输入类型为DateTimeKind.Unspecified
时,这才真正重要。)查看您的编辑,您似乎实际上将
2020-07-21T13:55:22.99
存储在数据库中。如果该字段旨在解释为 UTC,那么您确实应该在生成的 JSON 中看到 13 点。但是,它还应该包含一个尾随的Z
以指示数据是 UTC。您的 JSON 实际上应该如下所示:
[ { "Timestamp":"2020-07-21T13:55:22.990Z" } ]
默认情况下,它可能会有一些额外的小数位,这很好。
您没有得到该结果的原因以及
JavaScriptSerializer
创建的原始值是错误的,是因为您没有设置DateTimeKind.Utc
从数据库读取的值。您需要使用DateTime.SpecifyKind
更改代码才能明确执行此操作。例如,您可以将内部循环修改为:foreach (DataColumn column in dataTable.Columns) { object o = row[column]; if (o is DateTime) { o = DateTime.SpecifyKind((DateTime)o, DateTimeKind.Utc); } rowAsDictionary.Add(column.ColumnName, o); }
一般来说,您的代码中存在很多次优的情况。实际上,您应该使用可枚举的或结构化类的列表,而不是对象字典,并且您应该使用
DataReader
而不是DataTable
。另外,在大多数框架中,例如在 ASP.net 中,您应该直接返回该列表并让框架进行 JSON 转换。换句话说,您可能根本不应该在此方法中转换为 JSON。
关于c# - 如何让 Newtonsoft 按原样反序列化日期并将其命名为 utc?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63020230/