Aracılığıyla paylaş


Nasıl yapılır: Tarih ve saat aritmetiğinde saat dilimlerini kullanma

Normalde, DateTime veya DateTimeOffset değerleriyle tarih ve saat hesaplamaları yaptığınızda, sonuç herhangi bir saat dilimi ayarlama kuralını yansıtmaz. Tarih ve saat değerinin saat dilimi açıkça tanımlanabilir olduğunda bile (örneğin, Kind özelliği olarak Localayarlandığında) bu durum geçerlidir. Bu konu, belirli bir saat dilimine ait tarih ve saat değerlerinde aritmetik işlemlerin nasıl gerçekleştirildiğini gösterir. Aritmetik işlemlerin sonuçları, saat diliminin ayarlama kurallarını yansıtır.

Ayarlama kurallarını tarih ve saat aritmetiğine uygulamak için

  1. Bir tarih ve saat değerini ait olduğu saat dilimiyle yakından eşleştirmek için bazı yöntemler uygulayın. Örneğin, hem tarih ve saat değerini hem de saat dilimini içeren bir yapı bildirin. Aşağıdaki örnek, bir DateTime değeri saat dilimine bağlamak için bu yaklaşımı kullanır.

    // Define a structure for DateTime values for internal use only
    internal struct TimeWithTimeZone
    {
        TimeZoneInfo TimeZone;
        DateTime Time;
    }
    
    ' Define a structure for DateTime values for internal use only
    Friend Structure TimeWithTimeZone
        Dim TimeZone As TimeZoneInfo
        Dim Time As Date
    End Structure
    
  2. ConvertTimeToUtc yöntemini veya ConvertTime yöntemini çağırarak bir saati Eşgüdümlü Evrensel Saat'e (UTC) dönüştürün.

  3. Aritmetik işlemi UTC saatinde gerçekleştirin.

  4. yöntemini çağırarak saati UTC'den özgün saatin ilişkili saat dilimine dönüştürün TimeZoneInfo.ConvertTime(DateTime, TimeZoneInfo) .

Örnek

Aşağıdaki örnek, 9 Mart 2008 saat 01:30 Merkezi Standart Saati'ne iki saat otuz dakika ekler. Saat diliminin yaz saati geçişi otuz dakika sonra, 9 Mart 2008'de saat 02:00'de gerçekleşir. Örnek, önceki bölümde listelenen dört adımı izlediğinden, 9 Mart 2008'de elde edilen süreyi doğru bir şekilde 05:00 olarak bildirir.

using System;

public struct TimeZoneTime
{
    public TimeZoneInfo TimeZone;
    public DateTime Time;

    public TimeZoneTime(TimeZoneInfo tz, DateTime time)
    {
        ArgumentNullException.ThrowIfNull(tz);

        TimeZone = tz;
        Time = time;
    }

    public TimeZoneTime AddTime(TimeSpan interval)
    {
        // Convert time to UTC
        DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(Time, TimeZone);
        // Add time interval to time
        utcTime = utcTime.Add(interval);
        // Convert time back to time in time zone
        return new TimeZoneTime(TimeZone, TimeZoneInfo.ConvertTime(utcTime,
                                TimeZoneInfo.Utc, TimeZone));
    }
}

public class TimeArithmetic
{
    public const string TzName = "Central Standard Time";

    public static void Main()
    {
        try
        {
            TimeZoneTime cstTime1, cstTime2;

            TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(TzName);
            DateTime time1 = new(2008, 3, 9, 1, 30, 0);
            TimeSpan twoAndAHalfHours = new(2, 30, 0);

            cstTime1 = new TimeZoneTime(cst, time1);
            cstTime2 = cstTime1.AddTime(twoAndAHalfHours);
            Console.WriteLine($"{cstTime1.Time} + {twoAndAHalfHours.ToString()} hours = {cstTime2.Time}");
        }
        catch
        {
            Console.WriteLine($"Unable to find {TzName}.");
        }
    }
}
Public Structure TimeZoneTime
    Public TimeZone As TimeZoneInfo
    Public Time As Date

    Public Sub New(tz As TimeZoneInfo, time As Date)
        If tz Is Nothing Then _
           Throw New ArgumentNullException("The time zone cannot be a null reference.")

        Me.TimeZone = tz
        Me.Time = time
    End Sub

    Public Function AddTime(interval As TimeSpan) As TimeZoneTime
        ' Convert time to UTC
        Dim utcTime As DateTime = TimeZoneInfo.ConvertTimeToUtc(Me.Time, _
                                                                Me.TimeZone)
        ' Add time interval to time
        utcTime = utcTime.Add(interval)
        ' Convert time back to time in time zone
        Return New TimeZoneTime(Me.TimeZone, TimeZoneInfo.ConvertTime(utcTime, _
                                TimeZoneInfo.Utc, Me.TimeZone))
    End Function
End Structure

Module TimeArithmetic
    Public Const tzName As String = "Central Standard Time"

    Public Sub Main()
        Try
            Dim cstTime1, cstTime2 As TimeZoneTime

            Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tzName)
            Dim time1 As Date = #03/09/2008 1:30AM#
            Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)

            cstTime1 = New TimeZoneTime(cst, time1)
            cstTime2 = cstTime1.AddTime(twoAndAHalfHours)

            Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, _
                                                       twoAndAHalfHours.ToString(), _
                                                       cstTime2.Time)
        Catch
            Console.WriteLine("Unable to find {0}.", tzName)
        End Try
    End Sub
