ASP.NET 4.6 MVC 如何 return Json 结果包括具有正确时区的日期时间数据?
ASP.NET 4.6 MVC How to return a Json result including datetime data with correct timezone?
我希望return Json 结果包含从数据库查询的日期时间。在我的本地机器上测试没有任何问题,但是,在发布到生产服务器后,所有日期时间都提前 3 小时显示。我认为这是由于服务器位于另一个时区。
需要帮助解决这个问题。
数据库中的数据(MS SQL):
StartDt: 2019-07-02 04:00:00.000
Controller.cs:
[HttpGet]
public ActionResult GetAll()
{
CalendarModel calendarModel = new CalendarModel();
var calendarEvents = from cal in db.Calendar
orderby cal.created descending
select cal;
return Json(calendarEvents, JsonRequestBehavior.AllowGet);
}
Json 从我的电脑中获取的结果:
[
{
//some data
"startDt": "/Date(1562054400000)/",
//some data
},
上面的日期时间被解析为“2019-07-02T04:00:00.000-04:00”,是正确的。
Json 从生产服务器获取的结果(从同一数据库查询):
[
{
//some data
"startDt": "/Date(1562065200000)/",
//some data
},
这个日期时间是“2019-07-02T07:00:00.000-04:00”,这是错误的。
--------更新我的解决方案--------
感谢@TommasoBertoni
的回答启发了我这个问题的关键原因是由于默认的Unspecified
DateTime Kind但是变成了local
而Json 序列化。所以只需要将DateTime Kind设置为UTC
就可以解决,但是要注意前端解析DateTime也需要将其设为UTC
否则会被认为是local
默认情况下。
Controller.cs:
[HttpGet]
public ActionResult GetAll()
{
CalendarModel calendarModel = new CalendarModel();
var calendarEvents = from cal in db.Calendar
orderby cal.created descending
select cal;
//Add this
foreach (var item in calendarEvents)
{
item.startDt = DateTime.SpecifyKind(item.startDt, DateTimeKind.Utc);
}
return Json(calendarEvents, JsonRequestBehavior.AllowGet);
}
.js
(使用 moment.js
库)
//parse it as utc
moment.utc(startDt).format("YYYY-MM-DDTHH:mm:ss")
问题是 ASP.NET 使用 custom Microsoft JSON date format,将 DateTime 值编码为 /Date(ticks)/
,其中 ticks 表示自纪元 (UTC) 以来的毫秒数。
所以 1989 年 11 月 29 日,4:55:30 AM,在 UTC 中被编码为 /Date(628318530718)/
(更多信息参见 here)。
示例:
- Microsoft JSON 日期格式:
/Date(1563464520158)/
- ISO 8601 格式:
2019-07-18T15:42:02.4592008Z
如果 DateTime 具有 Unspecified
类型,它将被假定为 Local
并且该值将转换为 UTC 以获得自纪元以来的刻度。
这种 json 格式 仍在 MVC 中使用,但不用于 Web API:这意味着当您处于 Controller
并使用 Json(...)
序列化结果,您将获得 non-ISO 格式,但如果您使用的是 ApiController
,则默认序列化程序为 Json.NET,它支持 ISO 8601格式,不会转换 DateTime 值。
因此,要解决此问题 要么切换到 Web APIs,要么如果您想继续使用 MVC 控制器,您可以查看这些问题的答案:
- Setting the default JSON serializer in ASP.NET MVC
- Using JSON.NET as the default JSON serializer in ASP.NET MVC 3
- How to use Json.NET for JSON modelbinding in an MVC5 project
...或者您可以在 json 序列化之前强制 DateTime Kind 为 Utc,但我不建议这样做。
class TestRepo
{
public IEnumerable<DateTime> GetDates()
{
var now = DateTime.Now;
// Use DateTime instances with different Kind
// showing that it doesn't impact the serialization format.
var utc = DateTime.SpecifyKind(new DateTime(now.Ticks), DateTimeKind.Utc);
var local = DateTime.SpecifyKind(new DateTime(now.Ticks), DateTimeKind.Local);
var unspecified = DateTime.SpecifyKind(new DateTime(now.Ticks), DateTimeKind.Unspecified);
return new DateTime[] { utc, local, unspecified };
}
}
// MVC controller
public class MVCValuesController : Controller
{
public ActionResult Index()
{
IEnumerable<DateTime> dates = new TestRepo().GetDates();
return Json(dates, JsonRequestBehavior.AllowGet);
}
}
// json result:
[
"/Date(1563465361835)/", // <-- Utc
"/Date(1563458161835)/", // <-- Local
"/Date(1563458161835)/" // <-- Unspecified
]
// Web API controller
public class ValuesController : ApiController
{
public IEnumerable<DateTime> Get()
{
IEnumerable<DateTime> dates = new TestRepo().GetDates();
return dates;
}
}
// json result:
[
"2019-07-18T15:56:03.6401158Z", // <-- Utc
"2019-07-18T15:56:03.6401158+02:00", // <-- Local
"2019-07-18T15:56:03.6401158" // <-- Unspecified
]
我希望return Json 结果包含从数据库查询的日期时间。在我的本地机器上测试没有任何问题,但是,在发布到生产服务器后,所有日期时间都提前 3 小时显示。我认为这是由于服务器位于另一个时区。
需要帮助解决这个问题。
数据库中的数据(MS SQL):
StartDt: 2019-07-02 04:00:00.000
Controller.cs:
[HttpGet]
public ActionResult GetAll()
{
CalendarModel calendarModel = new CalendarModel();
var calendarEvents = from cal in db.Calendar
orderby cal.created descending
select cal;
return Json(calendarEvents, JsonRequestBehavior.AllowGet);
}
Json 从我的电脑中获取的结果:
[
{
//some data
"startDt": "/Date(1562054400000)/",
//some data
},
上面的日期时间被解析为“2019-07-02T04:00:00.000-04:00”,是正确的。
Json 从生产服务器获取的结果(从同一数据库查询):
[
{
//some data
"startDt": "/Date(1562065200000)/",
//some data
},
这个日期时间是“2019-07-02T07:00:00.000-04:00”,这是错误的。
--------更新我的解决方案--------
感谢@TommasoBertoni
的回答启发了我这个问题的关键原因是由于默认的Unspecified
DateTime Kind但是变成了local
而Json 序列化。所以只需要将DateTime Kind设置为UTC
就可以解决,但是要注意前端解析DateTime也需要将其设为UTC
否则会被认为是local
默认情况下。
Controller.cs:
[HttpGet]
public ActionResult GetAll()
{
CalendarModel calendarModel = new CalendarModel();
var calendarEvents = from cal in db.Calendar
orderby cal.created descending
select cal;
//Add this
foreach (var item in calendarEvents)
{
item.startDt = DateTime.SpecifyKind(item.startDt, DateTimeKind.Utc);
}
return Json(calendarEvents, JsonRequestBehavior.AllowGet);
}
.js
(使用 moment.js
库)
//parse it as utc
moment.utc(startDt).format("YYYY-MM-DDTHH:mm:ss")
问题是 ASP.NET 使用 custom Microsoft JSON date format,将 DateTime 值编码为 /Date(ticks)/
,其中 ticks 表示自纪元 (UTC) 以来的毫秒数。
所以 1989 年 11 月 29 日,4:55:30 AM,在 UTC 中被编码为 /Date(628318530718)/
(更多信息参见 here)。
示例:
- Microsoft JSON 日期格式:
/Date(1563464520158)/
- ISO 8601 格式:
2019-07-18T15:42:02.4592008Z
如果 DateTime 具有 Unspecified
类型,它将被假定为 Local
并且该值将转换为 UTC 以获得自纪元以来的刻度。
这种 json 格式 仍在 MVC 中使用,但不用于 Web API:这意味着当您处于 Controller
并使用 Json(...)
序列化结果,您将获得 non-ISO 格式,但如果您使用的是 ApiController
,则默认序列化程序为 Json.NET,它支持 ISO 8601格式,不会转换 DateTime 值。
因此,要解决此问题 要么切换到 Web APIs,要么如果您想继续使用 MVC 控制器,您可以查看这些问题的答案:
- Setting the default JSON serializer in ASP.NET MVC
- Using JSON.NET as the default JSON serializer in ASP.NET MVC 3
- How to use Json.NET for JSON modelbinding in an MVC5 project
...或者您可以在 json 序列化之前强制 DateTime Kind 为 Utc,但我不建议这样做。
class TestRepo
{
public IEnumerable<DateTime> GetDates()
{
var now = DateTime.Now;
// Use DateTime instances with different Kind
// showing that it doesn't impact the serialization format.
var utc = DateTime.SpecifyKind(new DateTime(now.Ticks), DateTimeKind.Utc);
var local = DateTime.SpecifyKind(new DateTime(now.Ticks), DateTimeKind.Local);
var unspecified = DateTime.SpecifyKind(new DateTime(now.Ticks), DateTimeKind.Unspecified);
return new DateTime[] { utc, local, unspecified };
}
}
// MVC controller
public class MVCValuesController : Controller
{
public ActionResult Index()
{
IEnumerable<DateTime> dates = new TestRepo().GetDates();
return Json(dates, JsonRequestBehavior.AllowGet);
}
}
// json result:
[
"/Date(1563465361835)/", // <-- Utc
"/Date(1563458161835)/", // <-- Local
"/Date(1563458161835)/" // <-- Unspecified
]
// Web API controller
public class ValuesController : ApiController
{
public IEnumerable<DateTime> Get()
{
IEnumerable<DateTime> dates = new TestRepo().GetDates();
return dates;
}
}
// json result:
[
"2019-07-18T15:56:03.6401158Z", // <-- Utc
"2019-07-18T15:56:03.6401158+02:00", // <-- Local
"2019-07-18T15:56:03.6401158" // <-- Unspecified
]