[英]Calculate Years, Months, weeks and Days
在我的應用程序中,用戶輸入兩個日期。 預定的開始日期和預定的結束日期。 我們必須獲取這些日期,並根據差異填充 4 個字段。
所以,假設他選擇 2010 年 1 月 1 日作為開始,2011 年 3 月 2 日作為結束,我們需要以:
年:1 月:2 周:0 天 1
這意味着總持續時間為 1 年 2 個月零 1 天。
有這樣做的標准方法嗎? 或者我是否需要編寫一個具有很多非常棘手的邏輯的方法來解決這個問題? 我希望我很幸運,並且會有一個日期差異類型.Net class 可用。
這是一個完整的方法,周數不包括在內,但可以相對簡單地添加。 這是一個有點復雜的問題(在 stackoverflow 上以多種方式提出並以多種方式回答得很差),但仍然可以回答。 TimeSpan object 為我們提供了部分所需內容,但只能持續幾天。 我已經針對此方法編寫了大量測試,如果您發現漏洞,請發表評論。
這將做的是比較 2 個日期,獲取年、月、日、小時和分鍾。 (例如,某些事件發生在 1 年、6 個月、3 天、4 小時和 7 分鍾前)
因為這個問題已經被問過很多次並試圖回答很多次,所以我不確定它是否會被注意到,但如果是這樣的話,它應該會提供價值。
public static void TimeSpanToDateParts(DateTime d1, DateTime d2, out int years, out int months, out int days, out int hours, out int minutes)
{
if (d1 < d2)
{
var d3 = d2;
d2 = d1;
d1 = d3;
}
var span = d1 - d2;
months = 12 * (d1.Year - d2.Year) + (d1.Month - d2.Month);
//month may need to be decremented because the above calculates the ceiling of the months, not the floor.
//to do so we increase d2 by the same number of months and compare.
//(500ms fudge factor because datetimes are not precise enough to compare exactly)
if (d1.CompareTo(d2.AddMonths(months).AddMilliseconds(-500)) <= 0)
{
--months;
}
years = months / 12;
months -= years * 12;
if (months == 0 && years == 0)
{
days = span.Days;
}
else
{
var md1 = new DateTime(d1.Year, d1.Month, d1.Day);
// Fixed to use d2.Day instead of d1.Day
var md2 = new DateTime(d2.Year, d2.Month, d2.Day);
var mDays = (int) (md1 - md2).TotalDays;
if (mDays > span.Days)
{
mDays = (int)(md1.AddMonths(-1) - md2).TotalDays;
}
days = span.Days - mDays;
}
hours = span.Hours;
minutes = span.Minutes;
}
您可以使用此免費庫的DateDiff class:
// ----------------------------------------------------------------------
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
我也需要這個,但就我而言,沒有周部分(所以只有年、月和日)。 鑒於此,這就是我所做的:
DateTime startDate = DateTime.ParseExact (start, "dd/MM/yyyy",CultureInfo.InvariantCulture);
DateTime endDate = DateTime.ParseExact (end, "dd/MM/yyyy",CultureInfo.InvariantCulture);
int days=0;
int months = 0;
int years = 0;
//calculate days
if (endDate.Day >= startDate.Day) {
days = endDate.Day - startDate.Day;
} else {
var tempDate = endDate.AddMonths (-1);
int daysInMonth = DateTime.DaysInMonth (tempDate.Year, tempDate.Month);
days = daysInMonth - (startDate.Day - endDate.Day);
months--;
}
//calculate months
if (endDate.Month >= startDate.Month) {
months+=endDate.Month - startDate.Month;
} else {
months+= 12 - (startDate.Month - endDate.Month);
years--;
}
//calculate years
years+=endDate.Year - startDate.Year;
Debug.WriteLine (string.Format("{0} years, {1} months, {2} days",years,months,days));
如果你想更動態地顯示這個,你也可以使用這個代碼:
//build the string
var result = "";
if (years!=0){
result = years == 1 ? years + " year" : years + " years";
}
if (months != 0) {
if (result != "") {
result += ", ";
}
result += months == 1 ? months + " month" : months + " months";
}
if (days != 0) {
if (result != "") {
result += ", ";
}
result += days == 1 ? days + " day" : days + " days";
}
Debug.WriteLine (result);
應該這樣做。 關鍵是如果給定的 2 個日期之間有奇數個閏日,則將天數減 1。
/// <summary>
/// //Assume DateTime dt1 < DateTime dt2, print out difference between dt1 to dt2 in years, months, weeks and days
/// </summary>
/// <param name="dt1"></param>
/// <param name="dt2"></param>
static void DateDiff(DateTime dt1, DateTime dt2)
{
DateTime zeroTime = new DateTime(1, 1, 1);
int leapDaysInBetween = CountLeapDays(dt1, dt2);
TimeSpan span = dt2 - dt1;
int years = (zeroTime + span).Year - 1;
int months = (zeroTime + span).Month - 1;
int days = (zeroTime + span).Day - (leapDaysInBetween % 2 == 1 ? 1 : 0);
int weeks = days / 7;
int remainingdays = days % 7;
Console.WriteLine(String.Format("\nThe difference between date {0} and date {1} is: \n\t {2} year(s), {3} month(s), and {4} day(s).", dt1, dt2, years, months, days));
Console.WriteLine(String.Format("\nThe difference between date {0} and date {1} is: \n\t {2} year(s), {3} month(s), {4} week(s) and {5} day(s).", dt1, dt2, years, months, weeks, remainingdays));
}
private static int CountLeapDays(DateTime dt1, DateTime dt2)
{
int leapDaysInBetween = 0;
int year1 = dt1.Year, year2 = dt2.Year;
DateTime dateValue;
for (int i = year1; i <= year2; i++)
{
if (DateTime.TryParse("02/29/" + i.ToString(), out dateValue))
{
if (dateValue >= dt1 && dateValue <= dt2)
leapDaysInBetween++;
}
}
return leapDaysInBetween;
}
運行了這些測試:
static void Main(string[] args)
{
DateDiff(new DateTime(2010, 1, 1), new DateTime(2012, 2, 9));
DateDiff(new DateTime(2010, 1, 1), new DateTime(2012, 4, 9));
DateDiff(new DateTime(2010, 1, 1), new DateTime(2020, 2, 9));
DateDiff(new DateTime(2010, 1, 1), new DateTime(2020, 4, 9));
DateDiff(new DateTime(2020, 2, 29), new DateTime(2021, 2, 28));
DateDiff(new DateTime(2019, 2, 28), new DateTime(2021, 2, 28));
}
這些是打印輸出:
日期 1/1/2010 12:00:00 AM 和日期 4/9/2012 12:00:00 AM 之間的差異是:2 年、3 個月和 9 天。
日期 1/1/2010 12:00:00 AM 和日期 4/9/2012 12:00:00 AM 之間的差異是:2 年、3 個月、1 周和 2 天(s).
日期 1/1/2010 12:00:00 AM 和日期 2/9/2020 12:00:00 AM 之間的差異是:10 年、1 個月和 9 天。
日期 1/1/2010 12:00:00 AM 和日期 2/9/2020 12:00:00 AM 之間的差異是:10 年、1 個月、1 周和 2 天(s).
日期 1/1/2010 12:00:00 AM 和日期 4/9/2020 12:00:00 AM 之間的差異是:10 年、3 個月和 9 天。
日期 1/1/2010 12:00:00 AM 和日期 4/9/2020 12:00:00 AM 之間的差異是:10 年、3 個月、1 周和 2 天(s).
日期 2/29/2020 12:00:00 AM 和日期 2/28/2021 12:00:00 AM 之間的差異是:1 年、0 個月和 0 天。
日期 2/29/2020 12:00:00 AM 和日期 2/28/2021 12:00:00 AM 之間的差異是:1 年、0 個月、0 周和 0 天(s).
日期 2/28/2019 12:00:00 AM 和日期 2/28/2021 12:00:00 AM 之間的差異是:2 年、0 個月和 1 天。
日期 2/28/2019 12:00:00 AM 和日期 2/28/2021 12:00:00 AM 之間的差異是:2 年、0 個月、0 周和 1 天(s).
public partial class Age1 : System.Web.UI.Page
{
private int Years;
private int Months;
private int Days;
DateTime Cday;
DateTime Bday;
protected void Page_Load(object sender, EventArgs e)
{
txtCurrentDate.Enabled = false;
txtCurrentDate.Text = DateTime.Now.ToString("g");
Cday = Convert.ToDateTime(txtCurrentDate.Text);
}
protected void Button1_Click(object sender, EventArgs e)
{
Bday = Convert.ToDateTime(txtBirthdate.Text);
AgeCaluclation(Bday, Cday);
txtBirthdate.Text = "";
txtCurrentDate.Text = "";
lblAge.Text = this.Years+" Years "+this.Months+" Months " +this.Days+ "Days";
}
private Age1 AgeCaluclation(DateTime Bday, DateTime Cday)
{
if ((Cday.Year - Bday.Year) > 0 ||
(((Cday.Year - Bday.Year) == 0) &&
((Bday.Month < Cday.Month) ||
((Bday.Month == Cday.Month) &&
(Bday.Day <= Cday.Day)))))
{
int DaysInBdayMonth = DateTime.DaysInMonth(Bday.Year, Bday.Month);
int DaysRemain = Cday.Day + (DaysInBdayMonth - Bday.Day);
if(Cday.Month > Bday.Month)
{
this.Years = Cday.Year - Bday.Year;
this.Months = Cday.Month - (Bday.Month + 1) + Math.Abs(DaysRemain / DaysInBdayMonth);
this.Days = (DaysRemain % DaysInBdayMonth + DaysInBdayMonth) % DaysInBdayMonth;
}
else if (Cday.Month == Bday.Month)
{
if (Cday.Day >= Bday.Day)
{
this.Years = Cday.Year - Bday.Year;
this.Months = 0;
this.Days = Cday.Day - Bday.Day;
}
else
{
this.Years = (Cday.Year - 1) - Bday.Year;
this.Months = 11;
this.Days = DateTime.DaysInMonth(Bday.Year, Bday.Month) - (Bday.Day - Cday.Day);
}
}
else
{
this.Years = (Cday.Year - 1) - Bday.Year;
this.Months = Cday.Month + (11 - Bday.Month) + Math.Abs(DaysRemain / DaysInBdayMonth);
this.Days = (DaysRemain % DaysInBdayMonth + DaysInBdayMonth) % DaysInBdayMonth;
}
}
else
{
throw new ArgumentException("Birthday date must be earlier than current date");
}
return this;
}
}
我創建了這個用於返回 2 個日期之間的年、月和日差異。
public static Dictionary<string, int> TimeSpanToDateParts(DateTime fromDate,DateTime toDate)
{
int years;
int months;
int days;
Dictionary<string, int> dateParts = new Dictionary<string, int>();
if (toDate < fromDate)
{
return TimeSpanToDateParts(toDate,fromDate);
}
var span = toDate - fromDate;
months = 12 * (toDate.Year - fromDate.Year) + (toDate.Month - fromDate.Month);
if (toDate.CompareTo(fromDate.AddMonths(months).AddMilliseconds(-500)) <= 0)
{
--months;
}
years = months / 12;
months -= years * 12;
if (months == 0 && years == 0)
{
days = span.Days;
}
else
{
days = toDate.Day;
if (fromDate.Day > toDate.Day)
days = days + (DateTime.DaysInMonth(toDate.Year, toDate.Month - 1) - fromDate.Day);
else
days = days - fromDate.Day;
}
dateParts.Add("Years", years);
dateParts.Add("Months", months);
dateParts.Add("Days", days);
return dateParts;
}
我認為TimeSpan是你要找的,但它不會做幾年或幾個月,因為它們的長度不同。
下面的例子來自上面的鏈接;
// Define two dates.
DateTime date1 = new DateTime(2010, 1, 1, 8, 0, 15);
DateTime date2 = new DateTime(2010, 8, 18, 13, 30, 30);
// Calculate the interval between the two dates.
TimeSpan interval = date2 - date1;
Console.WriteLine("{0} - {1} = {2}", date2, date1, interval.ToString());
// Display individual properties of the resulting TimeSpan object.
Console.WriteLine(" {0,-35} {1,20}", "Value of Days Component:", interval.Days);
Console.WriteLine(" {0,-35} {1,20}", "Total Number of Days:", interval.TotalDays);
Console.WriteLine(" {0,-35} {1,20}", "Value of Hours Component:", interval.Hours);
Console.WriteLine(" {0,-35} {1,20}", "Total Number of Hours:", interval.TotalHours);
Console.WriteLine(" {0,-35} {1,20}", "Value of Minutes Component:", interval.Minutes);
Console.WriteLine(" {0,-35} {1,20}", "Total Number of Minutes:", interval.TotalMinutes);
Console.WriteLine(" {0,-35} {1,20:N0}", "Value of Seconds Component:", interval.Seconds);
Console.WriteLine(" {0,-35} {1,20:N0}", "Total Number of Seconds:", interval.TotalSeconds);
Console.WriteLine(" {0,-35} {1,20:N0}", "Value of Milliseconds Component:", interval.Milliseconds);
Console.WriteLine(" {0,-35} {1,20:N0}", "Total Number of Milliseconds:", interval.TotalMilliseconds);
Console.WriteLine(" {0,-35} {1,20:N0}", "Ticks:", interval.Ticks);
// the example displays the following output:
// 8/18/2010 1:30:30 PM - 1/1/2010 8:00:15 AM = 229.05:30:15
// Value of Days Component: 229
// Total Number of Days: 229.229340277778
// Value of Hours Component: 5
// Total Number of Hours: 5501.50416666667
// Value of Minutes Component: 30
// Total Number of Minutes: 330090.25
// Value of Seconds Component: 15
// Total Number of Seconds: 19,805,415
// Value of Milliseconds Component: 0
// Total Number of Milliseconds: 19,805,415,000
// Ticks: 198,054,150,000,000
調查 C# TimeSpan結構。 它不會持續數月或數年,但會持續數天。 這讓事情變得更容易。
如果您首先計算總月數和總天數,則邏輯並不過分復雜。 然后很容易用除法和模法做一些 integer 的數學運算。
DateTime start_date = new DateTime(2010, 1, 1);
DateTime end_date = new DateTime(2011, 3, 2);
int diff_years = end_date.Year - start_date.Year;
int diff_months = end_date.Month - start_date.Month;
int total_months = 12 * diff_years + diff_months;
DateTime near_end_date = start_date.AddMonths(total_months);
int total_days = (int)end_date.Subtract(near_end_date).TotalDays;
int years = total_months / 12;
int months = total_months % 12;
int weeks = total_days / 7;
int days = total_days % 7;
Console.WriteLine($"Years: {years} Months: {months} Weeks: {weeks} Days: {days}");
這給出了Years: 1 Months: 2 Weeks: 0 Days: 1
正如預期的那樣。
這是我剛剛構建的轉換器。 我沒有嘗試上面的所有解決方案,但我嘗試過的所有解決方案在某種程度上仍然略有偏差。 這考慮了年、閏年、月、周、日等,然后獲取最后兩個最有用的值 YM 或 MW 或 WD 或 DH。 這很簡單,但我的項目需要它,也許對以后的人有幫助。 當然,如果出於某種原因這不好,我相信你們都會告訴我。
DateTime beforeDate = topic.lastActive.ToLocalTime();
DateTime futureDate = DateTime.Now.ToLocalTime();
int minutes = 0;
int hours = 0;
int days = 0;
int weeks = 0;
int months = 0;
int years = 0;
Dictionary<int, int> dictMonths = new Dictionary<int, int> { };
dictMonths.Add(1, 31);
if (DateTime.IsLeapYear(futureDate.Year))
dictMonths.Add(2, 29);
else
dictMonths.Add(2, 28);
dictMonths.Add(3, 31);
dictMonths.Add(4, 30);
dictMonths.Add(5, 31);
dictMonths.Add(6, 30);
dictMonths.Add(7, 31);
dictMonths.Add(8, 31);
dictMonths.Add(9, 30);
dictMonths.Add(10, 31);
dictMonths.Add(11, 30);
dictMonths.Add(12, 31);
//Time difference between dates
TimeSpan span = futureDate - beforeDate;
hours = span.Hours;
minutes = span.Minutes;
//Days total
days = span.Days;
//Find how many years
DateTime zeroTime = new DateTime(1, 1, 1);
// Because we start at year 1 for the Gregorian
// calendar, we must subtract a year here.
years = (zeroTime + span).Year - 1;
//find difference of days of years already found
int startYear = futureDate.Year - years;
for (int i = 0; i < years; i++)
{
if (DateTime.IsLeapYear(startYear))
days -= 366;
else
days -= 365;
startYear++;
}
//Find months by multiplying months in year by difference of datetime years then add difference of current year months
months = 12 * (futureDate.Year - beforeDate.Year) + (futureDate.Month - beforeDate.Month);
//month may need to be decremented because the above calculates the ceiling of the months, not the floor.
//to do so we increase before by the same number of months and compare.
//(500ms fudge factor because datetimes are not precise enough to compare exactly)
if (futureDate.CompareTo(beforeDate.AddMonths(months).AddMilliseconds(-500)) <= 0)
{
--months;
}
//subtract months from how many years we have already accumulated
months -= (12 * years);
//find how many days by compared to our month dictionary
int startMonth = beforeDate.Month;
for (int i = 0; i < months; i++)
{
//check if faulty leap year
if (startMonth == 2 && (months - 1 > 10))
days -= 28;
else
days -= dictMonths[startMonth];
startMonth++;
if (startMonth > 12)
{
startMonth = 1;
}
}
//Find if any weeks are within our now total days
weeks = days / 7;
if (weeks > 0)
{
//remainder is days left
days = days % 7;
}
Console.WriteLine(years + " " + months + " " + weeks + " " + days + " " + span.Hours + " " + span.Minutes);
if (years > 0)
{
if (years > 1 && months > 1)
return $"Latest Reply: {years} years, {months} months ago.";
else if (years > 1 && months == 0)
return $"Latest Reply: {years} years ago.";
else if (years == 1 && months == 0)
return $"Latest Reply: {years} year ago.";
else if (years > 1)
return $"Latest Reply: {years} years, {months} month ago.";
else if (months > 1)
return $"Latest Reply: {years} year, {months} months ago.";
else
return $"Latest Reply: {years} year, {months} month ago.";
}
else if (months > 0)
{
if (months > 1 && weeks > 1)
return $"Latest Reply: {months} months, {weeks} weeks ago.";
else if (months > 1 && weeks == 0)
return $"Latest Reply: {months} months ago.";
else if (months == 1 && weeks == 0)
return $"Latest Reply: {months} month ago.";
else if (months > 1)
return $"Latest Reply: {months} months, {weeks} week ago.";
else if (weeks > 1)
return $"Latest Reply: {months} month, {weeks} weeks ago.";
else
return $"Latest Reply: {months} month, {weeks} week ago.";
}
else if (weeks > 0)
{
if (weeks > 1 && days > 1)
return $"Latest Reply: {weeks} weeks, {days} days ago.";
else if (weeks > 1 && days == 0)
return $"Latest Reply: {weeks} weeks ago.";
else if (weeks == 1 && days == 0)
return $"Latest Reply: {weeks} week ago.";
else if (weeks > 1)
return $"Latest Reply: {weeks} weeks, {days} day ago.";
else if (days > 1)
return $"Latest Reply: {weeks} week, {days} days ago.";
else
return $"Latest Reply: {weeks} week, {days} day ago.";
}
else if (days > 0)
{
if (days > 1 && hours > 1)
return $"Latest Reply: {days} days, {hours} hours ago.";
else if (days > 1 && hours == 0)
return $"Latest Reply: {days} days ago.";
else if (days == 1 && hours == 0)
return $"Latest Reply: {days} day ago.";
else if (days > 1)
return $"Latest Reply: {days} days, {hours} hour ago.";
else if (hours > 1)
return $"Latest Reply: {days} day, {hours} hours ago.";
else
return $"Latest Reply: {days} day, {hours} hour ago.";
}
else if (hours > 0)
{
if (hours > 1 && minutes > 1)
return $"Latest Reply: {hours} hours, {minutes} minutes ago.";
else if (hours > 1 && minutes == 0)
return $"Latest Reply: {hours} hours ago.";
else if (hours == 1 && minutes == 0)
return $"Latest Reply: {hours} hour ago.";
else if (hours > 1)
return $"Latest Reply: {hours} hours, {minutes} minute ago.";
else if (minutes > 1)
return $"Latest Reply: {hours} hour, {minutes} minutes ago.";
else
return $"Latest Reply: {hours} hour, {minutes} minute ago.";
}
else if (minutes > 0)
{
if (minutes > 1)
return $"Latest Reply: {minutes} minutes ago.";
else
return $"Latest Reply: {minutes} minute ago.";
}
else
{
return $"Latest Reply: Just now.";
}
這是一個很老的問題,但還是時候問問 go。
重要的是要考慮月份有不同的天數。
public static (int, int, int) GetYearsMonthsDaysDifference(DateTime date1, DateTime date2)
{
DateTime startDate = date1;
DateTime endDate = date2;
if (date1 > date2)
{
startDate = date2;
endDate = date1;
}
var months = (endDate.Month + (12 - startDate.Month)) - (endDate.Day < startDate.Day ? 1 : 0);
var years = (endDate.Year - startDate.Year - (months < 12 ? 1 : 0));
months -= (months >= 12 ? 12 : 0);
var days = endDate.DayOfYear - startDate.AddYears(years).AddMonths(months).DayOfYear;
return (years, months, days);
}
在我的應用程序中,用戶輸入了兩個日期。 預定的開始日期和預定的結束日期。 我們必須采用這些日期,並根據差異填充 4 個字段。
所以,假設他選擇 2010 年 1 月 1 日作為開始,2011 年 3 月 2 日作為結束,我們需要結束:
年:1 月:2 周:0 天 1
意味着總持續時間為1年2個月1天。
有這樣做的標准方法嗎? 或者我是否需要編寫一個具有很多非常棘手的邏輯的方法來解決它? 我希望我會很幸運,並且會有一個 date-diff type.Net class 可用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.