C# Adding years and days in a single DateTime variable - c#

Am I missing something simple?
I am trying to calculate a date 17 years and 364 days before the given date.
Is there a way to do this without converting everything into days? I am trying to avoid dealing with leap years. I am doing the following:
DateTime date = Convert.ToDateTime(tId2);
string tId4a = Convert.ToString(tId4);
var age1 = tId4a.Substring(0, 2);
int age2 = Convert.ToInt32(age1) - 1;
DateTime sub1 = date.AddYears(-age2);
I was hoping to do something simple like:
DateTime sub1 = date.AddYears(-age2) + date.AddDays(-364);
I am being told that I cannot use the '+' in the DateTime.
Sorry, but I am new to this. The reason the age2 variable is used is because at times that value will change. But, the 364 should be consistent. I am creating something to test a date boundary.
Did I overlook something simple?
Thanks.

What you do is you add the "date age2 years ago" to the "date 364 days ago".
Instead do this:
DateTime sub1 = date.AddYears(-age2).AddDays(-364)
This at first subtracts the years and then subtracts the days from the resulting value.

You can't add dates, but you can certainly chain method calls together
date.AddYears(-age2).AddDays(-364);
This is for all intents and purposes the same thing as trying to add them together.

It really sounds like you want to go with tid4 years ago, but go to the next day after that.
The way you are doing it, is that you subtract 1 from that to get age2. Then you subtract that many years, and you also subtract 364 days from your date. This will be more sensitive to leap years. If the resulting date happens to be between Jan 1 and Feb 28 of a leap year, you will end up with one day later than you wanted.
364 is a very suspect number. I tend to think you are using that to mean "the number of days in a year minus one". But the number of days in a year is not always 365. In leap years, the number of days is 366. In such years, subtracting 364 is not 1 day less than a year. It is actually 2 days less than a year, so you would be off.
What you really should do, if I am reading you correct, is to just subtract the number of years, then add one day back in.
DateTime date = Convert.ToDateTime(tId2);
string tId4a = Convert.ToString(tId4);
int age = Convert.ToInt32(tId4a.Substring(0, 2))
DateTime sub1 = date.AddYears(-age).AddDays(1);

I think that it is valuable to mention that DateTime is an object, and that .AddYears(), .AddDays(), etc all return a new DateTime object which is why you cannot add them together like primitive types. So when you run:
DateTime sub1 = date.AddYears(-age2).AddDays(-364);
date.AddYears(-age2) returns a new object, and then .AddDays(-364) is using the new DateTime object and not the date instance.
For more info:
https://msdn.microsoft.com/en-us/library/system.datetime(v=vs.110).aspx

Related

How to get the number of days in a year from a given date

I need to calculate the day in a year from a given date, considering
the year too.
I'm in Brazil, so I'm using in the dd/mm/yyyy format
Console.WriteLine("Please inform the date in format dd/mm/yyyy");
DateTime dateInformed = DateTime.Parse(Console.ReadLine());
.
.
.
Console.WriteLine("The day of the year is:" + );
Examples:
If I receive: 21/10/2016 I show the number of days in 2016
If I receive: 21/10/1993 I show the number of days in 1993
Considering if it's leap year or not.
Sorry if I didn't explained well.
Thanks!
EDIT:
Some people reported as duplicate question, but I don't think so.
Let me try to explain in another way...
I'm going to receive the complete date from the user in Console.
I didn't figure out how to get the number of days in the year that the user gave to me in the format dd/mm/yyyy.
I think the calc is basically: date that the user entered - first day of the year. But I also need to know if this year is leap year or not.
But i don't know how to do this using DateTime in C#.
Another example...
25/10/2016 - 01/01/2016 = day 298 of the year
25/10/2015 - 01/01/2015 = day 297 of the year
I just have an idea receiving the day, month and year in different entrances.
Thank you!
Create a new DateTime object set at the last day of the year (31. December) and use the DayOfYear property.
int daysInYear=new DateTime(dateInformed.Year,12,31).DayOfYear;
Or check if it's a leap year using the IsLeapYear method:
int daysInYear=dateInformed.IsLeapYear()?366:365;
Reviewing the answers, my question, etc... I figure out how to know the day o the year from the given date...
That's my code in pt-br, but in the format aaaa-mm-dd.
using System;
public class Program
{
public static void Main()
{
Console.WriteLine("Informe a data no formato aaaa-mm-dd");
DateTime dataInformada = DateTime.Parse(Console.ReadLine());
Console.Write("Dia do ano: " + dataInformada.DayOfYear);
}
}
Thanks for everyone that tried to help me!

