Вычислить месяцы между, но отличными от всех других сообщений на этом сайте [дублировать]

Если вы не кодируете веб-приложение, убедитесь, что ваш класс, в котором выполняется @Autowiring, является весенним бобом. Как правило, весенний контейнер не будет знать о классе, который мы могли бы назвать весенним бобом. Мы должны рассказать весенний контейнер о наших весенних классах.

Этого можно достичь путем настройки в appln-contxt или лучший способ - аннотировать класс как @Component и, пожалуйста, не создавайте аннотированный класс, используя новый оператор. Убедитесь, что вы получили его из контекста Appln, как показано ниже.

@Component
public class MyDemo {


    @Autowired
    private MyService  myService; 

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
            System.out.println("test");
            ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
            System.out.println("ctx>>"+ctx);

            Customer c1=null;
            MyDemo myDemo=ctx.getBean(MyDemo.class);
            System.out.println(myDemo);
            myDemo.callService(ctx);


    }

    public void callService(ApplicationContext ctx) {
        // TODO Auto-generated method stub
        System.out.println("---callService---");
        System.out.println(myService);
        myService.callMydao();

    }

}
272
задан John Saunders 1 May 2011 в 23:24
поделиться

30 ответов

Предполагая, что день месяца не имеет значения (т.е. разница между 2011.1.1 и 2010.12.31 равна 1), с date1> date2, дающим положительное значение, а date2> date1 - отрицательное значение

((date1.Year - date2.Year) * 12) + date1.Month - date2.Month

Или, если вы хотите приблизительное количество «средних месяцев» между двумя датами, следующее должно работать для всех, но очень больших различий в дате.

date1.Subtract(date2).Days / (365.25 / 12)

Обратите внимание, что если вы должны использовать последнее решение, тогда ваши юнит-тесты должны указывать самый широкий диапазон дат, для которого ваше приложение разработано для работы и соответствующим образом оценивает результаты расчета.


Обновление (с помощью Gary )

Если использовать метод «средних месяцев», то для более «среднего числа дней в году» используется несколько более точный номер 365.2425 .

354
ответ дан Adam Ralph 21 August 2018 в 15:53
поделиться
  • 1
    @Kurru - 365/12 является приблизительной мерой средней длины месяца в днях. Это неточное измерение. Для небольших диапазонов дат эта погрешность может быть допущена, но для очень больших диапазонов дат эта погрешность может стать значительной. – Adam Ralph 9 January 2011 в 13:40
  • 2
    Я думаю, что необходимо учитывать компонент «День». Что-то вроде этого (date1.Year - date2.Year) * 12 + date1.Month - date2.Month + (date1.Day >= date2.Day ? 0 : -1) – DrunkCoder 22 November 2012 в 00:04
  • 3
    @DrunkCoder зависит от требований данной системы. В некоторых случаях ваше решение действительно может быть лучшим выбором. Например. важно учитывать, что происходит, когда две даты охватывают 31-дневный месяц, 30-дневный месяц, 28-дневный февраль или 29-й день февраля. Если результаты вашей формулы доставляют то, что требует система, то это, безусловно, правильный выбор. Если нет, то требуется другое. – Adam Ralph 23 November 2012 в 09:32
  • 4
    Во-вторых, что сказал Адам, я много лет писал код для актуариев. Некоторые вычисления были делятся на количество дней, округляются до 30, чтобы получить ежемесячную цифру . Иногда, считая месяцы, предполагается, что каждая дата начинается с первого числа месяца, считая целые месяцы соответственно . Нет метода best , когда дело доходит до расчета дат. Если вы не являетесь клиентом, на которого вы пишете код, подталкивайте его вверх по цепочке и выясните, может ли это быть вашим бухгалтером. – Binary Worrier 30 September 2013 в 08:53
  • 5
    365.2425 - это несколько более точное количество дней в григорианском календаре, если это то, что вы используете. Однако по DateTime.MaxValue (1 января 10000) разница составляет всего 59 дней. Кроме того, определение года может сильно отличаться в зависимости от вашей перспективы ru.wikipedia.org/wiki/Year . – Gary 22 September 2015 в 20:39

Вот гораздо более сжатое решение, использующее VB.Net DateDiff только для Year, Month, Day. Вы также можете загрузить библиотеку DateDiff в C #.

date1 должно быть & lt; = date2

VB.NET

Dim date1 = Now.AddDays(-2000)
Dim date2 = Now
Dim diffYears = DateDiff(DateInterval.Year, date1, date2) - If(date1.DayOfYear > date2.DayOfYear, 1, 0)
Dim diffMonths = DateDiff(DateInterval.Month, date1, date2) - diffYears * 12 - If(date1.Day > date2.Day, 1, 0)
Dim diffDays = If(date2.Day >= date1.Day, date2.Day - date1.Day, date2.Day + (Date.DaysInMonth(date1.Year, date1.Month) - date1.Day))

C #

DateTime date1 = Now.AddDays(-2000);
DateTime date2 = Now;
int diffYears = DateDiff(DateInterval.Year, date1, date2) - date1.DayOfYear > date2.DayOfYear ? 1 : 0;
int diffMonths = DateDiff(DateInterval.Month, date1, date2) - diffYears * 12 - date1.Day > date2.Day ? 1 : 0;
int diffDays = date2.Day >= date1.Day ? date2.Day - date1.Day : date2.Day + (System.DateTime.DaysInMonth(date1.Year, date1.Month) - date1.Day);
1
ответ дан Brent 21 August 2018 в 15:53
поделиться

Чтобы получить разницу в месяцах (включая начало и конец включительно), независимо от дат:

DateTime start = new DateTime(2013, 1, 1);
DateTime end = new DateTime(2014, 2, 1);
var diffMonths = (end.Month + end.Year * 12) - (start.Month + start.Year * 12);
9
ответ дан Chirag 21 August 2018 в 15:53
поделиться
  • 1
    Представьте, что start и end идентичны. Затем вы получаете результат 1. Как это правильно? Почему вы добавляете 1 к результату? Кто голосует за этот ответ: - /? – paul 18 December 2014 в 07:35
  • 2
    Для идентичных дат он будет давать результат как 1. В принципе, он будет считать все месяцы включительно начального и конечного месяцев. – Chirag 18 December 2014 в 12:29
  • 3
    не звучит как разница между двумя пунктами для меня. В чем разница между 2 и 2? Это действительно 1? Я бы предположил, что разница равна 0. – paul 18 December 2014 в 12:57

Использовать Noda Time :

LocalDate start = new LocalDate(2013, 1, 5);
LocalDate end = new LocalDate(2014, 6, 1);
Period period = Period.Between(start, end, PeriodUnits.Months);
Console.WriteLine(period.Months); // 16

(пример источника)

3
ответ дан Community 21 August 2018 в 15:53
поделиться

Я проверил использование этого метода в VB.NET через MSDN, и кажется, что он имеет много обычаев. В C # такого встроенного метода нет. (Даже это не очень хорошая идея), вы можете вызвать VB в C #.

  1. Добавить Microsoft.VisualBasic.dll в ваш проект в качестве ссылки
  2. использовать Microsoft.VisualBasic.DateAndTime.DateDiff в вашем коде
22
ответ дан Danny Chen 21 August 2018 в 15:53
поделиться
  • 1
    Почему вы думаете, что это не очень хорошая идея? Интуитивно я бы предположил, что библиотека является «просто другой библиотекой .NET» для среды выполнения. Заметьте, я играю здесь адвоката дьявола, я тоже был бы неспособен сделать это, потому что он просто «чувствует себя не так» (вроде обмана), но мне интересно, есть ли какая-то убедительная техническая причина не делать этого. – Adam Ralph 9 January 2011 в 13:33
  • 2
    @AdamRalph: Никакой причины вообще не делать этого. Эти библиотеки реализованы в 100% управляемом коде, так что это все равно, что и все остальное. Единственное возможное отличие заключается в том, что модуль Microsoft.VisualBasic.dll должен быть загружен, но время, необходимое для этого, незначительно. Нет никакой причины обманывать себя из тщательно проверенных и полезных функций только потому, что вы решили написать свою программу на C #. (Это касается таких вещей, как My.Application.SplashScreen.) – Cody Gray♦ 9 January 2011 в 13:43
  • 3
    Не могли бы вы передумать, если бы знали, что это написано на C #? Это было. По той же логике использование System.Data и PresentationFramework тоже обманывает значительную часть его, написанную на C ++ / CLI. – Hans Passant 9 January 2011 в 13:49
  • 4
    @AdamRalph: Любые конкретные примеры этого "странного багажа" что весной на ум? Или вы говорите это чисто гипотетически? И да, это может испортиться с умами некоторых ваших приятелей на C #, которые пишут эпическое количество кода, чтобы сделать что-то, что вы можете сделать в одной строке с правильным заявлением using, но я сомневаюсь, что будет какой-либо серьезный ущерб. – Cody Gray♦ 9 January 2011 в 14:21
  • 5
    @Cody Grey: согласен, пример тривиален, как вы проиллюстрируете. Это дополнительный «шум» кода, введенный при вызове такого необычного (из C # POV) метода, который я бы хотел избежать. В хорошо организованной команде такие вещи все равно будут подхвачены в обзоре кода и могут быть легко устранены. BTW - Я не пытаюсь атаковать VB6 / VB.NET. Я описал такие методы как «странные» только потому, что из .NET POV нет причин для существования DateAndTime.Year(), учитывая, что DateTime имеет свойство Year. Он существует только для того, чтобы сделать VB.NET более похожим на VB6. Будучи бывшим программистом VB6, я могу это оценить ;-) – Adam Ralph 10 January 2011 в 11:34

Если вы хотите точное количество полных месяцев, всегда положительный (2000-01-15, 2000-02-14 возвращает 0), учитывая полный месяц, когда вы достигнете того же дня в следующем месяце (что-то вроде возраста вычисление)

public static int GetMonthsBetween(DateTime from, DateTime to)
{
    if (from > to) return GetMonthsBetween(to, from);

    var monthDiff = Math.Abs((to.Year * 12 + (to.Month - 1)) - (from.Year * 12 + (from.Month - 1)));

    if (from.AddMonths(monthDiff) > to || to.Day < from.Day)
    {
        return monthDiff - 1;
    }
    else
    {
        return monthDiff;
    }
}

Исправление причины: старый код не был прав в некоторых случаях, например:

new { From = new DateTime(1900, 8, 31), To = new DateTime(1901, 8, 30), Result = 11 },

Test cases I used to test the function:

var tests = new[]
{
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 1, 1), Result = 0 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 1, 2), Result = 0 },
    new { From = new DateTime(1900, 1, 2), To = new DateTime(1900, 1, 1), Result = 0 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 2, 1), Result = 1 },
    new { From = new DateTime(1900, 2, 1), To = new DateTime(1900, 1, 1), Result = 1 },
    new { From = new DateTime(1900, 1, 31), To = new DateTime(1900, 2, 1), Result = 0 },
    new { From = new DateTime(1900, 8, 31), To = new DateTime(1900, 9, 30), Result = 0 },
    new { From = new DateTime(1900, 8, 31), To = new DateTime(1900, 10, 1), Result = 1 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1901, 1, 1), Result = 12 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1911, 1, 1), Result = 132 },
    new { From = new DateTime(1900, 8, 31), To = new DateTime(1901, 8, 30), Result = 11 },
};
29
ответ дан DisplayName 21 August 2018 в 15:53
поделиться
  • 1
    Чтобы избежать путаницы для других людей, я думаю, что это решение неверно. Используя тестовый пример: new { From = new DateTime(2015, 12, 31), To = new DateTime(2015, 6, 30), Result = 6 } тест завершится неудачно, так как результат равен 5. – Cristian Badila 16 December 2015 в 18:58
  • 2
    Добавил быстрый смысл с исправлением, предлагаю здесь – Cristian Badila 16 December 2015 в 19:57
  • 3
    Я не уверен, что получаю это, моя функция возвращает 6, как и должно: dotnetfiddle.net/MRZNnC – Guillaume86 17 December 2015 в 17:48
  • 4
    Я скопировал тестовый пример здесь, и он ошибся. Недопустимая спецификация должна быть: new { From = new DateTime(2015, 12, 31), To = new DateTime(2016, 06, 30), Result = 6 }. «Ошибка» лежит в коде to.Day < from.Day, который не учитывает, что месяцы могут заканчиваться в другом «день месяца». В этом случае с 31 декабря 2015 года до 30 июня 2016 года пройдут 6 полных месяцев (с июня 30 дней), но ваш код вернет 5. – Cristian Badila 18 December 2015 в 14:13
  • 5
    Ожидаемое поведение, на мой взгляд, хорошо, или это поведение, которое я, по крайней мере, ожидаю. Я задал полный месяц, когда вы достигнете того же дня (или в следующем месяце, как в этом случае). – Guillaume86 18 December 2015 в 16:32

На это не так много четких ответов, потому что вы всегда принимаете вещи.

Это решение вычисляет между двумя датами месяцев между предположением, что вы хотите сохранить день месяца для сравнения (что означает что день месяца учитывается в расчете)

Пример, если у вас есть дата 30 января 2012 года, 29 февраля 2012 года не будет месяца, а 01 марта 2013 года.

Он был протестирован довольно тщательно, возможно, его очистят позже, когда мы его используем, но здесь:

private static int TotalMonthDifference(DateTime dtThis, DateTime dtOther)
{
    int intReturn = 0;
    bool sameMonth = false;

    if (dtOther.Date < dtThis.Date) //used for an error catch in program, returns -1
        intReturn--;

    int dayOfMonth = dtThis.Day; //captures the month of day for when it adds a month and doesn't have that many days
    int daysinMonth = 0; //used to caputre how many days are in the month

    while (dtOther.Date > dtThis.Date) //while Other date is still under the other
    {
        dtThis = dtThis.AddMonths(1); //as we loop, we just keep adding a month for testing
        daysinMonth = DateTime.DaysInMonth(dtThis.Year, dtThis.Month); //grabs the days in the current tested month

        if (dtThis.Day != dayOfMonth) //Example 30 Jan 2013 will go to 28 Feb when a month is added, so when it goes to march it will be 28th and not 30th
        {
            if (daysinMonth < dayOfMonth) // uses day in month max if can't set back to day of month
                dtThis.AddDays(daysinMonth - dtThis.Day);
            else
                dtThis.AddDays(dayOfMonth - dtThis.Day);
        }
        if (((dtOther.Year == dtThis.Year) && (dtOther.Month == dtThis.Month))) //If the loop puts it in the same month and year
        {
            if (dtOther.Day >= dayOfMonth) //check to see if it is the same day or later to add one to month
                intReturn++;
            sameMonth = true; //sets this to cancel out of the normal counting of month
        }
        if ((!sameMonth)&&(dtOther.Date > dtThis.Date))//so as long as it didn't reach the same month (or if i started in the same month, one month ahead, add a month)
            intReturn++;
    }
    return intReturn; //return month
}
6
ответ дан Drakonoved 21 August 2018 в 15:53
поделиться
  • 1
    Пожалуйста, ответьте на английском языке (по сравнению с любым изобретенным языком ...) – kleopatra 30 September 2013 в 08:36
  • 2
    Почему бы просто не запустить startDate.AddMonths (monthCount) .ToShortDateString ()? Это не отвечает на исходный вопрос, который был задан в любом случае! – TabbyCool 15 April 2014 в 16:44
  • 3
    о, извините @TabbyCool, этот код хорошо работает в моей программе! программисты правило говорит: первый код работает, а затем оптимизация! tanx для урского комментария :) – reza akhlaghi 19 April 2014 в 06:29
