Returning difference between dates with days and months

2

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

How can you perform a function in C # that returns the number of days and months from a date, for example: You have a start date 7/18/2017 and a dead date 8/29/2017

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

If in the case the interest is 0.33 a month, then one month would be charged the 0.33 of interest and the 11 days would add the 0.121. but for that would require 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 pick up every day and divide by 30, but not every month has 30 days. So what is the most correct way to do this?

 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?

       }
    }
    
asked by anonymous 19.07.2017 / 00:46

1 answer

2

After issues and better understanding of the problem, much of the answer is not for the solution, it's much simpler than it seemed

When you create the difference between two dates ( DateTime ) receives a time interval, that is, a TimeSpan . From there it is only divide by the number of days.

(int)(timespan.Days/30.436875)

If you want to get 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 you the expected result in all situations, but you would need to have clear criteria on how to handle each situation, which you do not have in the question.

If the question was more detailed I would like more.

Or you can use the NodaTime that has everything ready.

You also have a response in the OS where you create a type DateTimeSpan that computes 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 placed GitHub for future reference .

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

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

Does not the code return anything? I could have used variable names in lowercase, right?

Is not there a way to date be of another type? I know the error is already elsewhere, but would not it be the case to fix it?

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

What's the use of using TryParse() if not checking if the conversion worked? Can the data come wrong or is it a guaranteed source that has a valid date?

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

if (DataAtual > DateVencimento) {

This worries me a little, but in your routine should not cause a problem.

decimal ValorDaMulta = ValoraSerPago / 100 * Multa;

Better this way. I'm considering that multa is a percentage.

What you need to know is the number of days, not the number of months. The original question did not even make sense. Interest is daily, you have to multiply the number of days that are late.

Worse, this whole account is wrong, it should look 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 placed GitHub for future reference .

If you have to deal with the error, the method needs to be well changed to deal with it, I followed the line you do not need, but I can not state that.

    
19.07.2017 / 01:08