Kendo UI 调度程序错误地转换时间,向后加减小时
Kendo UI Scheduler incorrectly converting times, adding and subtracting hours backwards
我正在使用 Kendo 调度程序,时区偏移似乎在与应该发生的相反的方向上增加和减少小时数。
当我将客户端时区更改为更西部的时区时,事件日期时间会增加小时数,而当我将客户端浏览器更改为更东部的时区时,小时数会被减去。
因此太平洋时区的客户端应该看到开始时间为 10:00 上午,但它显示为 4:00PM。设置为大西洋时区的客户端将开始时间视为 12:00PM。
调度程序代码:
$("#scheduler").kendoScheduler({
date: new Date(),
height: 900,
editable: false,
views: [
{
type: "month",
selected: true,
eventHeight: 50,
eventTemplate: $("#event-template-month").html(),
},{
type: "agenda",
eventHeight: 50,
eventTemplate: $("#event-template-sched").html(),
}
],
timezone: "America/New_York",
dataSource: webinarSchedule,
});
事件信息保存在本地 js 文件的数组中,如下所示:
var webinarSchedule = [//Date are in utc -5:00
{
title: "Part 1 <br/>The Golden Rule",
shortName: "1) The Golden Rule ",
presenter: "Bill Preston",
description: "A great event",
synopsis: "Learn stuff",
seriesNote: "The first of a 4-part series.",
registration: "https://attendee.gotowebinar.com/register/3782113333237861889",
start: new Date("2015/1/24 1:00 PM"),
end: new Date("2015/1/24 1:20 PM"),
},
是的,这似乎不对。
我发现在处理 JS 日期(或一般计算中的日期)时保持理智的唯一方法是使用 UTC 日期,以 ISO 格式序列化(通常,将 UTC 日期存储在服务器上也是一种更好的主意)。因此,我建议使用适用于源时区的 ISO 字符串创建您的事件:
{
title: "Part 1 <br/>The Golden Rule",
shortName: "1) The Golden Rule ",
presenter: "Bill Preston",
description: "A great event",
synopsis: "Learn stuff",
seriesNote: "The first of a 4-part series.",
registration: "https://attendee.gotowebinar.com/register/3782113333237861889",
start: new Date(Date.parse("2015-02-11T13:00:00-05:00")),
end: new Date(Date.parse("2015-02-11T13:20:00-05:00")),
}
然后根本不设置调度程序时区选项(因此它使用本地)。如果您需要传递给服务器,您可能还想先使用 toISOString
处理日期。
Scheduler 预计只接收和发送 UTC 日期 - 这就是为什么你应该使用 UTC 时区以正确的格式加载它的数据(否则当从字符串创建日期时,将使用本地用户时区,这是 JavaScript 具体行为):
start: new Date("2015-01-24T13:00:00.000Z"),
end: new Date("2015-01-24T13:20:00.000Z"),
此外,您可以将调度程序时区设置为 "Etc/UTC" - 这样,上述日期将按原样显示,无需在客户端进行转换:
$("#scheduler").kendoScheduler({
date: new Date("2015/1/24"),
timezone: "Etc/UTC",
这是一个基于上面代码片段的 JSFiddle:http://jsfiddle.net/loanburger/0s3Lcq17/
节目有点晚了,但我目前正在评估 Telerik 的 MVC 组件,并且在使用调度程序时遇到了类似的问题。我处理它的方式是让时区成为必需的,然后在服务器端我做了以下事情:
public SchedulerViewModel HandleTimezonesToUTC(SchedulerViewModel e)
{
TimeZoneInfoHelper tziHelper = new TimeZoneInfoHelper();
if (!string.IsNullOrEmpty(e.StartTimezone) && string.IsNullOrEmpty(e.EndTimezone))
{
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.StartTimezone));
e.Start = DateTime.SpecifyKind(e.Start, DateTimeKind.Unspecified);
e.End = DateTime.SpecifyKind(e.End, DateTimeKind.Unspecified);
e.Start = TimeZoneInfo.ConvertTimeToUtc(e.Start, tzi);
e.End = TimeZoneInfo.ConvertTimeToUtc(e.End, tzi);
}
if (!string.IsNullOrEmpty(e.StartTimezone) && !string.IsNullOrEmpty(e.EndTimezone))
{
TimeZoneInfo tziStart = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.StartTimezone));
TimeZoneInfo tziEnd = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.EndTimezone));
e.Start = TimeZoneInfo.ConvertTimeToUtc(e.Start, tziStart);
e.End = TimeZoneInfo.ConvertTimeToUtc(e.End, tziEnd);
}
return e;
}
public SchedulerViewModel HandleTimezonesFromUTC(SchedulerViewModel e)
{
TimeZoneInfoHelper tziHelper = new TimeZoneInfoHelper();
if (!string.IsNullOrEmpty(e.StartTimezone) && string.IsNullOrEmpty(e.EndTimezone))
{
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.StartTimezone));
e.Start = DateTime.SpecifyKind(e.Start, DateTimeKind.Utc);
e.End = DateTime.SpecifyKind(e.End, DateTimeKind.Utc);
e.Start = TimeZoneInfo.ConvertTimeFromUtc(e.Start, tzi);
e.End = TimeZoneInfo.ConvertTimeFromUtc(e.End, tzi);
}
if (!string.IsNullOrEmpty(e.StartTimezone) && !string.IsNullOrEmpty(e.EndTimezone))
{
TimeZoneInfo tziStart = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.StartTimezone));
TimeZoneInfo tziEnd = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.EndTimezone));
e.Start = TimeZoneInfo.ConvertTimeFromUtc(e.Start, tziStart);
e.End = TimeZoneInfo.ConvertTimeFromUtc(e.End, tziEnd);
}
return e;
}
通过这种方式,您将删除任何意外的 local->utc 转换,并且正如其他发帖人之一所说,让浏览器为您调整回当地时间。
理论上您不需要 fromUTC,但当我测试时,日历并未将其转换为本地时区。您可能只需分配一个 "kind" 即可,但我没有对此进行测试。
不确定您在做什么,但希望它能帮助您解决一些摇摆不定的时间问题。
我使用 moment.js
解决了这个问题
Javascript:
new Date(moment.utc("INSERT DATE HERE").format())
这样我就消除了时区问题。我不会更改 MVC 控制器上的日期。
我正在使用 Kendo 调度程序,时区偏移似乎在与应该发生的相反的方向上增加和减少小时数。
当我将客户端时区更改为更西部的时区时,事件日期时间会增加小时数,而当我将客户端浏览器更改为更东部的时区时,小时数会被减去。
因此太平洋时区的客户端应该看到开始时间为 10:00 上午,但它显示为 4:00PM。设置为大西洋时区的客户端将开始时间视为 12:00PM。
调度程序代码:
$("#scheduler").kendoScheduler({
date: new Date(),
height: 900,
editable: false,
views: [
{
type: "month",
selected: true,
eventHeight: 50,
eventTemplate: $("#event-template-month").html(),
},{
type: "agenda",
eventHeight: 50,
eventTemplate: $("#event-template-sched").html(),
}
],
timezone: "America/New_York",
dataSource: webinarSchedule,
});
事件信息保存在本地 js 文件的数组中,如下所示:
var webinarSchedule = [//Date are in utc -5:00
{
title: "Part 1 <br/>The Golden Rule",
shortName: "1) The Golden Rule ",
presenter: "Bill Preston",
description: "A great event",
synopsis: "Learn stuff",
seriesNote: "The first of a 4-part series.",
registration: "https://attendee.gotowebinar.com/register/3782113333237861889",
start: new Date("2015/1/24 1:00 PM"),
end: new Date("2015/1/24 1:20 PM"),
},
是的,这似乎不对。
我发现在处理 JS 日期(或一般计算中的日期)时保持理智的唯一方法是使用 UTC 日期,以 ISO 格式序列化(通常,将 UTC 日期存储在服务器上也是一种更好的主意)。因此,我建议使用适用于源时区的 ISO 字符串创建您的事件:
{
title: "Part 1 <br/>The Golden Rule",
shortName: "1) The Golden Rule ",
presenter: "Bill Preston",
description: "A great event",
synopsis: "Learn stuff",
seriesNote: "The first of a 4-part series.",
registration: "https://attendee.gotowebinar.com/register/3782113333237861889",
start: new Date(Date.parse("2015-02-11T13:00:00-05:00")),
end: new Date(Date.parse("2015-02-11T13:20:00-05:00")),
}
然后根本不设置调度程序时区选项(因此它使用本地)。如果您需要传递给服务器,您可能还想先使用 toISOString
处理日期。
Scheduler 预计只接收和发送 UTC 日期 - 这就是为什么你应该使用 UTC 时区以正确的格式加载它的数据(否则当从字符串创建日期时,将使用本地用户时区,这是 JavaScript 具体行为):
start: new Date("2015-01-24T13:00:00.000Z"),
end: new Date("2015-01-24T13:20:00.000Z"),
此外,您可以将调度程序时区设置为 "Etc/UTC" - 这样,上述日期将按原样显示,无需在客户端进行转换:
$("#scheduler").kendoScheduler({
date: new Date("2015/1/24"),
timezone: "Etc/UTC",
这是一个基于上面代码片段的 JSFiddle:http://jsfiddle.net/loanburger/0s3Lcq17/
节目有点晚了,但我目前正在评估 Telerik 的 MVC 组件,并且在使用调度程序时遇到了类似的问题。我处理它的方式是让时区成为必需的,然后在服务器端我做了以下事情:
public SchedulerViewModel HandleTimezonesToUTC(SchedulerViewModel e)
{
TimeZoneInfoHelper tziHelper = new TimeZoneInfoHelper();
if (!string.IsNullOrEmpty(e.StartTimezone) && string.IsNullOrEmpty(e.EndTimezone))
{
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.StartTimezone));
e.Start = DateTime.SpecifyKind(e.Start, DateTimeKind.Unspecified);
e.End = DateTime.SpecifyKind(e.End, DateTimeKind.Unspecified);
e.Start = TimeZoneInfo.ConvertTimeToUtc(e.Start, tzi);
e.End = TimeZoneInfo.ConvertTimeToUtc(e.End, tzi);
}
if (!string.IsNullOrEmpty(e.StartTimezone) && !string.IsNullOrEmpty(e.EndTimezone))
{
TimeZoneInfo tziStart = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.StartTimezone));
TimeZoneInfo tziEnd = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.EndTimezone));
e.Start = TimeZoneInfo.ConvertTimeToUtc(e.Start, tziStart);
e.End = TimeZoneInfo.ConvertTimeToUtc(e.End, tziEnd);
}
return e;
}
public SchedulerViewModel HandleTimezonesFromUTC(SchedulerViewModel e)
{
TimeZoneInfoHelper tziHelper = new TimeZoneInfoHelper();
if (!string.IsNullOrEmpty(e.StartTimezone) && string.IsNullOrEmpty(e.EndTimezone))
{
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.StartTimezone));
e.Start = DateTime.SpecifyKind(e.Start, DateTimeKind.Utc);
e.End = DateTime.SpecifyKind(e.End, DateTimeKind.Utc);
e.Start = TimeZoneInfo.ConvertTimeFromUtc(e.Start, tzi);
e.End = TimeZoneInfo.ConvertTimeFromUtc(e.End, tzi);
}
if (!string.IsNullOrEmpty(e.StartTimezone) && !string.IsNullOrEmpty(e.EndTimezone))
{
TimeZoneInfo tziStart = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.StartTimezone));
TimeZoneInfo tziEnd = TimeZoneInfo.FindSystemTimeZoneById(tziHelper.FindMSEquilivalent(e.EndTimezone));
e.Start = TimeZoneInfo.ConvertTimeFromUtc(e.Start, tziStart);
e.End = TimeZoneInfo.ConvertTimeFromUtc(e.End, tziEnd);
}
return e;
}
通过这种方式,您将删除任何意外的 local->utc 转换,并且正如其他发帖人之一所说,让浏览器为您调整回当地时间。
理论上您不需要 fromUTC,但当我测试时,日历并未将其转换为本地时区。您可能只需分配一个 "kind" 即可,但我没有对此进行测试。
不确定您在做什么,但希望它能帮助您解决一些摇摆不定的时间问题。
我使用 moment.js
解决了这个问题Javascript:
new Date(moment.utc("INSERT DATE HERE").format())
这样我就消除了时区问题。我不会更改 MVC 控制器上的日期。