So, the other day, ascendedguard was telling me about one of his projects. He is reading javascript style timestamps from an XML source, and storing them in his application as a DateTime. He is currently doing the conversions by hand. He asked me to find A better way™.
My method today will focus on implicit operators. Using implicit operators, we can create a drop in class to replace DateTime. This class will provide all the functionality of DateTime, as well as a seamless conversion to javascript style timestamps.
The class uses a UInt64 to hold the javascript style timestamp internally. It then has constructors to create a timestamp class from a UInt64, double, DateTime, or another Timestamp. It then uses those constructors in implicit operators to those data types.
Once complete, this class acts as a bridge between the data types. In your class, you simply change your DateTime classes to a Timestamp class. Your code requires no modifications to keep it working. You can now use this Timestamp as any of the supported data types. However, we want to read the timestamp from the XML file as a UInt64, so we need to create a second property, of type UInt64, which uses the Timestamp object as a field. So, in the end, you may have properties, Timestamp TimeModified, and UInt64 SAVE_TimeModified. Both of these properties would use the private field Timestamp m_TimeModified. Note, that you would need to put [XmlIgnore] on the Timestamp property.
Now, with this method, you have an ugly, unused SAVE_TimeModified property. You can strip that out of your class's public interface by making it internal, however that will break XmlSerializer. The stock XmlSerializer will not serialize internal members, as they are private to the XmlSerializer itself.
So, you have two choices. Use XmlSerializer, and deal with the SAVE_TimeModified, or manually parse the XML, and have SAVE_TimeModified hidden. In the next few days, I'm going to be working on my own custom XmlSerializer (again, a drop in class) which will handle not only internals, but much more.
The code for the class is below:
public class Timestamp
{
private static DateTime EPOCH = new DateTime(1970, 1, 1);
private UInt64 m_Value;
public UInt64 Value
{
get { return m_Value; }
set { m_Value = value; }
}
public Timestamp(UInt64 seconds)
{ Value = seconds; }
public Timestamp(DateTime datetime)
{ Value = (UInt64)datetime.Subtract(EPOCH).TotalSeconds; }
public Timestamp(Timestamp timestamp)
{ Value = timestamp.Value; }
public Timestamp(double seconds)
{ Value = (UInt64)seconds; }
public static implicit operator Timestamp(UInt64 seconds)
{ return new Timestamp(seconds); }
public static implicit operator Timestamp(DateTime datetime)
{ return new Timestamp(datetime); }
public static implicit operator Timestamp(double seconds)
{ return new Timestamp(seconds); }
public static implicit operator UInt64(Timestamp timestamp)
{ return timestamp.Value; }
public static implicit operator DateTime(Timestamp timestamp)
{ return EPOCH.AddSeconds(timestamp); }
public static implicit operator double(Timestamp timestamp)
{ return (double)timestamp.Value; }
}
0 comments:
Post a Comment