Skip to content

Instantly share code, notes, and snippets.

@MrZoidberg
Last active August 29, 2015 14:02
Show Gist options
  • Save MrZoidberg/c98b891180a3499216e7 to your computer and use it in GitHub Desktop.
Save MrZoidberg/c98b891180a3499216e7 to your computer and use it in GitHub Desktop.
DateTime struct with support of parsing and storing dates like this: {CURRENT_DATE}+1h5m2s
[Serializable]
public struct SmartDateTime : IFormattable, ISerializable, IXmlSerializable, IEquatable<SmartDateTime>, IConvertible
{
private bool _current;
private TimeSpan _diff;
private DateTime _value;
public bool IsCurrent
{
get { return _current; }
}
public DateTime Value
{
get { return _current ? DateTime.UtcNow + _diff : _value; }
}
public SmartDateTime(TimeSpan diffTimeSpan)
: this()
{
_current = true;
_diff = diffTimeSpan;
_value = DateTime.MinValue;
}
public SmartDateTime(DateTime value)
: this()
{
_current = false;
_diff = TimeSpan.Zero;
_value = value.ToUniversalTime();
}
// this constructor is used for deserialization
public SmartDateTime(SerializationInfo info, StreamingContext text): this()
{
_value = info.GetDateTime("Value");
_current = info.GetBoolean("IsCurrent");
_diff = ReadableTimeReader.ToTimeSpan(info.GetString("Diff"));
}
private static readonly SmartDateTime CurrentSmartDateTime = new SmartDateTime(TimeSpan.Zero);
public static SmartDateTime Current
{
get { return CurrentSmartDateTime; }
}
public bool Equals(SmartDateTime other)
{
return base.Equals(other);
}
public override string ToString()
{
if (_current)
{
return "Current date " + _diff;
}
return _value.ToString();
}
public string ToString(string format, IFormatProvider formatProvider)
{
if (_current)
{
return "Current date " + _diff;
}
return _value.ToString(format, formatProvider);
}
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("IsCurrent", _current);
info.AddValue("Value", _value);
info.AddValue("Diff", ReadableTimeReader.TimeSpanToString(_diff));
}
public XmlSchema GetSchema()
{
throw new NotImplementedException();
}
private const string CurrentDateKey = "{CURRENT_DATE}";
public void ReadXml(XmlReader reader)
{
string content = reader.ReadContentAsString();
if (content.Contains(CurrentDateKey))
{
_current = true;
_value = DateTime.MinValue;
string diffString = content.Replace(CurrentDateKey+"+", "").Trim();
if (String.IsNullOrEmpty(diffString))
{
_diff = ReadableTimeReader.ToTimeSpan(diffString);
}
}
else
{
_current = false;
_value = DateTime.Parse(content, CultureInfo.InvariantCulture);
}
}
public void WriteXml(XmlWriter writer)
{
if (_current)
{
if (_diff != TimeSpan.Zero)
{
writer.WriteValue(String.Format("{0}+{1}", CurrentDateKey, ReadableTimeReader.TimeSpanToString(_diff, true)));
}
else
{
writer.WriteValue(CurrentDateKey);
}
}
else
{
writer.WriteValue(_value.ToString(CultureInfo.InvariantCulture));
}
}
public static explicit operator SmartDateTime(DateTime dateTime)
{
SmartDateTime smartDateTime = new SmartDateTime(dateTime);
return smartDateTime;
}
public static implicit operator DateTime(SmartDateTime smartDateTime)
{
return smartDateTime.Value;
}
public TypeCode GetTypeCode()
{
return TypeCode.Object;
}
public bool ToBoolean(IFormatProvider provider)
{
throw new InvalidCastException();
}
public char ToChar(IFormatProvider provider)
{
throw new InvalidCastException();
}
public sbyte ToSByte(IFormatProvider provider)
{
throw new InvalidCastException();
}
public byte ToByte(IFormatProvider provider)
{
throw new InvalidCastException();
}
public short ToInt16(IFormatProvider provider)
{
throw new InvalidCastException();
}
public ushort ToUInt16(IFormatProvider provider)
{
throw new InvalidCastException();
}
public int ToInt32(IFormatProvider provider)
{
throw new InvalidCastException();
}
public uint ToUInt32(IFormatProvider provider)
{
throw new InvalidCastException();
}
public long ToInt64(IFormatProvider provider)
{
throw new InvalidCastException();
}
public ulong ToUInt64(IFormatProvider provider)
{
throw new InvalidCastException();
}
public float ToSingle(IFormatProvider provider)
{
throw new InvalidCastException();
}
public double ToDouble(IFormatProvider provider)
{
throw new InvalidCastException();
}
public decimal ToDecimal(IFormatProvider provider)
{
throw new InvalidCastException();
}
public DateTime ToDateTime(IFormatProvider provider)
{
return Value;
}
public string ToString(IFormatProvider provider)
{
if (_current)
{
return "Current date " + _diff;
}
return _value.ToString(provider);
}
public object ToType(Type conversionType, IFormatProvider provider)
{
throw new InvalidCastException();
}
}
public static class ReadableTimeReader
{
private const char HoursChar = 'h';
private const char MinutesChar = 'm';
private const char SecondsChar = 's';
public static TimeSpan ToTimeSpan(string value)
{
if (String.IsNullOrWhiteSpace(value))
return TimeSpan.Zero;
value = value.ToLowerInvariant().Replace(" ", String.Empty);
string[] parts = Regex.Split(value, @"(h)|(m)|(s)");
int hours = 0;
int minutes = 0;
int seconds = 0;
for (int index = 0; index < parts.Length - 1; index += 2)
{
string part = parts[index];
char partChar = parts[index + 1][0];
int partValue = Int32.Parse(part, CultureInfo.InvariantCulture);
switch (partChar)
{
case HoursChar:
{
hours = partValue;
break;
}
case MinutesChar:
{
minutes = partValue;
break;
}
case SecondsChar:
{
seconds = partValue;
break;
}
}
}
TimeSpan timeSpan = new TimeSpan(hours, minutes, seconds);
return timeSpan;
}
public static string TimeSpanToString(TimeSpan timeSpan, bool withoutSpaces = false)
{
StringBuilder sb = new StringBuilder();
if (timeSpan.Days > 0)
{
sb.AppendFormat("{0}d", timeSpan.Days);
}
string spaceChar = withoutSpaces ? "" : " ";
sb.AppendFormat("{1}{0}h", timeSpan.Hours, spaceChar);
sb.AppendFormat("{1}{0}m", timeSpan.Minutes, spaceChar);
sb.AppendFormat("{1}{0}s", timeSpan.Seconds, spaceChar);
return sb.ToString().Trim();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment