Как получить разницу между двумя датами в году / месяце / неделе / дне?

Как эффективно определить разницу между двумя датами в году / месяце / неделе / дне?

например. Разница между двумя датами составляет 1 год, 2 месяца, 3 недели, 4 дня.

Разница представляет собой число года (-ов), месяца (-ов), недели (-ей) и дня (-ов) между двумя датами.

Ответы на вопрос(21)

TimeSpan period = endDate.AddDays(1) - startDate;
DateTime date = new DateTime(period.Ticks);
int totalYears = date.Year - 1;
int totalMonths = ((date.Year - 1) * 12) + date.Month - 1;
int totalWeeks = (int)period.TotalDays / 7;

date.Month - 1, месяц 0 не существует

 19 окт. 2018 г., 08:44
Наконец, правильное решение без большого количества осложнений в других нескольких ответах. Я просто пропускаю totalDays, не считая дни, которые уже считаются неделями (7 модуль): (int) period.TotalDays% 7 ... Кроме того, он работает без добавления дня в endDate
Решение Вопроса

Это на самом деле довольно сложно. Разное общее количество дней может привести к тому же результату. Например:

19th June 2008 to 19th June 2010 = 2 years, but also 365 * 2 days

19th June 2006 to 19th June 2008 = 2 years, but also 365 + 366 days due to leap years

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

Дальнейшая путаница: вычитать (или прибавлять) месяцы сложно, когда вы можете начать с даты «30 марта». - что на месяц раньше?

Еще дальше путаница (may не имеет отношения к делу): даже день не всегда 24 часа. Дневной свет спасает кого-нибудь?

Еще больше путаницы (почти навернякаnot релевантно): даже минута не всегда 60 секунд. Дополнительные секунды очень сбивают с толку ...

У меня нет времени, чтобы выработать точный правильный способ сделать это прямо сейчас - этот ответ в основном состоит в том, чтобы подчеркнуть тот факт, что это не так просто, как может показаться.

РЕДАКТИРОВАТЬ: К сожалению, у меня не будет достаточно времени, чтобы ответить на этот вопрос полностью. Я хотел бы предложить вам начать с определения структуры, представляющейPeriod:

public struct Period
{
    private readonly int days;
    public int Days { get { return days; } }
    private readonly int months;
    public int Months { get { return months; } }
    private readonly int years;
    public int Years { get { return years; } }

    public Period(int years, int months, int days)
    {
        this.years = years;
        this.months = months;
        this.days = days;
    }

    public Period WithDays(int newDays)
    {
        return new Period(years, months, newDays);
    }

    public Period WithMonths(int newMonths)
    {
        return new Period(years, newMonths, days);
    }

    public Period WithYears(int newYears)
    {
        return new Period(newYears, months, days);
    }

    public static DateTime operator +(DateTime date, Period period)
    {
        // TODO: Implement this!
    }

    public static Period Difference(DateTime first, DateTime second)
    {
        // TODO: Implement this!
    }
}

Я предлагаю вам сначала реализовать оператор +, который должен сообщитьDifference метод - вы должны убедиться, чтоfirst + (Period.Difference(first, second)) == second для всехfirst/second ценности.

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

Позвольте себе день, чтобы реализовать это должным образом. Это хитрый материал.

Обратите внимание, что здесь я пропустил недели - это значение, по меньшей мере, легко, потому что оно всегда 7 дней. Таким образом, с учетом (положительного) периода вы будете иметь:

int years = period.Years;
int months = period.Months;
int weeks = period.Days / 7;
int daysWithinWeek = period.Days % 7;

(Я предлагаю вам избегать даже думать о негативных периодах - убедитесь, что все положительное, все время.)

 01 авг. 2011 г., 22:35
@ Джон Скит - Нода-Тайм (code.google.com/p/noda-time/wiki/Welcome) это реализовано?
 Ahmed05 июл. 2009 г., 14:41
Я хочу увидеть ваш "правильный способ сделать это".
 05 июл. 2009 г., 16:08
@Ahmed: я посмотрю, смогу ли я найти время позже.
 01 авг. 2011 г., 22:51
@ Дэвид: у битов периода еще не было огромного количества любви, и я не знаю, как это будет работать с неделями в миксе, но этоshould все в порядке ... попробуйте и подайте отчет об ошибке, если нет :)
 07 авг. 2013 г., 03:28
@DavidBasarab -Noda Time прошел долгий путь с тех пор, как этот пост был изначально написан. Теперь он может точно выполнить это требование сPeriod.Between(d1,d2).

Как насчет использованияSystem.Data.Linq пространство имен и егоSqlMethods.DateDiffMonth метод?

Например, скажите:

DateTime starDT = {01-Jul-2009 12:00:00 AM}
DateTime endDT = {01-Nov-2009 12:00:00 AM}

Затем:

int monthDiff = System.Data.Linq.SqlClient.SqlMethods.DateDiffMonth(startDT, endDT);

== & GT; 4

Есть и другиеDateDiff статические методы вSqlMethods учебный класс.

 24 янв. 2014 г., 01:20
Этот код ошибается в нескольких базовых тестах - см. Мой ответ.
 11 июл. 2011 г., 04:35
Этот метод говорит, что существует разница в 1 месяц между 31.12.2000 и 01.01.2001. Это хорошо, если вы работаете с компьютером по математике, но на самом деле не практично говорить, что две даты с интервалом всего в 1 день также с интервалом в 1 месяц.
 02 окт. 2012 г., 15:00
За исключением того, что ОП просили годами, месяцами, днями. ;)
 13 сент. 2011 г., 06:45
@Matt: Если я хочу разницу в день, я мог бы попросить об этом, но если я хочу разницу в месяце, ответ будет совершенно верным.
    Console.WriteLine("Enter your Date of Birth to Know your Current age in DD/MM/YY Format");
    string str = Console.ReadLine();
    DateTime dt1 = DateTime.Parse(str);
    DateTime dt2 = DateTime.Parse("10/06/2012");
    int result = (dt2 - dt1).Days;
    result = result / 365;
    Console.WriteLine("Your Current age is {0} years.",result);
 10 июн. 2012 г., 21:06
Ответ придет через годы.
 27 мая 2013 г., 15:01
Как указано в различных ответах на этой странице, этот ответ является неправильным (и неполным).

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

Результаты убедительны: ни один из вкладов кода не дает точного ответа на вопрос.Update: I now have four correct solutions to this question, including my own, see updates below.

Code tested

Исходя из этого вопроса, я протестировал код следующих пользователей: Мохаммед Иджас Насирудин, Раффин, Малу М.Н., Дейв, шт. Яни, Лк.

