DateTimeOffset در سی شارپ
DateTimeOffset در سی شارپ، تاریخ و زمان را همراه با اختلاف ساعت نسبت به UTC ذخیره میکند. برای کار با مناطق زمانی ایدهآل است.
26 اردیبهشت 1405
لینک کوتاه
DateTimeOffset در سی شارپ
DateTimeOffset در سیشارپ یک ساختار مقداری است که هم یک لحظه خاص در زمان (شامل سال، ماه، روز، ساعت، دقیقه، ثانیه و کسرهای ثانیه) و هم انحراف آن از ساعت هماهنگ جهانی (UTC) را به صورت یک مقدار TimeSpan ذخیره میکند.برخلاف DateTime که میتواند مبهم باشد (مثلاً نمیفهمد یک ساعت ۳:۰۰ مربوط به کدام منطقه زمانی است)، DateTimeOffset به طور صریح منطقه زمانی را نسبت به UTC مشخص میکند. به همین دلیل برای ذخیره زمان وقوع رویدادها، ثبت لاگها در سیستمهای توزیعشده و هر جایی که نیاز به حفظ اطلاعات دقیق منطقه زمانی بدون ابهام باشد، بسیار مناسبتر و ایمنتر است.
تفاوت DateTimeOffset با DateTime در سی شارپ
قبل از هر چیز، باید تفاوت اصلی بین DateTime و DateTimeOffset را درک کنیم:-
DateTime
فقط یک نقطه در زمان را ذخیره میکند، بدون اینکه بداند آن زمان متعلق به کدام منطقه زمانی است.
خاصیت Kind میتواند مشخص کند که زمان محلی (Local)، UTC، یا نامشخص (Unspecified) است، اما این اطلاعات برای محاسبات دقیق زمانی کافی نیست. -
DateTimeOffset
علاوه بر ذخیره نقطه در زمان، اختلاف آن با UTC را نیز به صورت ساعت و دقیقه (مثلاً 3:30+ یا 5:00-) ذخیره میکند.
این آفست به شما میگوید که زمان ذخیره شده چه قدر با UTC فاصله دارد.
DateTime dt = new DateTime(2024, 3, 15, 14, 30, 0);
DateTimeOffset dto = new DateTimeOffset(2024, 3, 15, 14, 30, 0, TimeSpan.FromHours(3.5));
// dto الان یعنی ساعت 14:30 در منطقهای که 3 ساعت و 30 دقیقه از UTC جلوتر است.

