如何在C#中转换时期时间?

489

如何在C#中将Unix 时期时间转换为实际时间?(始于1970年1月1日的时期)


1
除非我漏掉了什么,否则“纪元”只是特定计时方案的起点。例如1/1/0001、1/1/1970和1/1/2000。它更像是方案本身(例如朱利安历)的属性,而不是方案本身。 - Bob Kaufman
8
自纪元以来经过的时间是指自协调世界时1970年1月1日以来的秒数。 - Taylor Leese
重复,带有其他答案:https://dev59.com/MHA75IYBdhLWcg3wVXav - jpaugh
15个回答

751

2020更新

您可以使用DateTimeOffset来完成此操作。

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(epochSeconds);
DateTimeOffset dateTimeOffset2 = DateTimeOffset.FromUnixTimeMilliseconds(epochMilliseconds);

如果你需要 DateTime 对象而不是 DateTimeOffset,那么可以调用 DateTime 属性

DateTime dateTime = dateTimeOffset.DateTime;

原始回答

我猜你指的是Unix时间,它被定义为自1970年1月1日午夜(UTC)以来的秒数。

private static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

public static DateTime FromUnixTime(long unixTime)
{
    return epoch.AddSeconds(unixTime);
}

83
为了让这个功能正常工作,我不得不将 .AddSeconds 改为 .AddMilliseconds。您需要知道您的数字是来自秒还是毫秒,才能获得正确的结果。例如,对于以下日期:1406310305188(2014年7月25日)。http://www.epochconverter.com/ 还可以让您检查转换结果。 - jrandomuser
5
你应该将参数类型更改为double(因为AddSeconds接受double类型,因此会将其转换为double),或者在方法描述中添加免责声明,说明只有64位参数中的53位精度将被保留。 - tomosius
7
Unix纪元时间通常表示为自The Epoch以来的“秒数”。现在普遍使用自The Epoch以来的“毫秒数”(例如JavaScript),但经典定义是秒。最重要的是,只需知道您的输入值是什么(秒、毫秒、滴答声等),并使用正确的“AddXYZ”方法即可。 - T.J. Crowder
首先尝试使用AddMilliseconds,如果年份仍为1970,则使用AddSeconds。这样就可以始终正常工作,而无需担心毫秒或秒。此外,您还可以防止溢出异常。将大数字传递给AddSeconds会导致代码崩溃。 - Tono Nam
關於閏秒怎麼辦? - Paul Childs

244

.Net最新版本(v4.6)新增了对Unix时间的内置支持,包括从秒或毫秒表示的Unix时间转换为DateTimeOffset以及从DateTimeOffset转换为秒或毫秒表示的Unix时间。

  • 将秒表示的Unix时间转换为DateTimeOffset

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(1000);
  • DateTimeOffset 转换为 Unix 时间戳(秒):

long unixTimeStampInSeconds = dateTimeOffset.ToUnixTimeSeconds();
  • 将毫秒级 Unix 时间转换为 DateTimeOffset

DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(1000000);
  • DateTimeOffset 转换为毫秒级 Unix 时间:

long unixTimeStampInMilliseconds= dateTimeOffset.ToUnixTimeMilliseconds();
注意:这些方法用于将值转换为和从DateTimeOffset转换。若要获取DateTime表示,请使用DateTimeOffset.DateTime属性:
DateTime dateTime = dateTimeOffset.UtcDateTime;

1
我遇到了 'DateTimeOffset' does not contain a definition for 'FromUnixTimeSeconds' 的问题,我该如何解决? - Happy Bird
@HappyBird 你是在使用 .NET 4.6 或更高版本吗? - i3arnon
同样的事情 - 4.7.2版本中,DateTimeOffset没有FromUnixTimeMilliseconds方法... - Mikhail_Sam
1
我明白了,我不需要创建新的对象。这是一个静态方法。 - Mikhail_Sam
1
一开始我发现默认值有点令人困惑。因为1000是将毫秒转换为秒的因子。 - Tigerware

191

在此感谢LukeH,我整理了一些扩展方法以便于使用:

public static DateTime FromUnixTime(this long unixTime)
{
    var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    return epoch.AddSeconds(unixTime);
}

public static long ToUnixTime(this DateTime date)
{
    var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    return Convert.ToInt64((date - epoch).TotalSeconds);
}
请注意,下面有一条来自 CodesInChaos 的评论,指出上述的 FromUnixTime 返回一个带有 KindUtcDateTime,这是可以接受的,但上述的 ToUnixTime 更加可疑,因为它没有考虑给定的 date 是什么类型的 DateTime。为了允许 dateKindUtcLocal,请使用ToUniversalTime
public static long ToUnixTime(this DateTime date)
{
    var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    return Convert.ToInt64((date.ToUniversalTime() - epoch).TotalSeconds);
}

ToUniversalTime 方法将把一个 Local(或者 Unspecified)的 DateTime 转换成 Utc 时间。

如果你不想在从 DateTime 到 Unix 时间戳进行转换时创建一个 epoch DateTime 实例,你也可以这样做:

