Tuition Increase - c#

I am trying to get this to display Year 1 original tuition + interest rate then have all the interest rates compound afterwards. It gets stuck on Year 2 then just repeats.
private void button1_Click(object sender, EventArgs e)
{
double originalTuition = 6000.00;
double newTuition;
double interestRate = 0.02;
tuitionListBox.Items.Clear();
for (int year = 1; year <= 5; year++)
{
if (year == 1)
newTuition = originalTuition;
else
newTuition = originalTuition + (originalTuition * interestRate);
newTuition = newTuition + (newTuition * interestRate);
tuitionListBox.Items.Add(year + "\t" + newTuition.ToString("c"));
}
}

newTuition will always start with the same value after year 1 due to your ‘else’ block. My guess is you want to remove the first line of code after the ‘else’.

First initialize newTuition variable.
Then below code:
for (int year = 1; year <= 5; year++)
{
if (year == 1)
newTuition = originalTuition;
else
newTuition = newTuition + (newTuition * interestRate);
tuitionListBox.Items.Add(year + "\t" + newTuition.ToString("c"));
}

I would suggest creating a new method for clarity and reusability. Using brackets with if/else statements makes the code more easy to read, and thereby identifying the problem.
private List<double> GetAnnualTuitions(double originalTuition, double interestRate, int numOfYears)
{
double newTuition = 0;
List<double> tuitions = new List<double>();
for (int year = 1; year <= numOfYears; year++)
{
if (year == 1)
{
newTuition = originalTuition;
}
else
{
newTuition += (newTuition * interestRate);
}
tuitions.Add(newTuition);
}
return tuitions;
}

Related

Trouble Creating Math for Accurate Division of Two Lists of Doubles with Custom Carryover

I'm making an idle/click game in unity, and have a custom format that I'd like all the numbers in the game to display as. K for thousands, M for millions, B for billions, etc. See below example from a game called Tower of Heroes.
example
The displaying of these numbers and units works great. However, where I am running into an issue is with my decision to have arbitrarily large numbers in the game. I did not want to be limited by the constraints of double, and wanted the challenge of coming up with my own solution. I was able to do so, and even get most math operations to work with my solution. Addition, subtraction, multiplication, and exponents all work well enough. But I cannot figure out the logic/math for division...
So, I am using a list of doubles for each of my game variables.
Example: List<double> money = new List<double>(); would be a list containing the money the player currently has. Every position is limited to 0-999. Position 0 represents the "1's", position 1 the thousands, position 2 the millions, etc, with the list growing as large as it needs to. So if we had:
List<double> money = new List<double>()
{
10, //1's
50, //thousands (K)
200 //millions (M)
//etc.
};
that would be $200,050,010, or in my game's notation: 200M050K. (I only display the largest unit, or sometimes the largest two units)
For example, here is the addition method I have working:
//SuperAdd
public List<double> SuperAdd(List<double> baseValue, List<double> valueBeingAdded)
{
//declairing a new list to house the result
List<double> resultValue = new List<double>();
//making copies to not affect originals
List<double> baseValueCopy = baseValue;
List<double> valueBeingAddedCopy = valueBeingAdded;
//increase the # of tiers in our result list until it matches the largest of the two being added
while (resultValue.Count < Mathf.Max(valueBeingAddedCopy.Count, baseValueCopy.Count))
{
resultValue.Add(0);
//if needed adjust the size of the two lists being added together so they match
if (valueBeingAddedCopy.Count < baseValueCopy.Count) valueBeingAddedCopy.Add(0);
if (valueBeingAddedCopy.Count > baseValueCopy.Count) baseValueCopy.Add(0);
}
//add all the respective tiers together
for (int i = 0; i < resultValue.Count; i++)
{
//add all the tiers together
resultValue[i] = baseValueCopy[i] + valueBeingAddedCopy[i];
}
//check for any carry overs needed (>=1000)
for (int i = 0; i < resultValue.Count; i++)
{
//where this is true we need to carry over to next tier
if(resultValue[i] >= 1000)
{
//check if we are on the last existing tier
if(i + 1 == resultValue.Count)
{
//add an empty tier
resultValue.Add(0);
}
//calculate how many thousands need to be carried over, and what the remainder is
double nextTierAdder = Math.Floor(resultValue[i] / 1000);
double currentTierRemainder = resultValue[i] % 1000;
//apply both
resultValue[i] = currentTierRemainder;
resultValue[i + 1] += nextTierAdder;
}
}
//remove any empty blanks from the ends of the resultValue list
for (int i = resultValue.Count - 1; i > 0; i--)
{
if (resultValue[i] == 0) resultValue.RemoveAt(i);
else break;
}
//return resultValue
return resultValue;
}
So, what I'm looking to achieve is a similar method for division, pseudo code:
public List<double> SuperDivide(List<double> baseValue1, List<double> baseValue2)
{
//code goes here
return result;
}
What I have so far is some junk code as a placeholder until I figure out a correct solution that will return a List.
//SuperDivide result = bv1 / bv2
//this is currently only useful when the values are near one another in size
public double SuperDivide(List<double> baseValue1, List<double> baseValue2)
{
double result;
//check if one input list is way bigger than the other, and return a simplified result
//the 100 is because double has a max of 1.7x10^308, each position in our lists holds 1x10^3
if(baseValue1.Count - 100 > baseValue2.Count)
{
result = Math.Pow(10, 300);
return result;
}
if(baseValue2.Count - 10 > baseValue1.Count)
{
result = 0.00000000001; //arbitrary small # that isn't quite 0
return result;
}
//get the stopping position for the for loops (clamped at 5 due to double having a precision of 15 digits)
int stopPos1 = baseValue1.Count - Mathf.Clamp(baseValue1.Count, 1, 5);
int stopPos2 = baseValue2.Count - Mathf.Clamp(baseValue2.Count, 1, 5);
//empty strings to hold the #'s
string bv1String = "";
string bv2String = "";
//create a string of the largest digits in bv1
if (stopPos1 > 1)
{
//create a string of the largest digits in bv1
for (int i = baseValue1.Count - 1; i >= stopPos1; i--)
{
if (i == baseValue1.Count - 1)
{
bv1String = baseValue1[i].ToString();
}
else
{
if (baseValue1[i] < 10) bv1String = bv1String + "00" + baseValue1[i].ToString();
else if (baseValue1[i] < 100) bv1String = bv1String + "0" + baseValue1[i].ToString();
else bv1String = bv1String + baseValue1[i].ToString();
}
}
}
else
{
//create a string of the largest digits in bv1
for (int i = baseValue1.Count - 1; i >= 0; i--)
{
if (i == baseValue1.Count - 1)
{
bv1String = baseValue1[i].ToString();
}
else
{
if (baseValue1[i] < 10) bv1String = bv1String + "00" + baseValue1[i].ToString();
else if (baseValue1[i] < 100) bv1String = bv1String + "0" + baseValue1[i].ToString();
else bv1String = bv1String + baseValue1[i].ToString();
}
}
}
//create a string of the largest digits in bv1
if (stopPos2 > 1)
{
//create a string of the largest digits in bv2
for (int i = baseValue2.Count - 1; i >= stopPos2; i--)
{
if (i == baseValue2.Count - 1)
{
bv2String = baseValue2[i].ToString();
}
else
{
if (baseValue2[i] < 10) bv2String = bv2String + "00" + baseValue2[i].ToString();
else if (baseValue2[i] < 100) bv2String = bv2String + "0" + baseValue2[i].ToString();
else bv2String = bv2String + baseValue2[i].ToString();
}
}
}
else
{
//create a string of the largest digits in bv2
for (int i = baseValue2.Count - 1; i >= 0; i--)
{
if (i == baseValue2.Count - 1)
{
bv2String = baseValue2[i].ToString();
}
else
{
if (baseValue2[i] < 10) bv2String = bv2String + "00" + baseValue2[i].ToString();
else if (baseValue2[i] < 100) bv2String = bv2String + "0" + baseValue2[i].ToString();
else bv2String = bv2String + baseValue2[i].ToString();
}
}
}
//create numbers for the input lists
double bv1Double = double.Parse(bv1String);
double bv2Double = double.Parse(bv2String);
//adjust for one being bigger than the other, only by relative amount though
//only needed when one of them has 6+ tiers
if (baseValue1.Count > 5 && baseValue2.Count > 5)
{
if (baseValue1.Count > baseValue2.Count)
{
bv1Double *= Math.Pow(1000, baseValue1.Count - baseValue2.Count);
}
else if (baseValue1.Count < baseValue2.Count)
{
bv1Double *= Math.Pow(1000, baseValue2.Count - baseValue1.Count);
}
}
//calculate result
result = bv1Double / bv2Double;
return result;
}
Questions:
(1) If anyone can point me in the right direction for the math/logic of the special division, I can probably handle the coding.
(2) Would it be appropriate to make another post / add to this one my other math methods, looking for code suggestions? (I'm a self-taught novice and know there are a lot of improvements I could make to these methods)
If you want to keep your custom formatting and not switch to BigInteger, there might be a viable way to divide by using your existing addition and subtraction operators.
Since your values are stored in a list of integers, you should run through that list for each number and perform long divison.
I'm on my phone so I can't provide a code example, but the logic is somewhat straightforward.
https://en.wikipedia.org/wiki/Long_division
Let's say the calculation is 300/20
First step is to find the first subset of 300 that is equal to or larger than the 20.
That will be 30.
Then you find the qoutient and calculate the remainder, which is 1 and 10 respectively.
You then append the next number from the 300 (which is a 0) to the remainder (10). This will give you 100.
Then you do the same thing resulting in a qoutient of 5 and remainder of 0.
The remainder being zero means that the calculation is complete.
Then you append all the qoutients you've calculated and you have the result ("1" + "5" = "15")
For finding the qoutient and remainder you can use Euclidean Division that also only uses your existing addition and subtraction operators.
https://en.wikipedia.org/wiki/Division_algorithm
N / D = (Quotient, Remainder)
Algorithm:
R = N, Q = 0
while(N > D)
{
R= R - D
Q ++
}
Wikipedia has some nice visualisations and probably explains it clearer.
The main takeaway is that you should be able to implement this algorithm using your existing operators while only using addition and subtraction.
With the suggestion from Nicklas, I was able to put together the following chunk of code. I did a fair bit of testing and am fairly confident it is mostly / all correct. The follow-up question was going to be that during testing I found that operations resulting in a very large answer (ex: 10 trillion / 5) would take a long time. After thinking for a few minutes I came up with a decent solution for massive time savings. Now it will spit out stupidly big results instantly.
//assumes both inputs are positive and > 0
public List<double> SuperDivide(List<double> numerator, List<double> denominator)
{
//here we are going to adopt the notation used on the wiki page for long division
//inputs are numerator/denominator
//outputs are (Q,R) quotient and remainder
//create and set the Q to 0
List<double> quotient = new List<double>
{
0
};
//create a list of value 1
List<double> one = new List<double>
{
1
};
//declairing a new list to house the result
List<double> resultValue = new List<double>();
//empty strings to hold the #'s
string denomString = "";
string remainderString = "";
//create and set the R = N
List<double> remainder = new List<double>();
for (int i = 0; i < numerator.Count; i++)
{
remainder.Add(numerator[i]);
}
//getting a starting value
string compareResult = WhichIsBigger(remainder, denominator);
//calculate Q and R: while R >= D
while(compareResult =="A" || compareResult == "Equal")
{
//get the multiplier we can use to save calcs on big # results (xxxxxxxxxxxxxxxxxxx / yyyy)
List<double> testResult = DivTester(remainder, denominator);
//create a var for D * X, where X is the testResult
List<double> denomMult = SuperMultiply(denominator, testResult);
//Q = Q + X
quotient = SuperAdd(quotient, testResult);
//R = R - DX
remainder = SuperSubtract(remainder, denomMult);
compareResult = WhichIsBigger(remainder, denominator);
}
//if R = 0, return Q
if(remainder.Count == 1 && remainder[0] == 0)
{
return quotient;
}
//else return Q + (R/D)
else
{
//get the stopping position for the for loops (clamped at 5 due to double having a precision of 15 digits)
int stopPosR = remainder.Count - Mathf.Clamp(remainder.Count, 1, 5);
int stopPosD = denominator.Count - Mathf.Clamp(denominator.Count, 1, 5);
//create a string of the largest digits in R
if (stopPosR > 1)
{
for (int i = remainder.Count - 1; i >= stopPosR; i--)
{
//starting tier (largest #)
if (i == remainder.Count - 1)
{
remainderString = remainder[i].ToString();
}
else
{
if (remainder[i] < 10) remainderString = remainderString + "00" + remainder[i].ToString();
else if (remainder[i] < 100) remainderString = remainderString + "0" + remainder[i].ToString();
else remainderString = remainderString + remainder[i].ToString();
}
}
}
else
{
for (int i = remainder.Count - 1; i >= 0; i--)
{
//starting tier (largest #)
if (i == remainder.Count - 1)
{
remainderString = remainder[i].ToString();
}
else
{
if (remainder[i] < 10) remainderString = remainderString + "00" + remainder[i].ToString();
else if (remainder[i] < 100) remainderString = remainderString + "0" + remainder[i].ToString();
else remainderString = remainderString + remainder[i].ToString();
}
}
}
//create a string of the largest digits in D
if (stopPosD > 1)
{
for (int i = denominator.Count - 1; i >= stopPosD; i--)
{
if (i == denominator.Count - 1)
{
denomString = denominator[i].ToString();
}
else
{
if (denominator[i] < 10) denomString = denomString + "00" + denominator[i].ToString();
else if (denominator[i] < 100) denomString = denomString + "0" + denominator[i].ToString();
else denomString = denomString + denominator[i].ToString();
}
}
}
else
{
for (int i = denominator.Count - 1; i >= 0; i--)
{
if (i == denominator.Count - 1)
{
denomString = denominator[i].ToString();
}
else
{
if (denominator[i] < 10) denomString = denomString + "00" + denominator[i].ToString();
else if (denominator[i] < 100) denomString = denomString + "0" + denominator[i].ToString();
else denomString = denomString + denominator[i].ToString();
}
}
}
//create numbers for divsion of R/D
double remainderDoub = double.Parse(remainderString);
double denomDoub = double.Parse(denomString);
//adjust for one being bigger than the other, only by relative amount though
//only needed when one of them has 6+ tiers
if (remainder.Count > 5 && denominator.Count > 5)
{
if (remainder.Count > denominator.Count)
{
remainderDoub *= Math.Pow(1000, remainder.Count - denominator.Count);
}
else if (remainder.Count < denominator.Count)
{
denomDoub *= Math.Pow(1000, denominator.Count - remainder.Count);
}
}
resultValue.Add(remainderDoub / denomDoub);
resultValue = SuperAdd(resultValue, quotient);
return resultValue;
}
}
And the DivTester method:
//I'm sure there are much more effecient ways to determine this multiplier...
private List<double> DivTester(List<double> rem, List<double> denom)
{
//declairing a new list for testing, starting value of 1
List<double> ten = new List<double>()
{
10
};
//create and set the dCopy = denom
List<double> dCopy = new List<double>();
for (int i = 0; i < denom.Count; i++)
{
dCopy.Add(denom[i]);
}
//create and set the testerPass = 1
List<double> testerPass = new List<double>()
{
1
};
//getting a starting value
string compareResult = WhichIsBigger(rem, dCopy);
while(compareResult == "A")
{
dCopy = SuperMultiply(dCopy, ten);
//check and see if it is still successfull
compareResult = WhichIsBigger(rem, dCopy);
//if it passes, multiple testerPass by ten
if (compareResult == "A")
{
testerPass = SuperMultiply(testerPass, ten);
}
}
//return the largest multipler (10^X) that can be safely used
return testerPass;
}

Array & Loop calculations

I am doing a simple loan calculation of compound interest. When click "calculate", it will show in the list box the monthly payment every month and other information such as property tax. However, the information does not seem to appear at all.
private void btnCalculate_Click_1(object sender, EventArgs e)
{
decimal amount = 0.0m;
double principal;
double rate = 0.05;
int Years;
int timesPerYear = 12;
Years = int.Parse(tbLoanTerm.Text); ;
principal = int.Parse(tbAmount.Text);
int Months = 0;
decimal amountMonthly = 0.0m;
listBox1.Items.Add("Month \t\t\tMonthly Payment\t\t\tProperty Tax");
while(Months<=360)
{
Months = Years * 12;
double body = 1 + (rate / timesPerYear);
double exponent = timesPerYear * Years;
amount = Convert.ToInt32(principal * Math.Pow(body, exponent));
amountMonthly = amount / Months;
propertytaxdec = amount * Property_Tax;
listBox1.Items.Add(Months + "\t\t" + amountMonthly + "\t\t" + propertytaxdec);
Months++;
}
}

C# Winforms: Returning values to a button event

I'm completely new to C# programming, and I'm trying to make a custom calculator using Windows Forms.
Three text boxes txtMinSkill, txtMaxSkill, txtCooldown should be keyed values into, and clicking a button buttonCalculate should do some calculations and present the result in a label resultLabel.
I have managed to get everything working down to the skill.Display function, but I have no idea how to display the variables hours, minutes, seconds in the label. When I try to access them from within the button event, I just get a message that it does not exist in the current context. And I can't access the label from the Display method.
Can anyone assist? Thanks!
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void buttonCalculate_Click(object sender, EventArgs e)
{
double minSkill;
double maxSkill;
double coolDown;
minSkill = float.Parse(txtMinSkill.Text) * 10;
maxSkill = float.Parse(txtMaxSkill.Text) * 10;
coolDown = float.Parse(txtCooldown.Text);
SkillGainCalculator skill = new SkillGainCalculator();
skill.IntegerMax(maxSkill);
skill.RemainderMax(maxSkill);
skill.RemainderMin(minSkill);
skill.IntegerMin(minSkill);
skill.Calculate(minSkill,maxSkill);
skill.Display(coolDown);
}
}
class SkillGainCalculator
{
//member variables
private int integerMax;
private int remainderMax;
private int integerMin;
private int remainderMin;
private double counter;
const int constant = 6480;
private int i;
private double totalTime;
private int hours;
private int minutes;
private int seconds;
public double IntegerMax(double intMax)
{
integerMax = (int)((1000 - intMax) / 50);
return integerMax;
}
public int RemainderMax(double intMax)
{
remainderMax = (int)((1000 - intMax) % 50);
return remainderMax;
}
public int RemainderMin(double intMin)
{
remainderMin = (int)((1000 - intMin) % 50);
return remainderMin;
}
public int IntegerMin(double intMin)
{
if (remainderMin == 0)
{
integerMin = (int)((1000 - intMin) / 50) - 1;
return integerMin;
}
else
{
integerMin = (int)((1000 - intMin) / 50);
return integerMin;
}
}
public double Calculate(double intMax, double intMin)
{
for (i = integerMax; i <= integerMin; i++)
{
if (i == integerMax && remainderMax != 0)
{
if (intMax <= 700)
{
counter = counter + constant * Math.Pow(0.8, i) * (50 - remainderMax) / 50;
}
else
{
counter = counter + constant * Math.Pow(0.8, i) * (50 - remainderMax) / 50;
}
}
else if (i == integerMin && remainderMin != 0)
{
if (intMin < 700)
{
counter = counter + constant * Math.Pow(0.8, i) * remainderMin / 50;
}
else
{
counter = counter + constant * Math.Pow(0.8, i) * remainderMin / 50;
}
}
else if (i >= 6)
{
counter = counter + constant * Math.Pow(0.8, i);
}
else
{
counter = counter + constant * Math.Pow(0.8, i);
}
}
return counter;
}
public void Display(double clD)
{
totalTime = counter * clD / 3600;
hours = (int)(counter * clD / 3600);
minutes = (int)((totalTime - hours) * 3600 / 60);
seconds = (int)((totalTime - hours) * 3600 % 60);
}
}
I have no idea, what your code does and as #Steve already said your question misses some key infos. Nevertheless try changing your two methods Display and buttonCalculate_Click like this:
public string Display(double clD)
{
totalTime = counter * clD / 3600;
hours = (int)(counter * clD / 3600);
minutes = (int)((totalTime - hours) * 3600 / 60);
seconds = (int)((totalTime - hours) * 3600 % 60);
return "Hours: " + hours + ", Minutes: " + minutes + ", Seconds: " + seconds;
}
private void buttonCalculate_Click(object sender, EventArgs e)
{
double minSkill;
double maxSkill;
double coolDown;
minSkill = float.Parse(txtMinSkill.Text) * 10;
maxSkill = float.Parse(txtMaxSkill.Text) * 10;
coolDown = float.Parse(txtCooldown.Text);
SkillGainCalculator skill = new SkillGainCalculator();
skill.IntegerMax(maxSkill);
skill.RemainderMax(maxSkill);
skill.RemainderMin(minSkill);
skill.IntegerMin(minSkill);
skill.Calculate(minSkill, maxSkill);
resultLabel.Text = skill.Display(coolDown);
}
The method Display now generates the string you want to display and returns it when called so you can set resultLabel.Text from you calling method:

sum time from datetimepicker into textbox

in c# in a windows form I have five timepicker only time format.
The four values are written on 4 textbox.
I need in a fifth textbox or timepicker, to view the sum of hours of pprecedenti 4.
this code is wrong:
TimeSpan result = this.dateTimePicker22.Value + this.dateTimePicker23.Value + this.dateTimePicker24.Value + this.dateTimePicker25.Value + this.dateTimePicker26.Value);
this.textBox21.Text = result.ToString();
I calculate work hours so:
private void Calcolaweek1()
{
textBox23.MaxLength = 5;
DeleteChars();
if (textBox23.Text.Length == 2)
textBox23.Text += ":";
textBox23.SelectionStart = textBox23.Text.Length;
DateTime time = new DateTime();
this.textBox23.Text = time.ToString("HH:mm");
if ((textBox1.Text.Length > 0) && (textBox2.Text.Length > 0) && (textBox3.Text.Length > 0) && (textBox4.Text.Length > 0))
{
textBox23.MaxLength = 5;
TimeSpan result = this.dateTimePicker4.Value - this.dateTimePicker1.Value - (this.dateTimePicker3.Value - this.dateTimePicker2.Value);
this.textBox23.Text = result.ToString();
}
else if ((string.IsNullOrEmpty(textBox2.Text)) || (string.IsNullOrEmpty(textBox3.Text)))
{
TimeSpan result1 = this.dateTimePicker4.Value - this.dateTimePicker1.Value;
this.textBox23.Text = result1.ToString();
}
}
I must sum all work hours day
private void btnCalculate_Click(object sender, EventArgs e)
{
try
{
int hours = picker1.Value.Hour % 12 +
picker2.Value.Hour % 12 +
picker3.Value.Hour % 12 +
picker4.Value.Hour % 12 +
picker5.Value.Hour % 12;
int minutes = picker1.Value.Minute % 60 +
picker2.Value.Minute % 60 +
picker3.Value.Minute % 60 +
picker4.Value.Minute % 60 +
picker5.Value.Minute % 60;
TimeSpan fromMinutes = TimeSpan.FromMinutes(minutes);
var ts = hours + fromMinutes.Hours + ":" + fromMinutes.Minutes;
}
catch (Exception)
{
throw;
}
}

