Nodatime calculation of years/months/days in X days - c#

Say I have 678 days, how to calculate how many years, months and days are there from that moment?
Duration duration = Duration.FromStandardDays(678);
Instant now = SystemClock.Instance.Now;
Instant future = now + duration;
// I have to convert NodaTime.Instant to NodaTime.LocalDate but don't know how
Period period = Period.Between(now, future);
Console.WriteLine("{0} years, {1} months, {2} days", period.Years, period.Months, period.Days);

You can indeed do this with Noda Time.
First, you need a starting point. This uses the current day in the local time zone. You may wish to use a different day, or a different time zone, depending on your scenario.
Instant now = SystemClock.Instance.Now;
DateTimeZone timeZone = DateTimeZoneProviders.Bcl.GetSystemDefault();
LocalDate today = now.InZone(timeZone).Date;
Then just add the number of days:
int days = 678;
LocalDate future = today.PlusDays(days);
Then you can obtain a period with the units desired:
Period period = Period.Between(today, future, PeriodUnits.YearMonthDay);
Console.WriteLine("{0} years, {1} months, {2} days",
period.Years, period.Months, period.Days);
It's important to recognize that the result represents "time from now". Or if you substitute a different starting point, it's "time from (the starting point)". Under no circumstances should you just think that the result is X days = Y years + M months + D days. That would be nonsensical, since the number of days in a year and the number of days in a month depend on which year and month you're talking about.

You just need to add the number of days to the current time:
var now = DateTime.Now;
var future = now.AddDays(678);
int years = future.Year - now.Year;
int months = future.Month - now.Month;
if (months < 0)
{
years--;
months += 12;
}
int days = future.Day + DateTime.DaysInMonth(now.Year, now.Month) - now.Day;

Related

Adding two periods on nodatime

Where listObjAge is a list with multiple periods;
Period objTotalPeriod = listObjAge[0].period;
for (int i = 1; i < listObjAge.Count; i++) {
objTotalPeriod += listObjAge[i].period;
}
In-short:
What i am getting:
listObjAge[0].period + listObjAge[1].period = ????.
2 yr 1 mnth 28 days + 0 yr 8 mnth 30 days = 2 yr 9 mnth 58 days
// this result is not wrong but is there any way to correctly add days for the above code.
What i am expecting:
2 yr 1 mnth 28 days + 0 yr 8 mnth 30 days = 2 yr 10 mnth 28 days
As you can see i want to add results of two period. Is there any way we can achieve it using nodatime.
Solved:
I know its not correct theoretically. But it worked for me.
int intDays = 0;
for (int i = 0; i < listObjAge.Count; i++) {
intDays += listObjAge[i].period.Days; // adding all the days for every period
}
strYear = (intDays / 365).ToString();
strMonth = ((intDays % 365) / 30).ToString();
strDays = ((intDays % 365) % 30).ToString();
You should look at the user guide for Noda Time that describes arithmetic http://nodatime.org/2.0.x/userguide/arithmetic - look under the section "Adding a Period" for more information.
It's easiest to think about where this can be confusing with an example. Suppose we add "one month minus three days" to January 30th 2011:
Period period = Period.FromMonths(1) - Period.FromDays(3);
LocalDate date = new LocalDate(2011, 1, 30);
date = date + period;
If you give this puzzle to a real person, they may well come up with an answer of "February 27th" by waiting until the last moment to check the validity. Noda Time will give an answer of February 25th, as the above code is effectively evaluated as:
Period period = Period.FromMonths(1) - Period.FromDays(3);
LocalDate date = new LocalDate(2011, 1, 30);
date = date + Period.FromMonths(1); // February 28th (truncated)
date = date - Period.FromDays(3); // February 25th
The benefit of this approach is simplicity and predictability: when you know the rules, it's very easy to work out what Noda Time will do. The downside is that if you don't know the rules, it looks like it's broken.
With your code
According to the documentation, the result you are getting is the expected behavior based on the "rules". Simply, your addition operation on two two periods will evaluate to:
Years (2 + 0) = 2
Months(1 + 8) = 9
Days (28 + 30) = 58
Your comment:
this result is not wrong but is there any way to correctly add days for the above code.
What do you mean as "correct"? Are you saying that 28 + 30 = 58 is incorrect?
Alternatives
int days = 28 + 30; // carry over your days and +1 month or whatever logic you had in mind
int months = 1 + 8;
Period p1 = new PeriodBuilder { Days = days, Months = months }.Build();
It sounds like you're looking for something to normalize the months and days (and weeks?). The existing Normalize method deals with everything from "days downwards" (e.g. hours) so you can use that to start with:
public static Period NormalizeIncludingMonths(this Period period, int daysPerMonth)
{
period = period.Normalize();
int extraMonths = days / daysPerMonth;
int months = period.Months + extraMonths;
int extraYears = months / 12;
// Simplest way of changing just a few parts...
var builder = period.ToBuilder();
builder.Years += extraYears;
builder.Months = months % 12;
builder.Days = days % daysPerMonth;
return builder.Build();
}
So in your case, it sounds like you might want:
objTotalPeriod = objTotalPeriod.NormalizeIncludingMonths(31);
Note that arithmetic using this may well produce "odd" results, just as part of the nature of calendrical arithmetic.
Use this
public static Period add(Period b, Period c)
{
int years = b.year + c.year;
int months = b.month + c.month;
int days= b.days + c.days;
return new PeriodBuilder { Days = days, Months = months , Years = years}.Build();
}