public static long ToUnixTime(this DateTime date)
{
    return (date.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
}

6
如果日期是在UTC时区,ToUnixTime函数才能正常工作。你需要添加一个检查或者进行转换。(个人偏向于添加检查) - CodesInChaos
3
刚刚花了一个小时弄明白为什么这个不起作用。你需要使用“毫秒”而不是“秒”!!! - KristianB
7
“Unix时间”传统上是从Epoch以来的秒数,而不是毫秒数,尽管现在我会仔细检查某个人所使用的定义。秒数曾经足够好,并且以有符号32位值为基础给我们提供了合理的范围。 (这也是为什么格林威治标准时间2038年1月19日上午3点14分后不久可能是一个糟糕的时刻的原因...)使用毫秒是一种更现代的做法,这要归功于我们能够轻松处理64位值(包括整数和双精度IEEE-754值)。 - T.J. Crowder
5
谢谢提供这段代码。在创建时间戳时,建议明确将毫秒值设置为0。 例如: var epoch = new DateTime(1970, 1, 1, 0//, 0//, 0//, 0 /毫秒/, DateTimeKind.Utc); 如果不明确设置,毫秒值可能会变成1。这在我的测试中导致了一些不一致的结果。 - ctrlplusb
2
你应该使用 AddMilliseconds,并且应该使用 Double 而不是 Float。否则你会得到错误的时间。 - Axel

25

你实际上想要添加毫秒数,而不是秒数。添加秒数会导致超出范围的异常。


为什么?http://www.epochconverter.com/它说你要加上自1970年1月1日以来的秒数而不是毫秒数。 - Jamie R Rytlewski
如果你从毫秒开始,显然你需要使用 AddMillis,如果你从秒开始,显然你需要使用 AddSeconds - jamesSampica
我遇到了同样的问题,当我使用秒时一直超出范围。我试图转换的Unix时间是以毫秒为单位的,我原本以为它是以秒为单位的。我猜某些Unix时间是以毫秒为单位测量的。 - DoodleKana
Unix时间通常以秒为单位表示,但0.001也是有效的秒数(= 1毫秒)。如果不确定,请使用最大可能的精度。 - Him

23
Unix纪元是指自1970年1月1日UTC零点以来经过的秒数(减去闰秒)。这意味着在1970年1月1日午夜,Unix时间为0。Unix纪元也称为Unix时间、POSIX时间或Unix时间戳。 使用.NET Framework 4.6或更高版本,可以使用方法DateTimeOffset.ToUnixTimeMilliseconds()。它返回自1970-01-01T00:00:00.000Z以来经过的毫秒数。
var EPOCH = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

这里有详细的文档说明 DateTimeOffset.ToUnixTimeMilliseconds

要仅获取秒级别的EPOCH,您可以使用:

 var Epoch = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;

使用以下方法将Epoch转换为DateTime

private DateTime Epoch2UTCNow(int epoch) 
{
    return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(epoch); 
}

但由于 Unix 时间的表示方式在某些系统上是一个带符号的 32 位数字,该表示方式将在 2038 年 1 月 19 日 UTC 的 3:14:08 到达 231-1 秒后结束。这被称为 2038 年问题,即 32 位有符号 Unix 时间会溢出。

我建议将其保存为长整型而不是 int,并命名为 EPOCH_2038_SAFE

long EPOCH_2038_SAFE = 
(long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;

如果您想要更多信息,可以使用以下内容以更高的精度。

long EPOCH = DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1,0,0,0,0).Ticks;

3
DateTime.Ticks - 每个滴答是“一百纳秒”,这使它成为记住的一个额外“事情”。如果省略.Ticks,则从DateTime减法中可得到一个漂亮的TimeSpan实例。 - user2864740

14

如果您想要更好的性能,您可以使用这个版本。

public const long UnixEpochTicks = 621355968000000000;
public const long TicksPerMillisecond = 10000;
public const long TicksPerSecond = TicksPerMillisecond * 1000;

//[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static DateTime FromUnixTimestamp(this long unixTime)
{
    return new DateTime(UnixEpochTicks + unixTime * TicksPerSecond);
}

通过在net471下使用快速基准测试(BenchmarkDotNet)得出以下数字:

        Method |     Mean |     Error |    StdDev | Scaled |
-------------- |---------:|----------:|----------:|-------:|
         LukeH | 5.897 ns | 0.0897 ns | 0.0795 ns |   1.00 |
      MyCustom | 3.176 ns | 0.0573 ns | 0.0536 ns |   0.54 |

相比于LukeH版本,速度提升了2倍(如果性能很重要的话)。

这类似于DateTime内部工作的方式。


9
// convert datetime to unix epoch seconds
public static long ToUnixTime(DateTime date)
{
    var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    return Convert.ToInt64((date.ToUniversalTime() - epoch).TotalSeconds);
}

应该使用ToUniversalTime()函数来处理DateTime对象。


7

目前,您可以直接使用

DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()

它将会被返回为一个64位长的值


5

我使用以下扩展方法进行时间戳转换

public static int GetEpochSeconds(this DateTime date)
    {
        TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1);
        return (int)t.TotalSeconds;
    }

public static DateTime FromEpochSeconds(this DateTime date, long EpochSeconds)
    {
        var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
        return epoch.AddSeconds(EpochSeconds);

    }

3

从 .Net 4.6 版本开始,请使用

DateTimeOffset.Now.ToUnixTimeSeconds()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接