可能做过报表的朋友和我有同样的感受,就是老板可能会说,我要****年**月**日到****年**月**日之间各年度、各季度、各月份的销售情况比较的报表。
马上我们想的就是如何来划分这些时间段吧。举个例子,比如日期是从2006年3月15日到2007年3月15日,如何来划分呢?我们知道.NET有System.DateTime类,今天我们讲的就是如何来灵活的使用它,构建我们划分时间段的组件。
当然我想我需要先讲讲我们的划分原则,如上面的时间段所示,如果我们分年度来比较,那就是从06年3月15日到06年12月31日为一段,07年1月1日到3月15日为另一段;分季度的话当然是06-3-15至06-03-31、06-04-01至06-06-30... ...以此类推,再加上07-01-01至07-03-15一共5段;分月份不用多说,也是06-03-15至06-03-31、06-04-01至06-04-30... ... 07-02-01至07-02-28、07-03-01至07-03-15,一共13段。
好了,原则讲了,接下来就是看代码的实现了,我们这里假设销售的日期就是订单下达的日期(OrderDate)。
我们先建一个类DateDiffObject,并让它可序列化:
[Serializable]
public
class
DateDiffObject

{
public ArrayList SeperateDateByYear = new ArrayList();
public ArrayList SeperateDateByQuarter = new ArrayList();
public ArrayList SeperateDateByMonth = new ArrayList();

public DateDiffObject()

{

}
}
上面三个ArrayList分别就是记录我把时间段按不同标准划分后的结果。
然后,我们需要对用户输入进来的时间段进行各类分割了:
public
DateDiffObject GetDateDiffObject(DateTime BeginDate,DateTime EndDate)

{
DateDiffObject dateobj = new DateDiffObject();
//string[] quarter length is 12, record the quarter of each month

string[] quarter =
{"1","1","1","2","2","2","3","3","3","4","4","4"};

if(BeginDate.Year==EndDate.Year)

{
//Same Year
if(quarter[BeginDate.Month - 1] == quarter[EndDate.Month - 1])

{
//Same Quarter
if(BeginDate.Month!=EndDate.Month)

{
//Different Month
for(int i=0; i<=EndDate.Month - BeginDate.Month; i++)

{
if(i==0)

{
//Seperate the first date period
this.dateobj.SeperateDateByMonth.Add(" and OrderDate between '"+BeginDate.ToString("yyyy-MM-dd")+"' and '"+GetMonthLastDay(BeginDate)+"' ");
}
else if(i==EndDate.Month - BeginDate.Month)

{
//Seperate the last date period
this.dateobj.SeperateDateByMonth.Add(" and OrderDate between '"+GetMonthFirstDay(EndDate)+"' and '"+EndDate.ToString("yyyy-MM-dd")+"' ");
}
else

{
//Seperate the middle date period
this.dateobj.SeperateDateByMonth.Add(" and OrderDate between '"+GetMonthFirstDay(BeginDate.AddMonths(i))+"' and '"+GetMonthLastDay(BeginDate.AddMonths(i))+"' ");
}
}
}
}
else

{
//Different Quarter
for(int j=0; j<=Convert.ToInt32(quarter[EndDate.Month - 1]) - Convert.ToInt32(quarter[BeginDate.Month - 1]); j++)

{
if(j==0)

{
//Seperate the first date period
this.dateobj.SeperateDateByQuarter.Add(" and OrderDate between '"+BeginDate.ToString("yyyy-MM-dd")+"' and '"+GetQuarterLastDay(BeginDate)+"' ");
}
else if(j==EndDate.Month - BeginDate.Month)

{
//Seperate the last date period
this.dateobj.SeperateDateByQuarter.Add(" and OrderDate between '"+GetQuarterFirstDay(EndDate)+"' and '"+EndDate.ToString("yyyy-MM-dd")+"' ");
}
else

{
//Seperate the middle date period
this.dateobj.SeperateDateByQuarter.Add(" and OrderDate between '"+GetQuarterFirstDay(BeginDate.AddMonths(3*j - ((BeginDate.Month - 1) % 3)))+"' and '"+GetQuarterLastDay(BeginDate.AddMonths(3*j - ((BeginDate.Month - 1) % 3)))+"' ");
}
}
}
}
else

{
//Different Year
for(int k=0; k<=EndDate.Year - BeginDate.Year; k++)

{
if(k==0)

{
//Seperate the first date period --- Year
this.dateobj.SeperateDateByYear.Add(" and OrderDate between '"+BeginDate.ToString("yyyy-MM-dd")+"' and '"+GetYearLastDay(BeginDate)+"' ");
DateDiffObject newdateobj = new DateDiffObject();
//Use itself --- Recursion Method
newdateobj = GetDateDiffObject(DateType,BeginDate,DateTime.Parse(GetYearLastDay(BeginDate)));
for(int p=0; p<newdateobj.SeperateDateByQuarter.Count;p++)

{
dateobj.SeperateDateByQuarter.Add(newdateobj.SeperateDateByQuarter[p]);
}
for(int p=0; p<newdateobj.SeperateDateByMonth.Count;p++)

{
dateobj.SeperateDateByMonth.Add(newdateobj.SeperateDateByMonth[p]);
}
}
else if(k==EndDate.Year - BeginDate.Year)

{
//Seperate the last date period --- Year
this.dateobj.SeperateDateByYear.Add(" and OrderDate between '"+GetYearFirstDay(EndDate)+"' and '"+EndDate.ToString("yyyy-MM-dd")+"' ");
DateDiffObject newdateobj = new DateDiffObject();
//Use itself --- Recursion Method
newdateobj = GetDateDiffObject(DateType,DateTime.Parse(GetYearFirstDay(EndDate)),EndDate);
for(int p=0; p<newdateobj.SeperateDateByQuarter.Count;p++)

{
dateobj.SeperateDateByQuarter.Add(newdateobj.SeperateDateByQuarter[p]);
}
for(int p=0; p<newdateobj.SeperateDateByMonth.Count;p++)

{
dateobj.SeperateDateByMonth.Add(newdateobj.SeperateDateByMonth[p]);
}
}
else

{
//Seperate the middle date period --- Year
this.dateobj.SeperateDateByYear.Add(" and OrderDate between '"+GetYearFirstDay(BeginDate.AddYears(k))+"' and '"+GetYearLastDay(BeginDate.AddYears(k))+"' ");
DateDiffObject newdateobj = new DateDiffObject();
//Use itself --- Recursion Method
newdateobj = GetDateDiffObject(DateType,DateTime.Parse(GetYearFirstDay(BeginDate.AddYears(k))),DateTime.Parse(GetYearLastDay(BeginDate.AddYears(k))));
for(int p=0; p<newdateobj.SeperateDateByQuarter.Count;p++)

{
dateobj.SeperateDateByQuarter.Add(newdateobj.SeperateDateByQuarter[p]);
}
for(int p=0; p<newdateobj.SeperateDateByMonth.Count;p++)

{
dateobj.SeperateDateByMonth.Add(newdateobj.SeperateDateByMonth[p]);
}
}
}
}
return dateobj;
}
以上方法是用递归算法来截取个时间段然后返回一个DateDiffObject的对象。 其实大家可以看出来填入对象中各个ArrayList的数据就是SQL语句的一段,作为我们查询数据库的条件。
接下来就是我们在上面看到的例如GetMonthFirstDay(EndDate),GetMonthLastDay(BeginDate.AddMonths(i))等方法的实现,大家可以从方法名里看出它们将要实现的功能,就是获得每年、每季度、每月的第一天和最后一天:
public
string
GetMonthFirstDay(DateTime date)

