在C#中處理時(shí)間戳和時(shí)區(qū)的解決方法
介紹
處理時(shí)間戳和不同的時(shí)區(qū)可能是軟件開發(fā)中的一個(gè)棘手問題。尤其是當(dāng)系統(tǒng)不確定給定的日期時(shí)間是UTC還是本地時(shí)間時(shí),通常會遇到與時(shí)間轉(zhuǎn)換相關(guān)的問題。在這篇文章中,我將分享我們?nèi)绾卧贑#應(yīng)用程序中使用Unix時(shí)間來簡化時(shí)間管理的經(jīng)驗(yàn)。
問題
在我們的工作中,經(jīng)常遇到系統(tǒng)對給定的日期時(shí)間是UTC還是本地時(shí)間感到困惑,從而導(dǎo)致幾個(gè)小時(shí)的時(shí)間差異。這在不同時(shí)間格式和時(shí)區(qū)之間進(jìn)行轉(zhuǎn)換時(shí)尤其問題嚴(yán)重。
我們的解決方案
為了解決這些問題,我們決定使用Unix時(shí)間(以秒或毫秒為單位)來替換數(shù)據(jù)庫中的日期時(shí)間或字符串表示。Unix時(shí)間是一種定義明確的、與時(shí)區(qū)無關(guān)的時(shí)間表示方法,這使得時(shí)間處理和轉(zhuǎn)換變得更容易。
實(shí)現(xiàn)Timestamp類
在我們的C#代碼中,我們創(chuàng)建了一個(gè)封裝Unix時(shí)間(以毫秒為單位)的Timestamp
類。這個(gè)類提供了各種方法來轉(zhuǎn)換為其他時(shí)間格式或從其他時(shí)間格式轉(zhuǎn)換,確保所有時(shí)間操作的一致性和正確性。
Timestamp類定義
以下是我們定義的Timestamp
類:
public class Timestamp { public double UnixTime_ms { get; set; } = 0.0; public static DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); public static Timestamp CurrentTimestamp() { return FromDateTimeUTC(DateTime.UtcNow); } public static Timestamp FromUnixTimeSec(double unix_s) { return new Timestamp() { UnixTime_ms = unix_s * 1000.0, }; } public static Timestamp FromUnixTimeMilliSec(double unix_ms) { return new Timestamp() { UnixTime_ms = unix_ms, }; } public static Timestamp FromDateTimeUTC(DateTime dateTime) { if (dateTime.Kind == DateTimeKind.Unspecified) { dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc); } return new Timestamp() { UnixTime_ms = (dateTime - UnixEpoch).TotalMilliseconds }; } public static Timestamp FromTimestampUTC(string timestampUTC) { bool tryDateTime = DateTime.TryParse(timestampUTC, out DateTime res); if (tryDateTime) { long unixMs = new DateTimeOffset(res.ToUniversalTime()).ToUnixTimeMilliseconds(); return new Timestamp() { UnixTime_ms = unixMs, }; } else { return new Timestamp(); } } public override bool Equals(object obj) { return obj is Timestamp timestamp && UnixTime_ms == timestamp.UnixTime_ms; } public override int GetHashCode() { return -262018729 + UnixTime_ms.GetHashCode(); } public static bool operator ==(Timestamp left, Timestamp right) { return EqualityComparer<Timestamp>.Default.Equals(left, right); } public static bool operator !=(Timestamp left, Timestamp right) { return !(left == right); } public static bool operator >(Timestamp left, Timestamp right) { return left.UnixTime_ms > right.UnixTime_ms; } public static bool operator <(Timestamp left, Timestamp right) { return left.UnixTime_ms < right.UnixTime_ms; } public static bool operator >=(Timestamp left, Timestamp right) { return left.UnixTime_ms >= right.UnixTime_ms; } public static bool operator <=(Timestamp left, Timestamp right) { return left.UnixTime_ms <= right.UnixTime_ms; } }
轉(zhuǎn)換的擴(kuò)展方法
我們還創(chuàng)建了擴(kuò)展方法,用于在不同時(shí)間格式之間進(jìn)行轉(zhuǎn)換:
public static class TimestampExtensions { private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); public static double ToUnixS(this Timestamp timestamp) => timestamp.UnixTime_ms / 1000.0; public static double ToUnixMins(this Timestamp timestamp) => timestamp.UnixTime_ms / 60000.0; public static DateTime ToDateTimeUTC(this Timestamp timestamp) => UnixEpoch.AddMilliseconds(timestamp.UnixTime_ms).ToUniversalTime(); public static string ToLabel(this Timestamp timestamp) => timestamp.ToDateTimeUTC().ToString("yyyy/MM/dd h:mm:ss tt"); public static bool IsWithinRange(this Timestamp timestamp, Timestamp startTime, Timestamp endTime) { if (timestamp == null || startTime == null || endTime == null) { return false; } return timestamp.UnixTime_ms >= startTime.UnixTime_ms && timestamp.UnixTime_ms <= endTime.UnixTime_ms; } // 其他擴(kuò)展方法... }
在主邏輯中使用Timestamp類
在我們的主應(yīng)用程序邏輯中,我們專門使用Timestamp
類來表示時(shí)間。這種方法幫助我們避免了與時(shí)間轉(zhuǎn)換相關(guān)的任何問題,因?yàn)樗械臅r(shí)間相關(guān)數(shù)據(jù)都以一致的格式存儲和處理。
以下是我們在代碼中使用Timestamp
類的示例:
public class ExampleService { public void ProcessData() { // 獲取當(dāng)前時(shí)間作為Timestamp Timestamp currentTime = Timestamp.CurrentTimestamp(); // 將Timestamp轉(zhuǎn)換為DateTime以便顯示 DateTime displayTime = currentTime.ToDateTimeUTC(); // 記錄當(dāng)前時(shí)間 Console.WriteLine($"當(dāng)前時(shí)間: {currentTime.ToLabel()}"); } }
在數(shù)據(jù)庫視圖(View)中轉(zhuǎn)換Unix時(shí)間
為了方便讀懂?dāng)?shù)據(jù)庫中Unix時(shí)間,可以創(chuàng)建處理這些轉(zhuǎn)換的視圖(View)。以下是在SQL Server中的示例:
CREATE VIEW dbo.ExampleView AS SELECT Id, Name, Description, DATEADD(MILLISECOND, UnixTime_ms, '1970-01-01 00:00:00') AS DateTimeValue FROM dbo.ExampleTable;
在C#數(shù)據(jù)訪問層(DAO)中映射轉(zhuǎn)換
在查詢數(shù)據(jù)并將其映射到對象時(shí),可以在數(shù)據(jù)訪問層中處理這些轉(zhuǎn)換:
public class ExampleRepository { private readonly string connectionString; public ExampleRepository(string connectionString) { this.connectionString = connectionString; } public ExampleModel GetExampleById(int id) { using (var connection = new SqlConnection(connectionString)) { string query = "SELECT Id, Name, Description, UnixTime_ms FROM ExampleTable WHERE Id = @Id"; var exampleData = connection.QuerySingleOrDefault(query, new { Id = id }); if (exampleData != null) { return new ExampleModel { Id = exampleData.Id, Name = exampleData.Name, Description = exampleData.Description, Timestamp = Timestamp.FromUnixTimeMilliSec(exampleData.UnixTime_ms) }; } return null; } } }
這種方法的好處
通過使用Unix時(shí)間和專門的Timestamp
類,我們實(shí)現(xiàn)了以下幾個(gè)好處:
- 一致性:所有時(shí)間數(shù)據(jù)都以一致的、與時(shí)區(qū)無關(guān)的格式表示。
- 簡便性:封裝在
Timestamp
類中的轉(zhuǎn)換方法簡化了時(shí)間操作。 - 清晰性:代碼中明確顯示所有時(shí)間數(shù)據(jù)都以統(tǒng)一的方式處理,從而減少了錯(cuò)誤的風(fēng)險(xiǎn)。
結(jié)論
處理時(shí)間戳和時(shí)區(qū)可能很復(fù)雜,但通過使用Unix時(shí)間并將其封裝在Timestamp
類中,我們簡化了時(shí)間管理并避免了許多常見的陷阱。我希望這種方法也能幫助到你的項(xiàng)目。
以上就是在C#中處理時(shí)間戳和時(shí)區(qū)的解決方法的詳細(xì)內(nèi)容,更多關(guān)于C#處理時(shí)間戳和時(shí)區(qū)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用C#創(chuàng)建Windows服務(wù)的實(shí)例代碼
這篇文章主要介紹了使用C#創(chuàng)建Windows服務(wù)的實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07使用GetInvalidFileNameCharts生成文件名
這篇文章主要介紹了一個(gè)很實(shí)用的函數(shù)Path.GetInvalidFileNameCharts(),他可以很方便的生成一個(gè)有效的文件名稱2014-01-01C#實(shí)現(xiàn)在服務(wù)器端裁剪圖片的方法
這篇文章主要介紹了C#實(shí)現(xiàn)在服務(wù)器端裁剪圖片的方法,涉及C#操作圖片的相關(guān)技巧,需要的朋友可以參考下2015-04-04