I have multiple file in a folder with a naming convention
Name_MoreName_DDMMYYYY_SomeNumber_HHMMSS.txt
How can I get the file which has oldest Date and Time (i.e. oldest DDMMYYYY and HHMMSS).
Ex:
Name_MoreName_22012012_SomeNumber_072334.txt
Name_MoreName_22012012_SomeNumber_072134.txt
Name_MoreName_24012012_SomeNumber_072339.txt
Name_MoreName_22012012_SomeNumber_072135.txt
So the oldest file will be
Name_MoreName_22012012_SomeNumber_072134.txt
how can i take the oldest file only ?
Edit
This is what I have done so far.. in a forach loop I am reading file name one by one
private void FileInformation(string fileName, ref string concatFile)
{
try
{
string completeFileName = fileName.Trim();
string[] fileComponenets = completeFileName.Split('_');
string fileDate = string.Empty;
string fileTime = string.Empty;
if (fileComponenets.Length > 0)
{
fileDate = fileComponenets[4].Replace(".txt", "").Trim();
fileTime = fileComponenets[2].ToString();
concatFile = fileDate + "-" + fileTime;
}
}
catch (Exception ex)
{
}
}
-- Main function
string fileStats = string.Empty;
foreach (string filePath in arrFileCollection)
{
if (filePath.ToLower().Contains("Name_MoreName_")&&
filePath.ToLower().Contains(".txt"))
{
string concatFile = string.Empty;
FileInformation(filePath.Replace(dirPath, ""), ref concatFile);
fileStats = fileStats + "," + concatFile;
}
}
Now I am getting all date time in a string with comma seperated value. Now I am stuck up. How can I take the smallest among them and get the related file
EDIT2
Note: Framework is .NET 2.0
string oldestFile = Directory.EnumerateFiles(path)
.OrderBy(file => ExtractDateTimeFrom(file))
.First(); // FirstOrDefault
And write method which will parse your file name and extract date from it:
public static DateTime ExtractDateTimeFrom(string fileName)
{
Regex regex = new Regex(#".+_(\d\d\d\d\d\d\d\d)_.+_(\d\d\d\d\d\d).txt");
var match = regex.Match(fileName);
string dateString = match.Groups[1].Value + match.Groups[2].Value;
return DateTime.ParseExact(dateString, "ddMMyyyyHHmmsss", null);
}
.NET 2.0 Simplest solution:
string oldestFile = "";
DateTime oldestDate = DateTime.Max;
foreach(string fileName in Directory.GetFiles(path))
{
DateTime date = ExtractDateTimeFrom(fileName);
if (date < oldestDate)
{
oldestFile = fileName;
oldestDate = date;
}
}
something like this maybe?
string[] filePaths = Directory.GetFiles(#"c:\MyDir\");
Regex rex = new Regex(#"^.*_(\d+)\.txt");
int date = int.MaxValue;
int oldestdate = int.MaxValue;
String oldestfile;
foreach(String filePath in filePaths)
{
Match match = rex.Match(filePath);
if(match.Success)
date = int.Parse(match.Groups[0].Value);
if (date < oldestdate)
{
oldestdate = date;
oldestfile = filePath;
}
}
Use DirectoryInfo and FileInfo classes. For example, just to give idea:
IOrderedEnumerable<FileInfo> filesInfo = new DirectoryInfo("D:\\")
.EnumerateFiles()
.OrderBy(f=>f.FullName);
UPDATE: For .NET 2.0, I would suggest you to separate the comparison logic from your main code... so why not create a custom type implementing IComparable interface.
public class CustomFileInfo :IComparable<CustomFileInfo>
{
public string Name { get; set; }
public string MoreName { get; set; }
public DateTime FileDate { get; set; }
public int Number { get; set; }
public DateTime FileTime { get; set; }
public CustomFileInfo(string fileNameString)
{
string[] fileNameStringSplited = fileNameString.Split('_');
this.Name = fileNameStringSplited[0];
this.MoreName = fileNameStringSplited[1];
this.FileDate = DateTime.ParseExact(fileNameStringSplited[2], "ddMMyyyy", null);
this.Number = int.Parse(fileNameStringSplited[3]);
this.FileTime = DateTime.ParseExact(fileNameStringSplited[4], "HHmmss", null);
}
public int CompareTo(CustomFileInfo other)
{
// add more comparison criteria here
if (this.FileDate == other.FileDate)
return 0;
if (this.FileDate > other.FileDate)
return 1;
return -1;
}
}
And then in your code, you may simple get files using DirectoryInfo and compare each files...
FileInfo[] filesInfo = new DirectoryInfo("D:\\").GetFiles();
//set first file initially as minimum
CustomFileInfo oldestFileInfo = new CustomFileInfo(filesInfo[0].FullName);
for (int i = 1; i < filesInfo.Length; i++)
{
CustomFileInfo currentFileInfo = new CustomFileInfo(filesInfo[i].FullName);
//compare each file and keep the oldest file reference in oldestFileInfo
if (oldestFileInfo.CompareTo(currentFileInfo) < 0)
oldestFileInfo = currentFileInfo;
}
You may optimize code for use and customize the comparison code as per your criteria.
Use This:
Updated
List<string> address = new List<string>() { "Name_MoreName_22012011_SomeNumber_072334.txt",
"Name_MoreName_22012012_SomeNumber_072134.txt",
"Name_MoreName_24012012_SomeNumber_072339.txt",
"Name_MoreName_22012012_SomeNumber_072135.txt",};
DateTimeFormatInfo dtfi = new DateTimeFormatInfo();
dtfi.ShortDatePattern = "dd-MM-yyyy";
dtfi.DateSeparator = "-";
address = address.OrderBy(s => Convert.ToDateTime((s.Split('_')[2]).Insert(2, "-").Insert(5, "-"), dtfi)).ToList();
string oldest = address[0];
Related
I have a method that reads from a spreadsheet to create an Auction for my application. I am getting the exception below, and I was wondering why the range of my sheet was set to that and then how to change the range so that I can read the rest of my excel file.
public ActionResult Upload(UploadFile UploadFile)
{
if (ModelState.IsValid)
{
if (UploadFile.ExcelFile.ContentLength > 0)
{
if (UploadFile.ExcelFile.FileName.EndsWith(".xlsx") || UploadFile.ExcelFile.FileName.EndsWith(".xls"))
{
XLWorkbook wb;
//incase if the file is corrupt
try
{
wb = new XLWorkbook(UploadFile.ExcelFile.InputStream);
}
catch (Exception ex)
{
ModelState.AddModelError(String.Empty, $"Check your file. {ex.Message}");
return View();
}
IXLWorksheet ws = null;
try//incase if the sheet you are looking for is not found
{
ws = wb.Worksheet("sheet1");
}
catch
{
ModelState.AddModelError(String.Empty, "Sheet not found");
return View();
}
var firstRowUsed = ws.FirstRowUsed();
var auctionRow = firstRowUsed.RowUsed().RowBelow();
//create auction
string auctionName = auctionRow.Cell(1).Value.ToString();
DateTimeOffset startDate = DateTimeOffset.Parse(auctionRow.Cell(2).Value.ToString());
DateTimeOffset endDate = DateTimeOffset.Parse(auctionRow.Cell(3).Value.ToString());
string folderName = auctionRow.Cell(4).Value.ToString();
Models.Auction auction = new Models.Auction(auctionName, startDate, endDate, folderName);
db.Auctions.Add(auction);
//find the next table
var nextRow = auctionRow.RowBelow();
while (nextRow.IsEmpty())
{
nextRow = nextRow.RowBelow();
}
const int catNameCol = 1;
var firstCatRow = nextRow.RowUsed();
var catRow = firstCatRow.RowBelow();
//get categories from ws table and add to the auction
while (!catRow.Cell(catNameCol).IsEmpty())
{
string catName = catRow.Cell(1).Value.ToString();
int seqNo = Convert.ToInt32(catRow.Cell(2).Value.ToString());
string fileName = catRow.Cell(3).Value.ToString();
Cat cat = new Cat(auction.AuctionId, catName, seqNo, fileName);
auction.Cats.Add(cat);
catRow = catRow.RowBelow();
}
var findNextRow = catRow.RowBelow();
while (findNextRow.IsEmpty())
{
findNextRow = findNextRow.RowBelow();
}
const int itemNameCol = 1;
var itemRow = findNextRow.RowUsed().RowBelow();
while (!itemRow.Cell(itemNameCol).IsEmpty())
{
string itemName = itemRow.Cell(1).Value.ToString();
string itemDesc = itemRow.Cell(2).Value.ToString();
string catName = itemRow.Cell(3).Value.ToString();
string modelNo = itemRow.Cell(4).Value.ToString();
decimal retailValue = Convert.ToDecimal(itemRow.Cell(5).Value.ToString());
string fileName = itemRow.Cell(6).Value.ToString();
decimal initialBid = Convert.ToDecimal(itemRow.Cell(7).Value.ToString());
decimal increment = Convert.ToDecimal(itemRow.Cell(8).Value.ToString());
Cat itemCat = null;
foreach (var cat in auction.Cats)
{
if (catName == cat.CatName.Trim())
{
itemCat = cat;
}
}
Item item = new Item(itemName, itemDesc, modelNo, retailValue, fileName, startDate, endDate, initialBid, increment, null, null, null, itemCat);
itemCat.Items.Add(item);
itemRow = itemRow.RowBelow();
}
}
else
{
ModelState.AddModelError(String.Empty, "Only .xlsx and .xls files are allowed");
return View();
}
}
else
{
ModelState.AddModelError(String.Empty, "Not a valid file");
return View();
}
}
db.SaveChanges();
return View();
}
Exception:
Format of Excel Doc:
I am really new to this so let me know if there is some syntax to accomplish what I am trying to and fix this exception. Also let me know if there are anything that sticks out that I can change/improve. Thank you kindly
nextRow is a truncated row "C15: F15", and the data you are looking for is greater than this range. I think that there is also a ClosedXML error here.
In your case, it helps to take the entire row of the worksheet and then get used cells.
Try next:
var firstCatRow = nextRow.WorksheetRow().RowUsed();
Need help to get the 1st row record and return record as string in the << >> after while() loop.
There are a lot of columns in one row, I'm having a problem to declare it as string st? like usually string st = new string() please help to correct it
Thanks
public string Get_aodIdeal(string SubmittedBy)
{
String errMsg = "";
Guid? rguid = null;
int isOnContract = 0;
int isFreeMM = 0;
string _FileName;
DateTime InstallDateTime = DateTime.Now;
string FileDate = ToYYYYMMDD(DateTime.Now);
errMsg = "Unknown Error.";
SqlConnection conn = null; SqlCommand cmd = null;
string st = null;
conn = new SqlConnection(WebConfigurationManager.ConnectionStrings["iDeal"].ConnectionString);
cmd = new SqlCommand();
string SQL = "select TOP 1 * from table1 Order by SubmittedOn desc";
SqlDataAdapter sqd = new SqlDataAdapter(SQL, conn);
cmd.CommandTimeout = 1200;
conn.Open();
SqlDataReader sqr;
//sqd.SelectCommand.Parameters.Add("#Submitted", SqlDbType.Int).Value = PostID;
sqr = sqd.SelectCommand.ExecuteReader();
while (sqr.Read())
st = new string{
rguid = cmd.Parameters["#rguid"].Value as Guid?,
ridno = int.Parse(sqr["ridno"].ToString()),
SubmittedOn= DateTime.Parse(sqr["SubmittedOn"].ToString()),
SubmittingHost = sqr["SubmittingHost"].ToString(),
ServiceAgreementNo = sqr["ServiceAgreementNo"].ToString(),
DocumentID = sqr["DocumentID"].ToString(),
Source = sqr["Source"].ToString(),
FileName = sqr["FileName"].ToString(),
FileType = sqr["FileType"].ToString(),
FileDate = DateTime.Parse(sqr["FileDate"].ToString()),
InstallTime = DateTime.Parse(sqr["InstallTime"].ToString()),
CalenderCode = cmd.Parameters["CalenderCode"].Value as Guid,
isFreeMM = bool.Parse(sqr["isFreeMM"].ToString()),
isOnContract = bool.Parse(sqr["isOnContract"].ToString()),
isProcessed = bool.Parse(sqr["isProcessed"].ToString()),
ProcessedByFullName = sqr["ProcessedByFullName"].ToString(),
isDelete = bool.Parse(sqr["isDelete"].ToString()),
version = int.Parse(sqr["Version"].ToString()),
LastUpdatedBy = DateTime.Parse(sqr["LastUpdatedBy"].ToString()),
LastUpdatedOn = DateTime.Parse(sqr["LastUpdatedOn"].ToString()),
shopGuid = sqr["shopGuid"].ToString(),
MacID = sqr["MacID"].ToString(),
MSISDN = sqr["MSISDN"].ToString()
}
You can use a StringBuilder for this purpose as like the following:
StringBuilder strBuilder= new StringBuilder();
while (sqr.Read())
{
strBuilder.AppendFormat("PostID : {0}{1}",sqr["PostID"].ToString(),Environment.NewLine);
strBuilder.AppendFormat("dateposted : {0}{1}",sqr["dateposted"].ToString(),Environment.NewLine);
// And so on Build your string
}
Finally the strBuilder.ToString() will give you the required string. But More smarter way is Create a Class with necessary properties and an Overrided .ToString method for display the output.
Let AodIdeal be a class with an overrided ToString() method. And Let me defined it like the following :
public class AodIdeal
{
public int PostID { get; set; }
public string dateposted { get; set; }
public string Source { get; set; }
// Rest of properties here
public override string ToString()
{
StringBuilder ObjectStringBuilder = new StringBuilder();
ObjectStringBuilder.AppendFormat("PostID : {0}{1}", PostID, Environment.NewLine);
ObjectStringBuilder.AppendFormat("dateposted : {0}{1}",dateposted, Environment.NewLine);
ObjectStringBuilder.AppendFormat("Source : {0}{1}", Source, Environment.NewLine);
// and so on
return ObjectStringBuilder.ToString();
}
}
Then you can create an object of the class(let it be objAodIdeal), and make use of its properties instead for the local variables. And finally objAodIdeal.ToString() will give you the required output.
Example usage
AodIdeal objAodIdeal= new AodIdeal();
while (sqr.Read())
{
objAodIdeal.PostID = int.Parse(sqr["PostID"].ToString());
objAodIdeal.dateposted= sqr["dateposted"].ToString();
// assign rest of properties
}
string requiredString= objAodIdeal.ToString();
I've got a List of Document
public class Document
{
public string[] fullFilePath;
public bool isPatch;
public string destPath;
public Document() { }
public Document(string[] fullFilePath, bool isPatch, string destPath)
{
this.fullFilePath = fullFilePath;
this.isPatch = isPatch;
this.destPath = destPath;
}
The fullFilepath should a List or an Array of Paths.
For example:
Document 1
---> C:\1.pdf
---> C:\2.pdf
Document 2
---> C:\1.pdf
---> C:\2.pdf
---> C:\3.pdf
etc.
My problem if I am using an array string all Documents got "null" in its fullFilePath.
If I'm using a List for the fullFilePath all Documents got the same entries from the last Document.
Here is how the List is filled:
int docCount = -1;
int i = 0;
List<Document> Documents = new List<Document>();
string[] sourceFiles = new string[1];
foreach (string file in filesCollected)
{
string bc;
string bcValue;
if (Settings.Default.barcodeEngine == "Leadtools")
{
bc = BarcodeReader.ReadBarcodeSymbology(file);
bcValue = "PatchCode";
}
else
{
bc = BarcodeReader.ReadBacrodes(file);
bcValue = "009";
}
if (bc == bcValue)
{
if(Documents.Count > 0)
{
Array.Clear(sourceFiles, 0, sourceFiles.Length);
Array.Resize<string>(ref sourceFiles, 1);
i = 0;
}
sourceFiles[i] = file ;
i++;
Array.Resize<string>(ref sourceFiles, i + 1);
Documents.Add(new Document(sourceFiles, true,""));
docCount++;
}
else
{
if (Documents.Count > 0)
{
sourceFiles[i] = file;
i++;
Array.Resize<string>(ref sourceFiles, i + 1);
Documents[docCount].fullFilePath = sourceFiles;
}
}
}
You are using the same instance of the array for every document. The instance is updated with a new list of files at every inner loop, but an array is a reference to an area of memory (oversimplification, I know but for the purpose of this answer is enough) and if you change the content of that area of memory you are changing it for every document.
You need to create a new instance of the source files for every new document you add to your documents list. Moreover, when you are not certain of the number of elements that you want to be included in the array, it is a lot better to use a generic List and remove all that code that handles the resizing of the array.
First change the class definition
public class Document
{
public List<string> fullFilePath;
public bool isPatch;
public string destPath;
public Document() { }
public Document(List<string> fullFilePath, bool isPatch, string destPath)
{
this.fullFilePath = fullFilePath;
this.isPatch = isPatch;
this.destPath = destPath;
}
}
And now change your inner loop to
foreach (string file in filesCollected)
{
string bc;
string bcValue;
....
if (bc == bcValue)
{
List<string> files = new List<string>();
files.Add(file);
Documents.Add(new Document(files, true, ""));
docCount++;
}
else
Documents[docCount].fullFilePath.Add(file);
}
Notice that when you need to add a new Document I build a new List<string>, add the current file and pass everything at the constructor (In reality this should be moved directly inside the constructor of the Document class). When you want to add just a new file you could add it directly to the public fullFilePath property
Moving the handling of the files inside the Documents class could be rewritten as
public class Document
{
public List<string> fullFilePath;
public bool isPatch;
public string destPath;
public Document()
{
// Every constructory initializes internally the List
fullFilePath = new List<string>();
}
public Document(string aFile, bool isPatch, string destPath)
{
// Every constructory initializes internally the List
fullFilePath = new List<string>();
this.fullFilePath.Add(aFile);
this.isPatch = isPatch;
this.destPath = destPath;
}
public void AddFile(string aFile)
{
this.fullFilePath.Add(aFile);
}
}
Of course, now in you calling code you pass only the new file or call AddFile without the need to check for the list initialization.
The issue should be here:
string[] sourceFiles = new string[1];
If you move this line of code in your foreach you should solve this problem because in your foreach you always use the same variable, so the same reference.
int docCount = -1;
int i = 0;
List<Document> Documents = new List<Document>();
foreach (string file in filesCollected)
{
string[] sourceFiles = new string[1];
string bc;
string bcValue;
if (Settings.Default.barcodeEngine == "Leadtools")
{
bc = BarcodeReader.ReadBarcodeSymbology(file);
bcValue = "PatchCode";
}
else
{
bc = BarcodeReader.ReadBacrodes(file);
bcValue = "009";
}
if (bc == bcValue)
{
if(Documents.Count > 0)
{
Array.Clear(sourceFiles, 0, sourceFiles.Length);
Array.Resize<string>(ref sourceFiles, 1);
i = 0;
}
sourceFiles[i] = file ;
i++;
Array.Resize<string>(ref sourceFiles, i + 1);
Documents.Add(new Document(sourceFiles, true,""));
docCount++;
}
else
{
if (Documents.Count > 0)
{
sourceFiles[i] = file;
i++;
Array.Resize<string>(ref sourceFiles, i + 1);
Documents[docCount].fullFilePath = sourceFiles;
}
}
}
I have a log file that I am reading into different objects. One object starts at a Line that contains the words "Announce message" and the following lines contain the data that belongs to that message. This entry stops at a line that contains the word "Disposed".
I want to read all the data from between these 2 lines that, contains certain words.
Im currently using a Dictionary because the line with "Announce message" also contains a UID but the following lines contain the data for that UID.
How would you do that?
This is what i have come up with so far.
public static void P2PLogParser(List<FileInfo> fileList)
{
foreach (FileInfo fi in fileList)
{
//Læser alle linier i csv fil
foreach (var line in File.ReadAllLines(fi.FullName))
{
string MeterUID = GetMeterUID(line);
string MimHashcode = GetMimHashcode(line);
string FirmwareUploadStatus = GetFirmwareUploadStatus(line);
string IsKnown = GetIsKnown(line);
DateTime P2PTimeStamp = GetTimestamp(line);
if (IsMeterEntry(line) && !meters.ContainsKey(MeterUID))
{
string MeterNr = GetMeterUID(line).Replace("4B414D", "");
int meternr = int.Parse(MeterNr, System.Globalization.NumberStyles.HexNumber);
meters.Add(MeterUID, new Meter()
{
MeterUID = MeterUID,
MeterNR = meternr,
P2Pmeterentry = new List<P2PMeterEntry>()
});
}
if (IsMeterEntry(line))
{
P2PMeterEntry p2pmeter = new P2PMeterEntry
{
P2PTimeStamp = P2PTimeStamp,
MimHashcode = MimHashcode,
FirmwareUploadStatus = FirmwareUploadStatus,
IsKnown = IsKnown,
P2PMetersession = new List<P2PMeterSession>()
};
if (IsNoLongerMeterEntry(line))
{
string SessionLevel = GetLevel(line);
string SessionMessage = GetSessionMessage(line);
string Context = GetSessionContext(line);
P2PMeterSession MeterSession = new P2PMeterSession
{
SessionTimeStamp = P2PTimeStamp,
SessionLevel = SessionLevel,
SessionMessage = SessionMessage,
Context = Context
};
meterSession.Add(MeterSession);
}
meters[MeterUID].P2Pmeterentry.Add(p2pmeter);
}
}
}
}
and the IsMeterEntry and IsNoLongerMeterEntry
//IsMeterSession
public static bool IsMeterEntry(string text)
{
return text.ToLower().Contains("announce message received:");
}
public static bool IsNoLongerMeterEntry(string text)
{
return text.ToLower().Contains("context - disposed");
}
Implement a simple state machine with two states: IgnoreLine (initial state) and Announce.
for each line in log
if line contains "Announce message"
read UID
create a StringBuilder
set state=Announce
else if line contains "Disposed"
store the StringBuilder's content in the dictionary[uid]
set state=IgnoreLine
else if state==Announce and line contains "certain words"
append line to StringBuilder
I run into a little common problem with datetime class that I have no idea how to resolve.
I don't know what the error is but I see the troubleshooting tips are displayed as
When converting a string to DateTime, parse the string to take the date before putting each variable into the DateTime object. Make sure your method arguments are in the right format.
Here is the piece of code I extract from my program,
public IEnumerable<CONTACT_INFO> GetContactInfo(string tableName)
{
DataTable dt = GetUserInfo(tableName);
List<CONTACT_INFO> lst = new List<CONTACT_INFO>();
foreach (DataRow row in dt.Rows)
{
string sDate = "";
if(!string.IsNullOrEmpty(row["birthday"].ToString()))
{
sDate = row["birthday"].ToString();
}
string format = "yyyyMMdd";
System.Globalization.CultureInfo provider =CultureInfo.InvariantCulture;
string datetime = DateTime.Now.ToShortDateString();
if (!string.IsNullOrEmpty(sDate))
{
datetime = DateTime.ParseExact(sDate, format, provider).ToShortDateString();
}
if (row["companyname"].ToString().CompareTo("companylogo") != 0)
{
string profile_time = row["profile_timestamp"].ToString();
if (!string.IsNullOrEmpty(profile_time))
{
CSTimeZone time = new CSTimeZone();
profile_time = time.FromUnix(Convert.ToDouble(profile_time)).ToShortDateString()+" "+
time.FromUnix(Convert.ToDouble(profile_time)).ToLongTimeString();
}
string lastUseNetTime = row["last_used_networktime"].ToString();
if (!string.IsNullOrEmpty(lastUseNetTime))
{
CSTimeZone time = new CSTimeZone();
double sec = Convert.ToDouble(lastUseNetTime) * 60;
lastUseNetTime = time.FromUnix(Convert.ToDouble(sec)).ToShortDateString() + " " +
time.FromUnix(Convert.ToDouble(sec)).ToLongTimeString();
}
string lastOnlineTime = row["lastonline_timestamp"].ToString();
if (!string.IsNullOrEmpty(lastOnlineTime))
{
CSTimeZone time = new CSTimeZone();
lastOnlineTime = time.FromUnix(Convert.ToDouble(lastOnlineTime)).ToShortDateString() + " " +
time.FromUnix(Convert.ToDouble(lastOnlineTime)).ToLongTimeString();
}
lst.Add(new CONTACT_INFO()
{
gender=Convert.ToInt32(row["gender"].ToString()),
timezone=row["timezone"].ToString(),
fullName = row["fullname"].ToString(),
profile_timestamp = profile_time,
last_used_networktime = lastUseNetTime,
lastonline_timestamp = lastOnlineTime,
birthday = string.IsNullOrEmpty(sDate) ? "" : datetime
});
}
}
return lst;
}
The function FromUnix is written as
public DateTime FromUnix(double seconds)
{
DateTime datetime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).ToLocalTime();
return datetime.AddSeconds(seconds);
}
I am pretty sure this is a parsing problem
The following line would throw exceptions if the value of sDate is not in the defined format of yyyyMMdd
datetime = DateTime.ParseExact(sDate, format, provider).ToShortDateString();
I would first use TryParseExact instead of a simple Parse since you do not seem to be using try/catch clauses. It might be a good idea to use the debugger to see exactly where your program is failing.
Other example of potential failures in your code are
double sec = Convert.ToDouble(lastUseNetTime) * 60;
Use double.tryParse
Convert.ToInt32(row["gender"].ToString()
If gender turns out not to be a number another exception will be thrown
etc...