What is the exact Excel Days360 algorithm?

I'm porting some calculations from Excel to C# which use the Days360 function (the default/US method). Using the Wikipedia page as a guide, I came up with this code:
public static int Days360(DateTime a, DateTime b)
{
var dayA = a.Day;
var dayB = b.Day;
if (IsLastDayOfFebruary(a) && IsLastDayOfFebruary(b))
dayB = 30;
if (dayA == 31 || IsLastDayOfFebruary(a))
dayA = 30;
if (dayA == 30 && dayB == 31)
dayB = 30;
return ((b.Year - a.Year) * 12 + b.Month - a.Month) * 30 + dayB - dayA;
}
private static bool IsLastDayOfFebruary(DateTime date)
{
if (date.Month != 2)
return false;
int lastDay = DateTime.DaysInMonth(date.Year, 2);
return date.Day == lastDay;
}
I tested it with a (small) range of inputs and the results mostly agree with Excel's native function except if I use 2015-02-28 for both a and b. My code returns 0 and Excel -2.
My result seems more reasonable but at this point, I'd prefer to calculate the exact same result as Excel. There might be other inputs where they disagree so I don't want to make a special case just for that date.
Does anyone know the exact algorithm that Excel uses?
EDIT: There was a glaring bug in the original code I posted which is unrelated to the question. I had already fixed that one but I copied from the wrong file when posting the question.
According to this Wikipedia article the Microsoft Excel Days360 function is equivalent to 30/360 BMA/PSA. So to get exact results as MS Excel we need to implement the BMA/PSA method. I have implemented the method.
private double Days360(DateTime StartDate, DateTime EndDate)
{
int StartDay = StartDate.Day;
int StartMonth = StartDate.Month;
int StartYear = StartDate.Year;
int EndDay = EndDate.Day;
int EndMonth = EndDate.Month;
int EndYear = EndDate.Year;
if (StartDay == 31 || IsLastDayOfFebruary(StartDate))
{
StartDay = 30;
}
if (StartDay == 30 && EndDay == 31)
{
EndDay = 30;
}
return ((EndYear - StartYear) * 360) + ((EndMonth - StartMonth) * 30) + (EndDay - StartDay);
}
private bool IsLastDayOfFebruary(DateTime date)
{
return date.Month == 2 && date.Day == DateTime.DaysInMonth(date.Year, date.Month);
}
I had the same need, I found the solution in the function on line 51 of this phpexcel library
dateDiff360
this is part of the class code for the calculation
/**
* Identify if a year is a leap year or not
*
* #param integer $year The year to test
* #return boolean TRUE if the year is a leap year, otherwise FALSE
*/
public static function isLeapYear($year)
{
return ((($year % 4) == 0) && (($year % 100) != 0) || (($year % 400) == 0));
}
/**
* Return the number of days between two dates based on a 360 day calendar
*
* #param integer $startDay Day of month of the start date
* #param integer $startMonth Month of the start date
* #param integer $startYear Year of the start date
* #param integer $endDay Day of month of the start date
* #param integer $endMonth Month of the start date
* #param integer $endYear Year of the start date
* #param boolean $methodUS Whether to use the US method or the European method of calculation
* #return integer Number of days between the start date and the end date
*/
private static function dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, $methodUS)
{
if ($startDay == 31) {
--$startDay;
} elseif ($methodUS && ($startMonth == 2 && ($startDay == 29 || ($startDay == 28 && !self::isLeapYear($startYear))))) {
$startDay = 30;
}
if ($endDay == 31) {
if ($methodUS && $startDay != 30) {
$endDay = 1;
if ($endMonth == 12) {
++$endYear;
$endMonth = 1;
} else {
++$endMonth;
}
} else {
$endDay = 30;
}
}
return $endDay + $endMonth * 30 + $endYear * 360 - $startDay - $startMonth * 30 - $startYear * 360;
}
This algorithm also include the optional parameter method:
int startMonthDays = 0;
int endMonthDays = 0;
double diff = 0;
if(method.Equals("TRUE"))
{
if(dtStartDate.getDay() < 30)
{
startMonthDays = (30 - dtStartDate.getDay());
}
else
{
startMonthDays = 0;
}
if(dtEndDate.getDay() < 30)
{
endMonthDays = dtEndDate.getDay();
}
else
{
endMonthDays = 30;
}
diff = (dtEndDate.getYear() - dtStartDate.getYear())*360 +
(dtEndDate.getMonth() - dtStartDate.getMonth() - 1)*30 +
startMonthDays + endMonthDays;
}
else
{
if(DateCalendar.daysInMonth(dtStartDate.getYear(), dtStartDate.getMonth()) == dtStartDate.getDay())
{
startMonthDays = 0;
}
else
{
startMonthDays = (30 - dtStartDate.getDay());
}
if(DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) == dtEndDate.getDay())
{
if(dtStartDate.getDay() < DateCalendar.daysInMonth(dtStartDate.getYear(), dtStartDate.getMonth()) - 1)
{
if(DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) > 30)
{
endMonthDays = DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth());
}
else
{
endMonthDays = dtEndDate.getDay();
}
}
else
{
if(DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) > 30)
{
endMonthDays = DateCalendar.daysInMonth(dtEndDate.getYear(), dtEndDate.getMonth()) - 1;
}
else
{
endMonthDays = dtEndDate.getDay();
}
}
}
else
{
endMonthDays = dtEndDate.getDay();
}
diff = (dtEndDate.getYear() - dtStartDate.getYear())*360 +
(dtEndDate.getMonth() - dtStartDate.getMonth() - 1)*30 +
startMonthDays + endMonthDays;
}
with
public static int daysInMonth (int year, int month)
{
if (DateTime.IsLeapYear(year) && month == 2)
{
return 29;
}
else
{
return table[month - 1];
}
}
and
private static readonly int[] table = new int[]{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Test the next
public static int Days360(DateTime a, DateTime b)
{
var dayA = a.Day;
var dayB = b.Day;
if (IsLastDayOfMonth(a) && IsLastDayOfMonth(b)) {
dayB = Math.min(30, dayB);
} else if (dayA == 30 && dayB ==31) {
DayB = 30;
}
if (IsLastDayOfMonth(a))
dayA = 30;
return ((b.Year - a.Year) * 360 + b.Month - a.Month) * 30 + dayB - dayA;
}
private static bool IsLastDayOfMonth(DateTime date)
{
int lastDay = DateTime.DaysInMonth(date.Year, date.Month);
return date.Day == lastDay;
}

Categories

Resources