Объясните ToUnixTimeMilliseconds - PullRequest
2 голосов
/ 15 октября 2019

Я пытаюсь найти лучший способ конвертировать DateTime в метку времени Unix в C #

Я обнаружил, что существует метод DateTimeOffset.ToUnixTimeMilliseconds:

public long ToUnixTimeMilliseconds()
{
   return this.UtcDateTime.Ticks / 10000L - 62135596800000L;
}

Что означает этот метод? Какие константы используются?

UPD: я думаю, 10000L преобразуется из FRAME в миллисекунды. Но как насчет 62135596800000L?

1 Ответ

5 голосов
/ 15 октября 2019

Чтобы объяснить этот метод:

public long ToUnixTimeMilliseconds()
{
    return this.UtcDateTime.Ticks / 10000L - 62135596800000L;
}

Единицы DateTime.Ticks представляют собой интервалы в 100 наносекунд.

Деление этого на 10_000 дает миллисекунды, что объясняет деление на 10000L.

Это потому, что одна наносекунда равна одной миллиардной доли секунды или одной миллионной миллисекунде.

Чтобы преобразовать наносекунду в миллисекунду, вы, следовательно, разделите ее на 1_000_000.

ОднакоТики - это 100 наносекундных единиц, поэтому вместо деления на 1_000_000 вам придется делить на 1_000_000 / 100 = 10_000. Вот почему вы делите 100 наносекундных единиц на 10_000, чтобы получить миллисекунды.

Эпоха Unix (что соответствует нулевому времени Unix) - это полночь 1 января 1970 года.

Эпоха DateTime (что соответствует нулевому значению DateTime.Ticks): 1 января 0001.

Число миллисекунд между 1 января 0001 и 1 января 1970 г. равно 62135596800000. Это объясняет вычитание 62135596800000.

И вот он у вас!

Примечание: Вы можете вычислить приблизительное значение для количества миллисекунд следующим образом:

Approximate number of days per year = 365.24219 
Number of years between 0001 and 1970 = 1969 
Thus, total approx milliseconds = 1969 * 365.24219 * 24 * 60 * 60 * 1000
= 62135585750000

Точную цифру гораздо сложнеевычислить, но получается 62135596800000, как используется в приведенной выше формуле.

Фактически, из проверки исходного кода мы можем найти следующее:

public long ToUnixTimeSeconds() {
    // Truncate sub-second precision before offsetting by the Unix Epoch to avoid
    // the last digit being off by one for dates that result in negative Unix times.
    //
    // For example, consider the DateTimeOffset 12/31/1969 12:59:59.001 +0
    //   ticks            = 621355967990010000
    //   ticksFromEpoch   = ticks - UnixEpochTicks                   = -9990000
    //   secondsFromEpoch = ticksFromEpoch / TimeSpan.TicksPerSecond = 0
    //
    // Notice that secondsFromEpoch is rounded *up* by the truncation induced by integer division,
    // whereas we actually always want to round *down* when converting to Unix time. This happens
    // automatically for positive Unix time values. Now the example becomes:
    //   seconds          = ticks / TimeSpan.TicksPerSecond = 62135596799
    //   secondsFromEpoch = seconds - UnixEpochSeconds      = -1
    //
    // In other words, we want to consistently round toward the time 1/1/0001 00:00:00,
    // rather than toward the Unix Epoch (1/1/1970 00:00:00).
    long seconds = UtcDateTime.Ticks / TimeSpan.TicksPerSecond;
    return seconds - UnixEpochSeconds;
}

// Number of days in a non-leap year
private const int DaysPerYear = 365;
// Number of days in 4 years
private const int DaysPer4Years = DaysPerYear * 4 + 1;       // 1461
// Number of days in 100 years
private const int DaysPer100Years = DaysPer4Years * 25 - 1;  // 36524
// Number of days in 400 years
private const int DaysPer400Years = DaysPer100Years * 4 + 1; // 146097

// Number of days from 1/1/0001 to 12/31/1600
private const int DaysTo1601 = DaysPer400Years * 4;          // 584388
// Number of days from 1/1/0001 to 12/30/1899
private const int DaysTo1899 = DaysPer400Years * 4 + DaysPer100Years * 3 - 367;
// Number of days from 1/1/0001 to 12/31/1969
internal const int DaysTo1970 = DaysPer400Years * 4 + DaysPer100Years * 3 + DaysPer4Years * 17 + DaysPerYear; // 719,162        

Что мы можем теперь использовать, чтобы вычислить количество миллисекунд до 1970 года:

719162 (DaysTo1970) * 24 (hours) * 60 (minutes) * 60 (seconds) * 1000 (milliseconds) 
= 621355967990000
...