|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.ComponentModel.Design.Serialization;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
namespace System.ComponentModel
{
/// <summary>
/// Provides a type converter to convert <see cref='System.DateTimeOffset'/>
/// objects to and from various other representations.
/// </summary>
public class DateTimeOffsetConverter : TypeConverter
{
/// <summary>
/// Gets a value indicating whether this converter can convert an
/// object in the given source type to a <see cref='System.DateTimeOffset'/>
/// object using the specified context.
/// </summary>
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
/// <summary>
/// Gets a value indicating whether this converter can convert an
/// object to the given destination type using the context.
/// </summary>
public override bool CanConvertTo(ITypeDescriptorContext? context, [NotNullWhen(true)] Type? destinationType)
{
return destinationType == typeof(InstanceDescriptor) || base.CanConvertTo(context, destinationType);
}
/// <summary>
/// Converts the given value object to a <see cref='System.DateTime'/>
/// object.
/// </summary>
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
if (value is string text)
{
text = text.Trim();
if (text.Length == 0)
{
return DateTimeOffset.MinValue;
}
try
{
// See if we have a culture info to parse with. If so, then use it.
DateTimeFormatInfo? formatInfo = null;
if (culture != null)
{
formatInfo = (DateTimeFormatInfo?)culture.GetFormat(typeof(DateTimeFormatInfo));
}
if (formatInfo != null)
{
return DateTimeOffset.Parse(text, formatInfo);
}
else
{
return DateTimeOffset.Parse(text, culture);
}
}
catch (FormatException e)
{
throw new FormatException(SR.Format(SR.ConvertInvalidPrimitive, (string)value, nameof(DateTimeOffset)), e);
}
}
return base.ConvertFrom(context, culture, value);
}
/// <summary>
/// Converts the given value object to a <see cref='System.DateTimeOffset'/>
/// object using the arguments.
/// </summary>
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
{
// logic is exactly as in DateTimeConverter, only the offset pattern ' zzz' is added to the default
// ConvertToString pattern.
if (destinationType == typeof(string) && value is DateTimeOffset)
{
DateTimeOffset dto = (DateTimeOffset)value;
if (dto == DateTimeOffset.MinValue)
{
return string.Empty;
}
culture ??= CultureInfo.CurrentCulture;
DateTimeFormatInfo? formatInfo;
formatInfo = (DateTimeFormatInfo?)culture.GetFormat(typeof(DateTimeFormatInfo));
string format;
if (culture == CultureInfo.InvariantCulture)
{
// note: the y/m/d format used when there is or isn't a time component is not consistent
// when the culture is invariant, because for some reason InvariantCulture's date format is
// MM/dd/yyyy. However, this matches the behavior of DateTimeConverter so it is preserved here.
if (dto.TimeOfDay.TotalSeconds == 0)
{
// pattern just like DateTimeConverter when DateTime.TimeOfDay.TotalSeconds==0
// but with ' zzz' offset pattern added.
return dto.ToString("yyyy-MM-dd zzz", culture);
}
else
{
return dto.ToString(culture);
}
}
if (dto.TimeOfDay.TotalSeconds == 0)
{
// pattern just like DateTimeConverter when DateTime.TimeOfDay.TotalSeconds==0
// but with ' zzz' offset pattern added.
format = formatInfo!.ShortDatePattern + " zzz";
}
else
{
// pattern just like DateTimeConverter when DateTime.TimeOfDay.TotalSeconds!=0
// but with ' zzz' offset pattern added.
format = formatInfo!.ShortDatePattern + " " + formatInfo.ShortTimePattern + " zzz";
}
return dto.ToString(format, culture);
}
if (destinationType == typeof(InstanceDescriptor) && value is DateTimeOffset)
{
DateTimeOffset dto = (DateTimeOffset)value;
if (dto.Ticks == 0)
{
// Special case for empty DateTimeOffset
return new InstanceDescriptor(
typeof(DateTimeOffset).GetConstructor(new Type[] { typeof(long) }),
new object[] { dto.Ticks }
);
}
return new InstanceDescriptor(
typeof(DateTimeOffset).GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(TimeSpan) }),
new object[] { dto.Year, dto.Month, dto.Day, dto.Hour, dto.Minute, dto.Second, dto.Millisecond, dto.Offset }
);
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
}
|