Related
I am displaying a list of items in a data grid binded to dt_pdc. The DueDate column shows the date of the cheque, as day, month and year. When i'm sorting using descending, it does the following:
Date List & Order:
1---4/18/2020
2---4/2/2020
3---4/22/2020
When the day's first digit is less than another day's first digit, it is being sorted first, in the example, 18 april is coming before 2 april, however 22 april comes after 2 april.
Is there anything that i can fix in the sorting view, or do i have to write it in the DB as 02 instead of 2.
dt_pdc.Columns.Add("ID");
dt_pdc.Columns.Add("ChequeNumber");
dt_pdc.Columns.Add("DueDate");
dt_pdc.Columns.Add("Amount");
dt_pdc.Merge(Database.Accounts.Cheques.getPDCChequesSearch(dt_pdc));
dt_pdc.DefaultView.Sort = "DueDate ASC";
or do i have to write it in the DB as 02
no, that's just compounding the error (wait until you get an urgent support call on new year's day if you don't believe me); basically: stop storing dates as strings; store them as dates - i.e. DateTime; then everything will work correctly. If you absolutely must use string for some reason (and it would need to be a good reason), consider using ISO8601 format, i.e. store it as "2020-04-02"; this is then sortable naturally as a string, plus it is unambiguous (there is no question as to whether this is the 2nd of April or the 4th of February).
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
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.
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);
Working on an application where we would like the user to be able to enter incomplete dates.
In some cases there will only be a year - say 1854, or there might be a year and a month, for example March 1983, or there may be a complete date - 11 June 2001.
We'd like a single 'date' attribute/column - and to be able to sort on date.
Any suggestions?
Store the date as an integer -- yyyymmdd.
You can then zero out any month or day component that has not been entered
Year only: 1954 => 19540000
Year & Month: April 2004 => 20040400
January 1st, 2011 => 20110101
Of course I am assuming that you do not need to store any time of day information.
You could then create a struct to encapsulate this logic with useful properties indicating which level of granularity has been set, the relevant System.DateTime, etc
Edit: sorting should then work nicely as well
I can't think of a good way of using a single date field.
A problem you would get if you used January as the default month and 1 as the default day like others have suggested is, what happens when they actually pick January? How would you track if it's a selected January or a defaulted January.
I think you're going to have to store a mask along with the date.
You would only need a bit per part of the date, which would only be 6 bits of data.
M|D|Y|H|Min|S
Month Only 1|0|0|0|0|0 = 32
Year Only 0|0|1|0|0|0 = 8
Month+Year 1|0|1|0|0|0 = 40
AllButMinSec 1|1|1|1|0|0 = 60
You could put this into a Flag Enum to make it easier to use in code.
Well, you could do it via a single column and field that says 'IsDateComplete'.
If you only have the date field, then you'll need to encode the "incompleteness" in the date format itself, such that if the date is, say, < 1900, it's considered "Incomplete".
Personally, I'd go with an field on the side, that marks it as such. Easier to follow, easier to make decisions on, and allows for any dates.
It goes without saying, perhaps, that you can just create a date from DateTime.MinValue and then set what you "know".
Of course, my approach doesn't allow you to "know" what you don't know. (That is, you don't know that they've set the month). You could perhaps use a date-format specifier to mask that, and store it alongside as well, but it's potentially getting cumbersome.
Anyway, some thoughts for you.
One option is to use January as the default month, 1 as the default day, and 1900 or something like that as the default year. Incomplete dates would get padded out with those defaults, and incomplete dates would sort before complete ones in the same year.
Another, slightly more complex option is to use -1 for default day and year, and -1, 'NoMonth', or some such as the default month. Pad incomplete dates as above. This may make sorting a little hard depending on how you do it, but it gives you a way of telling which parts of the date are valid.
I know you'd rather have 1 column but, Instead of a single column one can always have a separate column for day, month and year. Not very difficult to do queries against, and it allways any of the components to be null.
Smehow encoding these states in the datetime itself will be harder to query.
What I did when last solving this problem, was to create a custom date type that kept track of which date parts was actually set and provided conversions to and from a DateTime. For storing in database i used one date field and then one boolean/bit to keep track of which date components that were actually set by the user.