Public Class ClassDateOperation
    Private prop_DifferenceInDay As Integer
    Private prop_DifferenceInMonth As Integer
    Private prop_DifferenceInYear As Integer


    Public Function DayMonthYearFromTwoDate(ByVal DateStart As Date, ByVal DateEnd As Date) As ClassDateOperation
        Dim differenceInDay As Integer
        Dim differenceInMonth As Integer
        Dim differenceInYear As Integer
        Dim myDate As Date

        DateEnd = DateEnd.AddDays(1)

        differenceInYear = DateEnd.Year - DateStart.Year

        If DateStart.Month <= DateEnd.Month Then
            differenceInMonth = DateEnd.Month - DateStart.Month
        Else
            differenceInYear -= 1
            differenceInMonth = (12 - DateStart.Month) + DateEnd.Month
        End If


        If DateStart.Day <= DateEnd.Day Then
            differenceInDay = DateEnd.Day - DateStart.Day
        Else

            myDate = CDate("01/" & DateStart.AddMonths(1).Month & "/" & DateStart.Year).AddDays(-1)
            If differenceInMonth <> 0 Then
                differenceInMonth -= 1
            Else
                differenceInMonth = 11
                differenceInYear -= 1
            End If

            differenceInDay = myDate.Day - DateStart.Day + DateEnd.Day

        End If

        prop_DifferenceInDay = differenceInDay
        prop_DifferenceInMonth = differenceInMonth
        prop_DifferenceInYear = differenceInYear

        Return Me
    End Function

    Public ReadOnly Property DifferenceInDay() As Integer
        Get
            Return prop_DifferenceInDay
        End Get
    End Property

    Public ReadOnly Property DifferenceInMonth As Integer
        Get
            Return prop_DifferenceInMonth
        End Get
    End Property

    Public ReadOnly Property DifferenceInYear As Integer
        Get
            Return prop_DifferenceInYear
        End Get
    End Property

End Class
1
ответ дан Edwin de Koning 21 August 2018 в 15:53
поделиться

У вас может быть такая функция.

Например, с 2012/12/27 по 2012/12/29 становится 3 дня. Аналогично, с 2012/12/15 до 2013/01/15 становится 2 месяца, потому что до 2013/01/14 это 1 месяц. с 15-го года начался второй месяц.

Вы можете удалить «=» во втором условии if, если вы не хотите включать оба дня в расчет. то есть с 2012/12/15 до 2013/01/15 составляет 1 месяц.

public int GetMonths(DateTime startDate, DateTime endDate)
{
    if (startDate > endDate)
    {
        throw new Exception("Start Date is greater than the End Date");
    }

    int months = ((endDate.Year * 12) + endDate.Month) - ((startDate.Year * 12) + startDate.Month);

    if (endDate.Day >= startDate.Day)
    {
        months++;
    }

    return months;
}
1
ответ дан Firnas 21 August 2018 в 15:53
поделиться

Расширенная структура Kirks с ToString (формат) и Duration (long ms)

 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 string ToString(string format)
    {
        format = format.Replace("YYYY", Years.ToString());
        format = format.Replace("MM", Months.ToString());
        format = format.Replace("DD", Days.ToString());
        format = format.Replace("hh", Hours.ToString());
        format = format.Replace("mm", Minutes.ToString());
        format = format.Replace("ss", Seconds.ToString());
        format = format.Replace("ms", Milliseconds.ToString());
        return format;
    }


    public static DateTimeSpan Duration(long ms)
    {
        DateTime dt = new DateTime();
        return CompareDates(dt, dt.AddMilliseconds(ms));
    }


    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();

        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);
                    }
                    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;
    }
}
0
ответ дан Ivan 21 August 2018 в 15:53
поделиться

Это ответ на ответ Кирка Волла. У меня недостаточно очков репутации, чтобы ответить на комментарий еще ...

