Summary:ASTERISK-07546: [patch] Applications/functions not picking up system timezone
Reporter:Hadley Rich (hads)Labels:
Date Opened:2006-08-17 22:16:16Date Closed:2007-01-18 15:16:47.000-0600
Versions:Frequency of
Environment:Attachments:( 0) 20070118__bug7748.diff.txt

I'm having some difficulty with my test system (trunk running on Debian testing) not picking up the system's timezone.

My local timezone is Pacific/Auckland (GMT+12) which is setup correctly
- date returns the correct time and timezone. /etc/localtime is a copy of /usr/share/zoneinfo/Pacific/Auckland. I have also tried setting TZ=Pacific/Auckland and running asterisk at that console which
didn't alter the behaviour.

The default behaviour of STRFTIME is meant to be to use the systems timezone if none is specified.

If I call a test extension with this in the dialplan;


then I get this output (shortened) ;

NoOp("SIP/800-081778a4", "Tue Aug 15 22:11:36 2006)")
NoOp("SIP/800-081778a4", "Wed Aug 16 10:11:36 2006)")

The same goes for Voicemail and other things such as SayUnixTime - they are showing GMT time although cdrs (using cdr-csv) and Asterisk logs show the correct localtime.

Feel free to point out something that I have done to cause this, at this stage I'd just like to figure it out.


I'm no C coder, but from looking at the code it appears that logs and cdrs use localtime_r directly whereas the dialplan functions/applications use the functions in stdtime/localtime.c in the Asterisk source.

Reading through localtime.c I can't see anywhere where the system timezone is read if these functions/applications are called with either a NULL or empty timezone argument (It differs depending on how you call the function/application). There is one reference to /etc/localtime in ast_tzset_basic (two if you count the one defined in TZDEFAULT). I added a debug statement above this line and it never seems to get called.

Of course it is quite likely that I just don't understand the code well enough.
Comments:By: Serge Vecher (serge-v) 2006-10-06 15:53:16

alright, what's the status here?

By: Tilghman Lesher (tilghman) 2006-10-07 02:41:16

hads: let me know if this patch changes anything on your end.

By: Hadley Rich (hads) 2006-10-07 17:00:27

Corydon76 - it makes localtime fail to compile (see below). I removed the second const from 'const char * const zone;' (which could be completely wrong - I don't really know C) and that allowed it to compile but unfortunately it didn't make a difference. Cheers.

  [CC] stdtime/localtime.c -> stdtime/localtime.o
stdtime/localtime.c: In function 'ast_localtime':
stdtime/localtime.c:1056: error: assignment of read-only location
stdtime/localtime.c: In function 'ast_mktime':
stdtime/localtime.c:1502: error: assignment of read-only location
make[1]: *** [stdtime/localtime.o] Error 1
make: *** [main] Error 2

By: Tilghman Lesher (tilghman) 2006-10-09 18:43:11

Okay, let's try that patch again.

By: Hadley Rich (hads) 2006-10-09 18:56:16

Still the same output (see below). Let me know if you would like any other information. Cheers.

Dialplan (shortened);

exten => s,n,NoOp(${STRFTIME(||%F %T)}))
exten => s,n,NoOp(${STRFTIME(|Pacific/Auckland|%F %T)}))

Output (shortened);

[Oct 10 12:54:29]     -- Executing [s@macro-stdexten:2] NoOp("SIP/800-081c3bc8", "2006-10-09 23:54:29)") in new stack
[Oct 10 12:54:29]     -- Executing [s@macro-stdexten:3] NoOp("SIP/800-081c3bc8", "2006-10-10 12:54:29)") in new stack

By: Paul Hewlett III (seagoon) 2006-10-18 03:01:49

I came across this issue as well and have done some research.
The basic problem is that Unix/Linux does not allow the display of time in different timezones within the same application. The assumption is that users will login with differing timezones and run applications that will show their timezone when time is displayed. This is fine for running separate applications but of course does not allow for multithreaded apps with threads having different timezones. What is needed is an additional arggument to localtime_r() that specifies the timezone - if null take the system-wide definition. This is not available so the stdtime/localtime.c has been written (I assume that it is copied from the glibc sources) and the equivalent function ast_localtime() provided that does allow for different timezones. Unfortunately this code now appears to be broken. Additionally, a lot of the asterisk code does not use it so localtime is inconsistent.
Note that the ENV() function uses setenv() to set the timezone as well so using this function will set the timezone for all threads as well.