Это были все ответы, которые содержали все три года, месяцы и дни в их коде. Обратите внимание, что два из них, Дейв и Джени, дали общее количество дней и месяцев, а не общее количество месяцев, оставшихся после подсчета лет, и общее количество дней, оставшихся после подсчета месяцев. Я думаю, что ответы неправильны с точки зрения того, что ОП, казалось, хотел, но модульные тесты, очевидно, не говорят вам много в этих случаях.(Note that in Jani's case this was my error and his code was actually correct - see Update 4 below)

Ответы Джона Скита, Агасолеймани, Мукеша Кумара, Ричарда, Колина, Шеира, как я только что видел, Чалки и Энди, были неполными. Это не означает, что ответы не были хорошими, фактически некоторые из них являются полезным вкладом в решение проблемы. Это просто означает, что не было кода, принимающего дваDateTimeс и возвращение 3intс, что я мог правильно проверить. Однако четыре из них говорят об использованииTimeSpan, Как многие люди упоминали,TimeSpan не возвращает значения, превышающие дни.

Другие ответы, которые я проверял, были от

question 3054715 - LukeH, ho1 and this. ___curious_geek question 6260372 - Chuck Rostance and Jani (same answer as this question) question 9 (!) - Dylan Hayes, Jon and Rajeshwaran S P

ответ этого .___ curious_geek - это код на странице, на которую он ссылался, и я не думаю, что он написал. Ответ Яни - единственный, который использует внешнюю библиотеку, Библиотека периодов времени для .Net.

Все остальные ответы на все эти вопросы казались неполными. Вопрос 9 касается возраста в годах, и три ответа - это те, которые превысили краткие и рассчитанные годы, месяцы и дни. Если кто-нибудь найдет дополнительные дубликаты этого вопроса, пожалуйста, дайте мне знать.

How I tested

Проще говоря: я сделал интерфейс

public interface IDateDifference
{
  void SetDates(DateTime start, DateTime end);
  int GetYears();
  int GetMonths();
  int GetDays();

}

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

Я написал кучу тестов NUnit в абстрактном обобщенном классе

[TestFixture]
public abstract class DateDifferenceTests<DDC> where DDC : IDateDifference, new()

и добавил пустой производный класс

public class Rajeshwaran_S_P_Test : DateDifferenceTests<Rajeshwaran_S_P>
{
}

в исходный файл для каждогоIDateDifference учебный класс.

NUnit достаточно умен, чтобы сделать все остальное.

The tests

Несколько из них были написаны заранее, а остальные были написаны, чтобы попытаться сломать, казалось бы, работающие реализации.

[TestFixture]
public abstract class DateDifferenceTests<DDC> where DDC : IDateDifference, new()
{
  protected IDateDifference ddClass;

  [SetUp]
  public void Init()
  {
    ddClass = new DDC();
  }

  [Test]
  public void BasicTest()
  {
    ddClass.SetDates(new DateTime(2012, 12, 1), new DateTime(2012, 12, 25));
    CheckResults(0, 0, 24);
  }

  [Test]
  public void AlmostTwoYearsTest()
  {
    ddClass.SetDates(new DateTime(2010, 8, 29), new DateTime(2012, 8, 14));
    CheckResults(1, 11, 16);
  }

  [Test]
  public void AlmostThreeYearsTest()
  {
    ddClass.SetDates(new DateTime(2009, 7, 29), new DateTime(2012, 7, 14));
    CheckResults(2, 11, 15);
  }

  [Test]
  public void BornOnALeapYearTest()
  {
    ddClass.SetDates(new DateTime(2008, 2, 29), new DateTime(2009, 2, 28));
    CheckControversialResults(0, 11, 30, 1, 0, 0);
  }

  [Test]
  public void BornOnALeapYearTest2()
  {
    ddClass.SetDates(new DateTime(2008, 2, 29), new DateTime(2009, 3, 1));
    CheckControversialResults(1, 0, 0, 1, 0, 1);
  }


  [Test]
  public void LongMonthToLongMonth()
  {
    ddClass.SetDates(new DateTime(2010, 1, 31), new DateTime(2010, 3, 31));
    CheckResults(0, 2, 0);
  }

  [Test]
  public void LongMonthToLongMonthPenultimateDay()
  {
    ddClass.SetDates(new DateTime(2009, 1, 31), new DateTime(2009, 3, 30));
    CheckResults(0, 1, 30);
  }

  [Test]
  public void LongMonthToShortMonth()
  {
    ddClass.SetDates(new DateTime(2009, 8, 31), new DateTime(2009, 9, 30));
    CheckControversialResults(0, 1, 0, 0, 0, 30);
  }

  [Test]
  public void LongMonthToPartWayThruShortMonth()
  {
    ddClass.SetDates(new DateTime(2009, 8, 31), new DateTime(2009, 9, 10));
    CheckResults(0, 0, 10);
  }

  private void CheckResults(int years, int months, int days)
  {
    Assert.AreEqual(years, ddClass.GetYears());
    Assert.AreEqual(months, ddClass.GetMonths());
    Assert.AreEqual(days, ddClass.GetDays());
  }

  private void CheckControversialResults(int years, int months, int days,
    int yearsAlt, int monthsAlt, int daysAlt)
  {
    // gives the right output but unhelpful messages
    bool success = ((ddClass.GetYears() == years
                     && ddClass.GetMonths() == months
                     && ddClass.GetDays() == days)
                    ||
                    (ddClass.GetYears() == yearsAlt
                     && ddClass.GetMonths() == monthsAlt
                     && ddClass.GetDays() == daysAlt));

    Assert.IsTrue(success);
  }
}

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

Есть две функции, которые делают всеAsserts,CheckResults() а такжеCheckControversialResults(), Они работают хорошо, чтобы сохранить набор текста и дать правильные результаты, но, к сожалению, они затрудняют, чтобы точно увидеть, что пошло не так (потому чтоAssert вCheckControversialResults() потерпит неудачу с «ожидаемым истиной», а не сообщит вам, какое значение было неверным. Если у кого-то есть лучший способ сделать это (избегайте писать одни и те же проверки каждый раз, но у вас есть более полезные сообщения об ошибках), пожалуйста, дайте мне знать.

CheckControversialResults() используется для пары случаев, когда кажется, что существует два разных мнения о том, что правильно. У меня есть собственное мнение, но я думал, что должен быть либеральным в том, что я принял здесь. Суть этого в том, чтобы решить, будет ли один год после 29 февраля 28 февраля или 1 марта.

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

Ни один тест не требует времени суток - всеDateTimeс в полночь. Включая времена, пока ясно, как работает округление до дней (я думаю, что это так), может появиться еще больше недостатков.

The results

Полная таблица результатов выглядит следующим образом:

ChuckRostance_Test 3 failures               S S S F S S F S F
Dave_Test 6 failures                        F F S F F F F S S
Dylan_Hayes_Test 9 failures                 F F F F F F F F F
ho1_Test 3 failures                         F F S S S S F S S
Jani_Test 6 failures                        F F S F F F F S S
Jon_Test 1 failure                          S S S S S S F S S
lc_Test 2 failures                          S S S S S F F S S
LukeH_Test 1 failure                        S S S S S S F S S
Malu_MN_Test 1 failure                      S S S S S S S F S
Mohammed_Ijas_Nasirudeen_Test 2 failures    F S S F S S S S S
pk_Test 6 failures                          F F F S S F F F S
Rajeshwaran_S_P_Test 7 failures             F F S F F S F F F
ruffin_Test 3 failures                      F S S F S S F S S
this_curious_geek_Test 2 failures           F S S F S S S S S

But note that Jani's solution was actually correct and passed all tests - see update 4 below.

Столбцы в алфавитном порядке названия теста:

AlmostThreeYearsTest AlmostTwoYearsTest BasicTest BornOnALeapYearTest BornOnALeapYearTest2 LongMonthToLongMonth LongMonthToLongMonthPenultimateDay LongMonthToPartWayThruShortMonth LongMonthToShortMonth

Три ответа не дали результатов, по одному тесту каждый, Jon's, LukeH и Manu MN. Имейте в виду, что эти тесты были написаны специально для устранения недостатков в этих ответах.

Каждый тест был пройден хотя бы одним фрагментом кода, что немного заверяет, что ни один из тестов не является ошибочным.

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

My conclusions

Есть три:

Calendars are hard. I wrote nine tests, including three where two answers are possible. Some of the tests where I only had one answer might not be unanimously agreed with. Just thinking about exactly what we mean when we say '1 month later' or '2 years earlier' is tricky in a lot of situations. And none of this code had to deal with all the complexities of things like working out when leap years are. All of it uses library code to handle dates. If you imagine the 'spec' for telling time in days, weeks, months and years written out, there's all sorts of cruft. Because we know it pretty well since primary school, and use it everyday, we are blind to many of the idiosyncracies. The question is not an academic one - various types of decomposition of time periods into years, quarters and months are essential in accounting software for bonds and other financial products.

Writing correct code is hard. There were a lot of bugs. In slightly more obscure topics or less popular questions than the chances of a bug existing without having been pointed out by a commenter are much, much higher than for this question. You should really never, never copy code from SO into your program without understanding exactly what it does. The flipside of this is that you probably shouldn't write code in your answer that is ready to be copied and pasted, but rather intelligent and expressive pseudo-code that allows someone to understand the solution and implement their own version (with their own bugs!)

Unit tests are helpful. I am still meaning to post my own solution to this when I get round to it (for someone else to find the hidden, incorrect assumptions in!) Doing this was a great example of 'saving the bugs' by turning them into unit tests to fix the next version of the code with.

Update

Весь проект сейчас наhttps://github.com/jwg4/date-difference Это включает в себя мою собственную попыткуjwg.cs, который проходит все тесты, которые у меня есть на данный момент, включая несколько новых, которые проверяют правильное время суток. Не стесняйтесь добавлять либо больше тестов, чтобы сломать эту и другие реализации, либо лучший код для ответа на вопрос.

Update 2

@MattJohnson добавил реализацию, в которой используется NodaTime Джона Скита. Он проходит все текущие тесты.

Update 3

Ответ @ KirkWoll наРазница в месяцах между двумя датами был добавлен в проект на github. Он проходит все текущие тесты.

Update 4

@Jani указал в комментарии, что я неправильно использовал его код. Он предложил методы, которые правильно подсчитывают годы, месяцы и дни (наряду с некоторыми, которые подсчитывают общее количество дней и месяцев, а не остатки), однако я ошибочно использовал неправильные в моем тестовом коде. Я исправил свою обертку вокруг его кода, и теперь он проходит все тесты. Есть сейчасfour правильные решения, из которых Яни была первой. Две библиотеки использования (Intenso.TimePeriod и NodaTime) и две написаны с нуля.

 05 июл. 2009 г., 16:09
@ Ахмед: ОК, примените к трем датам, которые я перечислю в последнем абзаце. 2004-02-29 плюс один год это какая дата? 2004-03-1 плюс один год, какая дата?
 07 авг. 2013 г., 10:49
Большое спасибо за исправленный патч и новую реализацию.
 02 окт. 2012 г., 15:05
& quot; Календарь CultureInfo должен быть рассмотрен & quot; -- Вроде, как бы, что-то вроде. См мойgreatest integer metaphor выше. Как только вы проходите каждый выброс, вы возвращаетесь к 1 составному блоку. С 01.01.1900 по 01.01.2000 - 100 лет, независимо от того, что произошло между ними. И разве это не обман? ;) (Я шучу.) Но покаSystem.DateTime.DaysInMonth(intYear, intMonth) является точной, это действительно довольно простая проблема - за исключением тех лет, у которых нет 12 месяцев.
 27 мая 2013 г., 13:59
Бесполезно и излишне с годами и месяцами.
 02 окт. 2012 г., 15:00
За исключением того, что ОП просили годами, месяцами, днями. ;)
 Ahmed05 июл. 2009 г., 14:24
Год: количество лет между двумя датами.
 29 дек. 2013 г., 14:48
Спасибо за отличный обзор! Похоже, вы использовали свойства классаYears, Months а такжеDays (временные значения) вместоElapsedYears, ElapsedMonths а такжеElapsedDays.
 05 июл. 2009 г., 14:38
Я подозреваю, что DateTime.AddMonths может вызвать проблемы здесь из-за неравных месяцев. (31 января + 1 месяц?)
 13 янв. 2017 г., 08:19
@BradBamford Яни и мои верны. Яни в его ответе, а мой только в проекте GitHub.
 28 мая 2013 г., 11:52
without годы и месяцы.
 06 июл. 2009 г., 03:58
@Traples Согласен.
 29 дек. 2013 г., 19:09
Привет @Jani. Извините, если я использовал ваш код неправильно. Я постараюсь исправить свои тесты (или приму патч, если вы хотите отправить его), и обновлю результаты, когда у меня будет шанс.
 19 окт. 2018 г., 08:44
Наконец, правильное решение без большого количества осложнений в других нескольких ответах. Я просто пропускаю totalDays, не считая дни, которые уже считаются неделями (7 модуль): (int) period.TotalDays% 7 ... Кроме того, он работает без добавления дня в endDate
 05 июл. 2009 г., 20:44
Еще одна вещь ... Я мог бы изменить ее так, чтобы она сравнивалась с использованием & quot; & lt; = & quot; а не просто "& lt;". Таким образом, 7/5/09 составляет «1 месяц». более 6/5/09 вместо "4 недели и 2 дня".
 10 июн. 2012 г., 21:06
Ответ придет через годы.
 27 окт. 2012 г., 03:56
Зачем использовать что-то такое сложное, когда доступны более простые решения?
 13 сент. 2011 г., 06:45
@Matt: Если я хочу разницу в день, я мог бы попросить об этом, но если я хочу разницу в месяце, ответ будет совершенно верным.
 05 июл. 2009 г., 17:59
@ Джон Скит - Да, это очень хороший момент. Однако, как с этим справиться, будет зависеть от вашего определения разницы в месяце. тоже ... есть предложения?
 27 мая 2013 г., 14:01
Вы упускаете суть. Предполагается, что дни и недели описывают дни и недели, оставшиеся после вычитания целых месяцев и лет.
 27 мая 2013 г., 15:01
Как указано в различных ответах на этой странице, этот ответ является неправильным (и неполным).
 05 июл. 2009 г., 14:19
Самая большая единица времени, представленная TimeSpan - дни. Однако, поскольку оба года (високосный год) и месяцы различаются по длине, вам все равно придется сделать некоторую математику, чтобы выяснить их, и они не являются детерминированными, потому что фактические значения года имеют значение, но у вас не будет этой информации в самой структуре TimeSpan.
 27 мая 2013 г., 15:21
к несчастьюAddMonths() не работает так, как вы предполагаете.date.AddMonths(1).AddMonths(1) к сожалению не равноdate.AddMonths(2), как вы можете видеть, если вы беретеdate = new DateTime(2013,1,31), Это связано не с високосными годами, а с переменным числом дней в месяце.
 11 июл. 2011 г., 04:35
Этот метод говорит, что существует разница в 1 месяц между 31.12.2000 и 01.01.2001. Это хорошо, если вы работаете с компьютером по математике, но на самом деле не практично говорить, что две даты с интервалом всего в 1 день также с интервалом в 1 месяц.
 05 июл. 2009 г., 14:28
