我有以下用于转换为Unix Epoch时间戳的转换方法
public static class DateTimeHelpers
{
public static DateTime UnixEpoch()
{
return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
}
public static DateTime FromMillisecondsSinceUnixEpoch(long milliseconds)
{
return UnixEpoch().AddMilliseconds(milliseconds).ToLocalTime();
}
public static long ToMillisecondsSinceUnixEpoch(DateTime dateTime)
{
return (long)(dateTime - UnixEpoch()).TotalMilliseconds;
}
}
问题是(男孩这似乎是基本的东西),我设置了一个DateTime
我想要然后尝试转换为Unix-Time但返回的毫秒时间戳是+01:00小时,我想知道为什么呢?
我正在使用的代码是
DateTime startDate = new DateTime(2015, 10, 1, 0, 0, 0, 0, DateTimeKind.Utc);
long startMillis = DateTimeHelpers.ToMillisecondsSinceUnixEpoch(startDate);
这给出了startMillis = 1443657600000
,即“2015年10月1日星期四01:00:00(am)在欧洲/伦敦(BST)时区”。我想从ToMillisecondsSinceUnixEpoch
返回时间戳“2015/10/01 00:00:00”,我在这里缺少什么?
感谢您的时间。
编辑。我想做一些Java代码的等价。这产生了正确的时间戳。为什么我可以用Java而不是C#来做这个?无论如何代码
private static long ukTimeStringToUtcMillis(String s) {
SimpleDateFormat sdf = makeSimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
try {
return sdf.parse(s).getTime();
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
private static SimpleDateFormat makeSimpleDateFormat(String s) {
SimpleDateFormat sdf = new SimpleDateFormat(s);
sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
return sdf;
}
我像这样使用它
long timestamp = ukTimeStringToUtcMillis("2015-10-01T00:00:00.000");
这给出了timestamp = 1443654000000
,即“2015年10月1日星期四00:00:00(am)在欧洲/伦敦(BST)时区”。我对C#缺少什么?我试过了
var ukTimeZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTime unixEpoch = TimeZoneInfo.ConvertTime(
new DateTime(1970, 1, 1, 0, 0, 0), ukTimeZone, ukTimeZone);
long startMillis = (long)(startDate - unixEpoch).TotalMilliseconds;
long endMillis = (long)(endDate - unixEpoch).TotalMilliseconds;
这个ADDS一个小时!?
答案 0 :(得分:3)
如果我按照您的操作行事,您的测试代码将以UTC时间开始:
DateTime startDate = new DateTime(2015, 10, 1, 0, 0, 0, 0, DateTimeKind.Utc);
但是在FromMillisecondsSinceUnixEpoch
中你返回LocalTime。按原样使用代码,它不会进行往返:
Console.WriteLine(dt.ToUniversalTime());
Console.WriteLine("{0} {1}", ToMillisecondsSinceUnixEpoch(dt),
FromMillisecondsSinceUnixEpoch(ToMillisecondsSinceUnixEpoch(dt)));
10/1/2015 5:00:00 AM 1443657600000 10/1/2015 12:00:00 AM
如果我更改FromMillisecondsSinceUnixEpoch
:
public static DateTime FromMillisecondsSinceUnixEpoch(long milliseconds)
{
return UnixEpoch().AddMilliseconds(milliseconds).ToUniversalTime();
}
现在它将进行往返:
10/1/2015 5:00:00 AM 1443675600000 10/1/2015 5:00:00 AM
注意MilliSecondsSince对每个都是相同的。你不能只看那个,因为没有上下文。
我在Ref Source中找不到它,但是在减去之前,当TZ不同时,DateTime足够聪明。 (否则,很难解释1443675600000
如何在同一日期代表3个TimeSpans(2个对我而且一个对你而言)。
答案 1 :(得分:1)
一些事情:
如果可能,您应该使用DateTimeOffset
代替DateTime
进行此类操作。 DateTimeOffset
始终是一个特定的时刻,而DateTime
可能是,或者可能不是,取决于Kind
以及您如何坚持微妙的如何通过各种方法解释Kind
。
如果您使用DateTimeOffset
,并且您的目标是.NET 4.6或更高版本(或.NET Core),那么您可以使用内置的DateTimeOffset.FromUnixTimeMilliseconds
和ToUnixTimeMilliseconds
方法,而不是创建自己的方法。
您可以考虑使用Noda Time开源库,因为它为使用日期和时间的大多数应用程序增加了重要价值。
"Europe/London"
区域,那么您可以使用DateTimeZoneProviders.Tzdb["Europe/London"]
。现在,我的其余部分假设您不接受上述任何建议,并且与您在问题中提供的代码相关。
您已将UnixEpoch
实施为静态方法。由于它的值永远不会改变,因此它应该可以实现为静态属性,具有私有只读备份字段。它也可以实现为公共静态只读字段,但大多数人更喜欢通过属性公开它们。 (这些只是编码指南,但不要引入任何错误。)
在FromMillisecondsSinceUnixEpoch
方法中,您正在呼叫.ToLocalTime()
。应该省略。您也不需要致电.ToUniversalTime()
。只需返回添加毫秒的结果。 Kind
将为Utc
。如果您需要使用当地时间,请稍后进行转换 - 不在此功能内。
确认ID "GMT Standard Time"
适用于伦敦,而不是UTC。伦敦格林威治标准时间(UTC + 00:00)或BST(UTC + 01:00),具体取决于相关日期和时间。
认识到DateTime.ToLocalTime
和DateTime.ToUniversalTime
在UTC与运行代码的计算机上的当前本地时区之间进行转换。这可能是伦敦,或者可能是其他东西,具体取决于您的用例。如果您在服务器上运行,例如在ASP.Net Web应用程序中运行,那么依赖系统本地时区并不是一个好习惯。
在您使用TimeZoneInfo.ConvertTime
显示的代码中,由于您没有将DateTimeKind.Utc
分配给输入,因此该值将为DateTimeKind.Unspecified
。 ConvertTime
会将其解释为已属于源时区。由于您已经给出了相同的目的地时区,因此在大多数情况下,这将是一个无操作。
在同一个功能中,由于之前指定的原因,根据伦敦时间定义unixEpoch
无效。另请注意,在1970-01-01赛季,伦敦不是格林威治标准时间,而是实际上是在BST(被称为"英国标准时间"当时,而不是"英国夏令时")。 TZDB知道这一点,但它对于Windows时区和TimeZoneInfo
来说太过分了。 "GMT Standard Time"
Windows区域仅反映当前BST / GMT的规则,而不是当时生效的规则。
就转换您提供的Java代码而言,该函数以毫秒精度读取ISO 8601格式的字符串,在伦敦时区解释它,将其转换为UTC,并提供自Unix纪元以来的毫秒时间。有几种方法可以做到这一点:
.Net 3.5 +
public static long UkTimeStringToUtcMillis(string s)
{
string format = "yyyy-MM-dd'T'HH:mm:ss.FFF";
DateTime dt = DateTime.ParseExact(s, format, CultureInfo.InvariantCulture);
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(dt, tz);
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return (long) (utc - epoch).TotalMilliseconds;
}
.Net 4.6+ / .Net CoreCLR
public static long UkTimeStringToUtcMillis(string s)
{
string format = "yyyy-MM-dd'T'HH:mm:ss.FFF";
DateTime dt = DateTime.ParseExact(s, format, CultureInfo.InvariantCulture);
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
TimeSpan offset = tz.GetUtcOffset(dt);
DateTimeOffset dto = new DateTimeOffset(dt, offset);
return dto.ToUnixTimeMilliseconds();
}
野田时间
public static long UkTimeStringToUtcMillis(string s)
{
LocalDateTimePattern pattern = LocalDateTimePattern.ExtendedIsoPattern;
LocalDateTime dt = pattern.Parse(s).Value;
DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/London"];
Instant i = dt.InZoneLeniently(tz).ToInstant();
return i.Ticks / NodaConstants.TicksPerMillisecond;
}