Setting SAS date to UTC/GMT from external query [duplicate] - sas

I have a datetime value in GMT timezone. How can I convert it to my local timezone?
I would expect there to be a function for this. Please note that I can not just add or subtract the difference, because of the summertime.
For example the function could work like this:
data _null_;
gmtdatetime="17SEP14:09:42:10"dt;
localdatetime=tz2local(gmtdatetime,"GMT");
run;
I tried some combinations of formats and informats without luck:
data _null_;
gmtdatetime="17SEP14:09:42:10"dt;
a=put(gmtdatetime,E8601DZ20.0);*Converts the value to "2014-09-17T09:42:10Z" to indicate that it is GMT;
localdatetime=input(a,B8601DT.);*Reads the GMT value;
put localdatetime datetime.;*This still prints the value as the original GMT value...;
run;
Thanks,
Stig

I made a function that would return the GMT offset, but when I compiled it, I got this error:
ERROR: Built-in SAS FUNCTION or SUBROUTINE already exists with name 'GMToff'.
It turns out, there is an undocumented function in SAS that returns the GMT offset and by luck I chose the same name! Here are some examples of usage.
Anyways, it will not return the offset on a specific time, as I wanted, only for the current time.
Here is a function that will convert the datetime to "local" time, given a timezone (only supports GMT, but adding additional timezones as needed should be trivial):
proc fcmp outlib = Apfmtlib.funksjoner.localtime;
function localtime(datetime,tz$);
if upcase(tz)="GMT" then do;
offset_normal=3600;
offset_summer=7200;
end;
localtime=datetime+offset_normal;
/*If datetime is between 1 AM the last Sunday of March and 1 AM the last Sunday of October it is "summertime" in central Europe:*/
if intnx('week',mdy(3,31,year(datepart(datetime))),0)*86400 + 3600 le datetime le intnx('week',mdy(10,31,year(datepart(datetime))),0)*86400 + 3600 then localtime=datetime+offset_summer;;
return(localtime);
endsub;
quit;
options cmplib = Apfmtlib.funksjoner;
/*Usage examples:*/
data _null_;
gmtdatetime="17SEP14:09:42:10"dt;
localdatetime=localtime(gmtdatetime,"GMT");
put localdatetime datetime.;
gmtdatetime="17DEC14:09:42:10"dt;
localdatetime=localtime(gmtdatetime,"GMT");
put localdatetime datetime.;
run;

I have a datetime value in GMT timezone. How can I convert it to my
local timezone? I would expect there to be a function for this. Please
note that I can not just add or subtract the difference, because of
the summertime.
There is a function for that:
TZONEU2S Function
Converts a UTC date time value to a SAS date time value.
http://documentation.sas.com/?docsetId=nlsref&docsetTarget=n1ien0skr1u9swn1f00w7hizdg9c.htm&docsetVersion=9.4&locale=en
When you specify a zone ID, the time zone that SAS uses is determined by the time zone name and daylight savings time rules.
Example:
data;
do d = 20 to 30;
date = '28FEB2018'd + d;
dt = dhms(date, 12, 0, 0);
dt2 = tzoneu2s(dt,'EUROPE/LONDON');
output;
end;
format date E8601DA. dt dt2 E8601DT. ;
run;
proc print;
run;

In SAS 9.4 the function tzonesoff is available that I think may be the answer to your question. The function returns the difference between your timezone and GMT.
data _null_;
gmtdatetime="17SEP14:09:42:10"dt;
tzoffset = tzoneoff('Europe/Copenhagen');
localdatetime=gmtdatetime+tzoffset;
put localdatetime= datetime.;
run;
You can see a list of timezones here.
If your timezone observes daylight savings time then it is very important that you choose the 'Time Zone Information' column to specify your timezone. Don't choose the abbreviation else DST will be ignored. For example, if you live in Los Angeles, choose 'America/Los_Angeles' not 'PST' or 'PDT' which would hardcode the conversion to either -7 or -8 hours different.
You can see the difference between them here:
data utc_dst_test;
format midnight utc datetime22.;
do date = '01jan2019'd to '31dec2019'd;
midnight = dhms(date,0,0,0);
utc = tzones2u(midnight,'America/Los_Angeles'); * ADJUSTS BASED ON DAYLIGHT SAVINGS TIME;
utc = tzones2u(midnight,'PST'); * ALWAYS 8 HOURS DIFF;
output;
end;
run;
If you are working with historical time values, use the tzones2u() function as shown above. If you just apply an offset to everything it won't be calculating the DST appropriately. Also be aware that tzones2u() is a very slow function to call... if you start to notice your programs running slow check to see how often this is being called.

