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 subtra
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;
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;
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;
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.