Мне понравилось решение Кирка, и он собирался бесстыдно разорвать его и использовать в моем коде, но когда я просмотрел его, я понял, что это слишком сложно. Ненужное переключение и цикл, а также открытый конструктор, который бессмысленно использовать.

Вот мой переписывающий:

public class DateTimeSpan {
    private DateTime _date1;
    private DateTime _date2;
    private int _years;
    private int _months;
    private int _days;
    private int _hours;
    private int _minutes;
    private int _seconds;
    private int _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; } }

    public DateTimeSpan(DateTime date1, DateTime date2) {
        _date1 = (date1 > date2) ? date1 : date2;
        _date2 = (date2 < date1) ? date2 : date1;

        _years = _date1.Year - _date2.Year;
        _months = (_years * 12) + _date1.Month - _date2.Month;
        TimeSpan t = (_date2 - _date1);
        _days = t.Days;
        _hours = t.Hours;
        _minutes = t.Minutes;
        _seconds = t.Seconds;
        _milliseconds = t.Milliseconds;

    }

    public static DateTimeSpan CompareDates(DateTime date1, DateTime date2) {
        return new DateTimeSpan(date1, date2);
    }
}

Usage1, почти то же самое:

void Main()
{
    DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
    DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
    var dateSpan = new DateTimeSpan(compareTo, now);
    Console.WriteLine("Years: " + dateSpan.Years);
    Console.WriteLine("Months: " + dateSpan.Months);
    Console.WriteLine("Days: " + dateSpan.Days);
    Console.WriteLine("Hours: " + dateSpan.Hours);
    Console.WriteLine("Minutes: " + dateSpan.Minutes);
    Console.WriteLine("Seconds: " + dateSpan.Seconds);
    Console.WriteLine("Milliseconds: " + dateSpan.Milliseconds);
}

Usage2, похоже:

void Main()
{
    DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
    DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
    Console.WriteLine("Years: " + DateTimeSpan.CompareDates(compareTo, now).Years);
    Console.WriteLine("Months: " + DateTimeSpan.CompareDates(compareTo, now).Months);
    Console.WriteLine("Days: " + DateTimeSpan.CompareDates(compareTo, now).Days);
    Console.WriteLine("Hours: " + DateTimeSpan.CompareDates(compareTo, now).Hours);
    Console.WriteLine("Minutes: " + DateTimeSpan.CompareDates(compareTo, now).Minutes);
    Console.WriteLine("Seconds: " + DateTimeSpan.CompareDates(compareTo, now).Seconds);
    Console.WriteLine("Milliseconds: " + DateTimeSpan.CompareDates(compareTo, now).Milliseconds);
}
1
ответ дан John A 21 August 2018 в 15:53
поделиться

Вот комплексное решение для возврата DateTimeSpan, похожего на TimeSpan, за исключением того, что оно включает в себя все компоненты даты в дополнение к компонентам времени.

Использование:

void Main()
{
    DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
    DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
    var dateSpan = DateTimeSpan.CompareDates(compareTo, now);
    Console.WriteLine("Years: " + dateSpan.Years);
    Console.WriteLine("Months: " + dateSpan.Months);
    Console.WriteLine("Days: " + dateSpan.Days);
    Console.WriteLine("Hours: " + dateSpan.Hours);
    Console.WriteLine("Minutes: " + dateSpan.Minutes);
    Console.WriteLine("Seconds: " + dateSpan.Seconds);
    Console.WriteLine("Milliseconds: " + dateSpan.Milliseconds);
}

Выходы:

Years: 1 Months: 5 Days: 27 Hours: 1 Minutes: 36 Seconds: 50 Milliseconds: 0

Для удобства я включил логику в структуру DateTimeSpan, но вы можете перемещать метод CompareDates, где бы вы ни находились. Также обратите внимание: не имеет значения, какая дата предшествует другой.

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;
    }
}
191
ответ дан Kirk Woll 21 August 2018 в 15:53
поделиться
  • 1
    @KirkWoll спасибо. Но почему DateTimeSpan возвращает 34 дней для этой разницы во времени даты на самом деле это 35 timeanddate.com/date/… – Deeptechtons 26 November 2012 в 05:36
  • 2
    @Deeptechtons, хороший улов. Было несколько вопросов, которые вы мне доводили, причем оба вопроса относятся к дате начала 31, а дата «проходит через», месяцев с меньшим количеством дней. Я перевернул логику (так, что она идет от раннего к более позднему, чем наоборот), и теперь накапливает месяцы, не изменяя текущую дату (и, таким образом, проходя через промежуточные месяцы с меньшим количеством дней). Все еще не совсем уверен, какой идеальный результат должно быть при сравнении 10/31/2012 с 11/30/2012. Сейчас результат - 1 месяц. – Kirk Woll 26 November 2012 в 16:09
  • 3
    @KirkWoll благодарит за обновление, может быть, я получил еще несколько gotchas, позвольте мне подтвердить его после некоторых тестов Good Job :) – Deeptechtons 27 November 2012 в 06:16
  • 4
    Я написал ответ stackoverflow.com/a/17537472/1737957 на аналогичный вопрос, который опробовал предлагаемые ответы (и обнаружил, что большинство из них не работают). Этот ответ является одним из немногих, кто работает (согласно моему набору тестов). Ссылка на github на мой ответ. – jwg 21 August 2013 в 10:51
  • 5
    @KirkWoll - этот ответ, похоже, не работает для краевых случаев, когда дата от даты имеет значение дня, превышающее месяц даты, или дата источника - это високосный день. Попробуйте 2020-02-29 - 2021-06-29 - он возвращает «1y 4m 1d», но значение должно быть «1y 4m 0d», правильно? – Enigmativity 3 June 2015 в 09:29

