Convert 2-digit date to year in the 1900s - postgresql

I am using the string manipulations functions in PostgreSQL 9.6 to convert a 2-digit text year into a 4 digit year. I am able to convert the string into a date and year, but the I keep getting years in the 2000s instead of the 1900s.
select extract(year from to_date('58', 'YY'));
This returns 2058 instead of 1958.
Now all of my 2 digit dates are in the 1900s, but I cannot find a max function or parameter in the to_date() function that forces the date into the 1900s.
Anyone know how to change this behavior?

Exact behavior is defined in the manual here:
If the year format specification is less than four digits, e.g. YYY, and the supplied year is less than four digits, the year will be adjusted to be nearest to the year 2020, e.g. 95 becomes 1995.
Bold emphasis mine.
Since 2058 is closer to 2020 than 1958, the first one is the result you get from to_date('58', 'YY').
There is currently no setting to override this behavior. You have to provide the desired century explicitly if you disagree with the default. Similar to what Haleemur commented:
SELECT to_date('19' || <2-digit-year-variable>, 'YYYY');
But to_date() takes text input, not integer. Integer input would raise an exception like:
ERROR: function to_date(integer, unknown) does not exist
And if by:
convert a 2-digit text year into a 4 digit year
... you mean a 4 digit text year, it's cleaner to use to_char():
SELECT to_char(to_date('19' || '58', 'YYYY'), 'YYYY')
to_char() can return text in variable formats (unlike extract(), which returns a double precision number).
If the input is valid 2-digit strings (nothing but exactly 2 digits), a simple concatenation does the job, too
SELECT '19' || <2-digit-year-variable>

to convert a 2 digit year stored as text to a 4 digit year like 19xx you can do something like this:
SELECT ('19' || '58')::int
or user klin suggested
select 1900+ '58'

Related

how to keep datatype when substracting day from date/time column in SAS

My question is really simple, hope someone deigns to answer!.
Being very to new SAS, the date and its formats really is confusing me.
I have timestamp column from which I need to substract 2 days while keeping its datatype
The value of the column is "2022-04-20-19.37.57.714699"
What I need is "2022-04-18-19.37.57.714699"
When I try this I get number datatype:
PROC SQL;
CREATE TABLE my_table AS
SELECT
cust_id,query_date, (query_date)-2 as calc_date
FROM other_table
;quit;
I try format,datetime function, but ended up with "Statement is not valid or it is used out of proper order"
Thanks
Assuming that the QUERY_DATE variable is numeric and has datetime values in it (the number of seconds since 1960) then you can use the INTNX() function with the DTDAY interval to adjust the value by two days. To keep the same time of day use SAME for the alignment parameter.
intnx('dtday',query_date,-2,'same')
Alternatively you could just subtract 48 hours worth of seconds from the value.
query_date -2*'24:00:00't
If you want the values to display in a human readable way then attach any of the many datetime formats, such as DATETIME to the new variable.
CREATE TABLE my_table AS
SELECT cust_id,query_date
, intnx('dtday',query_date,2,'same') as calc_date format=datetime20.
FROM other_table
;
If the variable is just a string then you cannot subtract from strings. You will have to convert the strings into numbers to perform arithmetic. You probably have too many decimal places for SAS datetime informats/formats to replicate (and perhaps to be uniquely stored in a floating point value) so just convert the date part and then append back the rest to keep the same time of day. Since dates are stored as number of days you can just subtract the 2 days using normal subtraction.
put(input(query_date,yymmdd10.)-2,yymmdd10.)||substr(query_date,11)
This should solve your problem. The first issue to tackle is converting the date string into a sas datetime. The input() function with the anydtdtm. informat accomplishes that with a small caveat as seen in the output.
data test;
date_txt = '2022-04-20-19.37.57.714699';
query_date = input(date_txt, anydtdtm.); * convert string into sas datetime;
calc_date = intnx('dtday', query_date, -2, 's'); * backup 2 days preserving the time;
format query_date calc_date e8601dt26.6;
run;
date_txt
query_date
calc_date
2022-04-20-19.37.57.714699
2022-04-20T19:37:57.000000
2022-04-18T19:37:57.000000
The default width of the informat is 19 characters which excludes the fractional seconds, but the informat correctly converted the string into a datetime.
To attempt to capture the full width of the date string, I modified the informat to anydtdtm26.. However, that change resulted in an error and missing values for query_date and calc_date. Although the anydtdtm informat is robust with converting a wide variety of date and time formats, I suspected that the problem lies with the periods used to delimit the hours and minutes.
To correct that problem I used prxchange() function to replace the periods after hours and minutes with colons which are standard time componenent delimiters. That change allows the anydtdtm informat to properly convert the fractional seconds.
data test2;
date_txt = '2022-04-20-19.37.57.714699';
date_mod = prxchange('s/\./:/', 2, date_txt); * replace first 2 periods w/ colons;
query_date = input(date_mod, anydtdtm26.); * convert string into sas datetime;
calc_date = intnx('dtday', query_date, -2, 's'); * backup 2 days preserving the time;
format query_date calc_date e8601dt26.6;
run;
date_txt
date_mod
query_date
calc_date
2022-04-20-19.37.57.714699
2022-04-20-19:37:57.714699
2022-04-20T19:37:57.714699
2022-04-18T19:37:57.714699
Although I used a data step to illustrate the solution the functions can also be used in a SQL statement.

Can someone help me convert this sqlite query to a postgres query?

SELECT substr(strftime('%Y', date),3,2) AS month, 0 AS zero FROM listvalue
I have this query in SQLite, when I import it into Postgres I'm having problem translating the substr(strftime('%Y', date),3,2) part.
substr(strftime('%Y', date),3,2) extracts the last 2 digits of the year part of the column date, but in your code you alias it as month!
if you want to do the same in Postgresql you can use extract() to get the year, typecast it to varchar and use substr() to get the last 2 chars:
substr(extract(year from date)::varchar, 3, 2)
You can translate the expression with TO_CHAR function to PostgreSQL:
SUBSTR(TO_CHAR(date, 'YYYY'), 3, 2)
Note: The format %Y will return the year of the date and not the month as your query suggests.
The SQLite query will return the last to digits of year of the date. You can omit the SUBSTR in PostgreSQL call by using the apropriate format:
TO_CHAR(date, 'YY')
We suspect that you want to extract the last two digits of the year value from the date column. The strftime() function won’t work in Postgres server. So, suggest you to use either one of the below queries to achieve your requirement,
SELECT substring(date_part('year', date)::varchar, 3, 2) AS year, 0 AS zero FROM listvalue;
SELCT to_char(shipped_date, 'YY'), 0 AS zero from listvalue;
Thanks,
Renuka N.

How to extract month from a date in SAS

I am trying to extract a month from a date in SAS, but so far all my new month variables are coming up as missing.
I have attempted to use some combinations of the month() function in SAS, but so far it just comes up as missing. The dates are formatted as follows: 01/31/2017 (MMDDYY10.)
I have tried
month = month(end_date)
Month =catx('/',put(month(end_date),z2
I would like the Month to show up as a number (01) or a 3 letter code (JAN), currently it is just missing (.)
Thanks in advance!
For month() to return a missing value the end_date variable must be numeric and missing. If end_date were a character variable the log would show invalid numeric data.
Use the monname3. format to convert a date value to a $3. character value mon
monthname = put (end_date, monname3.);
Other alternatives are:
keep the date value unchanged and change the format, or
map the date value to the first of the month value and also format that
For example:
end_date_copy = end_date;
format end_date_copy monname3.;
end_date_month = intnx('month', end_date, 0);
format end_date_month monname3.;
What you ultimately do depends on how the mon is to be used downstream in reporting or aggregating.

SAS: Combine YEAR and MONTH data into a single mm/dd/yyyy date without changing types

Question: How do I combine YEAR and MONTH data into a single mm/dd/yyyy date without converting from numeric to character types?
I have date data which needs to be read into SAS. It comes in two columns, YEAR and MONTH. The data looks similar to this:
YEAR MONTH
2012 1
2012 1
2013 10
2012 2
2014 7
The data must be stored in mm/dd/yyyy format. For example, YEAR = 2013 and MONTH = 10 corresponds to 10/01/2013.
I have accomplished this via:
if month = 1 then
date = input(compress("01/01/"||year),mmddyy10.);
else if month = 2 then
date = input(compress("02/01/"||year),mmddyy10.);
...
However, the log gives the following note:
NOTE: Numeric values have been converted to character values at the
places given by:
(Line):(Column).
I understand that this is being done because SAS stores dates as numeric values since January 1, 1960. The Compress function returns a character value. Thus, the numeric data is being coerced into a character type.
While the above code sufficiently solves my problem, the note implies that date formatting should not be handled in this way (via type conversion).
Use the mdy() function:
date = mdy(month, 1, year)

Convert FM (FileMaker) timestamp to DateTime

I have some FileMaker timestamp which I don't know how to handle. (I discovered it by trial...)
Does someone know an algorithm to convert FM (File Maker) timestamp into DateTime?
I have read about the format on this page. Which includes a "FM dec Timestamp" button which makes the desired conversion, but gives no reference on how it does so!
Also, my timestamps differs in format from the one required in the site, mine has a size of 18 digits, whearas the site only allows 11.
Inserting 634890864000000000 and removing the trailing zeroes (to leave 11 digits), I got this date:
Wednesday, 2012-11-21 10:20:00
If you have FileMaker this should be as simple as:
Importing the number as text,
Making a new calculation field, resultingTimestamp, which takes the left 11 characters and converts to a TimeStamp:
GetAsTimestamp( Left( myImportedTimestamp ; 11 ) )
Doing conversion to Unix format, either programmatically or through display on the resultingTimestamp field on a Layout.
If you don't have FileMaker:
Take the left 11 digits of the FileMaker timestamp.
Subtract 62135596800 from the FileMaker timestamp to get the Unix (epoch) timestamp.
(Verified by taking the same date in each and subtracting the FileMaker date from the Unix date.)
Convert epoch time to human readable, for example according to one of the formulas found in the "Convert from epoch to human readable date" section of epochconverter.com.
To get your date:
create a calculation field with the following calculation:
TimeStamp/864000000000+1
set the return type to Date.
Also, I think the extra zeroes are fractions of a second, regardless the given formula deals with these.