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