Да, сначала вам нужно разобраться с годами и месяцами, прежде чем вы узнаете, сколько дней осталось для расчета недель и дней.
 05 июл. 2009 г., 20:38
+1 - я думаю, что это решение дает, пожалуй, наиболее интуитивный результат (как и метод AddMonths, который дает 28 или 29 февраля как один месяц после 31 января). Мы не стесняемся сказать, что 1 февраля - один месяц после 1 января, и в то же время, скажем, 1 марта - один месяц после 1 февраля ... даже при том, что разница в месяцах составляет 2 или 3 дня. длины.
 24 янв. 2014 г., 01:20
Этот код ошибается в нескольких базовых тестах - см. Мой ответ.
DateTime startTime = DateTime.Now;

DateTime endTime = DateTime.Now.AddSeconds( 75 );

TimeSpan span = endTime.Subtract ( startTime );
 Console.WriteLine( "Time Difference (seconds): " + span.Seconds );
 Console.WriteLine( "Time Difference (minutes): " + span.Minutes );
 Console.WriteLine( "Time Difference (hours): " + span.Hours );
 Console.WriteLine( "Time Difference (days): " + span.Days );

Выход:

Time Difference (seconds): 15
Time Difference (minutes): 1
Time Difference (hours): 0
Time Difference (days): 0
 28 мая 2013 г., 11:52
without годы и месяцы.
 27 мая 2013 г., 13:59
Бесполезно и излишне с годами и месяцами.
private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
{

        int gyear = dateTimePicker1.Value.Year; 
        int gmonth = dateTimePicker1.Value.Month; 
        int gday = dateTimePicker1.Value.Day; 
        int syear = DateTime.Now.Year; 
        int smonth = DateTime.Now.Month; 
        int sday = DateTime.Now.Day;

        int difday = DateTime.DaysInMonth(syear, gmonth);

        agedisplay = (syear - gyear); 

        lmonth = (smonth - gmonth);
        lday = (sday - gday);


        if (smonth < gmonth)
        {
            agedisplay = agedisplay - 1;
        }
        if (smonth == gmonth)
        {
            if (sday < (gday))
            {
                agedisplay = agedisplay - 1;
            }
        }

        if (smonth < gmonth)
        {
            lmonth = (-(-smonth)+(-gmonth)+12);
        }
        if (lday < 0)
        {
            lday = difday - (-lday);
            lmonth = lmonth - 1;
        }

        if (smonth == gmonth && sday < gday&&gyear!=syear)
        {
            lmonth = 11;
        }

            ageDisplay.Text = Convert.ToString(agedisplay) + " Years,  " + lmonth + " Months,  " + lday + " Days.";

    }

Дни: (endDate - startDate). Дни
Недели: (endDate - startDate) .Days / 7
Годы: Месяцы / 12
Месяцы: TimeSpan предоставляет только дни, поэтому используйте следующий код, чтобы получить количество полных месяцев между указанной датой начала и окончания. Например, количество полных месяцев между 01/10/2000 и 02/10/2000 равно 1. Число полных месяцев между 01/10/2000 и 02/09/2000 равно 0.

    public int getMonths(DateTime startDate, DateTime endDate)
    {
        int months = 0;

        if (endDate.Month <= startDate.Month)
        {
            if (endDate.Day < startDate.Day)
            {
                months = (12 * (endDate.Year - startDate.Year - 1))
                       + (12 - startDate.Month + endDate.Month - 1);
            }
            else if (endDate.Month < startDate.Month)
            {
                months = (12 * (endDate.Year - startDate.Year - 1))
                       + (12 - startDate.Month + endDate.Month);
            }
            else  // (endDate.Month == startDate.Month) && (endDate.Day >= startDate.Day)
            {
                months = (12 * (endDate.Year - startDate.Year));
            }
        }
        else if (endDate.Day < startDate.Day)
        {
            months = (12 * (endDate.Year - startDate.Year))
                   + (endDate.Month - startDate.Month) - 1;
        }
        else  // (endDate.Month > startDate.Month) && (endDate.Day >= startDate.Day)
        {
            months = (12 * (endDate.Year - startDate.Year))
                   + (endDate.Month - startDate.Month);
        }

        return months;
    }
 27 мая 2013 г., 14:01
Вы упускаете суть. Предполагается, что дни и недели описывают дни и недели, оставшиеся после вычитания целых месяцев и лет.

Вычесть дваDateTime случаи, чтобы дать вамTimeSpan который имеетDays имущество. (Например, в PowerShell):

PS > ([datetime]::today - [datetime]"2009-04-07")


Days              : 89
Hours             : 0
Minutes           : 0
Seconds           : 0
Milliseconds      : 0
Ticks             : 76896000000000
TotalDays         : 89
TotalHours        : 2136
TotalMinutes      : 128160
TotalSeconds      : 7689600
TotalMilliseconds : 7689600000

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

Предполагая, что вы хотите начать с вашей базовой даты, вы можете постепенно вычитать при подсчете первых лет (проверка на високосные годы), затем длины месяцев (индекс из startDate.Month), затем недели (оставшиеся дни, разделенные на 7), а затем дни (остаток ).

Есть много крайних случаев для рассмотрения, например, 2005-03-01 - один год с 2004-03-01,and from 2004-02-29 в зависимости от того, что вы подразумеваете под "годом".

 Ahmed05 июл. 2009 г., 14:24
Год: количество лет между двумя датами.
 05 июл. 2009 г., 14:28
Да, сначала вам нужно разобраться с годами и месяцами, прежде чем вы узнаете, сколько дней осталось для расчета недель и дней.
 05 июл. 2009 г., 16:09
@ Ахмед: ОК, примените к трем датам, которые я перечислил в последнем абзаце. 2004-02-29 плюс один год это какая дата? 2004-03-1 плюс один год, какая дата?

Для правильного расчета разницы Годы / Месяцы / НеделиCalendar изCultureInfo должны быть рассмотрены:

leap vs. non-leap years months with different count of days years with different count of weeks (varying by the first day of week and the calendar week rule)

DateDiff классБиблиотека периодов времени для .NET уважает все эти факторы:

// ----------------------------------------------------------------------
public void DateDiffSample()
{
  DateTime date1 = new DateTime( 2009, 11, 8, 7, 13, 59 );
  Console.WriteLine( "Date1: {0}", date1 );
  // > Date1: 08.11.2009 07:13:59
  DateTime date2 = new DateTime( 2011, 3, 20, 19, 55, 28 );
  Console.WriteLine( "Date2: {0}", date2 );
  // > Date2: 20.03.2011 19:55:28

  DateDiff dateDiff = new DateDiff( date1, date2 );

  // differences
  Console.WriteLine( "DateDiff.Years: {0}", dateDiff.Years );
  // > DateDiff.Years: 1
  Console.WriteLine( "DateDiff.Quarters: {0}", dateDiff.Quarters );
  // > DateDiff.Quarters: 5
  Console.WriteLine( "DateDiff.Months: {0}", dateDiff.Months );
  // > DateDiff.Months: 16
  Console.WriteLine( "DateDiff.Weeks: {0}", dateDiff.Weeks );
  // > DateDiff.Weeks: 70
  Console.WriteLine( "DateDiff.Days: {0}", dateDiff.Days );
  // > DateDiff.Days: 497
  Console.WriteLine( "DateDiff.Weekdays: {0}", dateDiff.Weekdays );
  // > DateDiff.Weekdays: 71
  Console.WriteLine( "DateDiff.Hours: {0}", dateDiff.Hours );
  // > DateDiff.Hours: 11940
  Console.WriteLine( "DateDiff.Minutes: {0}", dateDiff.Minutes );
  // > DateDiff.Minutes: 716441
  Console.WriteLine( "DateDiff.Seconds: {0}", dateDiff.Seconds );
  // > DateDiff.Seconds: 42986489

  // elapsed
  Console.WriteLine( "DateDiff.ElapsedYears: {0}", dateDiff.ElapsedYears );
  // > DateDiff.ElapsedYears: 1
  Console.WriteLine( "DateDiff.ElapsedMonths: {0}", dateDiff.ElapsedMonths );
  // > DateDiff.ElapsedMonths: 4
  Console.WriteLine( "DateDiff.ElapsedDays: {0}", dateDiff.ElapsedDays );
  // > DateDiff.ElapsedDays: 12
  Console.WriteLine( "DateDiff.ElapsedHours: {0}", dateDiff.ElapsedHours );
  // > DateDiff.ElapsedHours: 12
  Console.WriteLine( "DateDiff.ElapsedMinutes: {0}", dateDiff.ElapsedMinutes );
  // > DateDiff.ElapsedMinutes: 41
  Console.WriteLine( "DateDiff.ElapsedSeconds: {0}", dateDiff.ElapsedSeconds );
  // > DateDiff.ElapsedSeconds: 29

  // description
  Console.WriteLine( "DateDiff.GetDescription(1): {0}", dateDiff.GetDescription( 1 ) );
  // > DateDiff.GetDescription(1): 1 Year
  Console.WriteLine( "DateDiff.GetDescription(2): {0}", dateDiff.GetDescription( 2 ) );
  // > DateDiff.GetDescription(2): 1 Year 4 Months
  Console.WriteLine( "DateDiff.GetDescription(3): {0}", dateDiff.GetDescription( 3 ) );
  // > DateDiff.GetDescription(3): 1 Year 4 Months 12 Days
  Console.WriteLine( "DateDiff.GetDescription(4): {0}", dateDiff.GetDescription( 4 ) );
  // > DateDiff.GetDescription(4): 1 Year 4 Months 12 Days 12 Hours
  Console.WriteLine( "DateDiff.GetDescription(5): {0}", dateDiff.GetDescription( 5 ) );
  // > DateDiff.GetDescription(5): 1 Year 4 Months 12 Days 12 Hours 41 Mins
  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

DateDiff также рассчитывает разницу кварталов.

 02 окт. 2012 г., 15:05
& quot; Календарь CultureInfo должен быть рассмотрен & quot; -- Вроде, как бы, что-то вроде. См мойgreatest integer metaphor выше. Как только вы проходите каждый выброс, вы возвращаетесь к 1 составному блоку. С 01.01.1900 по 01.01.2000 - 100 лет, независимо от того, что произошло между ними. И разве это не обман? ;) (Я шучу.) Но покаSystem.DateTime.DaysInMonth(intYear, intMonth) является точной, это действительно довольно простая проблема - за исключением тех лет, у которых нет 12 месяцев.

использованиеВремя Нода:

var ld1 = new LocalDate(2012, 1, 1);
var ld2 = new LocalDate(2013, 12, 25);
var period = Period.Between(ld1, ld2);

Debug.WriteLine(period);        // "P1Y11M24D"  (ISO8601 format)
Debug.WriteLine(period.Years);  // 1
Debug.WriteLine(period.Months); // 11
Debug.WriteLine(period.Days);   // 24

