2011年10月2日 星期日

C# DateTime 與其他語言 DateTime 計算的注意事項

在 PHP、Java、C++ 等語言上面的日期類別在取 getTimeInMillis() 時…
以現在的日期時間來看應該是拿到類似 1317528009050 這樣的長整數…
但 C# 拿到的值非常不一樣…是類似 634531104000000000 這樣子的長整數…

若只是 Client 端自行需要取出 H、M、S 倒是不影響…
但若是兩個設備要做校時…那就要是雙方都能識別的格式嘍…

這兩種差異的原因在於計算起點不一致與單位不一致所引起的…
PHP、Java 等是以 Epoch 開始計算毫秒數,即 1970-01-01 00:00:00
而 C# 是以 0001-01-01 00:00:00 所開始計算的 100 奈秒數…
只要根據這兩項差異運算一下…再注意是否為 UTC 時間…其本上運算都不會有啥問題的…
因為我目前是在寫 Windows Phone 的專案碰到這個問題的…
所以範例是將從 Apache Server 上取回的時間轉成 C# DateTime 格式…


long lServerTime = /* 取到 Server 告知的時間,例如 1317528009050 */
DateTime dtServer = TransDateTime(lServerTime);

// 取得 Client、Server 相差的秒數
double diffSeconds = DateTime.Now.Subtract(dtServer).TotalSeconds;

....

public static DateTime TransDateTime(long time)
{
    long cTime = (time * 10000) + (new DateTime(1970, 1, 1, 8, 0, 0).Ticks);
    // 若要轉換的對像單位是秒而非毫秒,記得要多乘上 1000 如下
    // long cTime = (time * 10000000) + (new DateTime(1970, 1, 1, 8, 0, 0).Ticks);
    DateTime dTime = new DateTime(cTime);
    return dTime;
}


將 C# DateTime 轉為 Epoch 的方式也很簡單


// 轉為正常毫秒計算的 Epoch
long epochNow = Decimal.ToInt64(Decimal.Divide(DateTime.Now.Ticks - new DateTime(1970, 1, 1, 8, 0, 0).Ticks, 10000))

// 轉為秒數
long epochNow = Decimal.ToInt64(Decimal.Divide(DateTime.Now.Ticks - new DateTime(1970, 1, 1, 8, 0, 0).Ticks, 10000000))

// 此外若比較重視效率…也可以將上面的

DateTime.Now.Ticks - new DateTime(1970, 1, 1, 8, 0, 0).Ticks

// 簡化為

DateTime.UtcNow.Ticks - 621355968000000000



附記:Epoch 指的是 1970-01-01 起所經過的 "秒數" 所以是 10 位整數…

3 則留言:

  1. 請問,不是從1970-1-1 0:0:0開始計算的嗎? 那為什麼會是減去new DateTime(1970,1,1,8,0,0), 而不是new DateTime(1970,1,1,0,0,0)呢?

    回覆刪除