ASP.NET 4.6 MVC如何返回包含正确时区的dateson数据的Json结果?

时间:2019-07-18 10:21:52

标签: c# asp.net json asp.net-mvc .net-4.6

我希望返回一个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")

1 个答案:

答案 0 :(得分:0)

问题是ASP.NET使用custom Microsoft JSON date format,它将DateTime值编码为/Date(ticks)/,其中滴答表示自纪元(UTC)以来的毫秒数。
因此,1989年11月29日上午4:55:30,以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(...)序列化结果时,会得到非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
]