Вот как мы подходим к этому:

public static int MonthDiff(DateTime date1, DateTime date2)
{
    if (date1.Month < date2.Month)
    {
        return (date2.Year - date1.Year) * 12 + date2.Month - date1.Month;
    }
    else
    {
        return (date2.Year - date1.Year - 1) * 12 + date2.Month - date1.Month + 12;
    }
}
0
ответ дан Konstantin Chernov 21 August 2018 в 15:53
поделиться

Это из моей собственной библиотеки, вернет разницу между месяцами между двумя датами.

public static int MonthDiff(DateTime d1, DateTime d2)
{
    int retVal = 0;

    // Calculate the number of years represented and multiply by 12
    // Substract the month number from the total
    // Substract the difference of the second month and 12 from the total
    retVal = (d1.Year - d2.Year) * 12;
    retVal = retVal - d1.Month;
    retVal = retVal - (12 - d2.Month);

    return retVal;
}
1
ответ дан Matthias 21 August 2018 в 15:53
поделиться
  • 1
    Это работает? Я продолжаю получать 11 на бумаге для Jan-31-2014 и Dec-31-2013 – Dave Cousineau 17 August 2014 в 03:31

Вы можете сделать

if ( date1.AddMonths(x) > date2 )
25
ответ дан Mongus Pong 21 August 2018 в 15:53
поделиться
  • 1
    Это так просто и идеально подходит для меня. Я был приятно удивлен тем, что он работает по назначению при расчете даты с конца 1 месяца до даты в конце следующего месяца с меньшим количеством дней. Например .. 1-31-2018 + 1 месяц = ​​28 февраля 218 – lucky.expert 26 February 2018 в 16:05
  • 2
    Это одно из лучших решений. – barnacle.m 22 May 2018 в 12:39

Вот мой вклад, чтобы получить разницу в месяцах, которые, как я считаю, точны:

namespace System
{
     public static class DateTimeExtensions
     {
         public static Int32 DiffMonths( this DateTime start, DateTime end )
         {
             Int32 months = 0;
             DateTime tmp = start;

             while ( tmp < end )
             {
                 months++;
                 tmp = tmp.AddMonths( 1 );
             }

             return months;
        }
    }
}

Использование:

Int32 months = DateTime.Now.DiffMonths( DateTime.Now.AddYears( 5 ) );

Вы можете создать другой метод под названием DiffYears и применять точно такую ​​же логику, как указано выше, и AddYears вместо AddMonths в цикле while.

1
ответ дан Morgs 21 August 2018 в 15:53
поделиться
  var dt1 = (DateTime.Now.Year * 12) + DateTime.Now.Month;
  var dt2 = (DateTime.Now.AddMonths(-13).Year * 12) + DateTime.Now.AddMonths(-13).Month;
  Console.WriteLine(dt1);
  Console.WriteLine(dt2);
  Console.WriteLine((dt1 - dt2));
0
ответ дан Ryan Bennett 21 August 2018 в 15:53
поделиться

Вот простое решение, которое работает хотя бы для меня. Скорее всего, это не самый быстрый результат, потому что он использует замечательную функцию AddMonth DateTime в цикле:

public static int GetMonthsDiff(DateTime start, DateTime end)
{
    if (start > end)
        return GetMonthsDiff(end, start);

    int months = 0;
    do
    {
        start = start.AddMonths(1);
        if (start > end)
            return months;

        months++;
    }
    while (true);
}
2
ответ дан Simon Mourier 21 August 2018 в 15:53
поделиться
int nMonths = 0;
if (FDate.ToDateTime().Year == TDate.ToDateTime().Year)
     nMonths = TDate.ToDateTime().Month - FDate.ToDateTime().Month;                         
else
nMonths = (12 - FDate.Month) + TDate.Month;                          
0
ответ дан Thewads 21 August 2018 в 15:53
поделиться

Чтобы иметь возможность рассчитать разницу между двумя датами в месяцах, это совершенно логично, и это необходимо во многих бизнес-приложениях. Несколько кодеров, которые предоставили комментарии, такие как: какая разница в месяцах между «май 1,2010» и «16 июня 2010 года, какая разница в месяцах между 31 декабря 2010 года и 1 января 2011 года?», Не поняли самые основные бизнес-приложения.

