(title edited)
Good afternoon, all!
Using IBM i version 7.1 and looking to calculate difference between two dates in a query. Since nothing is ever easy, one date is in CYYMMDD format, the other (curdate()) is YYYY-MM-DD. I tried to CAST my CYYMMDD formatted date (field name APENGD) as a varchar(10) then wrapped that in a CAST as a date (since decimals can't be CASTed as dates):
Cast(Cast(APENGD + 19000000 As varchar(10)) As date) As math
but I only see a result ++++++++++++++ for whatever reason. I was able to test a few different versions of this and found I can't use DATE anywhere...can anyone suggest an alternative??
Thanks in advance!
Matt
casting varchar to date only works when the string includes separators.
At 7.1 you could use TIMESTAMP_FORMAT(), but you'd end up with a timestamp instead of just a date. But that's easily dealt with.
Date(Timestamp_format(char(APENGD + 19000000),'YYYYMMDD')) As math
My prefered solution when dealing with numeric/character value dates is creating a User Defined Function to handle conversion.
You could write your own, or use the one I do. iDate written by Alan Campin. Then your code would simple be:
idate(APENGD,'*CYMD') as nath
Note that if you're trying to use date differences in a WHERE clause, like so
WHERE CURRENT_DATE - 3 months <= idate(APENGD,'*CYMD')
The above will perform poorly since an existing index over APENGD can't be used (directly). Assuming a recent(6.1+) version of the OS, you can create a new index that includes the expression you're using to convert APENGD to date.
Or you could code it using the Date->Numeric function ConvertToIdate that Alan helpfully includes. That would allow existing indexes to be used.
WHERE ConvertToiDate(CURRENT_DATE - 3 months,'*CYMD') <= APENGD
The DDL was not offered [to define the column APENGD]. No matter, as the following should suffice, mostly irrespective the definition; either as a string or as a zero-scale numeric. The effect depends on the SQL recognition of a 14-character [up to 26-character, since some v7 release] character-string as an unformatted [i.e. lacking any delimiters, thus digits-only] TIMESTAMP representation:
date(timestamp((APENGD + 19000000) concat '000000'))
IBM i 7.3->Database->Reference->SQL reference->Language elements->Data types->Datetime values->String representations of datetime values->Timestamp strings
A string representation of a timestamp is a character or a Unicode graphic string that starts with a digit and has a length of at least 14 characters. …
If you want calculate difference between 2 dates, you can use:
`TIMESTAMPDIFF(32, cast(MYTIMESTAMP1 - MYTIMESTAMP2 as char(22)))`
The first argument of function specify the type of result.
1 : millisecond
16 : days
2 : second
32 : week
4 : minutes
64 : month
8 : hour
128 : trimester
256 : Year
Related
I recently got access to a legacy database where all dates are stored in an unfamiliar format I'm unable to translate, my initial research makes me think this is a Julian date type, but it seems to be a bit off?
Thankfully there's one date column that has a normal counterpart to it, but there are a lot of other dates where only the six digit code exists.
Any ideas what these dates are, or more importantly, how to convert between these two formats?
EX:
LEGACY/NORMAL
152409/2018-04-13
152413/2018-04-17
152427/2018-05-01
It's an ancient MS-SQL database tied to an even more ancient COBOL program if that's relevant information.
It could be the number of Days since 1600-12-31
i.e. 1-Jan-1601 = 1 etc.
Would like to see dates from a different year to confirm
Cobol Date functions
As SaggingRuffus pointed out. Many dialects of Cobol have functions that convert dates To/From Days since 31-Dec-1600
These functions include:
INTEGER-OF-DATE converts YYYYMMDD date to Days-since 31-12-1600
INTEGER-OF-DAY converts YYYYDDD date to Days-since 31-12-1600
DATE-TO-INTEGER converts Days since 31-12-1600 to YYYMMDD
DAY-OF-INTEGER converts Days since 31-12-1600 to YYYDDD
How I came to the Answer
I noticed that:
152413 - 152409 = 4 and 2018-04-17 is 4 days after 2018-04-13
152427 - 152413 = 14 and 2018-05-01 is 14 days after 2018-04-17
It was than a matter of doing the Date calculation which gives 31-dec-1600.
I also knew there where date formats where the date was stored as the number of days from 1600/1601. A date in a different year would confirm the format
Adding to Bruce Martin's answer:
Even ancient SQL Server support DATEADD/DATEDIFF, you just have to modify the start date to 1900 instead of 1600 using the constant 109208 (the number of dates inbetween).
dateadd(day, (legacydatecol- 109208), 0) as legacy2date
datediff(day, '19000101', datecol ) + 109208 as date2legacy
I have a Firebird database that saves the datetime field as a DOUBLE. I have created a ColdFusion datasource connection, so I can query the data remotely. While the rest of the data is being returned correctly, the datetime field is unreadable. I have tried using CAST and CONVERT to no avail. How can I convert this to a timestamp?
An example of the data stored is: 43016.988360
You can't just convert a DOUBLE PRECISION to a TIMESTAMP, not without explicitly defining how you want it mapped and writing that conversion yourself (or hoping there is an existing third-party UDF that does this for you).
A TIMESTAMP in Firebird is a date + time represented as an 8 byte value, where the date range is from January 1, 1 a.d. to December 31, 9999 a.d. and the time range is 00:00 to 23:59.9999 (so, 100 microsecond precision).
A DOUBLE PRECISION is - usually - the wrong type for storing date and time information, and as you haven't provided how that double value should be interpreted, we can't help you other than saying: there is no default method in Firebird to do this.
Based on the comments below, it looks like the value is a ColdFusion date value stored as double precision with the number of days since December 30th 1899, see also why is ColdFusion's Epoch Time Dec 30, 1899?. If this is really the case, then you can use the following for conversion to a TIMESTAMP:
select timestamp'1899-12-30 00:00' + 43016.988360 from rdb$database
Which will yield the value 2017-10-08 23:43:14.304. Using the value 43182.4931754 from the comments will yield 2018-03-23 11:50:10.354. That is a millisecond off from your expectation, but that might be a rounding/presentation issue, eg I get the exact expected date if I use 43182.49317539 instead.
I would strongly suggest you carefully test this with known values.
I have a date field that is pulling from a server as just an 8 digit number, and I would like to convert it to a standard date format.
For example, "20140501" would be converted to 05-01-2014
I tried using the DateTime code, but that didn't work for me. Any suggestions?
Many databases might recognize the string '20140501' as a date, because this is an ISO standard format. Hence, you might try this:
select cast(cast(datecol as varchar(255)) as date)
Whether or not this works depends on your database.
I have to run column checks for data consistency and the only thing that is throwing off my code is checking for character lengths for dates between certain parameters.
SEL
sum(case when ( A.date is null or (character_length(A.date) >8)) then 1 else 0 end ) as Date
from
table A
;
The date format of the column is YYYY-MM-DD, and the type is DA. When I run the script in SQL Assistant, I get an error 3580 "Illegal use of CHARACTERS, MCHARACTERS, or OCTET_LENGTH functions."
Preliminary research suggests that SQL Assistant has issues with the character_length function, but I don't know how to adjust the code to make it run.
with chareter length are you trying to get the memory used? Becuase if so that is constant for a date field. If you are trying to get the length of the string representation i think LENGTH(A.date) will suffice. Unfortanatly since teradata will pad zeros on conversions to string, I think this might always return 10.
UPDATE :
Okay so if you want a date in a special 'form' when you output it you need to select it properly. In teradata as with most DBs Date are not store in strings, but rather as ints, counting days from a given 'epoch' date for the database (for example the epoch might be 01/01/0000). Each date type in teradata has a format parameter, which places in the record header instructions on how to format the output on select. By default a date format is set to this DATE FROMAT 'MM/DD/YYYY' I believe. You can change that by casting.
Try SELECT cast(cast(A.date as DATE FORMAT 'MM-DD-YYYY') as CHAR(10)) FROM A. and see what happens. There should be no need to validate the form of the dates past a small sample to see if the format is correct. The second cast forces the database to perform the conversion and use the format header specified. Other wise what you might see is the database will pass the date in a date form to SQL Assitant and sql assitant will perform the conversion on the application level, using the format specified in its own setting rather then the one set in the database.
I am using SSIS (SQL 2008) to bring data over from an AS400. The date values are stored in the 400 as a 7 digit numeric. Here is the format: "CYYMMDD" C is a "century digit" where 0 = 1900 and 1 = 2000. I have been looking into derived columns and script components. I am very new to SSIS and all the casting required compounded with different cases is making me a dull boy. Also, I am losing leading zeros. I am not sure if that is b/c they are numeric type and I would see them correctly if I cast as string or not. Below is what I am seeing in SQL after a direct pull from the 400 using SSIS.
AS400 = Actual
101 01/01/1900 (I think these are "unknown" dates)
1231 12/31/1900 (I think these are "unknown" dates)
20702 07/02/1902
151231 12/31/1915
1000102 01/02/2000
1110201 02/01/2011
You should be able to use this expression
(DT_DBDATE) ((DT_STR) (AS400 + 19000000))
Firstly, add the leading zero's in a derived column task:
RIGHT("000000000" + (DT_STR,10,1252)AS400,7)
Pass this to another Derived column task, and use an expression to perform the conversion depending on the century digit, something like:
SUBSTRING([Derived Column 2],1,1) == "0" ? (DT_UI4)[Derived Column 2] + 19000000 : (DT_UI4)SUBSTRING([Derived Column 2],2,8) + 20000000
Which should give you something like 20110201. You can then convert this, or shred it into date parts as required.
Neither of the two answers were 100%, but both helped me to figure out the prob. Not sure whom to mark as "correct" Here is what I did. Had to do 2 derived columns.
1. ((DT_WSTR,8)(<<AS400>> + 19000000))
2. (DT_DBDATE)(SUBSTRING(DCDateString,1,4) + "-" + SUBSTRING(DCDateString,5,2) + "-" + SUBSTRING(DCDateString,7,2))
select substring(t1.datefield,4,2)|| '/' || substring(t1.datefield,6,2) || '/' || (cast(substring(t1.datefield,1,3) as integer) + 1900) as RegularDate from db.table1 t1
If I recall correctly, the century mark date didn't go back to 1900, but rather had to do with an arbitrary date. You might want to check the AS400 redbooks related to the Y2K dates. I programmed on the AS400 from 1992 - 2005. The break years are 1939 & 2039. Date before or after these respectively fail under the century mark system. This is because IBM decided that any two digit year greater than 39 referred to the 1900's, anything less than or equal to 39 referred to the 2000's. If you are dealing with future dates, this might cause a snag.