Я пытался найти четкий ответ по годам, месяцам и дням, и я не нашел ничего ясного. Если вы все еще ищете, отметьте этот метод:

        public static string GetDifference(DateTime d1, DateTime d2)
        {
            int[] monthDay = new int[12] { 31, -1, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
            DateTime fromDate;
            DateTime toDate;
            int year;
            int month;
            int day; 
            int increment = 0;

            if (d1 > d2)
            {
                fromDate = d2;
                toDate = d1;
            }
            else
            {
                fromDate = d1;
                toDate = d2;
            } 

            // Calculating Days
            if (fromDate.Day > toDate.Day)
            {
                increment = monthDay[fromDate.Month - 1];
            }

            if (increment == -1)
            {
                if (DateTime.IsLeapYear(fromDate.Year))
                {
                    increment = 29;
                }
                else
                {
                    increment = 28;
                }
            }

            if (increment != 0)
            {
                day = (toDate.Day + increment) - fromDate.Day;
                increment = 1;
            }
            else
            {
                day = toDate.Day - fromDate.Day;
            }

            // Month Calculation
            if ((fromDate.Month + increment) > toDate.Month)
            {
                month = (toDate.Month + 12) - (fromDate.Month + increment);
                increment = 1;
            }
            else
            {
                month = (toDate.Month) - (fromDate.Month + increment);
                increment = 0;
            }

            // Year Calculation
            year = toDate.Year - (fromDate.Year + increment);

            return year + " years " + month + " months " + day + " days";
        }

Високосные годы и неравные месяцы фактически делают эту проблему нетривиальной. Я уверен, что кто-то может придумать более эффективный способ, но вот один из вариантов - сначала приблизиться к малой стороне и скорректировать (не проверено):

public static void GetDifference(DateTime date1, DateTime date2, out int Years, 
    out int Months, out int Weeks, out int Days)
{
    //assumes date2 is the bigger date for simplicity

    //years
    TimeSpan diff = date2 - date1;
    Years = diff.Days / 366;
    DateTime workingDate = date1.AddYears(Years);

    while(workingDate.AddYears(1) <= date2)
    {
        workingDate = workingDate.AddYears(1);
        Years++;
    }

    //months
    diff = date2 - workingDate;
    Months = diff.Days / 31;
    workingDate = workingDate.AddMonths(Months);

    while(workingDate.AddMonths(1) <= date2)
    {
        workingDate = workingDate.AddMonths(1);
        Months++;
    }

    //weeks and days
    diff = date2 - workingDate;
    Weeks = diff.Days / 7; //weeks always have 7 days
    Days = diff.Days % 7;
}
 06 июл. 2009 г., 03:58
@Traples Согласен.
 05 июл. 2009 г., 14:38
Я подозреваю, что DateTime.AddMonths может вызвать проблемы здесь из-за неравных месяцев. (31 января + 1 месяц?)
 05 июл. 2009 г., 20:38
+1 - я думаю, что это решение дает, пожалуй, наиболее интуитивный результат (как и метод AddMonths, который дает 28 или 29 февраля как один месяц после 31 января). Мы не стесняемся сказать, что 1 февраля - один месяц после 1 января, и в то же время, скажем, 1 марта - один месяц после 1 февраля ... даже при том, что разница в месяцах составляет 2 или 3 дня. длины.
 05 июл. 2009 г., 20:44
Еще одна вещь ... Я мог бы изменить ее так, чтобы она сравнивалась с использованием & quot; & lt; = & quot; а не просто "& lt;". Таким образом, 7/5/09 составляет «1 месяц». более 6/5/09 вместо "4 недели и 2 дня".
 05 июл. 2009 г., 17:59
@ Джон Скит - Да, это очень хороший момент. Однако, как с этим справиться, будет зависеть от вашего определения разницы в месяце. тоже ... есть предложения?

Основываясь на ответе Хоакима, но исправляя вычисление, когда месяц конечной даты меньше, чем месяц начальной даты, и добавляя код для обработки даты окончания до начальной даты:

        public static class GeneralHelper
        {
          public static int GetYears(DateTime startDate, DateTime endDate)
            {
                if (endDate < startDate)
                    return -GetYears(endDate, startDate);

                int years = (endDate.Year - startDate.Year);

                if (endDate.Year == startDate.Year)
                    return years;

                if (endDate.Month < startDate.Month)
                    return years - 1;

                if (endDate.Month == startDate.Month && endDate.Day < startDate.Day)
                    return years - 1;

                return years;
            }

            public static int GetMonths(DateTime startDate, DateTime endDate)
            {
                if (startDate > endDate)
                    return -GetMonths(endDate, startDate);

                int months = 12 * GetYears(startDate, endDate);

                if (endDate.Month > startDate.Month)
                    months = months + endDate.Month - startDate.Month;
                else
                    months = 12 - startDate.Month + endDate.Month;

                if (endDate.Day < startDate.Day)
                    months = months - 1;

                return months;
            }
       }
    [TestClass()]
    public class GeneralHelperTest
    {
            [TestMethod]
            public void GetYearsTest()
            {
                Assert.AreEqual(0, GeneralHelper.GetYears(new DateTime(2000, 5, 5), new DateTime(2000, 12, 31)));
                Assert.AreEqual(0, GeneralHelper.GetYears(new DateTime(2000, 5, 5), new DateTime(2001, 4, 4)));
                Assert.AreEqual(0, GeneralHelper.GetYears(new DateTime(2000, 5, 5), new DateTime(2001, 5, 4)));
                Assert.AreEqual(1, GeneralHelper.GetYears(new DateTime(2000, 5, 5), new DateTime(2001, 5, 5)));
                Assert.AreEqual(1, GeneralHelper.GetYears(new DateTime(2000, 5, 5), new DateTime(2001, 12, 31)));

                Assert.AreEqual(0, GeneralHelper.GetYears(new DateTime(2000, 12, 31), new DateTime(2000, 5, 5)));
                Assert.AreEqual(0, GeneralHelper.GetYears(new DateTime(2001, 4, 4), new DateTime(2000, 5, 5)));
                Assert.AreEqual(0, GeneralHelper.GetYears(new DateTime(2001, 5, 4), new DateTime(2000, 5, 5)));
                Assert.AreEqual(-1, GeneralHelper.GetYears(new DateTime(2001, 5, 5), new DateTime(2000, 5, 5)));
                Assert.AreEqual(-1, GeneralHelper.GetYears(new DateTime(2001, 12, 31), new DateTime(2000, 5, 5)));
            }

            [TestMethod]
            public void GetMonthsTest()
            {
                Assert.AreEqual(0, GeneralHelper.GetMonths(new DateTime(2000, 5, 5), new DateTime(2000, 6, 4)));
                Assert.AreEqual(1, GeneralHelper.GetMonths(new DateTime(2000, 5, 5), new DateTime(2000, 6, 5)));
                Assert.AreEqual(1, GeneralHelper.GetMonths(new DateTime(2000, 5, 5), new DateTime(2000, 6, 6)));
                Assert.AreEqual(11, GeneralHelper.GetMonths(new DateTime(2000, 5, 5), new DateTime(2001, 5, 4)));
                Assert.AreEqual(12, GeneralHelper.GetMonths(new DateTime(2000, 5, 5), new DateTime(2001, 5, 5)));
                Assert.AreEqual(13, GeneralHelper.GetMonths(new DateTime(2000, 5, 5), new DateTime(2001, 6, 6)));

                Assert.AreEqual(0, GeneralHelper.GetMonths(new DateTime(2000, 6, 4), new DateTime(2000, 5, 5)));
                Assert.AreEqual(-1, GeneralHelper.GetMonths(new DateTime(2000, 6, 5), new DateTime(2000, 5, 5)));
                Assert.AreEqual(-1, GeneralHelper.GetMonths(new DateTime(2000, 6, 6), new DateTime(2000, 5, 5)));
                Assert.AreEqual(-11, GeneralHelper.GetMonths(new DateTime(2001, 5, 4), new DateTime(2000, 5, 5)));
                Assert.AreEqual(-12, GeneralHelper.GetMonths(new DateTime(2001, 5, 5), new DateTime(2000, 5, 5)));
                Assert.AreEqual(-13, GeneralHelper.GetMonths(new DateTime(2001, 6, 6), new DateTime(2000, 5, 5)));
            }
   }

EDIT Нет, это все еще не работает. Это не проходит этот тест:

Assert.AreEqual(24, GeneralHelper.GetMonths(new DateTime(2000, 5, 5), new DateTime(2003, 5, 5)));

Ожидаемое: & Lt; 24 & GT ;. Фактическое: & л; 12 & GT;

Я наткнулся на этот пост, пытаясь решить аналогичную проблему. Я пытался определить возраст животного в единицах лет, месяцев, недель и дней. Эти значения затем отображаются в SpinEdits, где пользователь может вручную изменить значения, чтобы найти / оценить дату рождения. Когда моей форме передавали дату рождения из месяца с менее чем 31 днем, вычисленное значение составляло 1 выходной. Я основал свое решение на ответе Ic выше.

Основной метод расчета, который вызывается после загрузки моей формы.

        birthDateDisplay.Text = birthDate.ToString("MM/dd/yyyy");

        DateTime currentDate = DateTime.Now;

        Int32 numOfDays = 0; 
        Int32 numOfWeeks = 0;
        Int32 numOfMonths = 0; 
        Int32 numOfYears = 0; 

        // changed code to follow this model http://stackoverflow.com/posts/1083990/revisions
        //years 
        TimeSpan diff = currentDate - birthDate;
        numOfYears = diff.Days / 366;
        DateTime workingDate = birthDate.AddYears(numOfYears);

        while (workingDate.AddYears(1) <= currentDate)
        {
            workingDate = workingDate.AddYears(1);
            numOfYears++;
        }

        //months
        diff = currentDate - workingDate;
        numOfMonths = diff.Days / 31;
        workingDate = workingDate.AddMonths(numOfMonths);

        while (workingDate.AddMonths(1) <= currentDate)
        {
            workingDate = workingDate.AddMonths(1);
            numOfMonths++;
        }

        //weeks and days
        diff = currentDate - workingDate;
        numOfWeeks = diff.Days / 7; //weeks always have 7 days

        // if bday month is same as current month and bday day is after current day, the date is off by 1 day
        if(DateTime.Now.Month == birthDate.Month && DateTime.Now.Day < birthDate.Day)
            numOfDays = diff.Days % 7 + 1;
        else
            numOfDays = diff.Days % 7;

        // If the there are fewer than 31 days in the birth month, the date calculated is 1 off
        // Dont need to add a day for the first day of the month
        int daysInMonth = 0;
        if ((daysInMonth = DateTime.DaysInMonth(birthDate.Year, birthDate.Month)) != 31 && birthDate.Day != 1)
        {
            startDateforCalc = DateTime.Now.Date.AddDays(31 - daysInMonth);
            // Need to add 1 more day if it is a leap year and Feb 29th is the date
            if (DateTime.IsLeapYear(birthDate.Year) && birthDate.Day == 29)
                startDateforCalc = startDateforCalc.AddDays(1);
        }

        yearsSpinEdit.Value = numOfYears;
        monthsSpinEdit.Value = numOfMonths;
        weeksSpinEdit.Value = numOfWeeks;
        daysSpinEdit.Value = numOfDays;

А затем, в моем обработчике события spinEdit_EditValueChanged, я вычисляю новую дату рождения, начиная с моего startDateforCalc, на основе значений в правках вращения. (SpinEdits ограничен только разрешением & gt; = 0)

birthDate = startDateforCalc.Date.AddYears(-((Int32)yearsSpinEdit.Value)).AddMonths(-((Int32)monthsSpinEdit.Value)).AddDays(-(7 * ((Int32)weeksSpinEdit.Value) + ((Int32)daysSpinEdit.Value)));
birthDateDisplay.Text = birthDate.ToString("MM/dd/yyyy");

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

 27 мая 2013 г., 15:21
к несчастьюAddMonths() не работает так, как вы предполагаете.date.AddMonths(1).AddMonths(1) к сожалению не равноdate.AddMonths(2), как вы можете видеть, если вы беретеdate = new DateTime(2013,1,31), Это связано не с високосными годами, а с переменным числом дней в месяце.

У меня есть ниже решение, которое работает правильно для меня (после выполнения некоторых тестовых случаев). Дополнительные тестовые случаи являются приемлемыми.

public class DateDiffernce
{
    private int m_nDays = -1;
    private int m_nWeek;
    private int m_nMonth = -1;
    private int m_nYear;

    public int Days
    {
        get
        {
            return m_nDays;
        }
    }

    public int Weeks
    {
        get
        {
            return m_nWeek;
        }
    }

    public int Months
    {
        get
        {
            return m_nMonth;
        }
    }

    public int Years
    {
        get
        {
            return m_nYear;
        }
    }

    public void GetDifferenceBetwwenTwoDate(DateTime objDateTimeFromDate, DateTime objDateTimeToDate)
    {
        if (objDateTimeFromDate.Date > objDateTimeToDate.Date)
        {
            DateTime objDateTimeTemp = objDateTimeFromDate;
            objDateTimeFromDate = objDateTimeToDate;
            objDateTimeToDate = objDateTimeTemp;
        }

        if (objDateTimeFromDate == objDateTimeToDate)
        {
            //textBoxDifferenceDays.Text = " Same dates";
            //textBoxAllDifference.Text = " Same dates";
            return;
        }

        // If From Date's Day is bigger than borrow days from previous month
        // & then subtract.
        if (objDateTimeFromDate.Day > objDateTimeToDate.Day)
        {
            objDateTimeToDate = objDateTimeToDate.AddMonths(-1);
            int nMonthDays = DateTime.DaysInMonth(objDateTimeToDate.Year, objDateTimeToDate.Month);
            m_nDays = objDateTimeToDate.Day + nMonthDays - objDateTimeFromDate.Day;

        }

        // If From Date's Month is bigger than borrow 12 Month 
        // & then subtract.
        if (objDateTimeFromDate.Month > objDateTimeToDate.Month)
        {
            objDateTimeToDate = objDateTimeToDate.AddYears(-1);
            m_nMonth = objDateTimeToDate.Month + 12 - objDateTimeFromDate.Month;

        }

       //Below are best cases - simple subtraction
        if (m_nDays == -1)
        {
            m_nDays = objDateTimeToDate.Day - objDateTimeFromDate.Day;
        }

        if (m_nMonth == -1)
        {
            m_nMonth = objDateTimeToDate.Month - objDateTimeFromDate.Month;
        }

        m_nYear = objDateTimeToDate.Year - objDateTimeFromDate.Year;
        m_nWeek = m_nDays / 7;
        m_nDays = m_nDays % 7;    
    }
}

ИспользоватьSubtract методDateTime объект, который возвращаетTimeSpan...

DateTime dt1 = new DateTime(2009, 3, 14);
DateTime dt2 = new DateTime(2008, 3, 15);

TimeSpan ts = dt1.Subtract(dt2);

Double days = ts.TotalDays;
Double hours = ts.TotalHours;
Double years = ts.TotalDays / 365;

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

Declare a intermediateDate variable and initialize to the originalDate Find difference between years.(yearDiff) Add yearDiff to intermediateDate and check whether the value is greater than today’s date. If newly obtained intermediateDate > today’s date adjust the yearDiff and intermediateDate by one. Continue above steps for month and Days.

Я использовал функции System.Data.Linq, чтобы найти разницу между годом, месяцем и днем. Пожалуйста, найдите код C # ниже

        DateTime todaysDate = DateTime.Now;
        DateTime interimDate = originalDate;

        ///Find Year diff
        int yearDiff = System.Data.Linq.SqlClient.SqlMethods.DateDiffYear(interimDate, todaysDate);
        interimDate = interimDate.AddYears(yearDiff);
        if (interimDate > todaysDate)
        {
            yearDiff -= 1;
            interimDate = interimDate.AddYears(-1);
        }

        ///Find Month diff
        int monthDiff = System.Data.Linq.SqlClient.SqlMethods.DateDiffMonth(interimDate, todaysDate);
        interimDate = interimDate.AddMonths(monthDiff);
        if (interimDate > todaysDate)
        {
            monthDiff -= 1;
            interimDate = interimDate.AddMonths(-1);
        }

        ///Find Day diff
        int daysDiff = System.Data.Linq.SqlClient.SqlMethods.DateDiffDay(interimDate, todaysDate);
 27 окт. 2012 г., 03:56
Зачем использовать что-то такое сложное, когда доступны более простые решения?
DateTime dt1 = new DateTime(2009, 3, 14);
DateTime dt2 = new DateTime(2008, 3, 15);

int diffMonth = Math.Abs((dt2.Year - dt1.Year)*12 + dt1.Month - dt2.Month)

Что ж, @Jon Skeet, если мы не беспокоимся о том, чтобы получить что-то более гранулированное, чем дни (и все же скручивать дни в большие единицы, а не иметь общее количество дней), согласно OP, это действительно не так уж сложно в C # , Что делает математику даты настолько сложной, так это то, что количество единиц в каждой составной единице часто меняется. Представьте, что на каждый 3-й галлон газа приходилось всего 3 кварта, а на каждый 12-й - 7, кроме пятницы, когда ...

К счастью, даты просто долгий путь черезнаибольшая целочисленная функция, Эти сумасшедшие исключения сводят с ума, если только вы не прошли весь дурацкий отряд, когда это уже не имеет большого значения. Если вы родились 25.12.1900 г., вы все равно РОВНО 100 на 25.12.2000 г. независимо от високосных лет или секунд или периодов перехода на летнее время, через которые вы прошли. Как только вы пробежались по процентам, которые составляют последний составной блок, вы возвращаетесь к единице. Вы добавили один и можете начать все сначала.

Это просто означает, что, если вы делаете годы от месяцев до дней, единственной странно включенной единицей является месяц (дней). Если вам нужно взять заем из значения месяца, чтобы обработать место, где вы вычитаете больше дней, чем у вас есть, вам просто нужно знать количество дней в предыдущем месяце. Никаких других выбросов не имеет значения.

И C # дает это вам в System.DateTime.DaysInMonth (intYear, intMonth).

(Если ваш текущий месяц меньше, чем ваш новый месяц, проблем не возникает. Каждый год имеет 12 месяцев.)

И то же самое, если мы пойдем более детально ... вам просто нужно знать, сколько (маленьких единиц) в последнем (составной единице). После того, как вы пройдете, вы получите еще одно целочисленное значение (составная единица). Затем вычтите, сколько маленьких единиц вы пропустили, начиная с того, что вы сделали. Затем добавьте обратно, сколько из тех, что вы прошли, прошли через разрыв составного блока с вашим Сейчас.

Итак, вот что я получил от моего первого среза при вычитании двух дат. Это может сработать. Надеюсь, полезно.

(РЕДАКТИРОВАТЬ: изменена проверка NewMonth & gt; OldMonth на NewMonth & gt; = OldMonth, поскольку нам не нужно брать один, если месяцы совпадают (то же самое относится и к дням). То есть 11 ноября 2011 года минус 9 ноября 2010 года давало - 1 год, 12 месяцев, 2 дня (т. Е. 2 дня, но королевский долг, который мы заимствовали, когда роялти не понадобилось).

(РЕДАКТИРОВАТЬ: пришлось проверять месяц = месяц, когда нам нужно было брать дни, чтобы вычесть dteThen.Day из dteNow.Day & dteNow.Day & lt; dteThen.Day, поскольку нам пришлось вычесть год, чтобы получить 11 месяцев, и дополнительные дни. Хорошо, так что есть несколько выбросов.; ^ D Я думаю, что я близок сейчас.)

private void Form1_Load(object sender, EventArgs e) {
DateTime dteThen = DateTime.Parse("3/31/2010");
DateTime dteNow = DateTime.Now;

int intDiffInYears = 0;
int intDiffInMonths = 0;
int intDiffInDays = 0;


if (dteNow.Month >= dteThen.Month)
{
    if (dteNow.Day >= dteThen.Day)
    {   // this is a best case, easy subtraction situation
        intDiffInYears = dteNow.Year - dteThen.Year;
        intDiffInMonths = dteNow.Month - dteThen.Month;
        intDiffInDays = dteNow.Day - dteThen.Day;
    }
    else
    {   // else we need to substract one from the month diff (borrow the one)
        // and days get wacky.

        // Watch for the outlier of Month = Month with DayNow < DayThen, as then we've 
        // got to subtract one from the year diff to borrow a month and have enough
        // days to subtract Then from Now.
        if (dteNow.Month == dteThen.Month)
        {
            intDiffInYears = dteNow.Year - dteThen.Year - 1;
            intDiffInMonths = 11; // we borrowed a year and broke ONLY 
            // the LAST month into subtractable days
            // Stay with me -- because we borrowed days from the year, not the month,
            // this is much different than what appears to be a similar calculation below.
            // We know we're a full intDiffInYears years apart PLUS eleven months.
            // Now we need to know how many days occurred before dteThen was done with 
            // dteThen.Month.  Then we add the number of days we've "earned" in the current
            // month.  
            //
            // So 12/25/2009 to 12/1/2011 gives us 
            // 11-9 = 2 years, minus one to borrow days = 1 year difference.
            // 1 year 11 months - 12 months = 11 months difference
            // (days from 12/25 to the End Of Month) + (Begin of Month to 12/1) = 
            //                (31-25)                +       (0+1)              =
            //                   6                   +         1                = 
            //                                  7 days diff
            //
            // 12/25/2009 to 12/1/2011 is 1 year, 11 months, 7 days apart.  QED.

            int intDaysInSharedMonth = System.DateTime.DaysInMonth(dteThen.Year, dteThen.Month);
            intDiffInDays = intDaysInSharedMonth - dteThen.Day + dteNow.Day;
        }
        else
        {
            intDiffInYears = dteNow.Year - dteThen.Year;
            intDiffInMonths = dteNow.Month - dteThen.Month - 1;

            // So now figure out how many more days we'd need to get from dteThen's 
            // intDiffInMonth-th month to get to the current month/day in dteNow.
            // That is, if we're comparing 2/8/2011 to 11/7/2011, we've got (10/8-2/8) = 8
            // full months between the two dates.  But then we've got to go from 10/8 to
            // 11/07.  So that's the previous month's (October) number of days (31) minus
            // the number of days into the month dteThen went (8), giving the number of days
            // needed to get us to the end of the month previous to dteNow (23).  Now we
            // add back the number of days that we've gone into dteNow's current month (7)
            // to get the total number of days we've gone since we ran the greatest integer
            // function on the month difference (23 to the end of the month + 7 into the
            // next month == 30 total days.  You gotta make it through October before you 
            // get another month, G, and it's got 31 days).

            int intDaysInPrevMonth = System.DateTime.DaysInMonth(dteNow.Year, (dteNow.Month - 1));
            intDiffInDays = intDaysInPrevMonth - dteThen.Day + dteNow.Day;
        }
    }
}
else
{
    // else dteThen.Month > dteNow.Month, and we've got to amend our year subtraction
    // because we haven't earned our entire year yet, and don't want an obo error.
    intDiffInYears = dteNow.Year - dteThen.Year - 1;

    // So if the dates were THEN: 6/15/1999 and NOW: 2/20/2010...
    // Diff in years is 2010-1999 = 11, but since we're not to 6/15 yet, it's only 10.
    // Diff in months is (Months in year == 12) - (Months lost between 1/1/1999 and 6/15/1999
    // when dteThen's clock wasn't yet rolling == 6) = 6 months, then you add the months we
    // have made it into this year already.  The clock's been rolling through 2/20, so two months.
    // Note that if the 20 in 2/20 hadn't been bigger than the 15 in 6/15, we're back to the
    // intDaysInPrevMonth trick from earlier.  We'll do that below, too.
    intDiffInMonths = 12 - dteThen.Month + dteNow.Month;

    if (dteNow.Day >= dteThen.Day)
    {
        intDiffInDays = dteNow.Day - dteThen.Day;
    }
    else
    {
        intDiffInMonths--;  // subtract the month from which we're borrowing days.

        // Maybe we shoulda factored this out previous to the if (dteNow.Month > dteThen.Month)
        // call, but I think this is more readable code.
        int intDaysInPrevMonth = System.DateTime.DaysInMonth(dteNow.Year, (dteNow.Month - 1));
        intDiffInDays = intDaysInPrevMonth - dteThen.Day + dteNow.Day;
    }

}

this.addToBox("Years: " + intDiffInYears + " Months: " + intDiffInMonths + " Days: " + intDiffInDays); // adds results to a rich text box.

}

Если вычесть два случаяDateTime, это вернет экземплярПромежуток времени, который будет представлять разницу между двумя датами.

 05 июл. 2009 г., 14:19
Самая большая единица времени, представленная TimeSpan - дни. Однако, поскольку оба года (високосный год) и месяцы различаются по длине, вам все равно придется сделать некоторую математику, чтобы выяснить их, и они не являются детерминированными, потому что фактические значения года имеют значение, но у вас не будет этой информации в самой структуре TimeSpan.

Ваш ответ на вопрос