End Module

Hem DateTime hem de DateTimeOffset değerler ait olabilecekleri herhangi bir saat diliminden bağımsızdır. Tarih ve saat aritmetiğini bir saat diliminin ayarlama kurallarını otomatik olarak uygulayacak şekilde gerçekleştirmek için, herhangi bir tarih ve saat değerinin ait olduğu saat dilimi hemen tanımlanabilir olmalıdır. Bu, bir tarih ve saatin ve ilişkili saat diliminin sıkı bir şekilde birleştirilmesi gerektiği anlamına gelir. Bunu yapmanın aşağıdakiler dahil olmak üzere birkaç yolu vardır:

  • Bir uygulamada kullanılan tüm zamanların belirli bir saat dilimine ait olduğunu varsayalım. Bazı durumlarda uygun olsa da, bu yaklaşım sınırlı esneklik ve muhtemelen sınırlı taşınabilirlik sunar.

  • Her ikisini de türün alanları olarak ekleyerek bir tarih ve saati ilişkili saat dilimiyle sıkı bir şekilde eşleştiren bir tür tanımlayın. Bu yaklaşım, tarih ve saat ile saat dilimini iki üye alanında depolamak için bir yapı tanımlayan kod örneğinde kullanılır.

Örnekte, DateTime değerleri üzerinde aritmetik işlemler gerçekleştirilerek saat dilimi ayarlama kurallarının nasıl sonuca uygulandığı gösterilmektedir. Ancak, DateTimeOffset değerler de aynı şekilde kolayca kullanılabilir. Özgün örnekteki kodun, DateTime yerine DateTimeOffset değerler kullanılarak nasıl uyarlanabileceğini gösteren aşağıdaki örnek.

using System;

public struct TimeZoneTime2
{
    public TimeZoneInfo TimeZone;
    public DateTimeOffset Time;

    public TimeZoneTime2(TimeZoneInfo tz, DateTimeOffset time)
    {
        ArgumentNullException.ThrowIfNull(tz);

        TimeZone = tz;
        Time = time;
    }

    public TimeZoneTime2 AddTime(TimeSpan interval)
    {
        // Convert time to UTC
        DateTimeOffset utcTime = TimeZoneInfo.ConvertTime(Time, TimeZoneInfo.Utc);
        // Add time interval to time
        utcTime = utcTime.Add(interval);
        // Convert time back to time in time zone
        return new TimeZoneTime2(TimeZone, TimeZoneInfo.ConvertTime(utcTime, TimeZone));
    }
}

public class TimeArithmetic2
{
    public const string tzName = "Central Standard Time";

    public static void Main()
    {
        try
        {
            TimeZoneTime2 cstTime1, cstTime2;

            TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(tzName);
            DateTime time1 = new(2008, 3, 9, 1, 30, 0);
            TimeSpan twoAndAHalfHours = new(2, 30, 0);

            cstTime1 = new TimeZoneTime2(cst,
                           new DateTimeOffset(time1, cst.GetUtcOffset(time1)));
            cstTime2 = cstTime1.AddTime(twoAndAHalfHours);
            Console.WriteLine($"{cstTime1.Time} + {twoAndAHalfHours.ToString()} hours = {cstTime2.Time}");
        }
        catch
        {
            Console.WriteLine($"Unable to find {tzName}.");
        }
    }
}
Public Structure TimeZoneTime
    Public TimeZone As TimeZoneInfo
    Public Time As DateTimeOffset

    Public Sub New(tz As TimeZoneInfo, time As DateTimeOffset)
        If tz Is Nothing Then _
           Throw New ArgumentNullException("The time zone cannot be a null reference.")

        Me.TimeZone = tz
        Me.Time = time
    End Sub

    Public Function AddTime(interval As TimeSpan) As TimeZoneTime
        ' Convert time to UTC
        Dim utcTime As DateTimeOffset = TimeZoneInfo.ConvertTime(Me.Time, TimeZoneInfo.Utc)
        ' Add time interval to time
        utcTime = utcTime.Add(interval)
        ' Convert time back to time in time zone
        Return New TimeZoneTime(Me.TimeZone, TimeZoneInfo.ConvertTime(utcTime, Me.TimeZone))
    End Function
End Structure

Module TimeArithmetic
    Public Const tzName As String = "Central Standard Time"

    Public Sub Main()
        Try
            Dim cstTime1, cstTime2 As TimeZoneTime

            Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tzName)
            Dim time1 As Date = #03/09/2008 1:30AM#
            Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)

            cstTime1 = New TimeZoneTime(cst, _
                           New DateTimeOffset(time1, cst.GetUtcOffset(time1)))
            cstTime2 = cstTime1.AddTime(twoAndAHalfHours)

            Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, _
                                                       twoAndAHalfHours.ToString(), _
                                                       cstTime2.Time)
        Catch
            Console.WriteLine("Unable to find {0}.", tzName)
        End Try
    End Sub
End Module

Bu ekleme, değeri önce UTC'ye dönüştürmeden doğrudan DateTimeOffset değerine uygulanırsa, sonuç doğru zaman noktasını yansıtır, ancak bu zaman için belirlenen saat diliminin ofsetini yansıtmaz.

Ayrıca bkz.