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

Как получить разницу между двумя датами в Год/Месяц/Неделя/День эффективным способом?

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

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

Ответ 1

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

  • 19 июня 2008 года по 19 июня 2010 года = 2 года, но также 365 * 2 дня

  • 19 июня 2006 года по 19 июня 2008 года = 2 года, но также 365 + 366 дней из-за високосных годов

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

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

Еще одна путаница (может быть, не актуальна): даже день не всегда 24 часа. Летний уход за кем-нибудь?

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

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

EDIT: К сожалению, у меня не будет достаточно времени, чтобы полностью ответить на этот вопрос. Я бы предложил начать с определения структуры, представляющей 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;

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

Ответ 2

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

Результаты являются окончательными: ни один из кодовых вкладов точно не отвечает на вопрос. Обновление: теперь у меня есть четыре правильных решения для этого вопроса, включая мои собственные, см. обновления ниже.

Проверено код

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

Это были ответы на все три года, месяцы и дни в их коде. Обратите внимание, что два из них, Дэйв и Яни, дали общее количество дней и месяцев, а не общее количество месяцев, оставшихся после подсчета лет, и общее количество дней, оставшихся после подсчета месяцев. Я думаю, что ответы неверны с точки зрения того, что, по-видимому, ожидал ОП, но, очевидно, в этих случаях тесты единицы не говорят вам об этом. (Обратите внимание, что в случае с Jani это была моя ошибка, и его код был прав - см. обновление 4 ниже)

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

Другие ответы, которые я тестировал, были из

  • вопрос 3054715 - LukeH, ho1 и это. ___ curious_geek
  • вопрос 6260372 - Чак Ростенс и Яни (тот же ответ, что и этот вопрос)
  • вопрос 9 (!) - Дилан Хейс, Джон и Раджешваран S P

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

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

Как я протестировал

Довольно просто: я создал интерфейс

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 достаточно умен, чтобы сделать все остальное.

Тесты

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

[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);
  }
}

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

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

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

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

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

Результаты

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

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

Но обратите внимание, что решение Jani было действительно правильным и прошло все тесты - см. обновление 4 ниже.

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

  • AlmostThreeYearsTest
  • AlmostTwoYearsTest
  • BasicTest
  • BornOnALeapYearTest
  • BornOnALeapYearTest2
  • LongMonthToLongMonth
  • LongMonthToLongMonthPenultimateDay
  • LongMonthToPartWayThruShortMonth
  • LongMonthToShortMonth

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

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

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

Мои выводы

Есть три:

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

  • Написание правильного кода сложно. Было много ошибок. В несколько более неясных темах или менее популярных вопросах, чем шансы на ошибку, не отмеченные комментатором, намного выше, чем для этого вопроса. Вы никогда не должны, никогда не копируете код из SO в свою программу, не понимая, что именно он делает. Это означает, что вы, вероятно, не должны писать код в своем ответе, который готов к копированию и вставке, а скорее интеллектуальный и выразительный псевдокод, который позволяет кому-то понять решение и реализовать свою собственную версию (со своими ошибками!)

  • Тестирование модулей полезно. Я все еще хочу опубликовать свое собственное решение, когда я подхожу к нему (чтобы кто-то еще нашел скрытые неверные предположения!). Это был отличный пример "сохранения ошибок", превратив их в модульные тесты на исправить следующую версию кода с помощью.

Update

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

Обновление 2

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

Обновление 3

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

Обновление 4

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

Ответ 3

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

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;
}

Ответ 4

Для правильного разностного расчета Years/Months/Week следует учитывать Календарь CultureInfo:

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

Класс DateDiff библиотеки Time Period для .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 также вычисляет разницу Quarters.

Ответ 5

Как насчет использования пространства имен 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);

== > 4

В классе SqlMethods существуют другие статические методы DateDiff.

Ответ 6

Вычтите два экземпляра 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, а с 2004-02-29 в зависимости от того, что вы подразумеваете под "Годом".

Ответ 7

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

Ответ 8

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

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

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

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

(Если ваш месяц "Месяц" меньше вашего месяца "В", нет проблем. Каждый год имеет 12 месяцев.)

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

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

(EDIT: Изменено NewMonth > Проверка OldMonth на NewMonth >= OldMonth, так как нам не нужно брать один, если месяцы одинаковые (то же самое в течение нескольких дней). То есть, 11 ноября 2011 года минус 9 ноября 2010 года -1 год, 12 месяцев, 2 дня (т.е. 2 ​​дня, но королевский, который мы заимствовали, когда роялти не нужно было.)

(EDIT: нужно было проверить месяц = ​​месяц, когда нам нужно было занять дни, чтобы вычесть dteThen.Day из dteNow.Day и dteNow.Day < dteThen.Day, так как нам пришлось вычитать год, чтобы получить 11 месяцев и дополнительные дни. Хорошо, так что есть несколько выбросов. ^ DI думаю, что я близко.)

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 
            // 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 the previous month (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 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 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 only 10.
    // Diff in months is (Months in year == 12) - (Months lost between 1/1/1999 and 6/15/1999
    // when dteThen clock wasn't yet rolling == 6) = 6 months, then you add the months we
    // have made it into this year already.  The clock 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.

}

Ответ 9

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)

Ответ 10

Я столкнулся с этим сообщением, пытаясь решить подобную проблему. Я пытался найти возраст животного в единицах Годов, Месяцев, Недели и Дней. Эти значения затем отображаются в 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 ограничены, чтобы разрешить только >= 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");

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

Ответ 11

Дни: (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;
    }

Ответ 12

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

  • Объявить переменную intermediateDate и инициализировать исходный файл
  • Найдите разницу между годами. (yearDiff)
  • Добавьте yearDiff в intermediateDate и проверьте, больше ли это значение на сегодняшний день.
  • Если недавно полученная промежуточная датa > сегодняшняя дата скорректирует yearDiff и intermediateDate на единицу.
  • Продолжайте выполнять шаги за месяц и дни.

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

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

Ответ 13

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.";

    }

Ответ 14

Используйте Noda Time:

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

Ответ 15

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.Year - 1, потому что год 0 не существует. date.Month - 1, месяц 0 не существует

Ответ 16

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

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 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 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;    
    }
}

Ответ 17

Используйте метод 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;

Ответ 18

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

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

Ожидаемое: < 24 > . Фактический: < 12 >

Ответ 19

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

        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";
        }

Ответ 20

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

Ответ 21

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