1

我有一个客户对象,其中包含有关客户出生日期、加入日期等的所有详细信息。

我想将所有日期字段转换为通用日期时间并存储在数据库中。

谁能帮助我如何从客户对象中获取所有日期字段并将其转换为通用日期时间?

我想要一个解决方案,当我调用 Customer.ChangeToUTC() 时,客户中存在的所有日期时间字段都应该更改为通用时间。

4

4 回答 4

2

我遇到了同样的问题。在我的情况下,解决方案是必要的,因为我们有太多不同的复杂模型和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);

您也可以从方法中获取TimeZineInfo对象:FindSystemTimeZoneById

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; }
}
于 2015-10-16T09:12:59.153 回答
1

这是一件简单的事情:

TimeZone ltz = TimeZone.CurrentTimeZone;

DateTime t1 = DateTime.Now;

DateTime t2 = ltz.ToUniversalTime(t1);
于 2012-10-01T06:02:27.507 回答
1

任何人都可以帮助我如何从客户对象中获取所有日期字段并将其转换为通用日期时间

只需手动执行即可。但是,我不会通过重用原始Customer类型中的属性来做到这一点。我要么您创建对象之前(当您第一次获取数据时)执行此操作,要么将其作为轻量级 DTO 的一部分执行,仅用于数据库传输。

当您知道如何解释任何特定属性时,对日期/时间属性的推理就足够困难了——如果您不知道某个属性是通用的、本地的还是未指定的,那将变得更加困难。

日期之类的事情甚至没有多大意义来考虑是否普遍。为了将它们存储在数据库中,您可能希望明确地使用它们来创建它们DateTimeKind.Utc,但从根本上说,日期就是日期。.NET 框架的问题之一是它没有单独的日期数据类型。

我有一个名为Noda Time的项目,它是 .NET 的替代日期/时间 API。当然,一种选择是使用它,但假设您想坚持使用 BCL 类型,我仍然认为值得阅读我们的概念类型选择文档,以帮助您以正确的方式思考日期和时间。最好弄清楚模型中的每个属性使用哪种类型,然后记录下来。您将希望在代码中以不同方式处理它们。

于 2012-10-01T06:03:01.450 回答
0

如果您熟悉日期时间,这很简单;

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

只需对您的所有日期字段执行上述操作,并在您的客户 ID 号上使用 where 子句运行更新查询。

于 2012-10-01T06:00:26.860 回答