你如何在C#中转换纪元时间?

How do you convert epoch time in C#?

如何在C中将Unix epoch time转换为实时?(从1970年1月1日开始的新纪元)


我假定您的意思是Unix时间,它定义为1970年1月1日午夜(UTC)以来的秒数。

1
2
3
4
5
public static DateTime FromUnixTime(long unixTime)
{
    return epoch.AddSeconds(unixTime);
}
private static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);


最新版本的.NET(v4.6)刚刚添加了对Unix时间转换的内置支持。这包括以秒或毫秒表示的到Unix时间和从Unix时间。

  • DateTimeOffset的Unix时间(秒):
1
DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeSeconds(1000);
  • DateTimeOffset到unix的时间(秒):
1
long unixTimeStampInSeconds = dateTimeOffset.ToUnixTimeSeconds();

  • DateTimeOffset的Unix时间(毫秒):
1
DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(1000000);
  • DateTimeOffset到unix的时间(毫秒):
1
long unixTimeStampInMilliseconds= dateTimeOffset.ToUnixTimeMilliseconds();

注:这些方法与DateTimeOffset相互转换。要获得DateTime表示,只需使用DateTimeOffset.DateTime属性:

1
DateTime dateTime = dateTimeOffset.UtcDateTime;


由于所有的功劳都归功于Lukeh,我将一些扩展方法放在一起以便于使用:

1
2
3
4
5
6
7
8
9
10
11
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返回一个DateTime,上面的KindUtc,这很好,但是上面的ToUnixTime更值得怀疑,因为这不能解释给定的DateTime是什么类型。为了使dateKind既可以是Utc也可以是Local使用ToUniversalTime

1
2
3
4
5
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);
}

ToUniversalTimeLocalUnspecifiedDateTime转换为Utc

如果不想在从datetime移动到epoch时创建epoch datetime实例,也可以执行以下操作:

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


您实际上想要添加毫秒(毫秒),而不是秒。添加秒将给您一个超出范围的异常。


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

1
2
3
4
5
6
7
8
9
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)中,我得到这个数字:

1
2
3
4
        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内部的工作方式。


1
2
3
4
5
6
// 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);
}

应该对datetime对象使用touniversaltime()。


我使用以下扩展方法进行历元转换

1
2
3
4
5
6
7
8
9
10
11
12
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);

    }


使用datetimeoffset.tounixtimemillises()方法返回1970-01-01t00:00:00.000z以来经过的毫秒数。

This is only supported with Framework 4.6 or higher

1
var EPOCH = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

这里有很好的记录:datetimeoffset.tounixTime毫秒


如果您不使用4.6,这可能有助于源代码:system.identitymodel.tokens

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    /// <summary>
    /// DateTime as UTV for UnixEpoch
    /// </summary>
    public static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);

    /// <summary>
    /// Per JWT spec:
    /// Gets the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the desired date/time.
    /// </summary>
    /// <param name="datetime">The DateTime to convert to seconds.</param>
    /// <remarks>if dateTimeUtc less than UnixEpoch, return 0</remarks>
    /// <returns>the number of seconds since Unix Epoch.</returns>
    public static long GetIntDate(DateTime datetime)
    {
        DateTime dateTimeUtc = datetime;
        if (datetime.Kind != DateTimeKind.Utc)
        {
            dateTimeUtc = datetime.ToUniversalTime();
        }

        if (dateTimeUtc.ToUniversalTime() <= UnixEpoch)
        {
            return 0;
        }

        return (long)(dateTimeUtc - UnixEpoch).TotalSeconds;
    }


如果您需要将包含UNIX time的timeval结构(秒、微秒)转换为DateTime而不丢失精度,则如下所示:

1
2
3
4
5
6
7
DateTime _epochTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private DateTime UnixTimeToDateTime(Timeval unixTime)
{
    return _epochTime.AddTicks(
        unixTime.Seconds * TimeSpan.TicksPerSecond +
        unixTime.Microseconds * TimeSpan.TicksPerMillisecond/1000);
}


这是我的解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public long GetTime()
{
    DateTime dtCurTime = DateTime.Now.ToUniversalTime();

    DateTime dtEpochStartTime = Convert.ToDateTime("1/1/1970 0:00:00 AM");

    TimeSpan ts = dtCurTime.Subtract(dtEpochStartTime);

    double epochtime;

    epochtime = ((((((ts.Days * 24) + ts.Hours) * 60) + ts.Minutes) * 60) + ts.Seconds);  

    return Convert.ToInt64(epochtime);
}