整个Angular应用程序的日期/时间都是参考PST编写的。
示例目标是将日期安排在太平洋标准时间下午4:30
我们今天了解到一个错误,如果我们发送日期"2021-03-17T16:30:00"
,我们的应用程序会在夏威夷时区创建new Date("2021-03-17T16:30:00")
。然后C#可能做了正确的事情,并将任何时间转换为太平洋本地时间(TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles"))
。因此,我们错误地转换为晚上7:30。
我们的API请求数据类型为日期。这个解决方案有效吗?然而,我觉得最后4行不会计入夏令时,或者可能会产生问题。
const inputDate = "2021-03-17T16:30:00";
const pstMoment = moment.tz(inputDate, 'America/Los_Angeles');
const clientTimeZoneName = Intl.DateTimeFormat().resolvedOptions().timeZone;
const clientMoment = pstMoment.clone().tz(clientTimeZoneName);
console.log(new Date(clientMoment.format())); // this will send to API
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.33/moment-timezone-with-data-10-year-range.js"></script>
注:代码解析不仅适用于夏威夷,也适用于可能没有夏令时的其他全球国家。我们的日程日期选择器使用字符串存储类型(inputDate(。
Typescript类
export interface ScheduleDto {
scheduleDate?: Date;
scheduleDate: "2021-03-18T02:30:00.000Z"
C#类
public class ScheduleDto
{
public DateTime? ScheduleDate { get; set; }
....
return TimeZoneInfo.ConvertTime(ScheduleDate , TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles"));
如果我理解正确的话,问题是您当前在客户端上的方法只是创建一个类似new Date("2021-03-17T16:30:00")
的Date
对象,它将使用本地时区来确定您所说的时间点。您希望它始终被解释为太平洋时间,但由于夏令时的原因,您不知道该使用哪个偏移量。
因此,你的问题的最终答案是——是的,你使用Moment时区编写的代码确实会应用正确的偏移量。不过,它有点冗长。您实际上不需要做任何与检测当前本地时区有关的事情。相反,您可以使用构建Date
对象
moment.tz('2021-03-17T16:30:00', 'America/Los_Angeles').toDate()
考虑到Moment的项目状态,最好使用Luxon(除非您已经在项目中广泛使用Moment(。在卢森,这将是:
luxon.DateTime.fromISO('2021-03-17T16:30:00', {zone: 'America/Los_Angeles'}).toJSDate()
或者,您可以从日期fns-tz开始使用zonedTimeToUtc
函数。
关键是,由于您正在构建一个Date
对象,所以您总是通过连线发送它的一些字符串表示。您似乎正在用.toISOString()
序列化这些Date
对象,这将发送UTC等效的"2021-03-18T02:30:00.000Z"
。使UTC时间点正确是最重要的。
在.NET代码中,如果将该值接收到DateTime
对象中,则由于字符串末尾的Z
,其Kind
属性将设置为Utc
。TimeZoneInfo.ConvertTime
将使用Kind
属性来确定转换的源时区,并且您已将目标时区提供为太平洋时间。
更简单的方法是不要在客户端代码中使用Date
对象,而是通过有线发送预期的日期和时间,而不使用偏移量"2021-03-17T16:30:00"
。在.NET代码中,DateTime.Kind
将是Unspecified
。那么您根本不会调用TimeZoneInfo.ConvertTime
,因为您已经在所需的时区中有了值。
替代方案:
对于TypeScript数据类型,可以使用字符串。
将来,当Temporal完成并完全集成到ECMAScript中时,可以使用PlainDateTime
。