Вот ответ на вышеупомянутые 2 комментария. Число месяцев между 1-м-май-2010 и 16-июн-2010 составляет 1 месяц, количество месяцев между 31 -dec-2010 и 1-jan-2011 - 0. Было бы очень глупо расчитывать их как 1,5 месяца и 1 секунду, как предлагали вышеперечисленные кодеры.

Люди, которые работали на кредитной карте, (g2)

Проблема в том, что такая функция не включена в C # или VB.NET, если на то пошло. Datediff учитывает только годы или компонент месяца, поэтому на самом деле бесполезно.

Вот некоторые реальные примеры того, где вам нужно и правильно может рассчитать месяцы:

Вы живете в краткосрочной прокате с 18 до 24 лет. Сколько месяцев вы там? Ответ прост - 6 месяцев

У вас есть счет в банке, где проценты рассчитываются и выплачиваются в конце каждого месяца. Вы депонируете деньги на 10-юн и выведете 29-окт (в том же году). Сколько месяцев вы интересуетесь? Очень простой ответ - 4 месяца (опять же, дополнительные дни не имеют значения)

В бизнес-приложениях, в большинстве случаев, когда вам нужно рассчитать месяцы, это потому, что вам нужно знать «полные» месяцы о том, как люди вычисляют время; не основанные на некоторых абстрактных / нерелевантных мыслях.

0
ответ дан Tom 21 August 2018 в 15:53
поделиться
  • 1
    Это одна из причин, почему бухгалтерский учет не является математикой. В бухгалтерском учете результат зависит от того, как вы его вычисляете. Я знаю ваши точки, и я знаю «общий вид бизнеса». на этом, но это объяснение явно неверно. Между 2012.11.30 и 2012.12.01 есть 0, или 1/30, или 1/31, или 1 или 2 месяца, в зависимости от того, что вы просили . Были ли даты эксклюзивными или включительно? Вы просили количество месяцев, скрещенных, тронутых или прошедших? Вы хотите округлить, округлить или точно? – quetzalcoatl 25 April 2013 в 16:18
  • 2
    Теперь объясните это деловому парню или бухгалтеру, и они вас озадачат. Для них всегда так очевидно, что они, конечно, означают X и Y и Z, как вы могли думать по-другому? & Quot; Теперь получите несколько бизнес-людей и попытайтесь заставить их согласиться на эту тему. Бухгалтеры с большей вероятностью согласятся, потому что в какой-то момент они будут использовать математику, чтобы проверить, с какими вариантами они могут случайно суммировать один и тот же период два раза и т. Д. Даже ваши примеры расчетов являются спорными и зависящими от региона или явно недействительными, поскольку они предполагают дополнительные бизнес-правила, такие как игнорирование дополнительных дней. – quetzalcoatl 25 April 2013 в 16:25
  • 3
    -1 Вы предполагаете, что все программное обеспечение является «бизнес-приложением». Цель данного кода не упоминается. Вы также принимаете все «бизнес-приложения», имеют те же правила, что определенно неверно. – Jesse Webb 29 March 2014 в 00:32

Вы можете использовать класс DateDiff библиотеки времени для .NET :

// ----------------------------------------------------------------------
public void DateDiffSample()
{
  DateTime date1 = new DateTime( 2009, 11, 8, 7, 13, 59 );
  DateTime date2 = new DateTime( 2011, 3, 20, 19, 55, 28 );
  DateDiff dateDiff = new DateDiff( date1, date2 );

  // differences
  Console.WriteLine( "DateDiff.Months: {0}", dateDiff.Months );
  // > DateDiff.Months: 16

  // elapsed
  Console.WriteLine( "DateDiff.ElapsedMonths: {0}", dateDiff.ElapsedMonths );
  // > DateDiff.ElapsedMonths: 4

  // description
  Console.WriteLine( "DateDiff.GetDescription(6): {0}", dateDiff.GetDescription( 6 ) );
  // > DateDiff.GetDescription(6): 1 Year 4 Months 12 Days 12 Hours 41 Mins 29 Secs
} // DateDiffSample
4
ответ дан user 21 August 2018 в 15:53
поделиться

вы можете использовать следующее расширение: Код

public static class Ext
{
    #region Public Methods

    public static int GetAge(this DateTime @this)
    {
        var today = DateTime.Today;
        return ((((today.Year - @this.Year) * 100) + (today.Month - @this.Month)) * 100 + today.Day - @this.Day) / 10000;
    }

    public static int DiffMonths(this DateTime @from, DateTime @to)
    {
        return (((((@to.Year - @from.Year) * 12) + (@to.Month - @from.Month)) * 100 + @to.Day - @from.Day) / 100);
    }

    public static int DiffYears(this DateTime @from, DateTime @to)
    {
        return ((((@to.Year - @from.Year) * 100) + (@to.Month - @from.Month)) * 100 + @to.Day - @from.Day) / 10000;
    }

    #endregion Public Methods
}

Реализация!