I made a format that will give me the offset from GMT to my timezone (in seconds). In central Europe Daylight Saving starts the last Sunday in March at 1 am GMT and ends the last Sunday in October at 1 am GMT.
data fmt(drop=year);
attrib hlo length=$1
start end format=datetime.;;
fmtname="gmtoff";
type="N";
do year=1980 to 2080;
start=intnx('week',mdy(3,31,year),0)*86400 + 3600;*Last Sunday in March 1 AM;
end=intnx('week',mdy(10,31,year),0)*86400 + 3600;*Last Sunday in October 1 AM;
label=7200;*Two hours offset in summertime;
output;
end;
start=.;end=.;
hlo="O";
label=3600;*When it is not summertime, it is one hour offset;
output;
run;
proc format cntlin=fmt;
run;
/*Example of usage:*/
data _null_;
gmtdatetime="17SEP14:09:42:10"dt;
localdatetime=gmtdatetime + put(gmtdatetime,gmtoff.);
put localdatetime datetime.;
gmtdatetime="17DEC14:09:42:10"dt;
localdatetime=gmtdatetime + put(gmtdatetime,gmtoff.);
put localdatetime datetime.;
run;

Related

How to transform specific time entry into month in SAS

I have a dataset with a column "Day" that has very specific time entries like the following. How can I transform these entries into month?
From
Day
31MAY2019:00:00:00
29MAY2020:00:00:00
30APR2021:00:00:00
To
Day
May 2019
May 2020
Apr 2021
You just need to use the datepart() function to get extract the date from the datetime value.
data want;
format datetime datetime20. date monyy7.;
datetime = '31MAY2019:00:00:00'dt;
date = datepart(datetime);
run;
Keep in mind this doesn't add the space in between the month and year and is still a number format. If you want this as a character you can do the following:
data want;
format datetime datetime20.;
datetime = '31MAY2019:00:00:00'dt;
date = put(datepart(datetime),monname3.)||' '||put(datepart(datetime),year.);
run;

I want to extract month data from a datetime format column in SAS

I have a data in format 01 Jan 19.00.00 (datetime), and I want to extract the month name only from it.
Tried the below code but getting output in numbers i.e. 1 2 3 and so on. I want the output either in Jan Feb mar format or January February march format.
data want;
set detail;
month = month(datepart(BEGIN_DATE_TIME));
run;
You can use the MONNAME format.
data test;
dt = datetime();
monname = put(datepart(dt),MONNAME.);
put monname=;
run;
If you want "OCT" not "OCTOBER" you can add a 3 to the format (MONNAME3.).
If you are using the value in a report the better approach might be to use a date value formatted with MONNAME.
The values of a date formatted variable will be ordered properly when the variable is used in a CLASS or BY statement. If you had instead computed a new variable as the month name, the default ordering of values would be alphabetical.
data want;
set have;
begin_date = datepart(BEGIN_DATE_TIME);
format begin_date MONNAME3.;
run;

I would like to get Date and Time separately from DATETIME. format