Calculate minutes from a certain time to current time c# [duplicate]

This question already has answers here:
What is the easiest way to subtract time in C#?
(7 answers)
Closed 8 years ago.
I have a certain time ie. 10.30 AM. The user makes entry in a table. If the user makes entry after 10.30 AM , then the number of minutes from 10.30 Am to the current time should be calculated and set to a string.
Here is what I tried uptil now:-
int hour = DateTime.Now.Hour;
int mins = DateTIme.Now.Minute
if(hour>10 && mins >30)
{
string lateBy = "You are late by:"+ //????? how do I calculate this?
}
Any help would be great
Use TimeSpan to find the difference between the 2 datetime values, and use the TotalMinutes property to get the difference in minutes.
DateTime today = DateTime.Today;
DateTime start = new DateTime(today.Year,today.Month,today.Day,10,30,00);
DateTime now = DateTime.Now;
int hour = now.Hour;
int mins = now.Minute;
TimeSpan ts = now.Subtract(start);
if(ts.TotalMinutes > 0) //Time now is after 10:30
{
string lateBy = "You are late by:"+ ts.TotalMinutes.ToString();
}
Ignoring dates and assuming it is always the same day as the 10:30 deadline day:
string lateBy = "You are late by:"+ ((hour-10)*60 + mins-30) + " minutes";
Note this only works before midnight, i.e. for the same day.
Since both are DateTime, you can make use of DateTime.Subract
DateTime a = new DateTime(2014, 06, 20, 10, 30, 00);
DateTime b = DateTime.Now;
Console.WriteLine("You are late by:"+b.Subtract(a).TotalMinutes +"minutes");
Console.ReadLine();