int Age;
int years;
int Months;
//Replace your own date
var d1 = new DateTime(2000, 10, 22);
var d2 = new DateTime(2003, 10, 20);
//Age
Age = d1.GetAge();
Age = d2.GetAge();
//positive
years = d1.DiffYears(d2);
Months = d1.DiffMonths(d2);
//negative
years = d2.DiffYears(d1);
Months = d2.DiffMonths(d1);
//Or
Months = Ext.DiffMonths(d1, d2);
years = Ext.DiffYears(d1, d2); 
1
ответ дан Waleed A.K. 21 August 2018 в 15:53
поделиться

Мое понимание общей разницы месяцев между двумя датами имеет интегральную и дробную часть (дата имеет значение).

Неотъемлемая часть - разница в полных месяцах.

дробная часть для меня - это разница в% дня (до полных дней месяца) между началом и окончанием месяца.

public static class DateTimeExtensions
{
    public static double TotalMonthsDifference(this DateTime from, DateTime to)
    {
        //Compute full months difference between dates
        var fullMonthsDiff = (to.Year - from.Year)*12 + to.Month - from.Month;

        //Compute difference between the % of day to full days of each month
        var fractionMonthsDiff = ((double)(to.Day-1) / (DateTime.DaysInMonth(to.Year, to.Month)-1)) -
            ((double)(from.Day-1)/ (DateTime.DaysInMonth(from.Year, from.Month)-1));

        return fullMonthsDiff + fractionMonthsDiff;
    }
}

С помощью этого расширения это результаты:

2/29/2000 TotalMonthsDifference 2/28/2001 => 12
2/28/2000 TotalMonthsDifference 2/28/2001 => 12.035714285714286
01/01/2000 TotalMonthsDifference 01/16/2000 => 0.5
01/31/2000 TotalMonthsDifference 01/01/2000 => -1.0
01/31/2000 TotalMonthsDifference 02/29/2000 => 1.0
01/31/2000 TotalMonthsDifference 02/28/2000 => 0.9642857142857143
01/31/2001 TotalMonthsDifference 02/28/2001 => 1.0
6
ответ дан Drakonoved 21 August 2018 в 15:53
поделиться
  • 1
    Пожалуйста, ответьте на английском языке (по сравнению с любым изобретенным языком ...) – kleopatra 30 September 2013 в 08:36
  • 2
    Почему бы просто не запустить startDate.AddMonths (monthCount) .ToShortDateString ()? Это не отвечает на исходный вопрос, который был задан в любом случае! – TabbyCool 15 April 2014 в 16:44
  • 3
    о, извините @TabbyCool, этот код хорошо работает в моей программе! программисты правило говорит: первый код работает, а затем оптимизация! tanx для урского комментария :) – reza akhlaghi 19 April 2014 в 06:29

Я написал функцию, чтобы выполнить это, потому что другие способы не работали для меня.

public string getEndDate (DateTime startDate,decimal monthCount)
{
    int y = startDate.Year;
    int m = startDate.Month;

    for (decimal  i = monthCount; i > 1; i--)
    {
        m++;
        if (m == 12)
        { y++;
            m = 1;
        }
    }
    return string.Format("{0}-{1}-{2}", y.ToString(), m.ToString(), startDate.Day.ToString());
}
6
ответ дан Drakonoved 21 August 2018 в 15:53
поделиться
  • 1
    Пожалуйста, ответьте на английском языке (по сравнению с любым изобретенным языком ...) – kleopatra 30 September 2013 в 08:36
  • 2
    Почему бы просто не запустить startDate.AddMonths (monthCount) .ToShortDateString ()? Это не отвечает на исходный вопрос, который был задан в любом случае! – TabbyCool 15 April 2014 в 16:44
  • 3
    о, извините @TabbyCool, этот код хорошо работает в моей программе! программисты правило говорит: первый код работает, а затем оптимизация! tanx для урского комментария :) – reza akhlaghi 19 April 2014 в 06:29

Есть 3 случая: в том же году, в предыдущем году и в другие годы.

Если день месяца не имеет значения ...

public int GetTotalNumberOfMonths(DateTime start, DateTime end)
{
    // work with dates in the right order
    if (start > end)
    {
        var swapper = start;
        start = end;
        end = swapper;
    }

    switch (end.Year - start.Year)
    {
        case 0: // Same year
            return end.Month - start.Month;

        case 1: // last year
            return (12 - start.Month) + end.Month;

        default:
            return 12 * (3 - (end.Year - start.Year)) + (12 - start.Month) + end.Month;
    }
}
6
ответ дан Drakonoved 21 August 2018 в 15:53
поделиться
6
ответ дан Drakonoved 1 November 2018 в 09:15
поделиться
1
ответ дан Drakonoved 1 November 2018 в 09:15
поделиться
6
ответ дан Drakonoved 1 November 2018 в 09:15
поделиться
6
ответ дан Drakonoved 1 November 2018 в 09:15
поделиться
6
ответ дан Drakonoved 1 November 2018 в 09:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: