Calculate the hours in 2 different days excluding the sunday - c#

mydt1 = Convert.ToDateTime(dt.Rows[0].ItemArray[7].ToString());
DateTime dt2 = DateTime.Now;
var hours = (dt2 - mydt1).TotalHours;
if (hours >= 0) {
txtElapse.Text = hours.ToString("0");
var totals = hours * 2;
txtFine.Text = totals.ToString("0");
} else {
txtFine.Text = "0";
txtElapse.Text = "0";
}
I'm creating a library system, and I'm working on the fine. However, I want to exclude every Sunday that passes on the timespan. I don't know how could I do it or what logic I can use.

So you want to get difference (TimeSpan) between 2 DateTime, but ignoring Sunday.
Here is my minimum reproducible example:
using System;
public class Program
{
public static void Main(string[] args)
{
DateTime dt1 = Convert.ToDateTime(args[0]);
DateTime dt2 = Convert.ToDateTime(args[1]);
TimeSpan x = dt2-dt1;
double hours = x.TotalHours;
int numOfWeek = (int)Math.Floor(x.TotalDays/7);
hours = hours - (numOfWeek * 24);
// if difference is more than 1 week, then subtract hours with week difference
DayOfWeek dt1_dow = dt1.DayOfWeek; // System.DayOfWeek is enum, 0=Sunday, 1=Monday, etc
DayOfWeek dt2_dow = dt2.DayOfWeek; // System.DayOfWeek is enum, 0=Sunday, 1=Monday, etc
if( (int)dt1_dow > (int)dt2_dow )
{
hours = hours - 24;
}
// if dt1's day of week is higher than dt2's day of week, then we can be sure that it go over one Sunday
Console.WriteLine(numOfWeek);
Console.WriteLine(hours);
}
}
You can use https://dotnetfiddle.net/ or compile it yourself as console application (in visual studio) or save it as file.cs text file then compile with mono in linux with rm file.exe ; csc file.cs ; mono file.exe '2021-11-05 03:00:00' '2021-11-10 03:00:00'
Test:
$ cal
November 2021
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Test cases:
$ mono a.exe '2021-11-05 03:00:00' '2021-11-10 03:00:00'
0
96
date 5 to 10: pass sunday, not more than 1 week, resulting in 96 hours (correct, since it's 4 days not counting sunday)
$ mono a.exe '2021-11-03 03:00:00' '2021-11-05 03:00:00'
0
48
date 3 to 5: does not pass sunday, not more than 1 week, resulting in 48 hours (correct, since it's 2 days)
$ mono a.exe '2021-11-03 03:00:00' '2021-11-15 03:00:00'
1
240
date 3 to 15: does not pass sunday, more than 1 week, resulting in 240 hours (correct, since it's 10 days not counting sunday)
So in your code:
mydt1 = Convert.ToDateTime(dt.Rows[0].ItemArray[7].ToString());
DateTime dt2 = DateTime.Now;
var hours = (dt2 - mydt1).TotalHours;
// start adding code
int numOfWeek = (int)Math.Floor(x.TotalDays/7);
hours = hours - (numOfWeek * 24);
DayOfWeek dt1_dow = dt1.DayOfWeek;
DayOfWeek dt2_dow = dt2.DayOfWeek;
if( (int)dt1_dow > (int)dt2_dow )
{
hours = hours - 24;
}
// end adding code
if (hours >= 0) {
txtElapse.Text = hours.ToString("0");
var totals = hours * 2;
txtFine.Text = totals.ToString("0");
} else {
txtFine.Text = "0";
txtElapse.Text = "0";
}

Related

Amount of weeks between 2 iso8601 dates

How do you calculate the amount of weeks between 2 ISO8601 dates using only the week and year number?
Input:
year1
week1
year2
week2
Output:
Amount of weeks according to ISO8601
I can calculate the amount of weeks in a year:
public static int AmountOfWeeksInYearIso8601(this DateTime dateTime)
{
var year = dateTime.Year;
var g = Math.Floor((year - 100d) / 400d) - Math.Floor((year - 102d) / 400d);
var h = Math.Floor((year - 200d) / 400d) - Math.Floor((year - 199d) / 400d);
var f = 5 * year + 12 - 4 * (Math.Floor(year / 100d) - Math.Floor(year / 400d)) + g + h;
return f % 28 < 5 ? 53 : 52;
}
Create DateTime values corresponding to the Mondays of the two weeks. See Calculate date from week number for how to do this. Subtract these to get the difference as a TimeSpan. Request its Days property to get the difference as a number of days. Divide by 7 to get the difference as a number of weeks.

How many days to add for "semi-monthly"

I have a enum type called PaymentFrequency whose values indicate how many payments per year are being made...
So I have
public enum PaymentFrequency
{
None = 0,
Annually = 1,
SemiAnnually = 2,
EveryFourthMonth = 3,
Quarterly = 4,
BiMonthly = 6,
Monthly = 12,
EveryFourthWeek = 13,
SemiMonthly = 24,
BiWeekly = 26,
Weekly = 52
}
Based on NumberOfPayments, PaymentFrequency, and FirstPaymentDate (of type DateTimeOffset) I want to calculate LastPaymentDate. But I am having issue figuring out how many time units (days, months) to add in case of SemiMonthly...
switch (paymentFrequency)
{
// add years...
case PaymentFrequency.Annually:
LastPaymentDate = FirstPaymentDate.AddYears(NumberOfPayments - 1);
break;
// add months...
case PaymentFrequency.SemiAnnually:
LastPaymentDate = FirstPaymentDate.AddMonths((NumberOfPayments - 1) * 6); // 6 months
break;
case PaymentFrequency.EveryFourthMonth:
LastPaymentDate = FirstPaymentDate.AddMonths((NumberOfPayments - 1) * 4); // 4 months
break;
case PaymentFrequency.Quarterly:
LastPaymentDate = FirstPaymentDate.AddMonths((NumberOfPayments - 1) * 3); // 3 months
break;
case PaymentFrequency.BiMonthly:
LastPaymentDate = FirstPaymentDate.AddMonths((NumberOfPayments - 1) * 2); // 2 months
break;
case PaymentFrequency.Monthly:
LastPaymentDate = FirstPaymentDate.AddMonths(NumberOfPayments - 1);
break;
// add days...
case PaymentFrequency.EveryFourthWeek:
LastPaymentDate = FirstPaymentDate.AddDays((NumberOfPayments - 1) * 4 * 7); // 4 weeks (1 week = 7 days)
break;
case PaymentFrequency.SemiMonthly:
// NOTE: how many days in semi month? AddMonths (0.5) does not work :)
LastPaymentDate = FirstPaymentDate.AddMonths((NumberOfPayments - 1) * 0.5); // 2 weeks (1 week = 7 days)
break;
case PaymentFrequency.BiWeekly:
LastPaymentDate = FirstPaymentDate.AddDays((NumberOfPayments - 1) * 2 * 7); // 2 weeks (1 week = 7 days)
break;
case PaymentFrequency.Weekly:
LastPaymentDate = FirstPaymentDate.AddDays((NumberOfPayments - 1) * 7); // 1 week (1 week = 7 days)
break;
case PaymentFrequency.None:
default:
throw new ArgumentException("Payment frequency is not initialized to valid value!", "paymentFrequency");
}
So, how many days/months should I use when using SemiMonthly?
Is this even possible without knowing exact # of days for each month in between?
Or is this really simple, and I have just run out of caffeine and I am not seeing forest for the trees :)
For Semi-Monthly, if your first payment was always the 1st payment of the month as well (that is, anytime from the 1st to the 13th, starting after 13th is problematic as discussed in the comments), you could do as follows:
// assuming first payment will be 1st of month, add month for every 2 payments
// num payments / 2 (int division, remainder is chucked)
// then add 15 days if this is even payment of the month
LastPaymentDate = FirstPaymentDate.AddMonths((NumberOfPayments - 1) / 2)
.AddDays((NumberOfPayments % 2) == 0 ? 15 : 0);
So for the 1st payment, this will add 0 months and 0 days so be 1st payment date. For 2nd payment, this will add 0 months (int dividision, remainder is chucked) and 15 days for 16th of month. For 3rd payment, this will add 1 month (1 / 3) and 0 days for 1st of next month, etc.
This is assuming that the FirstPaymentDate will be on the 1st of some given month. You can probably see where to go from here if you want to allow the 16th to be a starting date, etc.
Make sense?
So to illustrate, if we had:
DateTime LastPaymentDate, FirstPaymentDate = new DateTime(2011, 12, 5);
for(int numOfPayments=1; numOfPayments<=24; numOfPayments++)
{
LastPaymentDate = FirstPaymentDate.AddMonths((numOfPayments - 1) / 2)
.AddDays((numOfPayments % 2) == 0 ? 15 : 0);
Console.WriteLine(LastPaymentDate);
}
This loop would give us:
12/5/2011 12:00:00 AM
12/20/2011 12:00:00 AM
1/5/2012 12:00:00 AM
// etc...
10/20/2012 12:00:00 AM
11/5/2012 12:00:00 AM
11/20/2012 12:00:00 AM
Because months have varying lengths, you can't just add a pre-defined number. You have to know which month you are dealing with, and go from there.
If you know that the 1st and the 16th of a month are due dates, then the last payment is December 16th (assuming you are calculating for a calendar year).
The basic pairs for semi monthly payments are:
1 and 16 (the 1st and 16th day of a month)
15 and (2|3)? (the 15th and the last day of the month)
Peek and choose
I've recently had the same issue, but I needed to allow any date input. It's a bit of a mess and needs to be refactored, but this is what I came up with so far. February had some problems that I had to hack.
Date returnDate;
if (numberOfPayments % 2 == 0)
{
returnDate = date.AddMonths(numberOfPayments / 2);
if (date.Day == DateTime.DaysInMonth(date.Year, date.Month))//Last day of the month adjustment
{
returnDate = new Date(returnDate.Year, returnDate.Month, DateTime.DaysInMonth(returnDate.Year, returnDate.Month));
}
}
else
{
returnDate = date.Day <= 15 ? date.AddDays(15).AddMonths((numberOfPayments - 1) / 2) : date.AddDays(-15).AddMonths((numberOfPayments + 1) / 2);
if (date.Day == DateTime.DaysInMonth(date.Year, date.Month))//Last day of the month adjustment
{
returnDate = new Date(returnDate.Year, returnDate.Month, 15);
}
else if (date.Month == 2 && date.Day == 14)
{
returnDate = returnDate.AddMonths(-1);
returnDate = new Date(returnDate.Year, returnDate.Month, returnDate.Month == 2 ? 28 : 29);
}
else if (date.Month == 2 && date.Day == 15)
{
returnDate = returnDate.AddMonths(-1);
returnDate = new Date(returnDate.Year, returnDateMonth, DateTime.DaysInMonth(returnDate.Year, returnDate.Month));
}
}
return returnDate;

Get correct time

I am getting the current time and trying to split it into two separate variables.
I want the time to be in 12 hours not 24
When i do this the first and second variable are the same. How can i fix this?
int hour = DateTime.Now.Hour % 12;
if (hour == 0) hour = 12;
then,
FirstDigitHour = hour / 10;
secondDigitHour = hour % 10;
the time here is 6 pm so FirstDigitHour & secondDigitHour both = 6
the first digit should equal 0
If you're trying to format the time for display, I would advise you use the proper format string:
DateTime.Now.ToString("hh tt")
Which is the time in 2-digit 12-hour format (hh) with AM/PM (tt)
See the documentation:
http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx
Wouldn't this satisfy your need better
var x = DateTime.Now.ToString("hh");
it returns a string with hours in 12 hour format ( e.g. "01" or "02" ... "11" "12" )
Then you can just get the first and second digit like so
int firstDigit = Convert.ToInt32(x[0].ToString());
int secondDigit = Convert.ToInt32(x[1].ToString());
Seems to work fine for me.
int hr = 18; // 6pm
int hour = hr % 12;
if (hour == 0)
hour = 12;
int fd = hour/10;
int ld = hour%10;
in this case I have fd = 0 and ld = 6.
See it run.
Check if there is a second digit first... if DateTime.Now.Hour > 10. Then you have it.

How to calculate actual months difference (calendar year not approximation) between two given dates in C#?

Example: given two dates below, finish is always greater than or equal to start
start = 2001 Jan 01
finish = 2002 Mar 15
So from 2001 Jan 01 to the end of 2002 Feb
months = 12 + 2 = 14
For 2002 March
15/30 = 0.5
so grand total is 14.5 months difference.
It's very easy to work out by hand but how do I code it elegantly? At the moment I have the combination of a lot of if else and while loops to achieve what I want but I believe there are simpler solutions out there.
Update: the output needs to be precise (not approximation) for example:
if start 2001 Jan 01 and finish 2001 Apr 16, the output should be 1 + 1 + 1= 3 (for Jan, Feb and Mar) and 16 / 31 = 0.516 month, so the total is 3.516.
Another example would be if I start on 2001 Jul 5 and finish on 2002 Jul 10, the output should be 11 month up to the end of June 2002, and (31-5)/31 = 0.839 and 10/31 = 0.323 months, so the total is 11 + 0.839 + 0.323 = 12.162.
I extended Josh Stodola's code and Hightechrider's code:
public static decimal GetMonthsInRange(this IDateRange thisDateRange)
{
var start = thisDateRange.Start;
var finish = thisDateRange.Finish;
var monthsApart = Math.Abs(12*(start.Year - finish.Year) + start.Month - finish.Month) - 1;
decimal daysInStartMonth = DateTime.DaysInMonth(start.Year, start.Month);
decimal daysInFinishMonth = DateTime.DaysInMonth(finish.Year, finish.Month);
var daysApartInStartMonth = (daysInStartMonth - start.Day + 1)/daysInStartMonth;
var daysApartInFinishMonth = finish.Day/daysInFinishMonth;
return monthsApart + daysApartInStartMonth + daysApartInFinishMonth;
}
I gave an int answer before, and then realized what you asked for a more precise answer. I was tired, so I deleted and went to bed. So much for that, I was unable to fall asleep! For some reason, this question really bugged me, and I had to solve it. So here you go...
static void Main(string[] args)
{
decimal diff;
diff = monthDifference(new DateTime(2001, 1, 1), new DateTime(2002, 3, 15));
Console.WriteLine(diff.ToString("n2")); //14.45
diff = monthDifference(new DateTime(2001, 1, 1), new DateTime(2001, 4, 16));
Console.WriteLine(diff.ToString("n2")); //3.50
diff = monthDifference(new DateTime(2001, 7, 5), new DateTime(2002, 7, 10));
Console.WriteLine(diff.ToString("n2")); //12.16
Console.Read();
}
static decimal monthDifference(DateTime d1, DateTime d2)
{
if (d1 > d2)
{
DateTime hold = d1;
d1 = d2;
d2 = hold;
}
int monthsApart = Math.Abs(12 * (d1.Year-d2.Year) + d1.Month - d2.Month) - 1;
decimal daysInMonth1 = DateTime.DaysInMonth(d1.Year, d1.Month);
decimal daysInMonth2 = DateTime.DaysInMonth(d2.Year, d2.Month);
decimal dayPercentage = ((daysInMonth1 - d1.Day) / daysInMonth1)
+ (d2.Day / daysInMonth2);
return monthsApart + dayPercentage;
}
Now I shall have sweet dreams. Goodnight :)
What you want is probably something close to this ... which pretty much follows your explanation as to how to calculate it:
var startofd1 = d1.AddDays(-d1.Day + 1);
var startOfNextMonthAfterd1 = startofd1.AddMonths(1); // back to start of month and then to next month
int daysInFirstMonth = (startOfNextMonthAfterd1 - startofd1).Days;
double fraction1 = (double)(daysInFirstMonth - (d1.Day - 1)) / daysInFirstMonth; // fractional part of first month remaining
var startofd2 = d2.AddDays(-d2.Day + 1);
var startOfNextMonthAfterd2 = startofd2.AddMonths(1); // back to start of month and then to next month
int daysInFinalMonth = (startOfNextMonthAfterd2 - startofd2).Days;
double fraction2 = (double)(d2.Day - 1) / daysInFinalMonth; // fractional part of last month
// now find whole months in between
int monthsInBetween = (startofd2.Year - startOfNextMonthAfterd1.Year) * 12 + (startofd2.Month - startOfNextMonthAfterd1.Month);
return monthsInBetween + fraction1 + fraction2;
NB This has not been tested very well but it shows how to handle problems like this by finding well known dates at the start of months around the problem values and then working off them.
While loops for date time calculations are always a bad idea: see http://www.zuneboards.com/forums/zune-news/38143-cause-zune-30-leapyear-problem-isolated.html
Depending on how exactly you want your logic to work, this would at least give you a decent approximation:
// 365 days per year + 1 day per leap year = 1461 days every 4 years
// But years divisible by 100 are not leap years
// So 1461 days every 4 years - 1 day per 100th year = 36524 days every 100 years
// 12 months per year = 1200 months every 100 years
const double DaysPerMonth = 36524.0 / 1200.0;
double GetMonthsDifference(DateTime start, DateTime finish)
{
double days = (finish - start).TotalDays;
return days / DaysPerMonth;
}
One way to do this is that you'll see around quite a bit is:
private static int monthDifference(DateTime startDate, DateTime endDate)
{
int monthsApart = 12 * (startDate.Year - endDate.Year) + startDate.Month - endDate.Month;
return Math.Abs(monthsApart);
}
However, you want "partial months" which this doesn't give. But what is the point in comparing apples (January/March/May/July/August/October/December) with oranges (April/June/September/November) or even bananas that are sometimes coconuts (February)?
An alternative is to import Microsoft.VisualBasic and do this:
DateTime FromDate;
DateTime ToDate;
FromDate = DateTime.Parse("2001 Jan 01");
ToDate = DateTime.Parse("2002 Mar 15");
string s = DateAndTime.DateDiff (DateInterval.Month, FromDate,ToDate, FirstDayOfWeek.System, FirstWeekOfYear.System ).ToString();
However again:
The return value for
DateInterval.Month is calculated
purely from the year and month parts
of the arguments
[Source]
Just improved Josh's answer
static decimal monthDifference(DateTime d1, DateTime d2)
{
if (d1 > d2)
{
DateTime hold = d1;
d1 = d2;
d2 = hold;
}
decimal monthsApart = Math.Abs((12 * (d1.Year - d2.Year)) + d2.Month - d1.Month - 1);
decimal daysinStartingMonth = DateTime.DaysInMonth(d1.Year, d1.Month);
monthsApart = monthsApart + (1-((d1.Day - 1) / daysinStartingMonth));
// Replace (d1.Day - 1) with d1.Day incase you DONT want to have both inclusive difference.
decimal daysinEndingMonth = DateTime.DaysInMonth(d2.Year, d2.Month);
monthsApart = monthsApart + (d2.Day / daysinEndingMonth);
return monthsApart;
}
The answer works perfectly and while the terseness of the code makes it very small I had to break everything apart into smaller functions with named variables so that I could really understand what was going on... So, basically I just took Josh Stodola's code and Hightechrider's mentioned in Jeff's comment and made it smaller with comments explaining what was going on and why the calculations were being made, and hopefully this may help someone else:
[Test]
public void Calculate_Total_Months_Difference_Between_Two_Dates()
{
var startDate = DateTime.Parse( "10/8/1996" );
var finishDate = DateTime.Parse( "9/8/2012" ); // this should be now:
int numberOfMonthsBetweenStartAndFinishYears = getNumberOfMonthsBetweenStartAndFinishYears( startDate, finishDate );
int absMonthsApartMinusOne = getAbsMonthsApartMinusOne( startDate, finishDate, numberOfMonthsBetweenStartAndFinishYears );
decimal daysLeftToCompleteStartMonthPercentage = getDaysLeftToCompleteInStartMonthPercentage( startDate );
decimal daysCompletedSoFarInFinishMonthPercentage = getDaysCompletedSoFarInFinishMonthPercentage( finishDate );
// .77 + .26 = 1.04
decimal totalDaysDifferenceInStartAndFinishMonthsPercentage = daysLeftToCompleteStartMonthPercentage + daysCompletedSoFarInFinishMonthPercentage;
// 13 + 1.04 = 14.04 months difference.
decimal totalMonthsDifference = absMonthsApartMinusOne + totalDaysDifferenceInStartAndFinishMonthsPercentage;
//return totalMonths;
}
private static int getNumberOfMonthsBetweenStartAndFinishYears( DateTime startDate, DateTime finishDate )
{
int yearsApart = startDate.Year - finishDate.Year;
const int INT_TotalMonthsInAYear = 12;
// 12 * -1 = -12
int numberOfMonthsBetweenYears = INT_TotalMonthsInAYear * yearsApart;
return numberOfMonthsBetweenYears;
}
private static int getAbsMonthsApartMinusOne( DateTime startDate, DateTime finishDate, int numberOfMonthsBetweenStartAndFinishYears )
{
// This may be negative i.e. 7 - 9 = -2
int numberOfMonthsBetweenStartAndFinishMonths = startDate.Month - finishDate.Month;
// Absolute Value Of Total Months In Years Plus The Simple Months Difference Which May Be Negative So We Use Abs Function
int absDiffInMonths = Math.Abs( numberOfMonthsBetweenStartAndFinishYears + numberOfMonthsBetweenStartAndFinishMonths );
// Subtract one here because we are going to use a perecentage difference based on the number of days left in the start month
// and adding together the number of days that we've made it so far in the finish month.
int absMonthsApartMinusOne = absDiffInMonths - 1;
return absMonthsApartMinusOne;
}
/// <summary>
/// For example for 7/8/2012 there are 24 days left in the month so about .77 percentage of month is left.
/// </summary>
private static decimal getDaysLeftToCompleteInStartMonthPercentage( DateTime startDate )
{
// startDate = "7/8/2012"
// 31
decimal daysInStartMonth = DateTime.DaysInMonth( startDate.Year, startDate.Month );
// 31 - 8 = 23
decimal totalDaysInStartMonthMinusStartDay = daysInStartMonth - startDate.Day;
// add one to mark the day as being completed. 23 + 1 = 24
decimal daysLeftInStartMonth = totalDaysInStartMonthMinusStartDay + 1;
// 24 / 31 = .77 days left to go in the month
decimal daysLeftToCompleteInStartMonthPercentage = daysLeftInStartMonth / daysInStartMonth;
return daysLeftToCompleteInStartMonthPercentage;
}
/// <summary>
/// For example if the finish date were 9/8/2012 we've completed 8 days so far or .24 percent of the month
/// </summary>
private static decimal getDaysCompletedSoFarInFinishMonthPercentage( DateTime finishDate )
{
// for septebmer = 30 days in month.
decimal daysInFinishMonth = DateTime.DaysInMonth( finishDate.Year, finishDate.Month );
// 8 days divided by 30 = .26 days completed so far in finish month.
decimal daysCompletedSoFarInFinishMonthPercentage = finishDate.Day / daysInFinishMonth;
return daysCompletedSoFarInFinishMonthPercentage;
}
This solution calculates whole months and then adds the partial month based on the end of the time period. This way it always calculates full months between the dates' day-of-month and then calculates the partial month based on the number of remaining days.
public decimal getMonthDiff(DateTime date1, DateTime date2) {
// Make parameters agnostic
var earlyDate = (date1 < date2 ? date1 : date2);
var laterDate = (date1 > date2 ? date1 : date2);
// Calculate the change in full months
decimal months = ((laterDate.Year - earlyDate.Year) * 12) + (laterDate.Month - earlyDate.Month) - 1;
// Add partial months based on the later date
if (earlyDate.Day <= laterDate.Day) {
decimal laterMonthDays = DateTime.DaysInMonth(laterDate.Year, laterDate.Month);
decimal laterPartialMonth = ((laterDate.Day - earlyDate.Day) / laterMonthDays);
months += laterPartialMonth + 1;
} else {
var laterLastMonth = laterDate.AddMonths(-1);
decimal laterLastMonthDays = DateTime.DaysInMonth(laterLastMonth.Year, laterLastMonth.Month);
decimal laterPartialMonth = ((laterLastMonthDays - earlyDate.Day + laterDate.Day) / laterLastMonthDays);
months += laterPartialMonth;
}
return months;
}
The calculation below is one that is according the way the Dutch Tax Authority wants months calculated. This means that when the starts day is for example feb 22, march 23 should be result in something above 1 and not just something like 0.98.
private decimal GetMonthDiffBetter(DateTime date1, DateTime date2)
{
DateTime start = date1 < date2 ? date1 : date2;
DateTime end = date1 < date2 ? date2 : date1;
int totalYearMonths = (end.Year - start.Year) * 12;
int restMonths = end.Month - start.Month;
int totalMonths = totalYearMonths + restMonths;
decimal monthPart = (decimal)end.Day / (decimal)start.Day;
return totalMonths - 1 + monthPart;
}`
This should get you where you need to go:
DateTime start = new DateTime(2001, 1, 1);
DateTime finish = new DateTime(2002, 3, 15);
double diff = (finish - start).TotalDays / 30;
the framework as a TimeSpan object that is a result of subtracting two dates.
the subtraction is already considering the various option of February(28/29 days a month) so in my opinion this is the best practice
after you got it you can format it the way you like best
DateTime dates1 = new DateTime(2010, 1, 1);
DateTime dates2 = new DateTime(2010, 3, 15);
var span = dates1.Subtract(dates2);
span.ToString("your format here");
private Double GetTotalMonths(DateTime future, DateTime past)
{
Double totalMonths = 0.0;
while ((future - past).TotalDays > 28 )
{
past = past.AddMonths(1);
totalMonths += 1;
}
var daysInCurrent = DateTime.DaysInMonth(future.Year, future.Month);
var remaining = future.Day - past.Day;
totalMonths += ((Double)remaining / (Double)daysInCurrent);
return totalMonths;
}

Refactor for Speed: Convert To a Date

I work for myself, I am a self-employed coder and as a result I don't have the luxury of code reviews or the ability to improve based upon peer programming. I am going to use this as an exercise to see if the StackOverflow community might help to review a simple method which i've written;
internal static DateTime CONVERT_To_DateTime(int binDate)
{
// 3/10/2008 = 1822556159
// 2/10/2008 = 1822523391
// 1/10/2008 = 1822490623
// 30/09/2008 = 1822392319
// 29/09/2008 = 1822359551
// September 30th 2008
// 1822392319 = 0x6c9f7fff
// 0x6c = 108 = 2008 (based on 1900 start date)
// 0x9 = 9 = September
// 0xf7fff - take top 5 bits = 0x1e = 30
// October 1st 2008
// 1822490623 = 0x6ca0ffff
// 0 x6c = 108 = 2008
// 0 xa = 10 = October
// 0x0ffff - take top 5 bits = 0x01 = 1
// OR using Binary (used by this function)
// a = 1822556159 (3/10/2008)
// 1101100 1010 00011 111111111111111
// b = 1822523391 (2/10/2008)
// 1101100 1010 00010 111111111111111
// c = 1822490623 (1/10/2008)
// 1101100 1010 00001 111111111111111
// D = 1822392319 (30/09/2008)
// 1101100 1001 11110 111111111111111
// Excess 111111 are probably used for time/seconds which
// we do not care for at the current time
var BaseYear = 1900;
// Dump the long date to binary
var strBinary = Convert.ToString(binDate);
// Calculate the year
var strBYear = strBinary.Substring(0, 7);
var iYear = Convert.ToInt32(strBYear, 2) + BaseYear;
// Calculate the month
var strBMonth = strBinary.Substring(7, 4);
var iMonth = Convert.ToInt32(strBMonth, 2);
// Calculate the day
var strBDay = strBinary.Substring(11, 5);
var iDay = Convert.ToInt32(strBDay, 2);
// ensure that month and day have two digits
var strDay = iDay < 10 ? "0" + iDay : iDay.ToString();
var strMonth = iMonth < 10 ? "0" + iMonth : iMonth.ToString();
// Build the final date
var convertedDate = iYear + strMonth + strDay;
return DateTime.ParseExact(convertedDate, "yyyyMMdd", null);
}
This is a method that takes a numeric representation of a date and converts it to a DateTime DataType. I would like the method to be reviewed to acheive the fastest possible execution time because it's being executed within a loop.
Any comments on the method is appreciated as this will be an exercise for me. i look forward to some responses.
Instead of converting to a string, then to integers, then to string, then to date, just get the integers by shifting and masking, and create the DateTime value directly from the integer values:
binDate >>= 15;
int day = binDate & 31;
binDate >>= 5;
int month = binDate & 15;
binDate >>= 8;
int year = binDate + 1900;
return new DateTime(year, month, day);
You're doing string manipulations. This is true performance killer when used in tight loops.
static DateTime ToDateTime(int value)
{
var year = (int)((value & 0xff000000) >> 24);
var month = (value & 0xf00000) >> 20;
var day = (value & (0xf8000)) >> 15;
return new DateTime(1900 + year, month, day);
}
Here's how you do that. First, take 1822490623 and convert it to binary:
0110 1100 1010 0000 1111 1111 1111 1111
This is a mask for year:
f f 0 0 0 0 0 0
This is for month:
0 0 f 0 0 0 0 0
And this is for day:
0 0 0 f 8 0 0 0
"Year" value has to be shifted right by 6 * 4 bits, "month" - by 5 * 4, and "day" - by 3 * 4 + 3 bits.
Welcome to the community, Phillis. :)
Anton is correct, your string manipulations are going to be slow. Because it looks like you're using the parameter as a bitfield, I'd suggest looking into the various (much faster) bit operators: <<, >>, &, |, and ~. It looks like you're trying to do binary manipulation, so use the operators built for it.
E.g. (untested, just off the cuff):
You start with a value of 0x6c9f7fff. The high order byte makes up the year. To mask out everything that isn't the year, do something like:
int year = ((binDate & 0xFF000000) >> 24) + BaseYear;
Likewise, the next 4 bits are the month, so:
int month = (binDate & 0x00F00000) >> 20;
int date = (binDate & 0x000F8000) >> 15;
return new DateTime(year, month, date);
I will suggest you to find the C/C++ code which does similar job; then port it into C#

Categories