How to get duration between start and end date [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Converting Days into Human Readable Duration Text
How do I calculate difference in years and months given a start and end
I use (end date - start date).TotalDays it returns total days. For example, 145 days
But I don't want total days.
It is possible to convert 145 days to 3 months and 25 days something like this.
A bit harder than it initially seems...
I suppose you could do something like this, which has the advantage of counting actual calendar months rather than estimating months to be 30days or similar.
var now = DateTime.Now;
var future = DateTime.Now.AddDays(new Random().NextDouble() * 365);
//dates above for example only
var xx = Enumerable.Range(0,int.MaxValue)
.Select(i => new{numMonths = i, date = now.AddMonths(i)})
.TakeWhile(x => x.date < future)
.Last();
var remainingDays = (future - xx.date).TotalDays;
Console.WriteLine("{0} months and {1} days",xx.numMonths,remainingDays);
if you assume a month to be 30 days, this below might help.
var start = DateTime.Today;
var end = DateTime.Today.AddDays(99);
var timeSpan = end.Subtract(start);
var months = (int)timeSpan.TotalDays / 30;
var days = timeSpan.TotalDays % 30;
var str = string.Format("{0} months, {1} days", months, days);
The difference of two DateTime objects results in a TimeSpan object. Since the time spanned by a month is not consistent among months, how would a TimeSpan object be represented by a number of months?
In order to calculate the number of months between two dates, you'd need to know the start date and end date ahead of time so you can calculate the actual number of months (keeping in mind leap years, etc.) between them.
If you want years, months, days:
Years = max number of years you can subtract from end date such that the result is still > start date.
Months = max number of months you can subtract from the previous result such that the result is still > start date.
Days = number of days between previous result and start date.
To overcome the number of days problem in a month, just look at the years and months
DateTime d1 = New DateTime(2002, 1, 1);
DateTime d2 = New DateTime(2000, 10, 1);
int years = Math.Abs((d1.Year - d2.Year));
int months = ((years * 12) + Math.Abs((d1.Month - d2.Month)));
Try use the time span to string...

Get Date Range by week number c# [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
In .net, knowing the week number how can I get the weekdays date?
Hello,
I've got a question for ya'll.
How do i get the date range of a given week number.
For example:
If I enter week 12 the output should be:
21-03-2011
22-03-2011
23-03-2011
24-03-2011
25-03-2011
26-03-2011
27-03-2011
I really hope you guys can help me out, i just cant find the awnser anywhere!
Thanks in advance.
Note
I appear to have missed bug. The current code have been updated as of 2012-01-30 to account for this fact and we now derive the daysOffset based on Tuesday which according to Mikael Svenson appears to solve the problem.
These ISO8601 week date calculations are a bit wonky, but this is how you do it:
DateTime jan1 = new DateTime(yyyy, 1, 1);
int daysOffset = DayOfWeek.Tuesday - jan1.DayOfWeek;
DateTime firstMonday = jan1.AddDays(daysOffset);
var cal = CultureInfo.CurrentCulture.Calendar;
int firstWeek = cal.GetWeekOfYear(jan1, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
var weekNum = ww;
if (firstWeek <= 1)
{
weekNum -= 1;
}
var result = firstMonday.AddDays(weekNum * 7 + d - 1);
return result;
Basically calculate a reference point, then add days, the hard stuff has to do with the fact that week 53 can sometimes occur in January and week 1 can sometimes occur in December. You need to adjust for that and this is one way to do that.
The above code calculates the date off a year (yyyy) and week number (ww) and day of week (d).
Find out which day of the week was the first January of the year (e.g. in 2011 it was Saturday)
Add the necessary count of days to become the next monday (2 days)
From this day on, add (Number of weeks - 1) * 7 days to get the first day of the week you are interested in
-Display this day plus the next days to get the whole week
Something like this should do the trick
DateTime d = new DateTime(someYear, 1, 1);
d.AddDays(numWeeks * 7);
for (int x = 0; x < 7; x++)
{
Console.WriteLine(d.ToShortDateString());
d.AddDays(1);
}

Age in years with decimal precision given a datetime

How can I get the age of someone given the date of birth in a C# datetime.
I want a precise age like 40.69 years old
This will calculate the exact age. The fractional part of the age is calculated relative to the number of days between the last and the next birthday, so it will handle leap years correctly.
The fractional part is linear across the year (and doesn't take into account the different lengths of the months), which seems to make most sense if you want to express a fractional age.
// birth date
DateTime birthDate = new DateTime(1968, 07, 14);
// get current date (don't call DateTime.Today repeatedly, as it changes)
DateTime today = DateTime.Today;
// get the last birthday
int years = today.Year - birthDate.Year;
DateTime last = birthDate.AddYears(years);
if (last > today) {
last = last.AddYears(-1);
years--;
}
// get the next birthday
DateTime next = last.AddYears(1);
// calculate the number of days between them
double yearDays = (next - last).Days;
// calcluate the number of days since last birthday
double days = (today - last).Days;
// calculate exaxt age
double exactAge = (double)years + (days / yearDays);
This would be an approximative calculation:
TimeSpan span = DateTime.Today.Subtract(birthDate);
Console.WriteLine( "Age: " + (span.TotalDays / 365.25).toString() );
BTW: see also this question on Stack Overflow: How do I calculate someone’s age in C#?
An approximite would be:
DateTime bd = new DateTime(1999, 1, 2);
TimeSpan age = DateTime.Now.Subtract(bd);
Console.WriteLine(age.TotalDays / 365.25);
The 40 years part is easy enough. But to get a truly accurate decimal point, I'm not sure how you translate the rest of the age into a decimal number. You see age is expressed in Years, Months, Days, Hours, Seconds. And the calculation isn't that easy. You have to deal with anniversary dates. Like if someone was born on January 31st, when are they 1 month old? The answer is March 1st. But in some years that is 28 days later and some years 29 days later. Here is a javascript implementation I did that tries to deal with this.
But I suppose the decimal could express the number of days since the most recent birthday anniversay divided by the number of days till the next birthday anniversary. And if you wanted to get more precise you could do it in seconds using the same principle.
But I think it is a poor representation of an age. We just don't usually represent an age like that.
And make sure your datetimes are in the same timezone for your comparisons.
You could do this:
Console.WriteLine(DateTime.Now.Date.Subtract(new DateTime(1980, 8, 1)).TotalDays / 365.25);
how much error is allowed in the fractional portion? a precise age would be
31 years, 10 days, 3 hours, etc. depending on the precision wanted.

Categories

Resources