我正在通过其API将日期/时间值推送到HubSpot CRM系统中。对于日期/时间值,HS API需要UNIX格式,该格式距离Epoch(1970年1月1日12:00 AM)毫秒。 [HubSpot docs: https://developers.hubspot.com/docs/faq/how-should-timestamps-be-formatted-for-hubspots-apis]
但是我的日期显示不正确。我正在从EST中的SQL数据库中提取日期,并执行以下转换:
string dbValue = "2019-02-03 00:00:00";
DateTime dt = Convert.ToDateTime(dbValue);
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc);
long apiValue = Convert.ToInt64(dt.Subtract(epoch).TotalMilliseconds);
但是,在HubSpot中,日期字段显示2/2/2019
。 HubSpot中的时区设置为UTC -4 Eastern Time。
似乎有一些转换问题,但是我不知道该怎么做才能更正它。我尝试使用DateTime.SpecifiyKind
将dt
显式设置为local,然后再转换为long:
dt = DateTime.SpecifyKind(dt, System.DateTimeKind.Local);
但是那也不起作用。我尝试进行基本测试:
var dt1 = new DateTime(2019, 4, 1, 12, 0, 0, DateTimeKind.Local);
var dt2 = new DateTime(2019, 4, 1, 12, 0, 0, DateTimeKind.Utc);
Console.WriteLine(dt1.Subtract(dt2).TotalSeconds);
但是结果是0
。我在CST工作,我期望能相差5个小时。我觉得我在这里缺少有关DateTimes如何在C#中工作的一些基本概念。
答案 0 :(得分:2)
几件事:
减去DateTime
的值不会考虑DateTimeKind
。
.NET Framework 4.6和更高版本在DateTimeOffset
类中内置了往返于Unix时间的转换功能,因此您根本不需要进行任何减法。
当您说EST
或CST
时,我假设您的意思是美国东部时间或美国中部时间。请记住,由于夏令时,EDT
或CDT
可能会应用于您的某些值。
如果值来自数据库,则不应从字符串进行解析。我假设您只是在此处给出示例。但是在您的实际代码中,您应该执行以下操作:
DateTime dt = (DateTime) dataReader("field");
(如果您使用的是Entity Framework或其他ORM,则将为您处理此部分。)
所在的SQL Server时区无关紧要。dbValue
所代表的时区很重要。最佳做法是按照UTC时间保留时间,在这种情况下,服务器的时区应该无关紧要。
如果存储在SQL Server中的日期时间实际上是UTC,则只需执行以下操作:
long apiValue = new DateTimeOffset(dt, TimeSpan.Zero).ToUnixTimeMilliseconds();
如果存储在SQL Server中的日期时间确实是美国东部时间,那么您首先需要将东部时间转换为UTC:
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(dt, tz);
long apiValue = new DateTimeOffset(utc).ToUnixTimeMilliseconds();
请注意,Windows时区ID "Eastern Standard Time"
表示美国东部时间(包括EDT),适用时,尽管中间带有单词“ Standard”。
如果您在非Windows平台上的.NET Core中运行,请改为传递"America/New_York"
。 (如果您需要编写跨平台的弹性,请使用我的TimeZoneConverter库。)
最后,尽管假设数据库中的时间与访问数据库的代码在同一本地时间可能有些危险,但是如果您真的想进行此类赌博,则可以这样做这个:
long apiValue = new DateTimeOffset(dt).ToUnixTimeMilliseconds();
这仅在dt.Kind
为DateTimeKind.Unspecified
或DateTimeKind.Local
时有效,因为它将应用本地时区。但是,我还是建议不要这样做。