ساختار داخلی DateTimeOffset در سی شارپ
DateTimeOffset دو فیلد اصلی دارد:-
DateTime
مقدار تاریخ و زمان اصلی (که معمولاً در UTC یا محلی ذخیره میشود) -
Offset
یک TimeSpan که نشاندهنده اختلاف با UTC است (معمولاً بین 14- تا 14+ ساعت)
مهم است بدانید که خود DateTimeOffset همیشه زمان را به صورت UTC در حافظه ذخیره نمیکند، بلکه زمان را همراه با آفست نگه میدارد.
اما متدهایی برای تبدیل به UTC دارد.
آیا به دنبال یک فرصت عالی برای یادگیری برنامهنویسی هستید؟ 🚀
با دوره آموزشی سیشارپ ما، شما میتوانید مهارتهای خود را به سطح جدیدی ارتقا دهید! این دوره بهطور کامل طراحی شده تا به شما کمک کند تا از مبتدی تا پیشرفته در دنیای برنامهنویسی سیشارپ پیش بروید.
👨🏫 چرا دوره ما را انتخاب کنید؟
- محتوای جامع و عملی: با پروژههای واقعی و تمرینات عملی، یادگیری را به تجربهای جذاب تبدیل کنید.
- مدرس مجرب: از تجربه و دانش مدرس حرفهای بهرهمند شوید که شما را در هر مرحله از یادگیری راهنمایی میکنند.
- پشتیبانی ۲۴/۷: هر زمان که سوالی داشتید، ما در کنار شما خواهیم بود تا به شما کمک کنیم.
- دسترسی مادامالعمر: به محتوای دوره دسترسی دائمی داشته باشید و هر زمان که خواستید، میتوانید به آن مراجعه کنید.
💡 فرصت را از دست ندهید!
بایادگیری سیشارپ، میتوانید در دنیای فناوری اطلاعات به یک متخصص تبدیل شوید و در پروژههای جذاب و چالشبرانگیز شرکت کنید.
همین امروز به جمع یادگیرندگان ما بپیوندید و اولین قدم را به سوی آیندهای روشنتر بردارید!
شرکت در دوره آموزش برنامه نویسی سی شارپ
نحوه ایجاد DateTimeOffset در سی شارپ
روشهای مختلفی برای ایجاد یک نمونه از DateTimeOffset وجود دارد:1. استفاده از سازنده (Constructor)
// با مشخص کردن سال، ماه، روز، ساعت، دقیقه، ثانیه و آفست
DateTimeOffset dto1 = new DateTimeOffset(2024, 12, 25, 10, 30, 0, TimeSpan.FromHours(2));
// با استفاده از DateTime موجود
DateTime dt = DateTime.Now;
DateTimeOffset dto2 = new DateTimeOffset(dt);
// با استفاده از DateTime و آفست جداگانه
DateTimeOffset dto3 = new DateTimeOffset(dt, TimeSpan.FromHours(-5));
2. استفاده از زمان فعلی
// زمان جاری در سیستم محلی با آفست محلی
DateTimeOffset now = DateTimeOffset.Now;
// زمان UTC جاری با آفست صفر
DateTimeOffset utcNow = DateTimeOffset.UtcNow;
3. تجزیه (Parsing) از رشته
string dateString = "2024-03-15T14:30:00+03:30";
DateTimeOffset parsed = DateTimeOffset.Parse(dateString);
// یا با استفاده از TryParse برای جلوگیری از خطا
if (DateTimeOffset.TryParse(dateString, out DateTimeOffset result))
{
Console.WriteLine($"Parsed: {result}");
}
4. استفاده از لیتورالهای جدید (C# 7.0+)
DateTimeOffset dto = new DateTimeOffset(2024, 3, 15, 14, 30, 0, TimeSpan.Zero);

خاصیتهای مهم DateTimeOffset در سی شارپ
DateTimeOffset دارای خاصیتهای متعددی است که دسترسی به اجزای مختلف زمان و آفست را ممکن میسازد:DateTimeOffset dto = DateTimeOffset.Now;
Console.WriteLine($"تاریخ: {dto.Date}");
Console.WriteLine($"روز: {dto.Day}");
Console.WriteLine($"روز هفته: {dto.DayOfWeek}");
Console.WriteLine($"روز سال: {dto.DayOfYear}");
Console.WriteLine($"ساعت: {dto.Hour}");
Console.WriteLine($"میلیثانیه: {dto.Millisecond}");
Console.WriteLine($"دقیقه: {dto.Minute}");
Console.WriteLine($"ماه: {dto.Month}");
Console.WriteLine($"آفست: {dto.Offset}");
Console.WriteLine($"ثانیه: {dto.Second}");
Console.WriteLine($"تیک (Tick): {dto.Ticks}");
Console.WriteLine($"زمان در روز: {dto.TimeOfDay}");
Console.WriteLine($"سال: {dto.Year}");
Console.WriteLine($"UTC زمان: {dto.UtcDateTime}");
Console.WriteLine($"UTC تیک: {dto.UtcTicks}");
متدهای کلیدی DateTimeOffset
تبدیل به UTC و زمان محلی
DateTimeOffset localTime = DateTimeOffset.Now;
DateTimeOffset utcTime = localTime.ToUniversalTime(); // تبدیل به UTC
DateTimeOffset backToLocal = utcTime.ToLocalTime(); // بازگشت به محلی
نکته مهم: تبدیل ()ToUniversalTime زمان را به UTC تبدیل میکند و آفست را صفر قرار میدهد.
برعکس، ()ToLocalTime از منطقه زمانی سیستم فعلی برای محاسبه استفاده میکند.
عملیات ریاضی روی DateTimeOffset
مشابه DateTime، میتوانید روی DateTimeOffset عملیات جمع و تفریق انجام دهید:
DateTimeOffset start = new DateTimeOffset(2024, 1, 1, 0, 0, 0, TimeSpan.Zero);
// اضافه کردن 5 روز
DateTimeOffset after5Days = start.AddDays(5);
// اضافه کردن 3 ساعت و 20 دقیقه
DateTimeOffset later = start.AddHours(3).AddMinutes(20);
// محاسبه تفاوت بین دو DateTimeOffset
TimeSpan difference = later - start;
Console.WriteLine($"اختلاف: {difference.TotalHours} ساعت");
متدهای موجود برای اضافه کردن:
-
()AddDays(), AddHours(), AddMinutes(), AddSeconds(), AddMilliseconds
-
()AddMonths(), AddYears
-
()AddTicks
-
Add(TimeSpan)
مقایسه DateTimeOffset
دو DateTimeOffset را میتوان با عملگرهای مقایسهای (==، !=، <، >، <=، >=) مقایسه کرد.نکته جالب این است که مقایسه بر اساس زمان UTC انجام میشود، نه مقدار ظاهری:
DateTimeOffset dto1 = new DateTimeOffset(2024, 3, 15, 14, 0, 0, TimeSpan.FromHours(2));
DateTimeOffset dto2 = new DateTimeOffset(2024, 3, 15, 12, 0, 0, TimeSpan.Zero);
// این دو زمان معادل هستند چون هر دو نشاندهنده 12:00 UTC هستند
bool isEqual = dto1 == dto2; // true
// برای مقایسه دقیق با در نظر گرفتن آفست (برابر بودن دقیقا همان لحظه)
bool exactlyEqual = dto1.EqualsExact(dto2); // false
متدهای کمکی
// بررسی اینکه آیا زمان در روز صرفهجویی (Daylight Saving) است
bool isDaylightSaving = dto.IsDaylightSavingTime();
// دریافت مقدار DateTime (بدون آفست)
DateTime dateTimeValue = dto.DateTime; // همان زمان ذخیره شده بدون تغییر
// دریافت زمان محلی (با در نظر گرفتن منطقه زمانی سیستم)
DateTimeOffset local = dto.ToLocalTime();
سریالایز کردن (Serialize) DateTimeOffset
یکی از نقاط قوت DateTimeOffset سریالایز کردن آسان آن به فرمتهای استاندارد مانند JSON و XML است:-
JSON (با System.Text.Json یا Newtonsoft.Json)
public class Event
{
public string Name { get; set; }
public DateTimeOffset StartTime { get; set; }
}
Event myEvent = new Event
{
Name = "کنفرانس بینالمللی",
StartTime = new DateTimeOffset(2024, 5, 20, 9, 0, 0, TimeSpan.FromHours(3.5))
};
string json = System.Text.Json.JsonSerializer.Serialize(myEvent);
Console.WriteLine(json);
// {"Name":"کنفرانس بینالمللی","StartTime":"2024-05-20T09:00:00+03:30"}
// دیسریالایز کردن
Event deserialized = System.Text.Json.JsonSerializer.Deserialize<Event>(json);
-
فرمت ISO 8601
فرمت استاندارد ISO 8601 (yyyy-MM-ddTHH:mm:ss±hh:mm) بهترین انتخاب برای تبادل زمان بین سیستمهای مختلف است.
DateTimeOffset به طور پیشفرض از این فرمت پشتیبانی میکند:
DateTimeOffset now = DateTimeOffset.Now;
string isoString = now.ToString("O"); // "O" برای Round-trip format
// خروجی: 2024-03-15T14:30:00.1234567+03:30
ذخیرهسازی در پایگاه داده SQL Server
در SQL Server، نوع داده datetimeoffset معادل مستقیم DateTimeOffset در سیشارپ است:// Entity Framework Core
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public DateTimeOffset CreatedAt { get; set; }
}
// ذخیرهسازی خودکار انجام میشود
using (var context = new MyDbContext())
{
var product = new Product
{
Name = "لپتاپ",
CreatedAt = DateTimeOffset.UtcNow
};
context.Products.Add(product);
context.SaveChanges();
}
با Dapper:
string sql = "INSERT INTO Orders (OrderDate) VALUES (@OrderDate)";
DateTimeOffset orderDate = DateTimeOffset.Now;
connection.Execute(sql, new { OrderDate = orderDate });
بهترین شیوه DateTimeOffset در سی شارپ
1. همیشه از UTC برای ذخیرهسازی استفاده کنید
اگر سیستم شما در چند منطقه زمانی کار میکند، بهترین کار این است که زمانها را به UTC تبدیل کنید و همراه با آفست اصلی (اگر نیاز است) ذخیره کنید:// دریافت زمان از کاربر
DateTimeOffset userInput = GetUserDateTime();
// ذخیره UTC
DateTimeOffset utcForStorage = userInput.ToUniversalTime();
// همچنین آفست اصلی را هم اگر نیاز دارید ذخیره کنید
TimeSpan originalOffset = userInput.Offset;
2. برای نمایش به کاربر، به زمان محلی تبدیل کنید
DateTimeOffset storedUtc = GetFromDatabase();
DateTimeOffset userLocalTime = storedUtc.ToLocalTime();
Console.WriteLine($"زمان رویداد در منطقه شما: {userLocalTime}");
3. از DateTimeOffset.Now به جای DateTime.Now استفاده کنید
DateTime.Now میتواند گمراهکننده باشد چون Kind آن Local است اما آفست ندارد.DateTimeOffset.Now آفست محلی سیستم را هم ارائه میدهد.
4. هنگام سریالایز کردن، از Round-trip format استفاده کنید
string serialized = dateTimeOffset.ToString("O", CultureInfo.InvariantCulture);
// بعداً
DateTimeOffset deserialized = DateTimeOffset.Parse(serialized, null, DateTimeStyles.RoundtripKind);
5. مراقب عملیات مقایسه باشید
// اینها معادلاند (نشاندهنده یک لحظه در زمان)
DateTimeOffset a = new DateTimeOffset(2024, 1, 1, 12, 0, 0, TimeSpan.Zero);
DateTimeOffset b = new DateTimeOffset(2024, 1, 1, 14, 0, 0, TimeSpan.FromHours(2));
Console.WriteLine(a == b); // true
// ولی اینها دقیقاً برابر نیستند
Console.WriteLine(a.EqualsExact(b)); // false

