BookmarkSubscribeRSS Feed
Rahul_SAS
Quartz | Level 8

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

12 REPLIES 12
PaigeMiller
Diamond | Level 26

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).

--
Paige Miller
Kurt_Bremser
Super User

You could add your own calculation to the SAS range, using this resource:

https://www.timeanddate.com/countdown/generic?year=1&month=1&day=1&p0=259&msg=Zero+day&ud=2&font=cur... 

 

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.

Rahul_SAS
Quartz | Level 8

Thank you for the help but I have to do this in SAS itself.

Kurt_Bremser
Super User

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.

ballardw
Super User

@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.

 

Tom
Super User Tom
Super User

@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;

Tom_0-1691078580431.png

 

mkeintz
PROC Star

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.

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------
PaigeMiller
Diamond | Level 26

@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?

--
Paige Miller
mkeintz
PROC Star

@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.

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------
mkeintz
PROC Star

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;

 

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------
mkeintz
PROC Star

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

  1. 5 groups of 400 years (from 0001-01-01 through 2000-12-31).
     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, like
    ndays_0001_through_2000 = intck('day',01jan1601'd,01jan3601'd)

    And the directly calculated number of days from 2000-12-31 to through 2023-01-01
  2. ndays_2001_through_2022 = intck('day','01jan2000'd,'01jan2023'd);

Then just add  ndays_0001_through_2000  +  ndays_2001_through_2022.

 

 

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 12 replies
  • 3481 views
  • 8 likes
  • 6 in conversation