{
return date.ToString("yyyy-MM-01");
}

public
string
GetMonthLastDay(DateTime date)

{
return DateTime.Parse(date.ToString("yyyy-MM-01")).AddMonths(1).AddDays(-1).ToShortDateString();
}

public
string
GetQuarterFirstDay(DateTime date)

{
return date.AddMonths(0 - ((date.Month - 1) % 3)).ToString("yyyy-MM-01");
}

public
string
GetQuarterLastDay(DateTime date)

{
return DateTime.Parse(date.AddMonths(3 - ((date.Month - 1) % 3)).ToString("yyyy-MM-01")).AddDays(-1).ToShortDateString();
}

public
string
GetYearFirstDay(DateTime date)

{
return DateTime.Parse(date.ToString("yyyy-01-01")).ToShortDateString();
}

public
string
GetYearLastDay(DateTime date)

{
return DateTime.Parse(date.ToString("yyyy-01-01")).AddYears(1).AddDays(-1).ToShortDateString();
}
都是用DateTime类来实现的,原理很简单,每个月的第一天当然是****-**-01,最后一天就是下个月的第一天减去一天所得到的,季度和年份也是同理,大家有兴趣可以推敲一下,这里就不再赘述了。^^
最后,就是调用它的时候了,我们先讲它序列化为一个XML文档,存放在一个特定目录下,我们这里用一个组件来管理它:
public
class
DateDiffObjectSerialize : iDateObjectSerialize

{
private string strPath = "./XMLDoc/"+HttpContext.Current.Request.Cookies["UserID"].Value + "/DateDiffObject.xml";
private DateDiffObject dateobj = new DateDiffObject();

public DateDiffObjectSerialize()

{

}

public DateDiffObjectSerialize(string Path)

{
this.strPath = Path;
}

public void SerializeDateObject(DateDiffObject dateobj)

{
FileInfo fi = new FileInfo(strPath);
if(fi.Exists)

{
fi.Delete();
}
XmlSerializer s = new XmlSerializer(typeof(DateDiffObject));
Stream stream = new FileStream(HttpContext.Current.Server.MapPath(strPath),FileMode.Create);
s.Serialize(stream, dateobj);
stream.Close();
}

public void SerializeDateObject(DateDiffObject dateobj,string FilePath)

{
strPath = FilePath;

FileInfo fi = new FileInfo(strPath);
if(fi.Exists)

{
fi.Delete();
}
XmlSerializer s = new XmlSerializer(typeof(DateDiffObject));
Stream stream = new FileStream(HttpContext.Current.Server.MapPath(strPath),FileMode.Create);
s.Serialize(stream, dateobj);
stream.Close();
}

public DateDiffObject DeserializeDateObject()

{
FileStream s = File.OpenRead(HttpContext.Current.Server.MapPath(strPath));
XmlSerializer xs = new XmlSerializer(typeof(DateDiffObject));
dateobj = (DateDiffObject)xs.Deserialize(s);
s.Close();
return dateobj;
}

public DateDiffObject DeserializeDateObject(string FilePath)

{
strPath = FilePath;
FileStream s = File.OpenRead(HttpContext.Current.Server.MapPath(strPath));
XmlSerializer xs = new XmlSerializer(typeof(DateDiffObject));
dateobj = (DateDiffObject)xs.Deserialize(s);
s.Close();
return dateobj;
}
}
要调用DateDiffObject时只是需要将它反序列化出来,按需提取里面的数据,然后组装到你查询语句中就行了。
结束语:
至于为什么要把它进行序列化,主要是我对方便使用的考量在里面,我就碰到这样的要求,不但要看报表,还要看相应的图片显示,年度、季度、月份的比较可以随时切换,当然你也可以不讲他序列化了,这个就见仁见智吧。