Add into this mix the fact that using the TZ environment variable to set timezones is not workable _ I remember spending many hours trying to figure out a TZ string for a town in Canada some years ago. The 3/4 letter TZ mnemonic for timezones also is unworkable in the general sense - some timezones are ambiguous - in Aus there are a number of timezones that are the same as some in USA - see the PostGreSQL docs for the details.

With these issues in mind, Linux adopted the timezone definitions characterised by Continent/Town. If you want to see what timezones are available use the tzselect command to find an appropriate tiemzone for your area. All timezone definitions should follow this scheme as it is correct for all normal and obscure cases. The documentation for the tzset() call unfortunately still describes the original TZ definitions first - consequently most people miss the ':' character required when using the new scheme.

If you do not want to alter the asterisk source code, then define TZ thus

     export TZ=:Pacific/Auckland

before firing up asterisk.

A better solution is to alter stdtime/localtime.c and change the ast_localtime() to directly call localtime_r() - in this case you will forego having the ability to display localtime in different timezones in different threads but I cannot think that this feature is so important that the effort of maintaining all that code in stdtime/localtime.c is worth it. The timezone args to SayUnixTime and STRFTIME can also be removed.

By: Tilghman Lesher (tilghman) 2006-10-18 11:41:08

The reason ast_localtime() was created was for precisely the reason you stated; that is, localtime_r() is dependent upon an environmental variable, which is global to all threads.  You cannot change that variable without affecting all threads.

That is why your "better solution" is not workable.  This feature is extremely important for people who need to have their system respond in multiple timezones at the same time.

I'm not sure why this is broken for this one user, because it definitely is not broken for the vast majority of Asterisk installations.

And you assume wrongly that this was copied from glibc.  This was taken from the FreeBSD sources to libc, this section of which was placed into the public domain, so there were no disclaimers to contend with.

By: Tilghman Lesher (tilghman) 2006-11-16 13:18:28.000-0600

Can't reproduce.

By: Steve Murphy (murf) 2006-11-17 12:59:42.000-0600

I'll give this complaint some "due diligence".

I put the suggest code into my code on an ubuntu system, and get:

   -- Executing [88@extension:1] NoOp("Zap/50-1", "Fri Nov 17 11:45:19 2006") in new stack
   -- Executing [88@extension:2] NoOp("Zap/50-1", "Fri Nov 17 11:45:19 2006") in new stack

and then I tried it on a fedora-core-3 system:

   -- Executing [778@workext:1] NoOp("Zap/6-1", "Fri Nov 17 11:57:40 2006") in new stack
   -- Executing [778@workext:2] NoOp("Zap/6-1", "Fri Nov 17 11:57:40 2006") in new stack

that's the only two linux's I have around at the moment.
Sorry, if we can't reproduce it, we usually can't fix it.

By: Steve Murphy (murf) 2006-11-17 13:02:43.000-0600

Sorry, can't reproduce this at the moment.

By: Steve Murphy (murf) 2006-11-17 13:03:48.000-0600

If anybody thinks they have the key to this, feel free to reopen!

By: jerjer (jerjer) 2007-01-16 22:23:39.000-0600

crw requested re-opening

By: crw (crw) 2007-01-16 22:33:45.000-0600

The key to reproducing this is to call


on a newly running system.  You cannot call any other date functions
before calling it this way.  The key is the blank timezone (second argument).
For example, if you instead call


The bug will not occur and everything will be correct until asterisk is

In summary, if the first thing you execute on a newly running asterisk is:


Both the times will be in GMT and all other calls will report GMT.
However if the first you execute this instead:


all times from then on will be in localtime.

I suspect a bug in ast_tzset() and friends.

By: Serge Vecher (serge-v) 2007-01-18 11:46:49.000-0600

what asterisk release/revision have you reproduced this on?

By: crw (crw) 2007-01-18 11:50:22.000-0600

Sorry for not reporting that.
This occurs on 1.2 and 1.4.

I should also mention the reason this was occurring to
me is that I was passing the format (arg3) but had
left the timezone (arg2) blank.  My current workaround
is to actually supply the local timezone in arg2.

By: Tilghman Lesher (tilghman) 2007-01-18 11:57:43.000-0600

Okay, new patch to test.

By: crw (crw) 2007-01-18 12:55:24.000-0600

That seems to have fixed the timezone problem I was
having (seemingly randomly) for the last year or two!

You need to add an
#include "asterisk/strings.h"
to the patch.

By: Tilghman Lesher (tilghman) 2007-01-18 15:16:47.000-0600

Committed, rev 51255, 51256, 51257.