Returning difference between days and months

Asked

Viewed 9,941 times

3

I am developing a C# function that calculates the interest applied to a given account. for this it is necessary to know the correct difference between days and months.

How is it possible to execute a function in C# that returns the number of days and months between a date, for example: We have an initial date 18/07/2017 and a final date 29/08/2017

Then 08/29/2017 - 07/18/2017 Would result in a string "Month:1 and Days:11"

If in the case the interest is 0.33 per month, then 1 month would be charged the 0.33 interest and the 11 days would add the 0.121. but for this it would be necessary an application that would result correctly the days and months.

If I use Subtract It is only possible to return the number of days, so I could take every day and divide by 30, but not every month has 30 days. So what is the most correct way to perform this function?

 public CalcularValor(decimal ValorASerPago, string pDataVencimento, decimal Juros, decimal Multa){

     DateTime DateVencimento, DataAtual = DateTime.Now;
     DateTime.TryParse(pDataVencimento+" "+"23:59:59", out DateVencimento);   


     if (DataAtual > DateVencimento) { // Caso a conta esteja vencida é acrescentado os juros e multa

          decimal ValorDaMulta = (ValoraSerPago*Multa)/100;
          int TotalDia = (DataAtual.Subtract(DateVencimento)).Days; 
          // Como saber quantos meses e dias restam para aplicar o valor correta referente ao juros de acordo com o tempo de vencimento?

       }
    }

1 answer

4


After editing and better understanding of the problem most of the answer does not serve for the solution, it is much simpler than it seemed

When it creates the difference between two dates (DateTime) receives an interval of time, ie a TimeSpan. Then it’s just divided by the number of days.

(int)(timespan.Days/30.436875)

If you want to catch the remaining days just get the rest:

timespan.Days - ((int)(timespan.Days/30.436875) * 30.436875)

If you want years:

(int)(timespan.Days/365.2425)

This may not give the expected result in all situations, but it would need to have clear criteria of how to deal with each situation, which there is in the question.

If the question were more fancy I would do more fancy.

Or you can use the Nodatime who has everything ready.

Also has a response in the OS where it creates a type DateTimeSpan which calculates this according to the criteria adopted by that programmer.

public struct DateTimeSpan
{
    private readonly int years;
    private readonly int months;
    private readonly int days;
    private readonly int hours;
    private readonly int minutes;
    private readonly int seconds;
    private readonly int milliseconds;

    public DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
    {
        this.years = years;
        this.months = months;
        this.days = days;
        this.hours = hours;
        this.minutes = minutes;
        this.seconds = seconds;
        this.milliseconds = milliseconds;
    }

    public int Years { get { return years; } }
    public int Months { get { return months; } }
    public int Days { get { return days; } }
    public int Hours { get { return hours; } }
    public int Minutes { get { return minutes; } }
    public int Seconds { get { return seconds; } }
    public int Milliseconds { get { return milliseconds; } }

    enum Phase { Years, Months, Days, Done }

    public static DateTimeSpan CompareDates(DateTime date1, DateTime date2)
    {
        if (date2 < date1)
        {
            var sub = date1;
            date1 = date2;
            date2 = sub;
        }

        DateTime current = date1;
        int years = 0;
        int months = 0;
        int days = 0;

        Phase phase = Phase.Years;
        DateTimeSpan span = new DateTimeSpan();
        int officialDay = current.Day;

        while (phase != Phase.Done)
        {
            switch (phase)
            {
                case Phase.Years:
                    if (current.AddYears(years + 1) > date2)
                    {
                        phase = Phase.Months;
                        current = current.AddYears(years);
                    }
                    else
                    {
                        years++;
                    }
                    break;
                case Phase.Months:
                    if (current.AddMonths(months + 1) > date2)
                    {
                        phase = Phase.Days;
                        current = current.AddMonths(months);
                        if (current.Day < officialDay && officialDay <= DateTime.DaysInMonth(current.Year, current.Month))
                            current = current.AddDays(officialDay - current.Day);
                    }
                    else
                    {
                        months++;
                    }
                    break;
                case Phase.Days:
                    if (current.AddDays(days + 1) > date2)
                    {
                        current = current.AddDays(days);
                        var timespan = date2 - current;
                        span = new DateTimeSpan(years, months, days, timespan.Hours, timespan.Minutes, timespan.Seconds, timespan.Milliseconds);
                        phase = Phase.Done;
                    }
                    else
                    {
                        days++;
                    }
                    break;
            }
        }

        return span;
    }
}

I put in the Github for future reference.


With issues in question it became clear that the problem was another. Let’s analyze the code posted and improve it:

public CalcularValor(decimal ValorASerPago, string pDataVencimento, decimal Juros, decimal Multa){

The code does not return anything? Could have used the variable names in lower case, right?

There is no way this date is of another type? I know the mistake is already in another place, but it would not be the case to fix it?

DateTime.TryParse(pDataVencimento + " "+"23:59:59", out DateVencimento);

What’s the point of using the TryParse() Will not check if the conversion has worked? The data may be wrong or it is guaranteed source that has a valid date?

In C# 7 you can use DateTime.TryParse(pDataVencimento + " "+"23:59:59", out var DateVencimento); and need not even declare the variable before.

if (DataAtual > DateVencimento) {

It worries me a little, but in your routine should not cause trouble.

decimal ValorDaMulta = ValoraSerPago / 100 * Multa;

Better that way. I’m considering multa is a percentage.

What you need to know is the number of days and not the number of months. The original question didn’t even make sense. Interest is daily, you have to multiply the day number that is late.

Worse, this whole account is wrong, it should be something like this:

public decimal CalcularValorTotal(decimal valorAPagar, string dataVencimento, decimal juros, decimal multa) {
    var vencimento = DateTime.Parse(dataVencimento);
    var hoje = DateTime.Now;
    if (hoje > vencimento) {
        var valorMulta = valorAPagar / 100 * Multa;
        var valorJuros = (hoje.Date - vencimento.Date).Days * juros;
        return valorAPagar + valorMulta + valorJuros;
    }
    return valorAPagar;
}

I put in the Github for future reference.

If I have to fix the error, the method needs to be well changed to deal with it, I followed the line I don’t need, but I can’t claim that.

  • Because in function (int)(timespan.Days/30.436875) the value of 30 has the decimals? this method would return the correct result taking into account that not every month has 30 days?

  • Correct, depending on the criteria, because it linearizes the months, which is not quite true.

  • I made an issue in the question, is it clearer to you? With this method it would be possible to solve the problem in question?

  • Where’s your code? Where’s your specific problem? Putting in more irrelevant information doesn’t make it any clearer. The problem is clear, what you don’t have is details. So the answer has some details, but not as many as you could if you put in the details you’re doing. You just stuffed sausage. But this information shows that your problem is another completely different from what is in the question, this is not how you calculate interest. Even this problem of calculating interest that is another different question has no criteria for knowing the exact way to calculate it.

  • The start of the interest application is not a problem, but an exact way to return the correct date in months and days.

  • If you start from the wrong problem, the solution will be wrong.

  • So you can give me some tutorial or something related so I can solve this issue correctly

  • There is no such thing, perhaps it is the case to open another question, but you need to give details, show what you are doing. I improved the answer and this is the real solution.

Show 3 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.