我希望返回一个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导致,但是在Json序列化时变成local
。因此,只需将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")
答案 0 :(得分:0)
问题是ASP.NET使用custom Microsoft JSON date format,它将DateTime值编码为/Date(ticks)/
,其中滴答表示自纪元(UTC)以来的毫秒数。
因此,1989年11月29日上午4:55:30,以UTC编码为/Date(628318530718)/
(有关更多信息,请参见here)。
示例:
/Date(1563464520158)/
2019-07-18T15:42:02.4592008Z
如果DateTime的类型为Unspecified
,则将其假定为Local
,并且该值将被赋给UTC,以便获取自纪元以来的滴答声。
此json格式仍在MVC中使用,但在Web API中未使用:这意味着当您处于Controller
并使用Json(...)
序列化结果时,会得到非ISO格式,但是如果您使用的是ApiController
,则默认序列化程序是Json.NET,它支持ISO 8601格式,并且不会转换DateTime值。
因此,要解决此问题,无论是切换到Web API还是要继续使用MVC控制器,都可以看到以下问题的答案:
...或者您可以在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
]