В С#/.NET TimeSpan
имеет TotalDays
, TotalMinutes
и т.д., но я не могу найти формулу для общей разницы месяцев. Меняются переменные дни в месяц и високосные годы. Как я могу получить TotalMonths?
Изменить Извините за неясность: я знаю, что я не могу получить это от TimeSpan
, но я думал, что использование TotalDays
и TotalMinutes
будет хорошим примером для выражения того, что Я искал... кроме того, что я пытаюсь получить Total Months.
Пример: 25 декабря 2009 г. - 6 октября 2009 г. = 2 ВсегоМонты. 6 октября по 5 ноября составляет 0 месяцев. 6 ноября, 1 месяц. 6 декабря, 2 месяца
Ответ 1
Вы не сможете получить это от TimeSpan
, потому что "месяц" является переменной единицей измерения. Вам придется рассчитать его сами, и вам придется выяснить, как именно вы хотите, чтобы он работал.
Например, должны ли даты, подобные July 5, 2009
и August 4, 2009
, использовать разницу в один месяц или нулевой месяц? Если вы скажете, что он должен дать один, то что насчет July 31, 2009
и August 1, 2009
? Это месяц? Разве это просто разница значений Month
для дат или больше связана с фактическим периодом времени? Логика для определения всех этих правил является нетривиальной, поэтому вам придется определить свой собственный и реализовать соответствующий алгоритм.
Если все, что вам нужно, просто разница в месяцах - полностью игнорируя значения даты - тогда вы можете использовать это:
public static int MonthDifference(this DateTime lValue, DateTime rValue)
{
return (lValue.Month - rValue.Month) + 12 * (lValue.Year - rValue.Year);
}
Обратите внимание, что это возвращает относительную разницу, а это означает, что если rValue
больше, чем lValue
, тогда возвращаемое значение будет отрицательным. Если вы хотите абсолютную разницу, вы можете использовать это:
public static int MonthDifference(this DateTime lValue, DateTime rValue)
{
return Math.Abs((lValue.Month - rValue.Month) + 12 * (lValue.Year - rValue.Year));
}
Ответ 2
(Я понимаю, что это старый вопрос, но...)
Это относительно больно делать в чистом .NET. Я бы рекомендовал свою собственную библиотеку Noda Time, которая специально предназначена для таких вещей:
LocalDate start = new LocalDate(2009, 10, 6);
LocalDate end = new LocalDate(2009, 12, 25);
Period period = Period.Between(start, end);
int months = period.Months;
(Существуют и другие варианты, например, если вам нужно только количество месяцев в разные годы, вы должны использовать Period period = Period.Between(start, end, PeriodUnits.Months);
)
Ответ 3
Возможно, вы не хотите знать о дробях в месяц; Как насчет этого кода?
public static class DateTimeExtensions
{
public static int TotalMonths(this DateTime start, DateTime end)
{
return (start.Year * 12 + start.Month) - (end.Year * 12 + end.Month);
}
}
// Console.WriteLine(
// DateTime.Now.TotalMonths(
// DateTime.Now.AddMonths(-1))); // prints "1"
Ответ 4
Вам нужно будет определить, что вы подразумеваете под TotalMonths для начала.
Простое определение помещает месяц в 30.4 дней (365.25/12).
Кроме того, любое определение, включающее дроби, кажется бесполезным, и более общее целочисленное значение (целые месяцы между датами) также зависит от нестандартных бизнес-правил.
Ответ 5
Вам нужно самому работать с датами. Как вы справляетесь со временем окончания в конце будет зависеть от того, что вы хотите использовать для.
Один из способов - подсчитать месяц и затем исправить дни в конце. Что-то вроде:
DateTime start = new DateTime(2003, 12, 25);
DateTime end = new DateTime(2009, 10, 6);
int compMonth = (end.Month + end.Year * 12) - (start.Month + start.Year * 12);
double daysInEndMonth = (end - end.AddMonths(1)).Days;
double months = compMonth + (start.Day - end.Day) / daysInEndMonth;
Ответ 6
Я написал очень простой метод расширения для DateTime
и DateTimeOffset
для этого. Я хотел, чтобы он работал точно так же, как и свойство TotalMonths
на TimeSpan
, то есть вернул счетчик полных месяцев между двумя датами, игнорируя любые частичные месяцы. Поскольку он основан на DateTime.AddMonths()
, он соблюдает разные месяцы и возвращает то, что человек понимает как период месяцев.
(К сожалению, вы не можете реализовать его как метод расширения в TimeSpan, потому что это не сохраняет знания о фактических датах, и в течение нескольких месяцев они важны.)
Код и тесты являются доступными на GitHub. Код очень прост:
public static int GetTotalMonthsFrom(this DateTime dt1, DateTime dt2)
{
DateTime earlyDate = (dt1 > dt2) ? dt2.Date : dt1.Date;
DateTime lateDate = (dt1 > dt2) ? dt1.Date : dt2.Date;
// Start with 1 month difference and keep incrementing
// until we overshoot the late date
int monthsDiff = 1;
while (earlyDate.AddMonths(monthsDiff) <= lateDate)
{
monthsDiff++;
}
return monthsDiff - 1;
}
И он передает все эти случаи unit test:
// Simple comparison
Assert.AreEqual(1, new DateTime(2014, 1, 1).GetTotalMonthsFrom(new DateTime(2014, 2, 1)));
// Just under 1 month diff
Assert.AreEqual(0, new DateTime(2014, 1, 1).GetTotalMonthsFrom(new DateTime(2014, 1, 31)));
// Just over 1 month diff
Assert.AreEqual(1, new DateTime(2014, 1, 1).GetTotalMonthsFrom(new DateTime(2014, 2, 2)));
// 31 Jan to 28 Feb
Assert.AreEqual(1, new DateTime(2014, 1, 31).GetTotalMonthsFrom(new DateTime(2014, 2, 28)));
// Leap year 29 Feb to 29 Mar
Assert.AreEqual(1, new DateTime(2012, 2, 29).GetTotalMonthsFrom(new DateTime(2012, 3, 29)));
// Whole year minus a day
Assert.AreEqual(11, new DateTime(2012, 1, 1).GetTotalMonthsFrom(new DateTime(2012, 12, 31)));
// Whole year
Assert.AreEqual(12, new DateTime(2012, 1, 1).GetTotalMonthsFrom(new DateTime(2013, 1, 1)));
// 29 Feb (leap) to 28 Feb (non-leap)
Assert.AreEqual(12, new DateTime(2012, 2, 29).GetTotalMonthsFrom(new DateTime(2013, 2, 28)));
// 100 years
Assert.AreEqual(1200, new DateTime(2000, 1, 1).GetTotalMonthsFrom(new DateTime(2100, 1, 1)));
// Same date
Assert.AreEqual(0, new DateTime(2014, 8, 5).GetTotalMonthsFrom(new DateTime(2014, 8, 5)));
// Past date
Assert.AreEqual(6, new DateTime(2012, 1, 1).GetTotalMonthsFrom(new DateTime(2011, 6, 10)));
Ответ 7
Я бы сделал это следующим образом:
static int TotelMonthDifference(this DateTime dtThis, DateTime dtOther)
{
int intReturn = 0;
dtThis = dtThis.Date.AddDays(-(dtThis.Day-1));
dtOther = dtOther.Date.AddDays(-(dtOther.Day-1));
while (dtOther.Date > dtThis.Date)
{
intReturn++;
dtThis = dtThis.AddMonths(1);
}
return intReturn;
}
Ответ 8
На этот вопрос не так много четких ответов, потому что вы всегда предполагаете что-то.
Это решение вычисляет между двумя датами месяцы между тем, если вы хотите сохранить день месяца для сравнения (это означает, что день месяца учитывается при расчете)
Например, если у вас дата 30 января 2012 года, 29 февраля 2012 года будет не месяцем, а 01 марта 2013 года.
Он был довольно тщательно протестирован, возможно, позже будет очищен, когда мы его используем, и использует две даты вместо промежутка времени, что, вероятно, лучше. Надеюсь, это поможет кому-нибудь еще.
private static int TotalMonthDifference(DateTime dtThis, DateTime dtOther)
{
int intReturn = 0;
bool sameMonth = false;
if (dtOther.Date < dtThis.Date) //used for an error catch in program, returns -1
intReturn--;
int dayOfMonth = dtThis.Day; //captures the month of day for when it adds a month and doesn't have that many days
int daysinMonth = 0; //used to caputre how many days are in the month
while (dtOther.Date > dtThis.Date) //while Other date is still under the other
{
dtThis = dtThis.AddMonths(1); //as we loop, we just keep adding a month for testing
daysinMonth = DateTime.DaysInMonth(dtThis.Year, dtThis.Month); //grabs the days in the current tested month
if (dtThis.Day != dayOfMonth) //Example 30 Jan 2013 will go to 28 Feb when a month is added, so when it goes to march it will be 28th and not 30th
{
if (daysinMonth < dayOfMonth) // uses day in month max if can't set back to day of month
dtThis.AddDays(daysinMonth - dtThis.Day);
else
dtThis.AddDays(dayOfMonth - dtThis.Day);
}
if (((dtOther.Year == dtThis.Year) && (dtOther.Month == dtThis.Month))) //If the loop puts it in the same month and year
{
if (dtOther.Day >= dayOfMonth) //check to see if it is the same day or later to add one to month
intReturn++;
sameMonth = true; //sets this to cancel out of the normal counting of month
}
if ((!sameMonth)&&(dtOther.Date > dtThis.Date))//so as long as it didn't reach the same month (or if i started in the same month, one month ahead, add a month)
intReturn++;
}
return intReturn; //return month
}
Ответ 9
Старый вопрос я знаю, но может кому-то помочь. Я использовал ответ, принятый @Adam выше, но затем проверил, является ли разница 1 или -1, затем проверьте, является ли это полная разница календарного месяца. Таким образом, 21/07/55 и 20/08/55 не будет полным месяцем, а 21/07/55 и 21/07/55 будет.
/// <summary>
/// Amended date of birth cannot be greater than or equal to one month either side of original date of birth.
/// </summary>
/// <param name="dateOfBirth">Date of birth user could have amended.</param>
/// <param name="originalDateOfBirth">Original date of birth to compare against.</param>
/// <returns></returns>
public JsonResult ValidateDateOfBirth(string dateOfBirth, string originalDateOfBirth)
{
DateTime dob, originalDob;
bool isValid = false;
if (DateTime.TryParse(dateOfBirth, out dob) && DateTime.TryParse(originalDateOfBirth, out originalDob))
{
int diff = ((dob.Month - originalDob.Month) + 12 * (dob.Year - originalDob.Year));
switch (diff)
{
case 0:
// We're on the same month, so ok.
isValid = true;
break;
case -1:
// The month is the previous month, so check if the date makes it a calendar month out.
isValid = (dob.Day > originalDob.Day);
break;
case 1:
// The month is the next month, so check if the date makes it a calendar month out.
isValid = (dob.Day < originalDob.Day);
break;
default:
// Either zero or greater than 1 month difference, so not ok.
isValid = false;
break;
}
if (!isValid)
return Json("Date of Birth cannot be greater than one month either side of the date we hold.", JsonRequestBehavior.AllowGet);
}
else
{
return Json("Date of Birth is invalid.", JsonRequestBehavior.AllowGet);
}
return Json(true, JsonRequestBehavior.AllowGet);
}
Ответ 10
case IntervalType.Month:
returnValue = start.AddMonths(-end.Month).Month.ToString();
break;
case IntervalType.Year:
returnValue = (start.Year - end.Year).ToString();
break;
Ответ 11
Принятый ответ отлично работает, когда вы хотите полных месяцев.
Мне понадобились неполные месяцы. Это решение, которое я придумал за неполные месяцы:
/// <summary>
/// Calculate the difference in months.
/// This will round up to count partial months.
/// </summary>
/// <param name="lValue"></param>
/// <param name="rValue"></param>
/// <returns></returns>
public static int MonthDifference(DateTime lValue, DateTime rValue)
{
var yearDifferenceInMonths = (lValue.Year - rValue.Year) * 12;
var monthDifference = lValue.Month - rValue.Month;
return yearDifferenceInMonths + monthDifference +
(lValue.Day > rValue.Day
? 1 : 0); // If end day is greater than start day, add 1 to round up the partial month
}
Мне также нужна была разница в году с той же потребностью в неполных годах. Вот решение, которое я придумал:
/// <summary>
/// Calculate the differences in years.
/// This will round up to catch partial months.
/// </summary>
/// <param name="lValue"></param>
/// <param name="rValue"></param>
/// <returns></returns>
public static int YearDifference(DateTime lValue, DateTime rValue)
{
return lValue.Year - rValue.Year +
(lValue.Month > rValue.Month // Partial month, same year
? 1
: ((lValue.Month = rValue.Month)
&& (lValue.Day > rValue.Day)) // Partial month, same year and month
? 1 : 0);
}
Ответ 12
Проблема с месяцами заключается в том, что это не простая мера - они не являются постоянными. Вам нужно будет определить свои правила для того, что вы хотите включить, и работать оттуда. Например, с 1 января по 1 февраля - вы можете утверждать, что там участвуют 2 месяца, или вы можете сказать, что это один месяц. Тогда как насчет "1 января 20:00" до "1 февраля 00:00" - это не совсем полный месяц. Это 0? 1? как насчет другого пути (1 января 00:00 до 1 февраля 20:00)... 1? 2?
Сначала определите правила, тогда вам придется самому закодировать их, я боюсь...
Ответ 13
Если вы хотите получить результат 1
между 28th Feb
и 1st March
:
DateTime date1, date2;
int monthSpan = (date2.Year - date1.Year) * 12 + date2.Month - date1.Month
Ответ 14
Эта библиотека вычисляет разницу в месяцах, учитывая все части DateTime:
// ----------------------------------------------------------------------
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
} // DateDiffSample
Ответ 15
Ниже на самом деле самый точный способ, которым вы можете это сделать, поскольку определение "1 месяц" изменяется в зависимости от того, в каком месяце оно находится, а остальные ответы учитывают это! Если вам нужна дополнительная информация о проблеме, которая не встроена в фреймворк, вы можете прочитать это сообщение: Объект реального времени с .Years и .Months (однако, прочитав этот пост не нужен, чтобы понять и использовать функцию ниже, он работает на 100%, без присущих неточностей приближения, которые другие любят использовать - и не стесняйтесь заменить функцию .ReverseIt встроенной функцией .Reverse, вы можете иметь на вашем фреймворке (он здесь только для полноты).
Обратите внимание, что вы можете получить любое количество дат/времени, секунды, минуты или минуты, минуты и минуты, в любом месте до нескольких лет (что будет содержать 6 частей/сегментов). Если вы укажете две верхние и более года, она вернется "1 год и 3 месяца назад" и не вернет остальных, потому что вы запросили два сегмента. если ему всего несколько часов, тогда он вернется только "2 часа и 1 минута назад". Конечно, те же правила применяются, если вы укажете 1, 2, 3, 4, 5 или 6 segmets (максимум на 6, поскольку секунды, минуты, часы, дни, месяцы, годы составляют только 6 типов). Он также будет исправлять проблемы с грамматикой, такие как "минуты" и "минута", в зависимости от того, будет ли она 1 минута или более, одинаковой для всех типов, а генерируемая строка будет всегда грамматически корректной.
Вот несколько примеров использования:
bAllowSegments определяет количество сегментов для отображения... то есть: если 3, то возвращаемая строка будет (в качестве примера)... "3 years, 2 months and 13 days"
(не будет включать в себя часы, минуты и секунды, когда вернутся 3 категории времени), если, однако, дата была более новой датой, например, что-то несколько дней назад, указав одни и те же сегменты (3), вместо этого вернет "4 days, 1 hour and 13 minutes ago"
, поэтому это учитывает все!
если bAllowSegments равно 2, он вернет "3 years and 2 months"
, и если 6 (максимальное значение) вернет "3 years, 2 months, 13 days, 13 hours, 29 minutes and 9 seconds"
, но напомните, что он будет NEVER RETURN
что-то вроде этого "0 years, 0 months, 0 days, 3 hours, 2 minutes and 13 seconds ago"
, поскольку он понимает, что нет данных даты в верхних 3 сегментах и игнорирует их, даже если вы укажете 6 сегментов, так что не беспокойтесь:). Конечно, если в нем есть сегмент с 0, он учитывает это при формировании строки и будет отображаться как "3 days and 4 seconds ago"
и игнорирует часть "0 часов"! Наслаждайтесь и прокомментируйте, если хотите.
Public Function RealTimeUntilNow(ByVal dt As DateTime, Optional ByVal bAllowSegments As Byte = 2) As String
' bAllowSegments identifies how many segments to show... ie: if 3, then return string would be (as an example)...
' "3 years, 2 months and 13 days" the top 3 time categories are returned, if bAllowSegments is 2 it would return
' "3 years and 2 months" and if 6 (maximum value) would return "3 years, 2 months, 13 days, 13 hours, 29 minutes and 9 seconds"
Dim rYears, rMonths, rDays, rHours, rMinutes, rSeconds As Int16
Dim dtNow = DateTime.Now
Dim daysInBaseMonth = Date.DaysInMonth(dt.Year, dt.Month)
rYears = dtNow.Year - dt.Year
rMonths = dtNow.Month - dt.Month
If rMonths < 0 Then rMonths += 12 : rYears -= 1 ' add 1 year to months, and remove 1 year from years.
rDays = dtNow.Day - dt.Day
If rDays < 0 Then rDays += daysInBaseMonth : rMonths -= 1
rHours = dtNow.Hour - dt.Hour
If rHours < 0 Then rHours += 24 : rDays -= 1
rMinutes = dtNow.Minute - dt.Minute
If rMinutes < 0 Then rMinutes += 60 : rHours -= 1
rSeconds = dtNow.Second - dt.Second
If rSeconds < 0 Then rSeconds += 60 : rMinutes -= 1
' this is the display functionality
Dim sb As StringBuilder = New StringBuilder()
Dim iSegmentsAdded As Int16 = 0
If rYears > 0 Then sb.Append(rYears) : sb.Append(" year" & If(rYears <> 1, "s", "") & ", ") : iSegmentsAdded += 1
If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn
If rMonths > 0 Then sb.AppendFormat(rMonths) : sb.Append(" month" & If(rMonths <> 1, "s", "") & ", ") : iSegmentsAdded += 1
If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn
If rDays > 0 Then sb.Append(rDays) : sb.Append(" day" & If(rDays <> 1, "s", "") & ", ") : iSegmentsAdded += 1
If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn
If rHours > 0 Then sb.Append(rHours) : sb.Append(" hour" & If(rHours <> 1, "s", "") & ", ") : iSegmentsAdded += 1
If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn
If rMinutes > 0 Then sb.Append(rMinutes) : sb.Append(" minute" & If(rMinutes <> 1, "s", "") & ", ") : iSegmentsAdded += 1
If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn
If rSeconds > 0 Then sb.Append(rSeconds) : sb.Append(" second" & If(rSeconds <> 1, "s", "") & "") : iSegmentsAdded += 1
parseAndReturn:
' if the string is entirely empty, that means it was just posted so its less than a second ago, and an empty string getting passed will cause an error
' so we construct our own meaningful string which will still fit into the "Posted * ago " syntax...
If sb.ToString = "" Then sb.Append("less than 1 second")
Return ReplaceLast(sb.ToString.TrimEnd(" ", ",").ToString, ",", " and")
End Function
Конечно, вам понадобится функция "ReplaceLast", которая берет исходную строку и аргумент, определяющий, что нужно заменить, и другой аргумент, определяющий, что вы хотите заменить, и он заменяет только последнее событие из этой строки... я включил мой, если у вас его нет или он не хочет его реализовывать, так что вот он, он будет работать "как есть" без каких-либо изменений. Я знаю, что функция reverseit больше не нужна (существует в .net), но функции ReplaceLast и ReverseIt переносятся с дней pre -.net, поэтому, пожалуйста, извините, как это датируется (все еще работает 100% tho, используется em более десяти лет, может гарантировать, что они являются ошибками бесплатно)...:). веселит.
<Extension()> _
Public Function ReplaceLast(ByVal sReplacable As String, ByVal sReplaceWhat As String, ByVal sReplaceWith As String) As String
' let empty string arguments run, incase we dont know if we are sending and empty string or not.
sReplacable = sReplacable.ReverseIt
sReplacable = Replace(sReplacable, sReplaceWhat.ReverseIt, sReplaceWith.ReverseIt, , 1) ' only does first item on reversed version!
Return sReplacable.ReverseIt.ToString
End Function
<Extension()> _
Public Function ReverseIt(ByVal strS As String, Optional ByVal n As Integer = -1) As String
Dim strTempX As String = "", intI As Integer
If n > strS.Length Or n = -1 Then n = strS.Length
For intI = n To 1 Step -1
strTempX = strTempX + Mid(strS, intI, 1)
Next intI
ReverseIt = strTempX + Right(strS, Len(strS) - n)
End Function
Ответ 16
Если вы хотите получить точный номер, вы не можете использовать только Timespan, так как вам нужно знать, какие месяцы вы имеете в виду, и имеете ли вы дело с високосным годом, как вы сказали.
Либо идите для приблизительного числа, либо выполните некоторую фальсификацию с исходными DateTimes
Ответ 17
http://www.astro.uu.nl/~strous/AA/en/reken/juliaansedag.html
Если вы можете получить время, преобразованное из григорианской даты, в число юлианских дней, вы можете просто создать оператора для сравнения zulian day number, который может быть типом double, чтобы получить месяцы, дни, секунды и т.д. Проверьте приведенную выше ссылку на алгоритм преобразования от григорианского к юлианскому.
Ответ 18
Нет встроенного способа сделать это точно в idiomatic-С#. Есть некоторые обходные пути, такие как этот пример CodeProject, который люди закодировали.
Ответ 19
Если вы имеете дело с месяцами и годами, вам нужно что-то, что знает, сколько дней каждый месяц имеет и какие годы високосные годы.
Введите Григорианский календарь (и другие культурные Calendar).
В то время как Календарь не предоставляет методы для прямого вычисления разницы между двумя точками во времени, у него есть методы, такие как
DateTime AddWeeks(DateTime time, int weeks)
DateTime AddMonths(DateTime time, int months)
DateTime AddYears(DateTime time, int years)
Ответ 20
DateTime start = new DateTime(2003, 12, 25);
DateTime end = new DateTime(2009, 10, 6);
int compMonth = (end.Month + end.Year * 12) - (start.Month + start.Year * 12);
double daysInEndMonth = (end - end.AddMonths(1)).Days;
double months = compMonth + (start.Day - end.Day) / daysInEndMonth;
Ответ 21
Метод возвращает список, содержащий 3 элемента: первый год, второй - месяц и конец - день:
public static List<int> GetDurationInEnglish(DateTime from, DateTime to)
{
try
{
if (from > to)
return null;
var fY = from.Year;
var fM = from.Month;
var fD = DateTime.DaysInMonth(fY, fM);
var tY = to.Year;
var tM = to.Month;
var tD = DateTime.DaysInMonth(tY, tM);
int dY = 0;
int dM = 0;
int dD = 0;
if (fD > tD)
{
tM--;
if (tM <= 0)
{
tY--;
tM = 12;
tD += DateTime.DaysInMonth(tY, tM);
}
else
{
tD += DateTime.DaysInMonth(tY, tM);
}
}
dD = tD - fD;
if (fM > tM)
{
tY--;
tM += 12;
}
dM = tM - fM;
dY = tY - fY;
return new List<int>() { dY, dM, dD };
}
catch (Exception exception)
{
//todo: log exception with parameters in db
return null;
}
}
Ответ 22
Вот мой вклад, чтобы получить разницу в месяцах, которые я нашел точными:
namespace System
{
public static class DateTimeExtensions
{
public static Int32 DiffMonths( this DateTime start, DateTime end )
{
Int32 months = 0;
DateTime tmp = start;
while ( tmp < end )
{
months++;
tmp = tmp.AddMonths( 1 );
}
return months;
}
}
}
Использование:
Int32 months = DateTime.Now.DiffMonths( DateTime.Now.AddYears( 5 ) );
Вы можете создать другой метод под названием DiffYears и применить точно такую же логику, как указано выше, и AddYears вместо AddMonths в цикле while.
Ответ 23
Поздно, но я думаю, что это может быть полезно кому-то. Большинство людей, как правило, измеряют месяц за месяцем по дате, исключая тот факт, что месяцы приходят в разных вариантах. Используя эту мысль, я создал один лайнер, который сравнивает даты для нас. Используя следующий процесс.
- Любые # лет старше 1 года, когда год сравнения будет умножен на 12, нет случая, когда это может быть равно менее 1 года.
- Если конечный год больше, нам нужно оценить, больше ли текущий день или равен предыдущему дню
2А. Если конечный день больше или равен, мы берем текущий месяц, а затем добавляем 12 месяцев, чтобы вычесть месяц начала месяца
2B. Если конечный день меньше начального дня, мы выполняем те же действия, что и выше, за исключением того, что мы добавляем 1 к стартовому месяцу, прежде чем вычесть
-
Если конечный год не больше, мы выполняем то же самое, что и 2A/2B, но не добавляем 12 месяцев, потому что нам не нужно оценивать в течение года.
DateTime date = new DateTime(2003, 11, 25);
DateTime today = new DateTime(2004, 12, 26);
var time = (today.Year - date.Year > 1 ? (today.Year - date.Year - 1) * 12 : 0) + (today.Year > date.Year ? (today.Day >= date.Day ? today.Month + 12 - date.Month : today.Month + 12 - (date.Month + 1)) : (today.Day >= date.Day ? today.Month - date.Month : today.Month - (date.Month + 1)));
Ответ 24
Рассчитайте количество месяцев между 2 датами:
$date1 = '2017-01-20';
$date2 = '2019-01-20';
$ts1 = strtotime($date1);
$ts2 = strtotime($date2);
$year1 = date('Y', $ts1);
$year2 = date('Y', $ts2);
$month1 = date('m', $ts1);
$month2 = date('m', $ts2);
echo $joining_months = (($year2 - $year1) * 12) + ($month2 - $month1);
Ответ 25
DateTime dtEnd = DateTime.Now.AddDays(59);
DateTime dtBegin = DateTime.Now;
var diff = (dtEnd-dtBegin).TotalDays;
lblDateDiff.Text = Math.Floor(diff/30).ToString() + " month('s) and " + (diff%30).ToString() + " days";
возвращает 1 месяц и 29 дней.
Конечно, это зависит от того, сколько месяцев составляет 30 дней.. но это довольно близко к правильному значению дней и месяцев между датами.