Hi Experts,
I have to calculate the date difference in days between 0001-01-01 and 2023-01-01. I know 0001-01-01 is an invalid date but need to meet the business requirement.
Thanks
Rahul
You'd have to write your own data step to account for days prior to sometime around 1583, factoring in the 11 days skipped when the change was made to start the Gregorian calendar. Also, you'd have to account for the fact that leap years are handled differently in the previous Julian calendar (by the way, named after Julius Caesar, yes that Julius Caesar).
You could add your own calculation to the SAS range, using this resource:
But I would recommend that you ask the masters of your business rule how many days they calculate between 0001-01-01 and 1960-01-01 (the zero day used in SAS). You can then always use this number in your calculations.
Thank you for the help but I have to do this in SAS itself.
Take the number shown on the website. Take the raw value of today's date in SAS and subtract it. You now have the number of days from 0001-01-01 to the SAS zero day, which will be constant and can be stored in a macro variable. Add this to the raw SAS value of 2023-01-01, or any other SAS date, as needed.
For a very simple (and crude) calculation you can use the average length of a Gregorian year (365.2425 days).
@Rahul_SAS wrote:
Thank you for the help but I have to do this in SAS itself.
SAS does not recognize 0001-01-01 as a valid date. Reason: way too many different calendar systems that have been in use. Because of calendar reforms over the centuries a "date" in one country could be different in another.
SAS supports actual date values starting in year 1582. Not to mention things like Hebrew and Persian and other calendars starting a long time before the Christian era (I am assuming that year 0001 is supposed to be the first year in the Christian era if not then other things arise).
If you are only going to compare month=1 and day=1 then Year(currentdatevariable); returns 2023 and the number of years between the two "values" and you can use that for some things.
But you haven't provided what you expect as an answer or if any other dates are ever involved.
I agree that you need to have someone tell you what the rules and expected results are.
@Rahul_SAS wrote:
Thank you for the help but I have to do this in SAS itself.
You can do any calculation you can explain in SAS code.
But SAS cannot make up your mind for you about what calculation you should want to do.
So once you have the actual rule for what value a string like '0001-01-01' should be evaluated to you can start writing logic for how convert a date like '01JAN2023'd into a number that represents days since that other number.
The best advice you got is for you to ask whoever it is that wants this calculated what number is the right answer for the date '01JAN1960'd (which SAS stores as the number zero). Lets assume that is some number like: 715,525. Then to convert a string like '2023-01-01' into the number of days since '0001-01-01' you just need to add that number to the number you get when you convert '2023-01-01' into a date.
data test;
string='2023-01-01';
date=input(string,yymmdd10.);
format date date9.;
days = 715525 + date;
format days comma10.;
run;
We can be confident about counting days since 15OCT1582, (the start of the Gregorian Calendar).
But what calendar do you intend to use to get all the way back to 0001-01-01?
In other words, what is the meaning of 0001-01-01? If it's the Proleptic Gregorian calendar, you have a fairly straightforward task. Just count years (time 365), add one for every year divisible by 4, then subtract 1 for every year divisible by 100 (except those divisible by 400).
Failure to do this correctly for 1900 made Lotus-123 (and its imitator Excel) produce errors for dates prior to March 1, 1900, because it falsely assumes that there was a 2/29/1900.
But if you want Jan 1, 0001 identified by a pre-Gregorian calendar (Julian maybe?), then things get messy.
@mkeintz wrote:
But if you want Jan 1, 0001 identified by a pre-Gregorian calendar (Julian maybe?), then things get messy.
Not sure why you say this (and yes, I admit we're not talking about SAS any more, we're talking about history), the Julian calendar was very regular, 365 days, plus 1 leap day every 4th year, without exception, all the way back to 46 BC. Pre-Julian calendars would be a nightmare, as the length of the year varied by the whim of the ruler of Rome. The only way historians have figured out the lengths of the year previous to this was either from historical documents about the length of the year, or by historical documents recording eclipses. Now that would be tough to program. And as soon as you move outside the Roman world, there are a gazillion different calendars around the world, each with different rules and lengths.
But your other point is a good one ... which calendar's 1/1/0001 are we talking about, anyway? Can you enlighten us, @Rahul_SAS ? And why anyone even need to do this task, other than as a programming assignment to make life difficult for students, or maybe for astronomy?
@PaigeMiller wrote:
@mkeintz wrote:
But if you want Jan 1, 0001 identified by a pre-Gregorian calendar (Julian maybe?), then things get messy.
Not sure why you say this (and yes, I admit we're not talking about SAS any more, we're talking about history), the Julian calendar was very regular, 365 days, plus 1 leap day every 4th year, without exception, all the way back to 46 BC. Pre-Julian calendars would be a nightmare, as the length of the year varied by the whim of the ruler of Rome. The only way historians have figured out the lengths of the year previous to this was either from historical documents about the length of the year, or by historical documents recording eclipses. Now that would be tough to program. And as soon as you move outside the Roman world, there are a gazillion different calendars around the world, each with different rules and lengths.
@PaigeMiller: point taken. I said it will get messy out of sheer ignorance/laziness - since I didn't bother to find out how far back the Julian went.
This doesn't exactly answer your question, but here is some code to produce human-readable proleptic Gregorian calendar (PGC) dates from date values consistent with SAS date values. The DATE9 format will display correct PGC human-readable values back to 01JAN1582.
Before that you have to build a string.
%let fourhundredyears=%eval(%sysevalf("01jan2000"d)-%sysevalf("01jan1600"d));
%put &=fourhundredyears;
data _null_;
do date='15oct1582'd-578101 /*01jan0000 per Proleptic Gregorian Calendar */
,'14oct1582'd,'01jan1900'd;
do _offset=0 by 1 while (date<'01jan1582'd);
date=date + &fourhundredyears;
end;
date_string=cats(put(date,date5.),put(year(date)-_offset*400,z4.));
date=date - _offset*&fourhundredyears;
put date_string=;
end;
drop _offset;
run;
If you literally just want the number of days between 0001-01-01 and 2023-01-01 then you know it is the number of days in 2022 years.
The only question is how to define all those years.
If the years are ALL defined using the Gregorian Calendar convention, then you have
ndays_0001_through_2000 = 5*intck('day','01jan1601'd,'01jan2001'd)
I chose 400 years because that is the longest cycle defined in the Gregorian Calendar, so any 400 year range would do. I also could have avoided the multiplication by choosing some valid (for SAS date calculations) 2000 year interval, likendays_0001_through_2000 = intck('day',01jan1601'd,01jan3601'd)
ndays_2001_through_2022 = intck('day','01jan2000'd,'01jan2023'd);
Then just add ndays_0001_through_2000 + ndays_2001_through_2022.
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.