簡體   English   中英

將復雜對象中的所有 DateTime 字段從本地時區轉換為 UTC

[英]Convert all DateTime fields in a complex object from local time zone to UTC

我有一個客戶對象,其中包含有關客戶出生日期、加入日期等的所有詳細信息。

我想將所有日期字段轉換為通用日期時間並存儲在數據庫中。

任何人都可以幫助我如何從客戶對象中獲取所有日期字段並將其轉換為通用日期時間?

我想要一個解決方案,當我調用 Customer.ChangeToUTC() 時,客戶中存在的所有日期時間字段都應更改為世界時。

我遇到了同樣的問題。 在我的情況下,解決方案是必要的,因為我們有太多不同的帶有DateTime字段的復雜模型。 為了我的需要,我編寫了下一個擴展:

public static class ObjectExtensions
{
    /// <summary>
    /// Convert all DateTime fields in a complex object from UTC to a destination time zone.
    /// </summary>
    /// <typeparam name="TInput">Type of an object that will be converted.</typeparam>
    /// <param name="obj">Object that will be deeply converted.</param>
    /// <param name="destTimeZone"><c>TimeZoneInfo</c> object of a destination time zone.</param>
    public static void DeepConvertFromUtc<TInput>(this TInput obj, TimeZoneInfo destTimeZone)
        where TInput : class
    {
        obj.DeepConvert(TimeZoneInfo.Utc, destTimeZone);
    }

    /// <summary>
    /// Convert all DateTime fields in a complex object from source time zone to UTC.
    /// </summary>
    /// <typeparam name="TInput">Type of an object that will be converted.</typeparam>
    /// <param name="obj">Object that will be deeply converted.</param>
    /// <param name="sourceTimeZone"><c>TimeZoneInfo</c> object of a source time zone.</param>
    public static void DeepConvertToUtc<TInput>(this TInput obj, TimeZoneInfo sourceTimeZone)
        where TInput : class
    {
        obj.DeepConvert(sourceTimeZone, TimeZoneInfo.Utc);
    }

    /// <summary>
    /// Convert all DateTime fields in a complex object from UTC to a destination time zone.
    /// </summary>
    /// <typeparam name="TInput">Type of an object that will be converted.</typeparam>
    /// <param name="obj">Object that will be deeply converted.</param>
    /// <param name="sourceTimeZone"><c>TimeZoneInfo</c> object of a source time zone.</param>
    /// <param name="destTimeZone"><c>TimeZoneInfo</c> object of a destination time zone.</param>
    public static void DeepConvertTime<TInput>(this TInput obj, TimeZoneInfo sourceTimeZone, TimeZoneInfo destTimeZone)
        where TInput : class
    {
        obj.DeepConvert(sourceTimeZone, destTimeZone);
    }

    private static void DeepConvert<TInput>(this TInput obj, TimeZoneInfo sourceTimeZone, TimeZoneInfo destTimeZone)
        where TInput : class
    {
        if (obj == null)
        {
            return;
        }

        var items = obj as ICollection;
        if (items != null)
        {
            foreach (var item in items)
            {
                item.DeepConvert(sourceTimeZone, destTimeZone);
            }

            return;
        }

        var props = obj.GetType().GetProperties();
        foreach (var prop in props.Where(prop => !IsIgnore(prop)))
        {
            if (prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(DateTime?))
            {
                prop.ConvertDateTime(obj, sourceTimeZone, destTimeZone);
                continue;
            }

            var value = prop.GetValue(obj);
            var list = value as ICollection;
            if (list != null)
            {
                foreach (var item in list)
                {
                    item.DeepConvert(sourceTimeZone, destTimeZone);
                }

                continue;
            }

            // here I check that an object is located in one of my assemblies
            if (prop.PropertyType.Assembly.FullName.StartsWith("Should be your namespace"))
            {
                value.DeepConvert(sourceTimeZone, destTimeZone);
            }
        }
    }

    private static void ConvertDateTime<TInput>(this PropertyInfo prop, TInput obj, TimeZoneInfo sourceTimeZone, TimeZoneInfo destTimeZone)
        where TInput : class
    {
        var value = prop.GetValue(obj);
        if (value != null)
        {
            var dateTime = DateTime.SpecifyKind((DateTime)value, DateTimeKind.Unspecified);
            value = TimeZoneInfo.ConvertTime(dateTime, sourceTimeZone, destTimeZone);

            var setMethod = prop.SetMethod;
            if (setMethod != null)
            {
                setMethod.Invoke(obj, new[] { value });
            }
        }
    }

    private static bool IsIgnore(this PropertyInfo prop)
    {
        var attr = prop.GetCustomAttribute<IgnoreUtcConversionAttribute>();
        return attr != null;
    }
}

public class IgnoreUtcConversionAttribute : Attribute
{
}

您可以非常簡單地使用它:

yourComplexObject.DeepConvertToUtc(TimeZoneInfo.Local);

// a collection could be converted as well
collection.DeepConvertToUtc(TimeZoneInfo.Local);

您也可以從FindSystemTimeZoneById方法中獲取TimeZineInfo對象:

var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Belarus Standard Time");
yourComplexObject.DeepConvertToUtc(timeZoneInfo);

如果您的模型中有兩種方式的引用,則必須使用[IgnoreUtcConversion]裝飾一個引用:

public class Customer
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public DateTime Birth { get; set; }

    public Address Address { get; set; }
}

public class Address
{
    public string Street { get; set; }

    public DateTime LastUpdated { get; set; }

    [IgnoreUtcConversion]
    public Customer Customer { get; set; }
}

這是一件簡單的事情:

TimeZone ltz = TimeZone.CurrentTimeZone;

DateTime t1 = DateTime.Now;

DateTime t2 = ltz.ToUniversalTime(t1);

任何人都可以幫助我如何從客戶對象中獲取所有日期字段並將其轉換為通用日期時間

只需手動完成即可。 但是,我不會通過重用原始Customer類型中的屬性來實現。 我要么創建對象之前(當您第一次獲取數據時)執行此操作,要么將其作為僅用於數據庫傳輸的輕量級 DTO 的一部分執行。

推理日期/時間屬性是夠硬,當你知道如何解釋任何特殊的性質-如果你不知道屬性是否將是普遍的,局部的,或者未指定它要困難得多。

諸如日期之類的事情即使考慮是否通用也沒有多大意義。 為了將它們存儲在數據庫中,您可能希望使用DateTimeKind.Utc顯式創建它們,但從根本上說,日期就是一個日期。 .NET 框架的問題之一是它沒有單獨的日期數據類型。

我有一個名為Noda Time的項目,它是 .NET 的替代日期/時間 API。 一種選擇當然是使用它,但假設您想堅持使用 BCL 類型,我仍然認為值得閱讀我們的概念類型選擇文檔,以幫助您以正確的方式思考日期和時間。 最好確定您用於模型中的每個屬性的類型,然后將其記錄下來。 您將希望在代碼中以不同方式處理它們。

如果您熟悉日期時間,這很簡單;

customer.BirthDate = customer.BirthDate.ToUniversalTime();

只需對所有日期字段執行上述操作,並在客戶 ID 號上使用 where 子句運行更新查詢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM