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).
Related
I have a datetime variable with value 12-02-2019 (12th Feb 2019) - this is what i want. But in my code, it is in MM-dd-yyyy format. It saves to db in MM-dd-yyyy format (2nd Dec 2019). When i return it from Datebase, it will be like 02-12-2019 (2nd Dec 2019).
int salesid = (int)dr["SalesID"]; // dr is the datarow
DateTime salesdate = (DateTime)dr["SalesDate"]; // 02-12-2019 (2nd Dec)
And I want to add 4 months to 12-02-2019 (12th Feb). But the runtime adds 4 months to 02-12-2019 (2nd dec) and i am getting 02-04-2020 !!!
DateTime servicedate = salesdate.AddMonths(4); // 2020-12-02
This is wrong. I want to specify the salesdate as 12th Feb 2019 and ii should get 12th June 2019 after adding 4 months to the salesdate.
How this is possible in c# ?
When you save to the DB, make sure you are specify a more verbose format that the DB cannot confuse. For example, if you supply write to the database with myDateTime.Format("dd MMM yyyy"); then it will not confuse the months and days around.
This will make sure that the format in your code, and in you database, all stay aligned.
The problem is in your INSERT statement. While you should be passing the DateTime as-is to your database API, instead of using strings, if you want a simple fix, instead of calling ToString() on your CurrentSaleItem.SaleDate, use a different overload that lets you specify the culture and/or format explicitly, like ToString(string, IFormatProvider)
I'm trying to calculate the age based on the DOB.
Int32 DOB = 19900427;
Int32 current = 20140111;
Int32 result = current - dob;
Now i just need to display the starting 2 digit of the result in a text box. Could you please help me with this?
Don't do it that way. Just don't. You can't get a useful age representation by subtracting one value from another - you'll find that the difference between two people who were born a day apart can differ massively based on exactly when those dates are.
For example, consider three people with birth dates of:
A: December 30th 2013 - 20131230
B: December 31st 2013 - 20131231
C: January 1st 2014 - 20140101
That gives a difference between the ages of A and B of 1, but a difference between the ages of B and C of 8870. It's surely not good for you.
Use DateTime to represent dates - or preferably, use LocalDate from my Noda Time library. Then you can determine the difference between the dates however you want - potentially just in a number of days, for example.
I get some data from a PICK/UniVerse database that includes dates in a 4 or 5 character numeric format. Here are some examples .. I grabbed the date values from the database, and compared it to the date being shown in an application:
9832 12/1/1994
10027 6/14/1995
10594 1/1/1997
Is it possible to convert these into something that can be put into Access as a Date/Time value?
As A test, I put 9832 in Excel as a General format and then change it to Short Date, it comes up as 12/1/1926. So it's off by exactly 68 years. This was true for 10027 and 10594 as well.
In C# you can use DateTime.FromOADate
DateTime dt = DateTime.FromOADate(41481);
Returns a DateTime equivalent to the specified OLE Automation Date.
That will give you:
dt = {26/07/2013 12:00:00 AM}
Later on you can insert that Date in your Access database.
Access Date/Time values are actually double precision floats. The whole number portion represents the day and the integer portion represents the time of day.
It looks like those Pick date numbers correspond directly to the date portions of Access Date/Time values. So you can use CDate to transform them.
? CDate(41481)
7/26/2013
Experiment some more to get a feel for this:
? Date()
7/26/2013
? CDbl(Date())
41481
Note, although your question is tagged with c#, you don't need that to do these conversions. You can do them with an Access query and ask the db engine to apply those functions.
Since it turned out those date numbers are consistently offset by 68 years, you can still do the conversion in an Access query.
? DateAdd("yyyy", 68, CDate(9832))
12/1/1994
? DateAdd("yyyy", 68, CDate(10027))
6/14/1995
? DateAdd("yyyy", 68, CDate(10594))
1/1/1997
Or ...
? CDate(9832 + CLng(24837))
12/1/1994
? CDate(10027 + CLng(24837))
6/14/1995
? CDate(10594 + CLng(24837))
1/1/1997
A little late to this thread but I'll post some more detail: The Pick / MultiValue DBMS stores dates as an integer with date 0 = 12/31/1967. So as I write this on Jan 16, 2014 the internal Pick date is 16818. If you use the following you'll get that magic number 24837:
DateTime.Parse("12/31/1967").Subtract( DateTime.FromOADate(0)).Days
So add that to your Pick Date to get the OADate.
If you're using any of the common MV DBMS libraries for extracting data (UniObjects, U2.NET, mv.NET ...) you shouldn't need to convert the date like this. A typical function might look like:
string date = OConv( record["PurchaseDate"], "d2/" ); // "01/16/14"
Or rather than extracting the data in the internal DBMS format, you really should be getting it in external format to start. Ask the DBMS developer who provided the data to do this for you. It's real easy on their side to return " date'd2/' " rather than just "date".
Feel free to contact me directly if you need more info in this area.
All multivalue database dates (this includes UniVerse and UniData) are based on a base date of 31st December 1967. You can resolve this to an external data in a number of ways.
The favourite - e.g. if using SQL or one of the internal database tools is to create a data dictionary entry for the field concerned with a date conversion field, For example:
'D2' for a 2-digit year
'D4' for a 4-digit year
'D4/' for a 4-digit year with slash separators
'D4/E' for a 4-digit year with slash separators and explicitly in European format (DD/MM/YYYY) as compared to US format (MM/DD/YYYY).
If no explicit formatting is given then the format will default to environmental settings. There are other formatting options as well and many can be used in combination (as with the above).
As previously advised, the alternative is to adjust the raw date with a formula. The date is in days since 31st December 1967 - The base data for all multivalue databases.
I am dealing with dates coming from the AS/400 that are a form of julian date. January 1st 2000 comes back as a string value of "1". If the date were in true julian form it would look like 2000001. The date 12/31/2049 is comes back from the AS/400 as "49365". Is there a way to format these dates in my C# code to look like standard short dates?
What does January 1, 2001 look like?
If it looks like "1001", you can pad on the left with zeros to 5 digits and then extract the 2-digit year as the first two digits and the day-of-year number as the last 3. It should then be a simple matter to convert the day-of-year number to a month and day; if nothing else you can do it with a bunch of if statements on day ranges.
If it looks like "11" because there are no leading zeros in the day number, you're just out of luck as there is no way to differentiate between many dates, such as January 1, 2001 and January 11, 2000.
P.S. These aren't Julian dates, they're a variation on ordinal dates.
IF your dates are always of the format 'yyddd':
If you can write your SQL statement directly, the following will work...
SELECT CAST('20' || julianDate as date)
FROM table
If you don't, consider writing a view that incorporates that behaviour (that's one of the reasons views exist...).
For obvious reasons, all dates will be considered year 2000 and later...
IF (for whatever reason) it's removing any leading zeros in each part (as pointed out in comments for #Anomie's answer), you are indeed simply toast. Frankly, the entire dataset is probably a loss, as I'm not sure how even RPG would be able to differentiate between certain dates properly at that point.
IBM defines *JUL date format as yy/ddd. It is not commonly used, but is is an available standard format supported on the AS/400. You say you have a string, so the assumption here is that it is stored as CHAR(5), or 5A in DDS.
If you column is called jdt, get the right number of digits in your string, in SQL, with:
RIGHT(('00000' || TRIM(jdt)),5)
Now put the slash in:
INSERT( RIGHT(('00000'||TRIM(jdt)),5) ,3,0,'/')
DB2/400 can cast this to a real date field, but it will only work properly if you can SET OPTION DATFMT=*JUL. How to do this from C# on Windows would depend on how you are connecting.
Let's suppose you can't find the way to set the date format on your connection.
Solution: Create a user defined function [UDF] in DB2.
First, choose an appropriate library to store the function in, and set that as your current library. In OS/400 CL, CHGCURLIB yourlib, or in SQL, SET SCHEMA = yourlib. Thus by default anything you create will go into this library.
I recommend storing the SQL definition for your UDF in a source member. (Ask if unfamiliar) You can execute the source with the RUNSQLSTM command.
Your function definition could look something like this:
CREATE FUNCTION CvtJul2Date( jdtin char(5) ) RETURNS DATE
LANGUAGE SQL
SPECIFIC CVTJUL2DT
DETERMINISTIC NO EXTERNAL ACTION
CONTAINS SQL
RETURNS NULL ON NULL INPUT
SET OPTION DATFMT = *JUL
BEGIN
RETURN(
date( insert( right(('00000'||trim(jdtin)),5) ,3,0,'/') )
);
END
The *JUL option is scoped to the UDF. Any SQL query that runs on the AS/400 should be able to do this conversion, regardless of the DATFMT of the job (assuming you have put this function in a library which is on that job's library list).
Oops... My bad. A method will still probably have to be written.
Based on your description, an increase of 1 is a new day? Looks like you will have to do some math to calculate the date. Maybe create a function like
public DateTime ConvertDate(int julianDate)
{
}
This is untested and may need some changes. But this would be my suggestion.
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.