I have a dataset that I need to remove all records that are outside of the current financial year.
I have a function that returns a boolean that suggests if the record will be deleted or not, for some reason it is telling me to delete records that are inside the current financial year... Maybe a logic issue?
The Function:
public static Boolean GetCurrentFinancialYear(DateTime CompareDate)
{
TimeSpan diff = DateTime.Now - CompareDate;
double Years = diff.TotalDays / 365.25;
double Months = diff.TotalDays / 12;
Boolean DeleteRecord = false;
var CurrentYear = DateTime.Today.Year;
var CurrentMonth = DateTime.Today.Month;
if(CompareDate.Month == 10 && CompareDate.Year == 2017)
{
var something = "nothing";
}
if (Months >= 13)
{
/// This is over a year old, safe bet its last finacial year or earlier
///
DeleteRecord = true;
}
else
{
var CurrentEndDate = new DateTime(DateTime.Now.Year, 7, 1);
var CurrentStartDate = new DateTime(DateTime.Now.Year - 1, 6, 30);
TimeSpan Enddiff = CurrentEndDate - CompareDate;
TimeSpan Startdiff = CurrentStartDate - CompareDate;
double EndMonths = Enddiff.TotalDays / 12;
double StartMonths = Startdiff.TotalDays / 12;
if (EndMonths < 12 && StartMonths > 0)
{
DeleteRecord = false;
}
else
{
DeleteRecord = true;
}
}
return DeleteRecord;
}
Found an extremely simple and elegant solution
public static Boolean GetCurrentFinancialYear(DateTime CompareDate)
{
Boolean DeleteRecord = false;
var CurrentEndDate = new DateTime(DateTime.Now.Year, 7, 1);
var CurrentStartDate = new DateTime(DateTime.Now.Year - 1, 6, 30);
if (CompareDate >= CurrentStartDate && CompareDate < CurrentEndDate)
{
DeleteRecord = false;
}
else
{
DeleteRecord = true;
}
return DeleteRecord;
}
Related
well I have the following problem I try to validate the RUC of the provider of my country, the question is that I have implemented the validation functions which are the following:
ID validation function
public class Verifica_Identificacion
{
internal static bool VerificaIdentificacion(string identificacion)
{
bool estado = false;
char[] valced = new char[13];
int provincia;
if (identificacion.Length >= 10)
{
valced = identificacion.Trim().ToCharArray();
provincia = int.Parse((valced[0].ToString() + valced[1].ToString()));
if (provincia > 0 && provincia < 25)
{
if (int.Parse(valced[2].ToString()) < 6)
{
estado = VC.VerificaCedula(valced);
}
else if (int.Parse(valced[2].ToString()) == 6)
{
estado = VSP.VerificaSectorPublico(valced);
}
else if (int.Parse(valced[2].ToString()) == 9)
{
estado = VPJ.VerificaPersonaJuridica(valced);
}
}
}
return estado;
}
}
This function depends on other validations that are carried out independently because there are some types of RUC, below the other three functions are shown
ID verification
public class VC
{
public static bool VerificaCedula(char[] validarCedula)
{
int aux = 0, par = 0, impar = 0, verifi;
for (int i = 0; i < 9; i += 2)
{
aux = 2 * int.Parse(validarCedula[i].ToString());
if (aux > 9)
aux -= 9;
par += aux;
}
for (int i = 1; i < 9; i += 2)
{
impar += int.Parse(validarCedula[i].ToString());
}
aux = par + impar;
if (aux % 10 != 0)
{
verifi = 10 - (aux % 10);
}
else
verifi = 0;
if (verifi == int.Parse(validarCedula[9].ToString()))
return true;
else
return false;
}
}
public sector verification
public class VSP
{
public static bool VerificaSectorPublico(char[] validarCedula)
{
int aux = 0, prod, veri;
veri = int.Parse(validarCedula[9].ToString()) + int.Parse(validarCedula[10].ToString()) + int.Parse(validarCedula[11].ToString()) + int.Parse(validarCedula[12].ToString());
if (veri > 0)
{
int[] coeficiente = new int[8] { 3, 2, 7, 6, 5, 4, 3, 2 };
for (int i = 0; i < 8; i++)
{
prod = int.Parse(validarCedula[i].ToString()) * coeficiente[i];
aux += prod;
}
if (aux % 11 == 0)
{
veri = 0;
}
else if (aux % 11 == 1)
{
return false;
}
else
{
aux = aux % 11;
veri = 11 - aux;
}
if (veri == int.Parse(validarCedula[8].ToString()))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
}
verification of legal person
public class VPJ
{
public static bool VerificaPersonaJuridica(char[] validarCedula)
{
int aux = 0, prod, veri;
veri = int.Parse(validarCedula[10].ToString()) + int.Parse(validarCedula[11].ToString()) + int.Parse(validarCedula[12].ToString());
if (veri > 0)
{
int[] coeficiente = new int[9] { 4, 3, 2, 7, 6, 5, 4, 3, 2 };
for (int i = 0; i < 9; i++)
{
prod = int.Parse(validarCedula[i].ToString()) * coeficiente[i];
aux += prod;
}
if (aux % 11 == 0)
{
veri = 0;
}
else if (aux % 11 == 1)
{
return false;
}
else
{
aux = aux % 11;
veri = 11 - aux;
}
if (veri == int.Parse(validarCedula[9].ToString()))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
}
What I would like is to use the "ID validation function" in a textbox that accepts the RUC as input so far the data entry and that is stored in the database I did it as follows, however, as you can see I can only enter the string of the ruc without the respective validation. I would like a help to use my validation function at the time of entering the ruc and save it, if the entry was correct, the message "Provider stored correctly" appears and if it was not entered successfully, exit the message "Wrong RUC re-enter data"
data entry code from stored procedure (data layer)
public void Insertar(string NombreProveedor, string rucProveedor)
{
comando.Connection = con.AbrirConexion();
comando.CommandText = "IngresarProveedor";
comando.CommandType = CommandType.StoredProcedure;
comando.Parameters.AddWithValue("#NombreProveedor", NombreProveedor);
comando.Parameters.AddWithValue("#rucProveedor", rucProveedor);
comando.ExecuteNonQuery();
comando.Parameters.Clear();
con.CerrarConexion();
}
data entry code (business cape)
private CD_RUC proveedor_cd = new CD_RUC();
public void InsertarProv(string NombreProveedor, string rucProveedor)
{
proveedor_cd.Insertar(NombreProveedor, rucProveedor);
}
save button settings (presentation layer)
private void btn_Guardar_Click(object sender, RoutedEventArgs e)
{
proveedorcn NPro = new proveedorcn();
NPro.InsertarProv(TXT_Nombre_Proveedor_P.Text, TXT_RUC.Text);
MessageBox.Show("Proveedor Ingresado Correctamente");
}
Trying to find the largest cohesive time for non-working-hours diff in a specific range.
The range that is looked at is defined by:
sDate = range start
eDate = range end
in this defined range, there could be existing registrations (orange blocks in image).
Could someone please give me some input on how to solve this issue.
This code will not compare existing post with each other.
public TimeSpan TimeNightRest(DateTime WhatDay, int dayRange, DataTable TimeData)
{
DateTime DayRangeStart = new DateTime(WhatDay.Year, WhatDay.Month, WhatDay.Day, 0, 0, 0);
DateTime DayRangeEnd = new DateTime(WhatDay.Year, WhatDay.Month, WhatDay.AddDays(dayRange).Day, 0, 0, 0);
TimeSpan nightRest = new TimeSpan();
foreach (DataRow drUnfiltered in TimeData.Rows)
{
DateTime sDate = DateTime.Parse(TimeData.Rows[0]["sDate"].ToString());
DateTime eDate = DateTime.Parse(TimeData.Rows[0]["eDate"].ToString());
//1. db-post cover range
if (sDate < WhatDay && eDate > WhatDay.AddDays(dayRange))
{
nightRest = TimeSpan.FromHours(0);
break;
}
//2. Post exists, start outside ends inside range
if(sDate < WhatDay && eDate < WhatDay.AddDays(dayRange))
{
nightRest = (WhatDay.addDays(dayRange) - eDate)
//More posts could exists that lower this value!!!
}
//3. Post exists, start inside ends outside range
if ((sDate > WhatDay && sDate <WhatDay.AddDays(dayRange)) && eDate > WhatDay.AddDays(dayRange))
{
nightRest = (sDate - WhatDay);
//More posts could exists that lower this value!!!
}
}
return nightRest;
}
I tried to write a different version, this code will compare different post trying to find the largest diff between them. But will fail to find posts that overlaps (no diff) and it will also fail with finding the correct diff with post that starts outside and ends inside the range and opposite.
`
///<Alternative></Alternative>
//1. - No Data Rest = 24h x DayRange
if (timeData.Rows.Count == 0)
{
nightRest = TimeSpan.FromHours(24 * dayRange);
}
///<Alternative></Alternative>
//2. - One Post, Compare to day start/end time
if (timeData.Rows.Count == 1)
{
DateTime sDate = Convert.ToDateTime(timeData.Rows[0]["sDate"].ToString());
DateTime eDate = Convert.ToDateTime(timeData.Rows[0]["eDate"].ToString());
TimeSpan range1 = (sDate - DayRangeStart);
TimeSpan range2 = (DayRangeEnd - eDate);
if (range1 > range2)
{
nightRest = range1;
}
else
{
nightRest = range2;
}
}
///<Alternative></Alternative>
//3. - If DataTable containes more than 1 post, then loop through to calculate diffrence
between post and day start/end
if (timeData.Rows.Count > 1)
{
int i = 1;
int RowCount = timeData.Rows.Count;
foreach (DataRow dr in timeData.Rows)
{
DateTime sDate = Convert.ToDateTime(dr["sdate"]);
DateTime eDate = Convert.ToDateTime(dr["edate"]);
DateTime prevPostSdate = new DateTime();
DateTime nextPostSdate = new DateTime();
//Only 1st time in loop
if (i != 1)
{
//Prev row
DataRow lastRow = timeData.Rows[(i - 1) - 1];
prevPostSdate = Convert.ToDateTime(lastRow["edate"]);
//prevPostEdate = Convert.ToDateTime(lastRow["edate"]);
}
else
{
prevPostSdate = DayRangeStart;
}
//If we are on EOF-post then dont get next post value, get instead range end value
if (i != RowCount)
{
//Next row
DataRow nextRow = timeData.Rows[(i - 1) + 1];
nextPostSdate = Convert.ToDateTime(nextRow["sdate"]);
}
else
{
nextPostSdate = DayRangeEnd;
}
///<Compare>Type #1
///Sdate inside && eDate inside
///</ Compare >
if (DayRangeStart < sDate && DayRangeEnd > eDate)
{
//Compair Range with Post-sdate & Post
//1. Range with Post-sdate
TimeSpan value1 = (sDate - prevPostSdate);
//2. Post-eDate with NextPostSdate
TimeSpan value2 = (nextPostSdate - eDate);
if (value1 > nightRest) nightRest = value1;
if (value2 > nightRest) nightRest = value2;
}
///<Compare>Type #2
///Sdate outside && eDate inside
///</ Compare >
if (DayRangeStart >= sDate && DayRangeEnd > eDate)
{
//Compair Range with Post-sdate & Post
//1. Range with Post-sdate
TimeSpan value1 = (nextPostSdate - eDate);
if (value1 > nightRest) nightRest = value1;
}
///<Compare>Type #3
///Sdate indise && eDate outside
///</ Compare >
if (DayRangeStart < sDate && DayRangeEnd <= eDate)
{
//Compare Range Post-sdate & Post
//1. Range with Post-sdate
TimeSpan value1 = (sDate - prevPostSdate);
//Console.WriteLine(value1);
if (value1 > nightRest) nightRest = value1;
}
///<Compare>Type #4
///Sdate outside && eDate outside
///</ Compare >
if (DayRangeStart >= sDate && DayRangeEnd <= eDate)
{
nightRest = TimeSpan.FromHours(0);
}
i++;
}
}
`
Well i manage to solve this. Probably some much better code out there but this does the work!
public DataTable FilterTable(DataTable table, DateTime startDate, DateTime endDate)
{
var filteredRows =
from row in table.Rows.OfType<DataRow>()
where (DateTime)row["sDate"] < endDate && startDate <= (DateTime)row["eDate"]
select row;
var filteredTable = table.Clone();
filteredRows.ToList().ForEach(r => filteredTable.ImportRow(r));
return filteredTable;
}
public TimeSpan TimeNightRest(DateTime WhatDay, int dayRange, DataTable TimeData)
{
DateTime DayRangeStart = DateTime.Parse(WhatDay.ToShortDateString());
DateTime DayRangeEnd = DateTime.Parse(DayRangeStart.AddDays(dayRange).ToShortDateString());
TimeSpan nightRest = new TimeSpan();
DataTable dtTime = FilterTable(TimeData, WhatDay, WhatDay.AddDays(dayRange));
//1. - No posts
if (dtTime.Rows.Count == 0)
{
nightRest = TimeSpan.FromHours(24 * dayRange);
}
//2. - One post Exists!
if (dtTime.Rows.Count == 1)
{
DateTime sDate = Convert.ToDateTime(dtTime.Rows[0]["sDate"].ToString());
DateTime eDate = Convert.ToDateTime(dtTime.Rows[0]["eDate"].ToString());
if (sDate < DayRangeEnd && DayRangeStart <= eDate)
{
TimeSpan range1 = (sDate - DayRangeStart);
TimeSpan range2 = (DayRangeEnd - eDate);
if (range1 > range2)
{
nightRest = range1;
}
else
{
nightRest = range2;
}
//Negative TimeSpans is ==> Zero
if(nightRest < TimeSpan.Zero)
{
nightRest = TimeSpan.FromHours(0);
}
}
else
{
nightRest = TimeSpan.FromHours(24 * dayRange);
}
}
//3. More then 1 post i db
if (dtTime.Rows.Count > 1)
{
int i = 1;
int RowCount = dtTime.Rows.Count;
foreach (DataRow dr in dtTime.Rows)
{
DateTime sDate = Convert.ToDateTime(dr["sdate"]);
DateTime eDate = Convert.ToDateTime(dr["edate"]);
if (sDate < DayRangeEnd && DayRangeStart <= eDate)
{
DateTime prevPostSdate = new DateTime();
DateTime nextPostSdate = new DateTime();
//1st loop
if (i != 1)
{
//Prev row
DataRow lastRow = dtTime.Rows[(i - 1) - 1];
prevPostSdate = Convert.ToDateTime(lastRow["edate"]);
}
else
{
prevPostSdate = DayRangeStart;
}
//If we are on EOF-post then dont get next post value, get instead range end value
if (i != RowCount)
{
//Next row
DataRow nextRow = dtTime.Rows[(i - 1) + 1];
nextPostSdate = Convert.ToDateTime(nextRow["sdate"]);
}
else
{
nextPostSdate = DayRangeEnd;
}
if (DayRangeStart < sDate && DayRangeEnd > eDate)
{
TimeSpan value1 = (sDate - prevPostSdate);
TimeSpan value2 = (nextPostSdate - eDate);
if (value1 > nightRest) nightRest = value1;
if (value2 > nightRest) nightRest = value2;
}
if (DayRangeStart >= sDate && DayRangeEnd > eDate)
{
TimeSpan value1 = (nextPostSdate - eDate);
if (value1 > nightRest) nightRest = value1;
}
if (DayRangeStart < sDate && DayRangeEnd <= eDate)
{
TimeSpan value1 = (sDate - prevPostSdate);
if (value1 > nightRest) nightRest = value1;
}
if (DayRangeStart >= sDate && DayRangeEnd <= eDate)
{
nightRest = TimeSpan.FromHours(0);
}
}
else
{
nightRest = TimeSpan.FromHours(24 * dayRange);
}
i++;
}
}
return nightRest;
}
I have a table named Attendancelogs where I am saving the records that I fetch from a biometric device, the table structure is;
LogType defines the type of log i.e. Biometric/Manual
CheckType defines the type of entry i.e. I or O
VerifyMode defines the type of punch i.e. Fingerprint/Password
isIgnore is used to exclude an entry from the logs.
Now, what I am trying to do is to write a function called sortFunc(); that will process on the already stored records in the Attendancelogs table. what this is suppose to do is;
Mark the checkType of each employee as I for the first entry, then O for their second entry of the date and so on.
If an employee has a last I at the end of the day, meaning no check out, then the next day's first punch of that employee (with in 12 AM - 7 AM) is considered check out for the previous day (marking as a nighter case for that employee) the rest entries are considered as sequential I and O.
any multiple entries within 10 seconds (or defined time) is ignored and marked CheckType as "Auto Ignored for x seconds"
If an employee is not allowed to use Card/Password then his CheckTypes are marked as Card not allowed or Password not allowed
Here is the function that I wrote;
public static bool inn = true;
public void sortLogs(int machineNum)
{
DateTime prevDate = DateTime.MinValue;
DateTime currentDate = DateTime.MinValue;
DateTime prevDateTime = DateTime.MinValue;
DateTime currentDateTime = DateTime.MinValue;
TimeSpan lowerBound = TimeSpan.Zero;
TimeSpan upperBound = TimeSpan.Zero;
var time = DateTime.ParseExact("00:00:00", "HH:mm:ss", null).ToString("hh:mm:ss tt", CultureInfo.GetCultureInfo("en-US"));
lowerBound = Convert.ToDateTime(time).TimeOfDay;
var time2 = DateTime.ParseExact("07:00:00", "HH:mm:ss", null).ToString("hh:mm:ss tt", CultureInfo.GetCultureInfo("en-US"));
upperBound = Convert.ToDateTime(time2).TimeOfDay;
upperBound = new TimeSpan(7, 0, 0);
var CheckType = "N/S";
bool isNighter = false;
List<AttendanceLog> firstDates = new List<AttendanceLog>();
AttendanceLog lastEmp = new AttendanceLog();
var empList = db.AttendanceLogs.OrderBy(x => x.EmpID).ThenBy(x => x.DateTime).ToList();
var countEmps = empList.DistinctBy(p => p.EmpID).Count();
string[,] array = new string[countEmps, 2];
var checkDevice = db.DeviceInformations.Where(xy => xy.DeviceID == machineNum && xy.IsActive == 1.ToString()).ToList();
AttendanceLog firstObj = new AttendanceLog();
int counter = 0;
int tempEmp = -1;
foreach (var emp in empList)
{
if (emp.EmpID == 0)
continue;
var cardAcceptance = db.Roles.Where(x => x.EmpID == emp.EmpID && x.Card_Acceptance == true).ToList();
var passwordAcceptance = db.Roles.Where(x => x.EmpID == emp.EmpID && x.Password_Acceptance == true).ToList();
currentDate = emp.Date;
currentDateTime = emp.DateTime;
if (emp.EmpID != tempEmp)
{
inn = true;
}
if (prevDateTime != DateTime.MinValue)
{
var seconds = (emp.DateTime - prevDateTime).TotalSeconds;
var settings = db.settings.Where(xy => xy.Constant_Name == "Entry Delay").FirstOrDefault();
if (settings.Constant_Value <= 0)
settings.Constant_Value = 10;
else
if (seconds > 0 && seconds < settings.Constant_Value)
{
//store prevDateTime in deleted table
emp.CheckType = "Auto Ignored: " + seconds + " seconds interval.";
// prevDateTime = emp.DateTime;
continue;
}
}
if (passwordAcceptance.Count <= 0)
{
if (emp.VerifyMode == "3")
{
try
{
emp.CheckType = "Password not allowed";
//db.SaveChanges();
continue;
}
catch (DbEntityValidationException e)
{
foreach (var eve in e.EntityValidationErrors)
{
foreach (var ve in eve.ValidationErrors)
{
}
}
throw;
}
}
}
if (cardAcceptance.Count <= 0)
{
if (emp.VerifyMode == "4")
{
try
{
emp.CheckType = "Card not allowed";
// db.SaveChanges();
continue;
}
catch (DbEntityValidationException e)
{
foreach (var eve in e.EntityValidationErrors)
{
foreach (var ve in eve.ValidationErrors)
{
}
}
throw;
}
}
}
if (counter != countEmps)
{
if (emp.EmpID != firstObj.EmpID)
{
array[counter, 0] = emp.EmpID.ToString();
firstObj.EmpID = emp.EmpID;
firstObj.Date = emp.Date;
counter++;
}
}
if (currentDate == firstObj.Date)
{
//check for entry delay
//get emp datetime here
//comapre with the slots
//if the datetime exsits in between
//otherwise store it with boolean flag for the first entry only, the rest should not be flagged
if (emp.DateTime.TimeOfDay > lowerBound && emp.DateTime.TimeOfDay < upperBound)
{
//consider the first check as nighter and then ignore the rest
}
else {
//checks after the upperBound means, no nighter
}
if (inn)
{
inn = false;
emp.CheckType = "I";
}
else
{
inn = true;
emp.CheckType = "O";
}
for (int i = 0; i < array.Length / 2; i++)
{
if (array[i, 0] == emp.EmpID.ToString())
{
array[i, 1] = emp.CheckType;
break;
}
}
//CheckType = emp.CheckType;
prevDate = currentDate;
prevDateTime = currentDateTime;
}
else
{
if (prevDate != currentDate)
{
if (emp.DateTime.TimeOfDay > lowerBound && emp.DateTime.TimeOfDay < upperBound)
{
//consider the first check as nighter and then ignore the rest
if (inn)
{
inn = false;
emp.CheckType = "I";
}
else
{
inn = true;
emp.CheckType = "O";
}
for (int i = 0; i < array.Length / 2; i++)
{
if (array[i, 0] == emp.EmpID.ToString())
{
array[i, 1] = emp.CheckType;
break;
}
}
//CheckType = emp.CheckType;
prevDate = currentDate;
prevDateTime = currentDateTime;
}
else
{
//checks after the upperBound means, no nighter
}
for (int i = 0; i < array.Length / 2; i++)
{
if (array[i, 0] == emp.EmpID.ToString())
{
if (array[i, 1] == "I")
{
emp.CheckType = "O";
inn = true;
}
else
{
emp.CheckType = "I";
inn = false;
}
}
}
}
else
{
if (inn)
{
inn = false;
emp.CheckType = "I";
}
else
{
inn = true;
emp.CheckType = "O";
}
for (int i = 0; i < array.Length / 2; i++)
{
if (array[i, 0] == emp.EmpID.ToString())
{
array[i, 1] = emp.CheckType;
}
}
}
prevDate = currentDate;
}
tempEmp = emp.EmpID.Value;
}
db.SaveChanges();
}
This did run but it messes up the "12 AM to 7 AM" checks and the password checks, i.e. not the accurate results.
As one of the example seen ^ consecutive O should not be there. I have been going crazy over this!
I have some values.
DateTime date=04/03/2015(date)
Total Woring days=6 (total)
Rotation Days=2 (rotationday)
Shift Group=S1(this group contain two shift id 1 and 2)
I want to run the shift for 6 days. but after each 2 days Shift id 1 rotate to shift id 2 and again after two days shift id 2 rotate to shift id 1 and so on...
My output should be like
04/03/2015=1
05/03/2015=1
06/03/2015=2
07/03/2015=2
08/03/2015=1
09/03/2015=1
I am getting shift id through a foreach loop. I tried like below mentioned way but not getting a proper resul. Please help me solve this issue
SqlCommand cmd2 = new SqlCommand("select ShiftID from ShiftGroup where
ShiftName='" + ide + "'", conn2);
SqlDataAdapter sda2 = new SqlDataAdapter(cmd2);
DataSet ds4 = new DataSet();
var rows2 = ds4.Tables[0].Rows;
if (ds4.Tables[0].Rows.Count > 0)
{
foreach (DataRow row2 in rows2)
{
string shiftname = Convert.ToString(row2["ShiftID"]);
DateTime date=04/03/2015(date)
Total Woring days=6 (total)
Rotation Days=2 (rotationday)
DateTime rotation= date.AddDays(rotationday);//
DateTime totaldate = date.AddDays(workingdays);
for (DateTime rotation = date; rotation <= totaldate; rotation = rotation.AddDays(1))//total working days
{
//to check rotation date
if (rotation <= totaldate )
{
allocation.shiftallocation( rotation, shiftid);
}
}
}
I am stucked with this from last day, anybody help me . No need of consider my for loop, kindly provide a for loop which generate the above mentioned output
You can try this,
DateTime date=DateTime.ParseExact("04/03/2015","dd/MM/yyyy",CultureInfo.InvariantCulture);
DateTime totaldate = date.AddDays(6);
for (int i=0; date <= totaldate; date = date.AddDays(1),i++)//total working days
{
if((i/2)%2==0)
Console.WriteLine(date+" "+1);
else
Console.WriteLine(date+" "+2);
}
Don't use dates at loop cycle, use abstract indicies. You can really abstract from concrete numbers and use only variables for managing result. So you can easily change rotationDays count and even workshifts labels array without changing cycle.
var date = DateTime.Parse("04/03/2015");
var totalWorkingDays = 15;
var rotationDays = 2;
var workshifts = new[] { "S1", "S2" };
var currentWorkshiftIndex = 0;
for (int dayIndex = 0; dayIndex <= totalWorkingDays; dayIndex++) {
if (dayIndex != 0 && dayIndex % rotationDays == 0) currentWorkshiftIndex = (currentWorkshiftIndex + 1) % workshifts.Length;
Console.WriteLine(date.AddDays(dayIndex) + " " + workshifts[currentWorkshiftIndex]);
}
var date = DateTime.Parse("04/03/2015");
var totalWorkingDays = 6;
var rotationDays = 2;
var rotationId = 1;
var rotationCounter = 1;
for (DateTime rotation = date;
rotation <= date.AddDays(totalWorkingDays);
rotation = rotation.AddDays(1))
{
Console.WriteLine(rotation + " " + rotationId);
if (rotationCounter++ == 2)
{
rotationCounter = 1;
rotationId = 3 - rotationId;
}
}
Or, with a linq query
var date = DateTime.Parse("04/03/2015");
var totalWorkingDays = 6;
var rotationDays = 2;
foreach (var d in Enumerable.Range(0, totalWorkingDays)
.Select((i, index) => date.AddDays(i) +
(((int)(index / rotationDays)) % 2 == 1 ? " 2" : " 1")))
{
Console.WriteLine(d);
}
According to your comment for the 5 working days a week, I wrote this:
var start = new DateTime(2015, 04, 03);
var working_day_count = 6;
var rotation_interval = 2;
var shifts = new List<int> { 1, 2 };
var rotation_count = 1;
var shift_index = 0;
for (var i = 0; i < working_day_count; i++) {
while ((start.DayOfWeek == DayOfWeek.Saturday) ||
(start.DayOfWeek == DayOfWeek.Sunday)) {
start = start.AddDays(1);
}
Console.WriteLine(start.ToString() + " = " + shifts[shift_index].ToString());
start = start.AddDays(1);
rotation_count++;
if (rotation_count > rotation_interval) {
rotation_count = 1;
shift_index++;
if (shift_index >= shifts.Count) {
shift_index = 0;
}
}
}
Just change the values of the first four varibales as you like.
I tried to make it easy to understand instead of performant or compact.
A generic solution with holidays taken into account.
int totalDays = 10;
int rotationDays = 3;
int[] shifts = new[] { 1, 2 };
string startDate = "04/03/2015";
var holidays = new List<DayOfWeek>(new[] { DayOfWeek.Saturday, DayOfWeek.Sunday, DayOfWeek.Tuesday });
var shiftAllocations = new Dictionary<DateTime, int>();
int currentShiftIndex = 0;
DateTime current = DateTime.ParseExact(startDate, "dd/MM/yyyy", CultureInfo.InvariantCulture);
for (int i = 0; i < totalDays; i += rotationDays)
{
var currentShiftId = shifts[currentShiftIndex];
// For each day from the current day till the number of shift rotation days, allocate the shift.
for (int j = 0; j < rotationDays;)
{
// If the current day is a holiday, move to the next day by incrementing i.
if (holidays.Contains(current.AddDays(i + j).DayOfWeek))
{
i++;
continue;
}
shiftAllocations.Add(current.AddDays(i + j), currentShiftId);
j++;
}
// Increase the shift index if the value is within the bounds. If not reset the index to the beginning
if ((currentShiftIndex + 1) >= shifts.Length)
currentShiftIndex = 0;
else
currentShiftIndex++;
}
foreach (var kvp in shiftAllocations)
{
Console.WriteLine(kvp.Key.ToString("dd/MM/yyyy") + ":" + kvp.Value);
}
I need to calculate the number of days between two dates (DateTime) but with a twist. I want to know how many days fall into each of the months that the two days span. Is there an easy way two do it?
Example:
I have start date 30/03/2011 and end date 05/04/2011 then the result should be something like:
var result = new Dictionary<DateTime, int>
{
{ new DateTime(2011, 3, 1), 2 },
{ new DateTime(2011, 4, 1), 5 }
};
You could try something like this:
using System;
using System.Collections.Generic;
static class Program {
// return dictionary tuple<year,month> -> number of days
static Dictionary<Tuple<int, int>, int> GetNumberOfDays(DateTime start, DateTime end) {
// assumes end > start
Dictionary<Tuple<int, int>, int> ret = new Dictionary<Tuple<int, int>, int>();
DateTime date = end;
while (date > start) {
if (date.Year == start.Year && date.Month == start.Month) {
ret.Add(
Tuple.Create<int, int>(date.Year, date.Month),
(date - start).Days + 1);
break;
} else {
ret.Add(
Tuple.Create<int, int>(date.Year, date.Month),
date.Day);
date = new DateTime(date.Year, date.Month, 1).AddDays(-1);
}
}
return ret;
}
static void Main(params string[] args) {
var days = GetNumberOfDays(new DateTime(2011, 3, 1), new DateTime(2011, 4, 1));
foreach (var m in days.Keys) {
Console.WriteLine("{0}/{1} : {2} days", m.Item1, m.Item2, days[m]);
}
}
}
You can use the class Month of the Time Period Library for .NET:
// ----------------------------------------------------------------------
public Dictionary<DateTime,int> CountMonthDays( DateTime start, DateTime end )
{
Dictionary<DateTime,int> monthDays = new Dictionary<DateTime, int>();
Month startMonth = new Month( start );
Month endMonth = new Month( end );
if ( startMonth.Equals( endMonth ) )
{
monthDays.Add( startMonth.Start, end.Subtract( start ).Days );
return monthDays;
}
Month month = startMonth;
while ( month.Start < endMonth.End )
{
if ( month.Equals( startMonth ) )
{
monthDays.Add( month.Start, month.DaysInMonth - start.Day + 1 );
}
else if ( month.Equals( endMonth ) )
{
monthDays.Add( month.Start, end.Day );
}
else
{
monthDays.Add( month.Start, month.DaysInMonth );
}
month = month.GetNextMonth();
}
return monthDays;
} // CountMonthDays
Usage:
// ----------------------------------------------------------------------
public void CountDaysByMonthSample()
{
DateTime start = new DateTime( 2011, 3, 30 );
DateTime end = new DateTime( 2011, 4, 5 );
Dictionary<DateTime, int> monthDays = CountMonthDays( start, end );
foreach ( KeyValuePair<DateTime, int> monthDay in monthDays )
{
Console.WriteLine( "month {0:d}, days {1}", monthDay.Key, monthDay.Value );
}
// > month 01.03.2011, days 2
// > month 01.04.2011, days 5
} // CountDaysByMonthSample
Simple yes, fast no:
DateTime StartDate = new DateTime(2011, 3, 30);
DateTime EndDate = new DateTime(2011, 4, 5);
int[] DaysPerMonth = new int[12];
while (EndDate > StartDate)
{
DaysPerMonth[StartDate.Month]++;
StartDate = StartDate.AddDays(1);
}
Here's my solution. I did a quick check and it seems to work... let me know if there are any problems:
public Dictionary<DateTime, int> GetMontsBetween(DateTime startDate, DateTime EndDate)
{
Dictionary<DateTime, int> rtnValues = new Dictionary<DateTime, int>();
DateTime startMonth = new DateTime(startDate.Year, startDate.Month, 1);
DateTime endMonth = new DateTime(EndDate.Year, EndDate.Month, 1);
//some checking
if (startDate >= EndDate)
{
rtnValues.Add(startMonth, 0); // Or return null;
}
else if (startDate.Month == EndDate.Month && startDate.Year == EndDate.Year)
{
rtnValues.Add(startMonth, EndDate.Day - startDate.Day);
}
else
{
//Add first month remaining days
rtnValues.Add(startMonth, DateTime.DaysInMonth(startDate.Year, startDate.Month) - startDate.Day);
//Add All months days inbetween
for (DateTime st = startMonth.AddMonths(1); st < endMonth; st = st.AddMonths(1))
{
rtnValues.Add(new DateTime(st.Year, st.Month, 1), DateTime.DaysInMonth(st.Year, st.Month) );
}
//Add last month days
rtnValues.Add(new DateTime(EndDate.Year, EndDate.Month, 1), EndDate.Day);
}
return rtnValues;
}
Little example of how we can accurately get the total months and days between 2 dates using the built-in DateTime.DaysInMonth method which gives us the number of days in each month so we can get 100% accuracy.
DateTime date1 = DateTime.Now.AddDays(60);
DateTime date2 = DateTime.Now;
TimeSpan ts = date1 - date2;
int totalDays = int.Parse(ts.TotalDays.ToString("0"));
int totalMonths = Math.Abs((date1.Month - date2.Month) + 12 * (date1.Year - date2.Year));
int months = 0;
int days = 0;
int totalDaysInMonths = 0;
for (int i = totalMonths; i > 0; i--)
{
int month = date2.Month + i;
int year = date1.Year;
if (month > 12)
{
year++;
int newMonth = month - 12;
month = newMonth;
}
totalDaysInMonths = totalDaysInMonths + DateTime.DaysInMonth(year, month);
}
if (totalDays > totalDaysInMonths)
{
months = totalMonths - 1;
days = totalDays - totalDaysInMonths;
}
else if (totalDays < totalDaysInMonths)
{
months = totalMonths - 1;
int tempTotalDaysInMonths = 0;
for (int i = months; i > 0; i--)
{
int month = date2.Month + i;
int year = date1.Year;
if (month > 12)
{
year++;
int newMonth = month - 12;
month = newMonth;
}
tempTotalDaysInMonths = tempTotalDaysInMonths + DateTime.DaysInMonth(year, month);
}
days = totalDays - tempTotalDaysInMonths;
}
else
{
months = totalMonths;
}
return string.Format("{0} months and {1} days", months, days);
A very quick and dirty run at it using linqpad:
DateTime start = DateTime.Parse("03/30/2011");
DateTime end = new DateTime(2011,04,05,23,59,59);
var startNextMonthFirstDay = new DateTime(start.Year, start.Month+1, 1);
var diffForStartMonth = (startNextMonthFirstDay - start);
var totalDiff = (end-start);
var diff = Math.Round(totalDiff.TotalDays);
var diffForEndMonth = diff - diffForStartMonth.Days;
Dictionary<DateTime, int> result = new Dictionary<DateTime, int>();
result.Add(new DateTime(start.Year, start.Month, 1), diffForStartMonth.Days);
result.Add(new DateTime(end.Year, end.Month, 1), (int)diffForEndMonth);
//Dictionary<DateTime,int>{{new DateTime(2011,3,1),2},{new DateTime(2011,4,1),5}}
result.Dump();
DateTime dt1 = new DateTime(2011, 12, 12);
DateTime dt2 = new DateTime(2011, 06, 12);
TimeSpan ts = dt1.Subtract(dt2);
String s = ts.Days.ToString();
MessageBox.Show(s);