我需要幻想在用户所选择的时区工作。服务器和客户端代码坚持使用JavaScript日期的问题。因此,为了达到要求,我已经将utc手动映射到客户端的日期:
dateToServer(date) {
const momentDate = moment(date);
let serverDate = null;
if (momentDate.isValid() && date) {
const browserUtcOffset = momentDate.utcOffset();
serverDate = momentDate
.utc()
.subtract(this.clientTimeZoneOffset, 'minutes')
.add(browserUtcOffset, 'minutes')
.toDate();
}
return serverDate;
}
dateToClient(date) {
const momentDate = moment(date);
let uiDate = null;
if (momentDate.isValid() && date) {
const browserUtcOffset = momentDate.utcOffset();
uiDate = momentDate
.utc()
.subtract(browserUtcOffset, 'minutes')
.add(this.clientTimeZoneOffset, 'minutes')
.toDate();
}
return uiDate;
}
我要添加/减去browserUtcOffset,因为当日期在服务器和客户端之间时,浏览器会自动添加/减去。
它运行良好,但是此解决方案缺少对DST的处理。我想检查DST在该日期是否有效,然后根据需要添加DST偏移量。
这里有C#代码,可以做到这一点:
string timeZone = "Central Standard Time";
TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZone);
DateTime date = new DateTime(2011, 3, 14);
Console.WriteLine(timeZoneInfo.BaseUtcOffset.TotalMinutes); // -360
Console.WriteLine(timeZoneInfo.GetUtcOffset(date).TotalMinutes); // -300
Console.WriteLine(timeZoneInfo.IsDaylightSavingTime(date)); // true
Console.WriteLine(timeZoneInfo.DaylightName);
Console.WriteLine(timeZoneInfo.SupportsDaylightSavingTime);
我在momentjs中发现了isDST
,当我将Windows本地时区设置为CST并在浏览器控制台中检查了moment([2011, 2, 14]).isDST();
时,我看到了。 isDST
的显示方式取决于浏览器的本地时间。
下一步,请尝试像我在C#中所做的那样使用moment-timezone来执行某项操作。不幸的是,我不知道如何实现这一目标。作为起点,我遇到的第一个问题是:UTC time
,Base offset(-360 in C# sample)
,timezone name: Central Standard Time
,但是时刻-时区中的时区不同。
moment.tz.names().map(name => moment.tz.zone(name)).filter(zone => zone.abbrs.find(abbr => abbr === 'CST') != null)
此代码返回68个时区。
为什么每个人都有很多修道院?直到什么意思?我要检查的时间是否为所选时区的UTC时间,即“中央标准时间”,即夏令时处于活动状态。再看一次C#示例:)
string timeZone = "Central Standard Time";
TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZone);
DateTime date = new DateTime(2011, 3, 14);
Console.WriteLine(timeZoneInfo.BaseUtcOffset.TotalMinutes); //-360
Console.WriteLine(timeZoneInfo.GetUtcOffset(date).TotalMinutes); //-300
Console.WriteLine(timeZoneInfo.IsDaylightSavingTime(date)); //true, I have checked is daylightsavingtime for the date
Console.WriteLine(timeZoneInfo.DaylightName);
Console.WriteLine(timeZoneInfo.SupportsDaylightSavingTime);
该应用程序已在angularjs 1.6.3上编写。
答案 0 :(得分:1)
几件事:
JavaScript中的Date
对象跟踪基于UTC的特定时间点。您可以通过调用.valueOf()
或.getTime()
看到该时间戳。只有某些函数和构造函数参数才能与本地时区一起使用(例如.toString()
)。该本地时区在调用函数时应用。一个人不能替代另一个时区(传递给toLocaleString
的选项对象除外)。因此,Date
对象 无法从一个时区转换为另一个时区。因为您的两个函数都接受一个Date
对象并返回一个Date
对象,所以您在中间所做的就是选择另一个时间点。这在使用Moment的add
和subtract
方法的函数中也可以看到。他们操纵表示的时间点-他们不更改时区。
通过传递this.clientTimeZoneOffset
,您似乎已将时区与时区偏移量混为一谈。这些是单独的概念,因为时区可能会由于DST的影响而经历多个不同的偏移,也可能由于历史发生的标准时间的变化而发生偏移。另请参见the timezone tag wiki中的“时区!=偏移”。仅传递客户的偏移量是没有用的,因为该偏移量仅适用于单个时间点。您不能将其用于时区转换,因为它无法告诉您其他时间点使用的偏移量。
相反,传递时区标识符。在.NET中的Windows上,它们看起来像"Central Standard Time"
(尽管有名称,但代表标准时间和夏令时),在JavaScript和大多数其他操作系统中,使用IANA时区名称。它们看起来像"America/Chicago"
。 timezone tag wiki中也对此进行了介绍。
如果您的.NET代码使用Windows标识符,则可以使用我的TimeZoneConverter库将Windows从Windows转换为IANA,然后将该字符串作为时区发送到浏览器。
< / li>使用Moment-Timezone,您可以像这样简单地检查DST:
moment.tz([2011, 2, 14], 'America/Chicago').isDST()
同样,您应该使用IANA time zone IDs,如果您在服务器端使用Windows时区,则TimeZoneConverter可以提供它们。
您可以考虑通过其TZDB时区提供程序在服务器端使用Noda Time。这样一来,您就可以在两侧使用IANA时区。在Linux或Mac OSX的.NET Core上运行时,TimeZoneInfo
也是如此。
使用CST
搜索缩写词时看到这么多条目的原因是时区缩写词模棱两可。您可能指的是美国中部标准时间,但您也可能指的是古巴标准时间或中国标准时间,或其他使用该缩写的其他地方。
关于untils
数组,通常不需要担心。 Moment-Timezone是内部数据的一部分,用于为选择时区偏移量和缩写选择正确的时间点。
您最后说的是一些不同的内容:
我要检查的是所选时区的UTC时间是否为“中央标准时间”,即夏令时是否处于活动状态。
我之前给出的示例假定您从该时区的本地时间开始。如果您是从UTC时间开始的,则如下所示:
moment.utc([2011, 2, 14]).tz('America/Chicago').isDST()
当然,您可以在传递数组的地方传递其他各种受支持的输入。 Moment docs可以为您提供可用的选项。
答案 1 :(得分:0)
请检查answer of Matt Johnson for this question。对我来说非常有用。
词汇
问题
主要问题当某人登录位于时区+3,但其帐户设置为-6的PC时。 angularjs和kendo在项目上使用,并且kendo时间仅适用于本机js日期。并且本机js日期始终在浏览器时区中,对于本示例来说为+3。但是我应该在-6中设置类似的东西。 F.e.例如,用户选择的时间为07:00,UTC为04:00(07:00-3),但是对于他的帐户,时区为-6,utc应该为13:00(07:00 + 6)。当我们将本地js日期(UI日期)转换为UTC并向后转换时,此对话会自动应用。因此,决定计算服务器上的偏移量并摆脱浏览器时区偏移量:utcTime = UItime + browserOffset - clientTimezoneBaseOffset - daylightSavingTimeOffset
。
但是,当需要恢复UI时间时会有问题,例如今天是06.06.2014,并且DST在该日期是正确的,但是当我们从服务器获取03.03.2014日期时,我们不知道DST是否在2014年03月03日处于活动状态。
答案
在服务器上的项目.net中,因此在数据库中存储了窗口的时区ID。我以另一种方式完成了该任务:依靠服务器DST来确定日期范围,该范围是从服务器上的最小日期开始,然后保存在本地存储中的客户端上。我喜欢这种情况
服务器是事实的来源之一,因此可以在任何客户端上执行计算而无需操纵时区。无需在IANA,Windows和Rails时区之间进行转换。但也有一个问题:需要预先计算介于DateTime.MinValue
至DateTime.MaxValue
范围内的DST,目前为了加快速度,我正在计算介于01.01.2000
至DateTime.Now
范围内的DST-将值从数据库转换为UI时就足够了,因为在数据库中,最小日期是2008年,但是对于html输入来说还不够,因为用户可以选择大于DateTime.Now
且小于{{1}的值}。为了解决这个问题,我正在计划使用TimeZoneConverter发送给客户端01.01.2000
,并且对于提供的日期(UI或服务器)不在IANATimezoneId
范围内的情况, [01.01.2000, DateTime.Now]
。
这是服务器端的新代码
moment.utc(date).tz(IANATimezoneId).isDST()
这是在客户端修改的dateToServer,dateToClient
private class DaylightSavingTimeDescriptor
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public bool IsDaylightSavingTime { get; set; }
}
private string GetDaylightSavingTimeDescriptorsJson(string timeZone)
{
string daylightSaveingTimeDescriptorsJson = String.Empty;
if(timeZone != null)
{
List<DaylightSavingTimeDescriptor> dstList = new List<DaylightSavingTimeDescriptor>();
TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZone);
DateTime startDate = new DateTime(2000, 1, 1);
DateTime dateIterator = startDate;
bool isDST = timeZoneInfo.IsDaylightSavingTime(startDate);
while (dateIterator < DateTime.Now)
{
bool currDST = timeZoneInfo.IsDaylightSavingTime(dateIterator);
if (isDST != currDST)
{
dstList.Add(new DaylightSavingTimeDescriptor()
{
EndTime = dateIterator.AddDays(-1),
IsDaylightSavingTime = isDST,
StartTime = startDate
});
startDate = dateIterator;
isDST = currDST;
}
dateIterator = dateIterator.AddDays(1);
}
daylightSaveingTimeDescriptorsJson = Newtonsoft.Json.JsonConvert.SerializeObject(dstList);
}
return daylightSaveingTimeDescriptorsJson;
}
PS
我想摆脱偏移量,并在客户端上使用moment-timezone,在服务器上使用timezone converter,但是如果客户要求,那将是稍后的时间,因为我以前从未尝试过,不确定它是否会正常工作,并且当前的解决方案是否正常。偏移也将用于dateinputs组件(angularjs),因为它们使用的是kendo-dateinput,其ng-model是浏览器本地时间中的JS Date,但是我提供了另一个时区,因此需要在组件内部进行转换。
从我的角度来看,PPS是最佳的解决方案,如果timezone converter和moment-timezone将按预期工作
无论如何,整个应用程序都在运行JS日期,因此,当莫斯科(美国)用户在kendo输入中选择日期时间时,或查看setup kendo-scheduler,或在kendo表中显示日期时,我需要用偏移量进行操作。但是,我计划不直接传递客户端偏移,而是计划借助timezone converter从服务器传递IANA时区ID,并直接从moment-timezone获取我需要的偏移。