مثال عملی: سیستم رزرواسیون بینالمللی
فرض کنید در حال طراحی یک سیستم رزرواسیون پرواز هستید که کاربران از سراسر جهان در آن ثبتنام میکنند:public class FlightReservation
{
public int Id { get; set; }
public string PassengerName { get; set; }
public DateTimeOffset DepartureTime { get; set; }
public DateTimeOffset ArrivalTime { get; set; }
public string DepartureAirport { get; set; }
public string ArrivalAirport { get; set; }
public TimeSpan GetFlightDuration()
{
// محاسبه با زمان UTC برای دقت
return ArrivalTime.ToUniversalTime() - DepartureTime.ToUniversalTime();
}
public void DisplayToUser(TimeZoneInfo userTimeZone)
{
DateTimeOffset userDeparture = TimeZoneInfo.ConvertTime(DepartureTime, userTimeZone);
DateTimeOffset userArrival = TimeZoneInfo.ConvertTime(ArrivalTime, userTimeZone);
Console.WriteLine($"مسافر: {PassengerName}");
Console.WriteLine($"پرواز از {DepartureAirport}: {userDeparture:yyyy/MM/dd HH:mm}");
Console.WriteLine($"رسیدن به {ArrivalAirport}: {userArrival:yyyy/MM/dd HH:mm}");
Console.WriteLine($"مدت پرواز: {GetFlightDuration().Hours} ساعت و {GetFlightDuration().Minutes} دقیقه");
}
}
// استفاده
var reservation = new FlightReservation
{
PassengerName = "علی رضایی",
// زمان پرواز از تهران (UTC+3:30)
DepartureTime = new DateTimeOffset(2024, 6, 15, 8, 0, 0, TimeSpan.FromHours(3.5)),
// زمان رسیدن به لندن (UTC+1)
ArrivalTime = new DateTimeOffset(2024, 6, 15, 10, 30, 0, TimeSpan.FromHours(1)),
DepartureAirport = "IKA",
ArrivalAirport = "LHR"
};
// نمایش برای کاربر در منطقه زمانی نیویورک (UTC-4)
TimeZoneInfo nyTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
reservation.DisplayToUser(nyTimeZone);
جمعبندی
DateTimeOffset یک ابزار قدرتمند و ضروری برای برنامهنویسانی است که با زمان در مقیاس جهانی کار میکنند. مزایای کلیدی آن عبارتند از:دقت در مناطق زمانی: با ذخیره آفست، همیشه میدانید زمان اصلی متعلق به کدام منطقه بوده است.
محاسبات صحیح: عملیات ریاضی روی DateTimeOffset به درستی مناطق زمانی و تغییرات ساعت را در نظر میگیرد.
سریالایز کردن آسان: پشتیبانی عالی از فرمت ISO 8601 و کار با JSON/XML.
سازگاری با پایگاه داده: پشتیبانی مستقیم در SQL Server و ORMهایی مانند EF Core.
کد خواناتر: به وضوح نشان میدهید که با زمان و منطقه زمانی سر و کار دارید.
توصیه من: در تمام پروژههای جدید، به جای DateTime از DateTimeOffset استفاده کنید، مگر اینکه دلایل قانعکنندهای برای عدم استفاده داشته باشید.
این کار شما را از بسیاری از باگهای مربوط به منطقه زمانی و ساعت تابستانی نجات میدهد.


کاربران ما
شما هم نظرتون با ما دریاره “DateTimeOffset در سی شارپ” اشتراک بزارید
برای ارسال نظر لطفا ورود یا ثبت نام کنید