How can I determine the last day of the month [duplicate]

This question already has answers here:
Last day of the month in .NET
(5 answers)
Closed 7 years ago.
How can I determine the last day of the month, for the tested month, when the user enters a date into textbox that is further from the available last day for that month? Also how do I feed that back to the user.
When the user enters the date, for example, of April 31, 2015, the date should automatically change to April 30, 2015.
I would like to try doing this using c#
3rd EDIT: The below will get you close to what you're asking for but really just make use of a datepicker control it will help prevent the majority of invalid dates and save you a good amount of development time
2nd EDIT: So TryParse is beneficial because if the date is valid, continue and your done. If you have an invalid date, which TryParse will tell you, then you can compare the value that was input for the day value and see how close it is to the end of the month, i.e. take 31 - 30 = 1, 1 number off so they probably meant 30
EDIT: To answer your question about finding an invalid date check this out: Validate a DateTime in C#
It shows how to detect an invalid date.
To answer your question about how to "guess" which validate date they are closest to I'd say it depends on how you have your date entered. If you do something like have them enter an int value for the day value I'd check to see what the highest day value is for the selected month and then see which one they are closest to (this is just a math operation at this point).
I think this will work
DateTime lastday = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.DaysInMonth(DateTime.Today.Year, DateTime.Today.Month));
This is an easy way:
//first day of next month
var dt = new DateTime(2015,4,1);
var lastDayOfMonth = dt.AddDays(-1).Day;
As far as delivering a message back to the user, it depends on the environment, technology and preferred approach.

Adding two DateTime objects together

Is there any better way to add one DateTime object to another one, than this:
DateTime first = new DateTime(2000, 1, 1);
DateTime second = new DateTime(11, 2, 5, 10, 10, 11);
DateTime result = first.AddYears(second.Year);
DateTime result = first.AddMonths(second.Month);
...
and so on...
In this example I'd like to get DateTime(2011, 3, 6, 10, 10, 11)
EDIT
After a intensive brainstorm it seems to there's no different way, but to facilitate it can be boxed inside additional class and operator+ just like in JonSkeet's answer
It doesn't make sense to add two DateTime values together. If you want to represent "11 years, 2 months, 5 days, 10 hours, 10 minutes and 11 seconds" then you should represent that. That's not the same as 0011-02-05T10:10:11. In particular, you'd never be able to add "2 months and 30 days" for example. Likewise you'd never be able to add just a single year, because you can't have 0 for month and day values within a date.
Now there's no BCL type to represent the idea of "11 years [...]" but you could create your own one reasonably easily. As an alternative, you could use my Noda Time project which has Period for precisely this purpose:
var localDateTime = new LocalDate(2000, 1, 10).AtMidnight();
var period = new PeriodBuilder {
Years = 11, Months = 2, Days = 5,
Hours = 10, Minutes = 10, Seconds = 11
}.Build();
var result = localDateTime + period;
Contrary to some other answers provided here, you cannot use TimeSpan for this purpose. TimeSpan doesn't have any concept of months and years, because they vary in length, whereas a TimeSpan represents a fixed number of ticks. (If your largest unit is days, then you're fine to use TimeSpan, but given your example, I assume you need months and years.)
If you don't want to use Noda Time, I'd recommend you fake up a Period-like class yourself. It's easy enough to do - for example:
// Untested and quickly hacked up. Lots more API you'd probably
// want, string conversions, properties etc.
public sealed class Period
{
private readonly int years, months, days, hours, minutes, seconds;
public Period(int years, int months, int days,
int hours, int minutes, int seconds)
{
this.years = years;
this.months = months;
this.days = days;
this.hours = hours;
this.minutes = minutes;
this.seconds = seconds;
}
public static DateTime operator+(DateTime lhs, Period rhs)
{
// Note: order of operations is important here.
// Consider January 1st + (1 month and 30 days)...
// what do you want the result to be?
return lhs.AddYears(rhs.years)
.AddMonths(rhs.months)
.AddDays(rhs.days)
.AddHours(rhs.hours)
.AddMinutes(rhs.minutes)
.AddSeconds(rhs.seconds);
}
}
Usage:
DateTime first = new DateTime(2000, 1, 1);
Period second = new Period(11, 2, 5, 10, 10, 11);
DateTime result = first + second;
You need to be aware of how DateTime.Add will handle impossible situations - for example adding a month to January 31st will give you February 28th/29th depending on whether or not it's a leap year.
The simple approach I've listed here, going through intermediate values, has its downsides, because that truncation can happen twice (adding years and then adding months) when it needn't - for example, "February 29th + 1 year + 1 month" might logically be "March 29th" but it will actually end up as "March 28th" as the truncation to February 28th will happen before the month is added.
Trying to work out a "right" way of doing calendrical arithmetic is fiendishly difficult, particularly as in some cases people may disagree about what the "right" answer is. In the above code I've opted for simplicity and predictability - depending on your real requirements, you may need something more complex.
DateTime first = new DateTime(2000, 1, 1);
DateTime second = new DateTime(11, 2, 5, 10, 10, 11);
DateTime result = new DateTime(first.Ticks + second.Ticks);
You have a DateTime which represents a point in time. And you want to add a number of years/months/days/hours/minutes/seconds to it.
A change in DataTime is not a point, it is a vector (a difference between points). It is really easy to mistake one for the other, as they often have similar structure. However, that kind of type error leads to lots of pain.
Avoiding it doesn't fix your pain, but it makes it manageable.
Adding two DateTime together is adding two points together. Sort of like adding the location of Los Angeles to New York.
Now, adding the "vector" of LA to NY to London makes sense -- because the travel vector is a vector, not a point. And point+vector is just a point.
So this means you need to create a time vector type. A simple time span is an option, but probably not appropriate: because you care about months, years and days, not nanoseconds or absolute time durations.
I'll dub the name of the vector a CalendarVector, as it represents movement on a Calendar, not in time itself.
An easy first pass is to create a tuple of each sub type of time -- years, months, days, etc -- then add them in some arbitrary order to your original DateTime with an overloaded operator+.
You should support:
DateTime = DateTime + CalendarVector
CalendarVector = CalendarVector + CalendarVector
CalendarVector = CalendarVector - CalendarVector
CalendarVector = int * CalendarVector
CalendarVector = - CalendarVector
DateTime = DateTime - CalendarVector
CalendarVector = DateTime - DateTime
ideally. The CalendarVector + DateTime overload is optional, but probably not needed.
However, this only gets you half way.
The big remaining problem is that CalendarVector addition does not commute. Adding 1 month to a DateTime, then adding 1 day, is different than adding 1 day then adding 1 month.
And this is fundamental.
There is the problem of "what does it mean to be 1 month after January 31st", which can be answered, but any reasonable answer to that question doesn't solve the commuting problem.
Your planned constructor -- where you feed it the number of years, months, days, hours, minutes seconds -- is thus ambiguous in what it means.
So a robust solution should not have that constructor.
A solution is to create Years, Months, Days, Hours, Minutes and Seconds types that you explicitly add together. The order they are added together is the order they are applied to the DateTime you add it to. Commuting and "simplification" is avoided until the final application on a DateTime -- so +1 year, +2 days, -1 month, -1 year, -2 days, +1 month is not the zero transformation.
There is a related problem with DateTime-DateTime -- it should return a CalendarVector v such that lhs = rhs + v, but there are multiple such vectors. The same problem can occur with spherical coordinates -- do you mean the short way around the Earth, or the long way? It doesn't matter in some contexts -- but then you halve the result to find the mid-way point. Plus, you get discontinuities as you approach "far side of the world".
So my advice would be to maintain a list of transformations on a DateTime object. 1 year is a transformation that consists of adding 1 to the year field, and then repairing the other fields so they are consistent. These transformations support negation. Addition is applying them one at a time, from left to right. Negation may also reverse the order of application, and adjacent transformations "of the same kind" may combine (so +1 month -1 month becomes the identity transformation, instead of a clamping operation based off next months' end of month), or not (so x = x+1 month,then x = x-1 month on the next line is the same as x = x + 1 month - 1 month).
Yet another approach is to insist that the user provide a policy for what to do in these exceptional circumstances (which happen ... all the time), because this problem is thorny enough that a library that "solves" the problem can at best highlight the problems and force the client programmer to think about them and make decisions.
Simplest is:
firstDateTime.AddTicks(secondDateTime.Ticks);

Getting number of months based on days in c#

I'm stuck trying to figure this one out..
We currently have a date criteria on our reports, that are limited by days, configurable of course, currently set to 90 days.. message says, it is limited by 90 days, however my boss wants to increase it to 13 months, unfortunately if I did that, I'd need to do it by days and it would say, 395 days..
Not a very friendly message..
Trying to figure out a way to satisfy this, my other only option is to add another settings that is limited by months as well as days. but then i still need to convert the months back to days which wont be perfect since not every month has same days..
Ideas?
You need to decide if you're going to use 13 months as the time interval, or some number of days that approximates to 13 months. If you use 13 months, then the number of days (or the end date for your report) is going to vary depending on the start date.
I would suggest making your report configurable for either months or days (storing not just the number, but the units in configuration). You can then display on the report whatever has been specified in the configuration (with the units from configuration, too) and calculate the end date for the query by adding the configured number of configured units to the start date.
If you try to do everything in days, when you're now working in months, you'll just make life difficult for yourself.
It's much easier to add 13 months to the start date to get the end date, than it is to try and (inaccurately) work out how many months in a given number of days.
Use the TimeSpan object to perform the calculations you need for your date criteria.
I would do something like this, given the number of days:
int myDays; // 390 or whatever
DateTime d1 = DateTime.Now;
DateTime d2 = d1.AddDays(myDays);
int monthsDiff = d2.Month - d1.Month + 12 * (d2.Year - d1.Year);
DateTime d3 = d1.AddMonths(monthsDiff);
TimeSpan tf = d2 - d3;
string msg = monthsDiff.ToString() + " months, " + tf.Days + " days";
TimeSpan give you duration between two DateTime objects. It can give it consistently in Days, Hours or Mins; Number of months would be different based upon actual start & end dates as different months have different number of actual days.
Having said that, you can always write a Utility method that gives you YourTimeSpan object that gives you number of Months etc based upon your calendar and StartDate / EndDates.
In your case you can make it even simpler by storing it separately in configuration, for example - ReportDuration_Years, ReportDuration_Months, ReportDuration_Days. This would allow you to create meaningful lable on your report as well as allow to identify StartDate and EndDate properly.
//Call this by passing values from configuration
private string GetNiceLookingLable(int? years, int? months, int? days){
var yearMessage = (years.HasValue)?String.Format("{0} Years", years):String.Empty;
var monthMessage = (months.HasValue)?String.Format("{0} Months", months):String.Empty;
var daysMessage = (days.HasValue)?String.Format("{0} Days", days):String.Empty;
// You probably want to concatenate them properly
return String.Format("{0} {1} {2}",yearMessage, monthMessage, daysMessage);
}
-
//Call this to get starting date
private DateTime getStartingDate(int? years, int? months,int? days){
var retDate = DateTime.Today;
if(years.HasValue){
retDate = retDate.AddYears(-1*years.Value);
}
if(months.HasValue){
retDate = retDate.AddMonths(-1*months.Value);
}
if(days.HasValue){
retDate = retDate.AddDays(-1*days.Value);
}
return retDate;
}

Calculating past datetime in C#

I am working on an algorithm in C# to calculate a past DateTime based on an input string with the following characteristics:
The string contains an integer followed by either 'D', 'M' or 'Y', such as "1D" or "90M".
The output will be DateTime.Now minus the corresponding number of days, months or years.
The issue I am having is that if, for instance, I switch the input string on a Regex (D, M or Y) and subtract the corresponding TimeSpan from DateTime.Now, the new TimeSpan() constructor does not accept months or years, only days.
if (new Regex(#"[0-9]+D").IsMatch(value))
{
newDate = DateTime.Now - TimeSpan(Int32.Parse(value.Replace("D", "")), 0, 0);
}
This logic is fine if the input string is in days, but the constructor for TimeSpan does not accept months or years, and it would be incredibly inaccurate if I assumed each month had 30 days, or each year had 365 days.
Does anyone have thoughts on how to implement this algorithm?
Thanks!
DateTime has AddMonths, AddDays and AddYears methods. Use them with minus to substract
Could you not rather try using the AddDays/AddMonths/AddYears but with negative numbers?
From DateTime.AddDays Method
The value parameter can be negative or
positive.
And then maybe just implement a switch stament to apply the appropriate Add method.
To subtract months, I create a new DateTime and just evaluate month/year. So 1/2010 - 6 months would be 6/2010... once you have the month/year established, you can look at the original datetime day component, and ensure it fits within the month.
That's what I did. Year was evaluated the same way. Subtracting days is easy; use the TimeSpan component to do it.
Remember that you can add negative amounts as well and check out this method and this one.
http://msdn.microsoft.com/en-us/library/3z48198e.aspx
TimeSpan.TryParse accepts very close to your string as long as you can fits its formatting OR convert from yours to its.

Categories

Resources