The enclosed patch fixes multiple problems:
1) Restores the TZ environment variable. This was a critical bug for us.
2) Sets the TZ environment variable using a static array. In my putenv man page, there is an explicit warning against using a local variable to set environment variables. There are probably other instances where this is done incorrectly in log4cxx.
3) Correctly calculates daylight savings in the southern hemisphere. Down here we have DST in January, not June.
diff -u -r1.1 timezone.cpp
--- ./src/timezone.cpp 28 Jul 2004 04:52:55 -0000 1.1
+++ ./src/timezone.cpp 3 Nov 2004 08:56:13 -0000
@@ -17,6 +17,7 @@
#include <log4cxx/helpers/timezone.h>
#include <locale>
+#define ENV_LENGTH 100
int getYear(int64_t date)
{
@@ -31,13 +32,16 @@
TimeZonePtr TimeZone::defaultTimeZone = new TimeZone(_T(""));
+static char tz_env_var[ENV_LENGTH+1];
+
TimeZone::TimeZone(const String& ID)
: ID(ID), rawOffset(0), DSTSavings(0)
{
- String timeZoneEnv = _T("TZ=") + ID;
-
- USES_CONVERSION;
- ::putenv((char *)T2A(timeZoneEnv.c_str()));
+ char *old_tz = getenv( "TZ" );
+ tz_env_var[ENV_LENGTH] = '\0';
+ strncpy( tz_env_var, "TZ=", ENV_LENGTH-1 );
+ strncat( tz_env_var, ID.c_str(), ENV_LENGTH-4 );
+ ::putenv( tz_env_var );
tzset();
time_t now = time(0);
@@ -49,7 +53,7 @@
Rule * rule = new Rule(year);
// we check if we found a daylight time
- if (rule->startDate != 0 && rule->endDate != 0)
+ if (rule->hasDSTDates())
{
// since we have computed a rule, we store it
rules.insert(RuleMap::value_type(year, rule));
@@ -59,6 +63,15 @@
{
delete rule;
}
+ if (old_tz)
+ {
+ putenv( old_tz-3 );
+ }
+ else
+ {
+ strcpy( tz_env_var, "log4TZUNSET=0" );
+ }
+ tzset();
}
TimeZone::~TimeZone()
@@ -115,8 +128,17 @@
}
}
- Rule * rule = it->second;
- return (date >= rule->startDate && date < rule->endDate);
+ return it->second->dateIsDST( date );
+}
+
+int TimeZone::Rule::IsAdjustedDST(time_t* t )
+{
+ int isDST = ::localtime(t)->tm_isdst;
+ if (invertDST && isDST>=0)
+ {
+ isDST = (isDST ? 0 : 1);
+ }
+ return isDST;
}
TimeZone::Rule::Rule(int year)
@@ -130,11 +152,12 @@
time_t t = ::mktime(&tm);
int isDST, day, hour, min;
+ invertDST = (::localtime(&t)->tm_isdst > 0 );
for (day = 0; day < 365; day++)
{
t += 60 * 60 * 24;
- isDST = ::localtime(&t)->tm_isdst;
+ isDST = IsAdjustedDST( &t );
if (startDate == 0)
{
if (isDST > 0)
@@ -145,14 +168,14 @@
{
t += 60 * 60;
- isDST = ::localtime(&t)->tm_isdst;
+ isDST = IsAdjustedDST( &t );
if (isDST > 0)
{
t -= 60 * 60;
for (min = 0; min < 60; min++)
{
t += 60;
- isDST =
::localtime(&t)->tm_isdst;
+ isDST = IsAdjustedDST(
&t );
if (isDST > 0)
{
startDate =
(int64_t)t * 1000;
@@ -173,14 +196,14 @@
{
t += 60 * 60;
- isDST = ::localtime(&t)->tm_isdst;
+ isDST = IsAdjustedDST( &t );
if (isDST == 0)
{
t -= 60 * 60;
for (min = 0; min < 60; min++)
{
t += 60;
- isDST =
::localtime(&t)->tm_isdst;
+ isDST = IsAdjustedDST( &t );
if (isDST == 0)
{
endDate = (int64_t)t *
1000;
@@ -200,4 +223,17 @@
}
}
+bool TimeZone::Rule::dateIsDST(int64_t date)
+{
+ if (!hasDSTDates())
+ {
+ return false;
+ }
+ bool ret_val = (date>=startDate && date<endDate);
+ if (invertDST)
+ {
+ ret_val = !ret_val;
+ }
+ return ret_val;
+}
diff -u -r1.1 -r1.3
--- ./include/log4cxx/helpers/timezone.h 28 Jul 2004 04:52:47 -0000
1.1
+++ ./include/log4cxx/helpers/timezone.h 26 Oct 2004 00:14:21 -0000
1.3
@@ -104,9 +104,19 @@
{
public:
Rule(int year);
+ inline bool dateIsDST(int64_t date);
+ inline bool hasDSTDates(){ return (startDate!=0 && endDate!=0); }
+ private:
int year;
- int64_t startDate;
- int64_t endDate;
+ int64_t startDate; // Start of first change to
_OR_ from DST
+ int64_t endDate; // Start of second change to
_OR_ from DST
+ bool invertDST;
+ /**
+ Queries if the given time is subject to Daylight savings
+ @return true if this time is adjusted for daylight savings time, false,
+ otherwise.
+ */
+ int IsAdjustedDST(time_t* t);
};
typedef std::map<long, Rule *> RuleMap;
