روش استفاده از نوع DateOnly در دات نت 6
نوعهای جدید معرفی شده، بسیار واضح هستند و مقصود از بکارگیری آنها را به خوبی بیان میکنند. برای مثال اگر نیاز بود تاریخی را بدون در نظر گرفتن قسمت زمان آن معرفی کنیم، میتوان از نوع DateOnly استفاده کرد؛ مانند تاریخ تولد، روزهای کاری و امثال آن. تا پیش از این برای معرفی یک چنین تاریخهایی، عموما قسمت زمان DateTime را با 00:00:00.000 مقدار دهی میکردیم؛ اما دیگر نیازی به این نوع تعاریف نیست و میتوان مقصود خود را صریحتر بیان کرد.
روش معرفی نمونهای از آن با معرفی سال، ماه و روز است:
var date = new DateOnly(2020, 04, 20);
var currentDate = DateOnly.FromDateTime(DateTime.Now);
همچنین در اینجا نیز همانند DateTime میتوان از متدهای Parse و یا TryParse، برای تبدیل یک رشته به معادل DateOnly آن، کمک گرفت:
if (DateOnly.TryParse("28/09/1984", new CultureInfo("en-US"), DateTimeStyles.None, out var result)) { Console.WriteLine(result); }
و یا میتوان توسط متد ParseExact، ساختار تاریخ دریافتی را دقیقا مشخص کرد:
DateOnly d1 = DateOnly.ParseExact("31 Dec 1980", "dd MMM yyyy", CultureInfo.InvariantCulture); // Custom format Console.WriteLine(d1.ToString("o", CultureInfo.InvariantCulture)); // "1980-12-31" (ISO 8601 format)
در حین نمونه سازی DateOnly، امکان ذکر تقویمهای خاص، مانند PersianCalendar نیز وجود دارد:
var persianCalendar = new PersianCalendar(); DateOnly d2 = new DateOnly(1400, 9, 6, persianCalendar); Console.WriteLine(d2.ToString("d MMMM yyyy", CultureInfo.InvariantCulture));
در اینجا همچنین متدهایی مانند AddDays، AddMonths و AddYears نیز بر روی date مهیا کار میکنند:
var newDate = date.AddDays(1).AddMonths(1).AddYears(1)
یک نکته: برخلاف DateTime، نوع DateOnly به همراه DateTimeKind مانند Utc و امثال آن نیست و همواره DateTimeKind آن Unspecified است.
روش استفاده از نوع TimeOnly در دات نت 6
نوع و ساختار TimeOnly، قسمت زمان را به نحو صریحی مشخص میکند؛ مانند ساعتی که باید هر روز راس آن، آلارمی به صدا درآید و یا جلسهای تشکیل شود و یا وظیفهای صورت گیرد. سازندهی آن overloadهای قابل توجهی را داشته و میتواند یکی از موارد زیر باشد:
public TimeOnly(int hour, int minute) public TimeOnly(int hour, int minute, int second) public TimeOnly(int hour, int minute, int second, int millisecond)
var startTime = new TimeOnly(10, 30);
var endTime = new TimeOnly(13, 00, 00);
و یا برای مثال میتوان این نمونهها را از هم کم کرد:
var diff = endTime - startTime;
Console.WriteLine($"Hours: {diff.TotalHours}");
TimeSpan ts = endTime.ToTimeSpan();
برای تبدیل قسمت زمان DateTime به TimeOnly، میتوان از متد FromDateTime به صورت زیر استفاده کرد:
var currentTime = TimeOnly.FromDateTime(DateTime.Now);
DateTime dt = date.ToDateTime(new TimeOnly(0, 0)); Console.WriteLine(dt);
و در این حالت اگر خواستیم بررسی کنیم که آیا زمانی بین دو زمان دیگر واقع شدهاست یا خیر، میتوان از متد IsBetween استفاده نمود:
var isBetween = currentTime.IsBetween(startTime, endTime); Console.WriteLine($"Current time {(isBetween ? "is" : "is not")} between start and end");
در اینجا امکان مقایسه این نمونهها، توسط عملگرهایی مانند < نیز وجود دارد:
var startTime = new TimeOnly(08, 00); var endTime = new TimeOnly(09, 00); Console.WriteLine($"{startTime < endTime}");
اگر نیاز به تبدیل رشتهای به TimeOnly بود، میتوان از متد ParseExact به همراه ذکر ساختار مدنظر، استفاده کرد:
TimeOnly time = TimeOnly.ParseExact("5:00 pm", "h:mm tt", CultureInfo.InvariantCulture); // Custom format Console.WriteLine(time.ToString("T", CultureInfo.InvariantCulture)); // "17:00:00" (long time format)
فرض کنید رکوردی را به صورت زیر تعریف کردهایم که از نوعهای جدید DateOnly و TimeOnly، تشکیل شدهاست:
public record DataTypeTest(DateOnly Date, TimeOnly Time);
var date = DateOnly.FromDateTime(DateTime.Now); var time = TimeOnly.FromDateTime(DateTime.Now); var test = new DataTypeTest(date, time); var json = JsonSerializer.Serialize(test);
Serialization and deserialization of 'System.DateOnly' instances are not supported.
برای رفع این مشکل میتوان ابتدا تبدیلگر ویژهی DateOnly و
public class DateOnlyConverter : JsonConverter<DateOnly> { private readonly string _serializationFormat; public DateOnlyConverter() : this(null) { } public DateOnlyConverter(string? serializationFormat) { _serializationFormat = serializationFormat ?? "yyyy-MM-dd"; } public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var value = reader.GetString(); return DateOnly.ParseExact(value!, _serializationFormat, CultureInfo.InvariantCulture); } public override void Write(Utf8JsonWriter writer, DateOnly value, JsonSerializerOptions options) => writer.WriteStringValue(value.ToString(_serializationFormat)); }
public class TimeOnlyConverter : JsonConverter<TimeOnly> { private readonly string _serializationFormat; public TimeOnlyConverter() : this(null) { } public TimeOnlyConverter(string? serializationFormat) { _serializationFormat = serializationFormat ?? "HH:mm:ss.fff"; } public override TimeOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var value = reader.GetString(); return TimeOnly.ParseExact(value!, _serializationFormat, CultureInfo.InvariantCulture); } public override void Write(Utf8JsonWriter writer, TimeOnly value, JsonSerializerOptions options) => writer.WriteStringValue(value.ToString(_serializationFormat)); }
var jsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); jsonOptions.Converters.Add(new DateOnlyConverter()); jsonOptions.Converters.Add(new TimeOnlyConverter()); var json = JsonSerializer.Serialize(test, jsonOptions);