Introduction
Here is a custom C# .NET Date
type (struct
) that will help you deal with conversions to and from string
s. The struct
implements the IComparable
interface and overrides the ToString
, Equals
and GetHashCode()
functions.
Background
Defining a struct
is almost similar to that of defining a class
:
[attributes] [modifiers] struct <structName> [: interfaces]
{
[struct-body]
}[;]
Like a class
, a struct
can contain other types and is sometimes referred to as a lightweight version of a class
because internally a struct
is a value type. Creating a struct
instance will not cause garbage collection (unless the constructor directly or indirectly creates a reference type instance) whereas creating a reference type instance can cause garbage collection. Another thing about a struct
is that it always has a built-in public
default constructor and no destructor.
How is a struct
different from a class
:
- a
struct
is implicitly sealed
, a class
isn't - a
struct
can't be abstract
, a class
can - a
struct
can't call : base()
in its constructor whereas a class
with no explicit base
class can - a
struct
can't extend another class
, a class
can - a
struct
can't declare protected
members (e.g. fields, nested types) a class
can - a
struct
can't declare abstract
function members, an abstract class
can - a
struct
can't declare virtual
function members, a class
can - a
struct
can't declare sealed
function members, a class
can - a
struct
can't declare override
function members, a class
can. The only exception to this rule is that a struct
can override the virtual
methods of System.Object
, viz, Equals()
, and GetHashCode()
, and ToString()
(more info on StructsVsClasses)
Struct Code
The Date
struct
looks like this:
using System;
using System.Text.RegularExpressions;
[Serializable]
public struct Date : IComparable
{
}
I want to build a ShortDate
struct
with three fields:
private UInt16 _day;
private UInt16 _month;
private UInt16 _year;
Next, I make those fields public
, so now my struct
has three properties:
public UInt16 Day
{
get { return _day; }
set
{
if (value > 31)
{
throw new ArgumentException("Day out of range[31]");
}
else
{
_day = value;
}
}
}
public UInt16 Month
{
get { return _month; }
set
{
if (value > 12)
{
throw new ArgumentException("Month out of range[12]");
}
else
{
_month = value;
}
}
}
public UInt16 Year
{
get { return _year; }
set
{
if (value.ToString().Length > 4)
{
throw new ArgumentException("Year out of range.");
}
else
{
_year = value;
}
}
}
Besides the default constructor that makes all the fields equal to zero, I've made another one that will fill the fields with data from the DateTime
parameter:
public Date(DateTime dt)
{
_month = Convert.ToUInt16(dt.Month);
_day = Convert.ToUInt16(dt.Day);
_year = Convert.ToUInt16(dt.Year);
}
IComparable
implementation and overrides of the ToString
, Equals
and GetHashCode()
functions:
public int CompareTo(object obj)
{
Date dt = (Date) obj;
UInt16 i = 0;
if (dt._day == _day)
{
i += 100;
}
if (dt._month == _month)
{
i += 010;
}
if (dt._year == _year)
{
i += 001;
}
return i;
}
public override bool Equals(object obj)
{
if (obj == null || ! (obj is Date))
return false;
try
{
Date other = (Date)obj;
return this._day == other._day
&& this._month == other._month
&& this._year == other._year;
}
catch
{
return false;
}
}
public override int GetHashCode()
{
return (_day ^ _month ^ _year);
}
public override string ToString()
{
return (_day.ToString() + "/" + _month.ToString() + "/" + _year.ToString());
}
public string ToString(string separator)
{
string s1="", s2="";
if(_day.ToString().Length == 1 )
{
s1="0";
}
if( _month.ToString().Length == 1 )
{
s2="0";
}
return (s1+_day.ToString()+separator+s2+_month.ToString()+separator+_year);
}
public static bool operator >(Date d1,Date d2)
{
if( d1.ToDateTime() > d2.ToDateTime() )
{
return true;
}
return false;
}
public static bool operator <(Date d1,Date d2)
{
if( d1.ToDateTime() < d2.ToDateTime() )
{
return true;
}
return false;
}
And finally some useful functions to help us manage this Date
type:
public bool IsDateTime(string dt)
{
Regex rgx = new
Regex(@"(?<Day>\d{1,2})/(?<Month>\d{1,2})/(?<Year>(?:\d{4}|\d{2}))");
if (rgx.IsMatch(dt))
{
return true;
}
else
{
return false;
}
}
public DateTime StringToDate(string dt)
{
if (IsDateTime(dt))
{
_day = Convert.ToUInt16(dt.Split('/')[0]);
_month = Convert.ToUInt16(dt.Split('/')[1]);
_year = Convert.ToUInt16(dt.Split('/')[2]);
}
else
{
throw new ArgumentException("The string can't be converted to a date");
}
return new DateTime(Year, Month, Day);
}
public DateTime StringToDate(string dt, char separator)
{
try
{
_day = Convert.ToUInt16(dt.Split(separator)[0]);
_month = Convert.ToUInt16(dt.Split(separator)[1]);
_year = Convert.ToUInt16(dt.Split(separator)[2]);
return new DateTime(Year, Month, Day);
}
catch (Exception)
{
throw new InvalidCastException("The input string is not a date format");
}
}
public DateTime ToDateTime()
{
return new DateTime(Year, Month, Day);
}
public static DateTime ToDateTime(Date dt)
{
return new DateTime(dt.Year, dt.Month, dt.Day);
}
Using the Code
You can now include the struct
into a project and try it out, here are some examples:
private void Page_Load(object sender, System.EventArgs e)
{
Date d1 = new Date();
Response.Write("Luna: "+d1.Month+" Zi: "+d1.Day+" An: "+d1.Year);
Date d2 = new Date(DateTime.Now);
Response.Write(d2.ToString());
Date d3 = new Date();
Response.Write(d3.StringToDate("01/02/05"));
Response.Write(d1.ToString()+" -d1- "+ d1.GetHashCode());
Response.Write(d2.ToString()+" -d2- "+ d2.GetHashCode());
Response.Write(d3.ToString()+" -d3- "+ d3.GetHashCode());
Date d4 = new Date();
d4.StringToDate("01/02/05");
Date d5 = new Date();
d5.Day = 1;
d5.Month = 5;
d5.Year = 05;
Response.Write(d4.ToString()+" Equals "+d5.ToString()+
"? "+d4.Equals(d5));
Response.Write(d4.ToString()+" CompareTo "+d5.ToString()+
"? "+d4.CompareTo(d5));
}
History
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.
A list of licenses authors might use can be found here.