I would like to get only date and time separately from 01JAN13:08:29:00
Format & Infomat available in Dataset is:
Date Num 8 DATETIME.(format) ANYDTDTM40(informat)
And If I run datepart() on 01JAN13:08:29:00 I get output as 19359 (I don't want it.)
The DATEPART function extracts the date value from a datetime value. The date value as you have seen is simply a number. A date format must be applied to a variable holding a date value. Base SAS variables have only two value types, character and numeric.
data want;
now_dtm = datetime();
now_dt = datepart(now_dtm);
now_dt_unformatted = now_dt;
format now_dtm datetime.;
format now_dt date9.; * <----- this is what you need, format stored in data set header information;
run;
proc print data=want;
run;
* you can change the format temporarily during a proc step;
proc print data=want;
format now_dt yymmdd10.; * <---- changes format for duration of proc step;
format now_dt_unformatted mmddyy10.;
run;
Actually 19,359 is exactly the value you want. You started with the number of seconds since 1960 and converted it to the number of days since 1960.
data x ;
dt = '01JAN13:08:29:00'dt ;
date = datepart(dt);
time = timepart(dt);
put (dt date time) (=);
run;
Results
dt=1672648140 date=19359 time=30540
You just need to attach a format to your new variable so that SAS will display the value in a format that humans will recognize. You could use a format like DATE9. to have it show 19,359 as 01JAN2013. Similarly you need to attach a format to the time part to make it print in format that human's will interpret as a time.
format date date9. time time8. ;

Convert GMT datetime to local

I have a datetime value in GMT timezone. How can I convert it to my local timezone?
I would expect there to be a function for this. Please note that I can not just add or subtract the difference, because of the summertime.
For example the function could work like this:
data _null_;
gmtdatetime="17SEP14:09:42:10"dt;
localdatetime=tz2local(gmtdatetime,"GMT");
run;
I tried some combinations of formats and informats without luck:
data _null_;
gmtdatetime="17SEP14:09:42:10"dt;
a=put(gmtdatetime,E8601DZ20.0);*Converts the value to "2014-09-17T09:42:10Z" to indicate that it is GMT;
localdatetime=input(a,B8601DT.);*Reads the GMT value;
put localdatetime datetime.;*This still prints the value as the original GMT value...;
run;
Thanks,
Stig
I made a function that would return the GMT offset, but when I compiled it, I got this error:
ERROR: Built-in SAS FUNCTION or SUBROUTINE already exists with name 'GMToff'.
It turns out, there is an undocumented function in SAS that returns the GMT offset and by luck I chose the same name! Here are some examples of usage.
Anyways, it will not return the offset on a specific time, as I wanted, only for the current time.
Here is a function that will convert the datetime to "local" time, given a timezone (only supports GMT, but adding additional timezones as needed should be trivial):
proc fcmp outlib = Apfmtlib.funksjoner.localtime;
function localtime(datetime,tz$);
if upcase(tz)="GMT" then do;
offset_normal=3600;
offset_summer=7200;
end;
localtime=datetime+offset_normal;
/*If datetime is between 1 AM the last Sunday of March and 1 AM the last Sunday of October it is "summertime" in central Europe:*/
if intnx('week',mdy(3,31,year(datepart(datetime))),0)*86400 + 3600 le datetime le intnx('week',mdy(10,31,year(datepart(datetime))),0)*86400 + 3600 then localtime=datetime+offset_summer;;
return(localtime);
endsub;
quit;
options cmplib = Apfmtlib.funksjoner;
/*Usage examples:*/
data _null_;
gmtdatetime="17SEP14:09:42:10"dt;
localdatetime=localtime(gmtdatetime,"GMT");
put localdatetime datetime.;
gmtdatetime="17DEC14:09:42:10"dt;
localdatetime=localtime(gmtdatetime,"GMT");
put localdatetime datetime.;
run;
I have a datetime value in GMT timezone. How can I convert it to my
local timezone? I would expect there to be a function for this. Please
note that I can not just add or subtract the difference, because of
the summertime.
There is a function for that:
TZONEU2S Function
Converts a UTC date time value to a SAS date time value.
http://documentation.sas.com/?docsetId=nlsref&docsetTarget=n1ien0skr1u9swn1f00w7hizdg9c.htm&docsetVersion=9.4&locale=en
When you specify a zone ID, the time zone that SAS uses is determined by the time zone name and daylight savings time rules.
Example:
data;
do d = 20 to 30;
date = '28FEB2018'd + d;
dt = dhms(date, 12, 0, 0);
dt2 = tzoneu2s(dt,'EUROPE/LONDON');
output;
end;
format date E8601DA. dt dt2 E8601DT. ;
run;
proc print;
run;
In SAS 9.4 the function tzonesoff is available that I think may be the answer to your question. The function returns the difference between your timezone and GMT.
data _null_;
gmtdatetime="17SEP14:09:42:10"dt;
tzoffset = tzoneoff('Europe/Copenhagen');
localdatetime=gmtdatetime+tzoffset;
put localdatetime= datetime.;
run;
You can see a list of timezones here.
If your timezone observes daylight savings time then it is very important that you choose the 'Time Zone Information' column to specify your timezone. Don't choose the abbreviation else DST will be ignored. For example, if you live in Los Angeles, choose 'America/Los_Angeles' not 'PST' or 'PDT' which would hardcode the conversion to either -7 or -8 hours different.
You can see the difference between them here:
data utc_dst_test;
format midnight utc datetime22.;
do date = '01jan2019'd to '31dec2019'd;
midnight = dhms(date,0,0,0);
utc = tzones2u(midnight,'America/Los_Angeles'); * ADJUSTS BASED ON DAYLIGHT SAVINGS TIME;
utc = tzones2u(midnight,'PST'); * ALWAYS 8 HOURS DIFF;
output;
end;
run;
If you are working with historical time values, use the tzones2u() function as shown above. If you just apply an offset to everything it won't be calculating the DST appropriately. Also be aware that tzones2u() is a very slow function to call... if you start to notice your programs running slow check to see how often this is being called.
I made a format that will give me the offset from GMT to my timezone (in seconds). In central Europe Daylight Saving starts the last Sunday in March at 1 am GMT and ends the last Sunday in October at 1 am GMT.
data fmt(drop=year);
attrib hlo length=$1
start end format=datetime.;;
fmtname="gmtoff";
type="N";
do year=1980 to 2080;
start=intnx('week',mdy(3,31,year),0)*86400 + 3600;*Last Sunday in March 1 AM;
end=intnx('week',mdy(10,31,year),0)*86400 + 3600;*Last Sunday in October 1 AM;
label=7200;*Two hours offset in summertime;
output;
end;
start=.;end=.;
hlo="O";
label=3600;*When it is not summertime, it is one hour offset;
output;
run;
proc format cntlin=fmt;
run;
/*Example of usage:*/
data _null_;
gmtdatetime="17SEP14:09:42:10"dt;
localdatetime=gmtdatetime + put(gmtdatetime,gmtoff.);
put localdatetime datetime.;
gmtdatetime="17DEC14:09:42:10"dt;
localdatetime=gmtdatetime + put(gmtdatetime,gmtoff.);
put localdatetime datetime.;
run;

Date calculations in SAS

I want to add 1 day to an arbitrary SAS date. I have the following code that works but I wonder wether there is built-in support for date calculations like this:
proc fcmp outlib=whatever;
function lastDayInYear(d);
if datdif(d,mdy(12,31,year(d)),'ACT/365')=0 then return(1); else return(0);
endsub;
function advanceDate(d);
if d=. then return(.);
if lastDayInYear(d) then
return(mdy(1,1,year(d)+1));
else
return(datejul(juldate7(d)+1));
endsub;
quit;
Dates are just numbers, so to advance the day by one, you just, um, add 1.
Where did you find that code? Talk about using a sledgehammer to crack a nut...
Itzy is right... just add 1. If you want to do more advanced date calculations you can use the intnx() and intck() functions.
e.g.
data _null_;
tomorrow = date() + 1;
same_day_next_month = intnx('month',date(),1,'same');
first_day_next_week = intnx('week' ,date(),1,'beginning');
last_day_of_year = intnx('year' ,date(),0,'end');
put _all_;
run;
In SAS, there's no DATE or DATETIME data type, such values are stored as generic Numeric data type, where for date: the number stored represents number of days between date represented and January 1st 1960. For datetime it's similar, only number of seconds is stored. You'll see this in code below.
Human readable date, time and datetime representation is achieved via SAS date/time formats.
For further explanation just do a search on SAS dates on web and documentation.
Back to you're question: to add one day to a value representing DATE, just do a mathematical addition: +1.
data _null_;
length mydate mydatetime 8;
mydate='1jan1960'd;
mydatetime='1jan1960:00:00:00'dt;
nextdate = mydate + 1;
nextminute = mydatetime + 60;
put mydate 8. +4 mydate yymmdds10.;
put nextdate 8. +4 nextdate yymmdds10.;
put mydatetime 12. +4 mydatetime datetime.;
put nextminute 12. +4 nextminute datetime.;
run;