blob: 023e51470ef047bf1bbd132003aa0fd7856bb9b5 [file] [log] [blame]
/***************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* *
* This software is published under the terms of the Apache Software *
* License version 1.1, a copy of which has been included with this *
* distribution in the license.apl file. *
***************************************************************************/
#include <log4cxx/helpers/timezone.h>
#include <locale>
int getYear(int64_t date)
{
time_t d = (time_t)(date / 1000);
return ::localtime(&d)->tm_year;
}
using namespace log4cxx;
using namespace log4cxx::helpers;
IMPLEMENT_LOG4CXX_OBJECT(TimeZone)
TimeZonePtr TimeZone::defaultTimeZone = new TimeZone(_T(""));
TimeZone::TimeZone(const String& ID)
: ID(ID), rawOffset(0), DSTSavings(0)
{
String timeZoneEnv = _T("TZ=") + ID;
USES_CONVERSION;
::putenv((char *)T2A(timeZoneEnv.c_str()));
tzset();
time_t now = time(0);
tm localNow = *::localtime(&now);
tm utcNow = *::gmtime(&now);
rawOffset = (int)::difftime(::mktime(&localNow), ::mktime(&utcNow)) * 1000;
int year = localNow.tm_year;
Rule * rule = new Rule(year);
// we check if we found a daylight time
if (rule->startDate != 0 && rule->endDate != 0)
{
// since we have computed a rule, we store it
rules.insert(RuleMap::value_type(year, rule));
DSTSavings = 3600 * 1000; // 1 hour
}
else
{
delete rule;
}
}
TimeZone::~TimeZone()
{
for (RuleMap::iterator it = rules.begin(); it != rules.end(); it++)
{
Rule * rule = it->second;
delete rule;
}
}
int TimeZone::getOffset(int64_t date) const
{
if (inDaylightTime(date))
{
return rawOffset + DSTSavings;
}
else
{
return rawOffset;
}
}
TimeZonePtr TimeZone::getDefault()
{
return defaultTimeZone;
}
TimeZonePtr TimeZone::getTimeZone(const String& ID)
{
return new TimeZone(ID);
}
bool TimeZone::inDaylightTime(int64_t date) const
{
if (!useDaylightTime())
{
return false;
}
time_t d = (time_t)(date / 1000);
int year = ::localtime(&d)->tm_year;
RuleMap::iterator it = rules.find(year);
if (it == rules.end())
{
synchronized sync(this);
it = rules.find(year);
if (it == rules.end())
{
it = rules.insert(RuleMap::value_type(
year, new Rule(year))).first;
}
}
Rule * rule = it->second;
return (date >= rule->startDate && date < rule->endDate);
}
TimeZone::Rule::Rule(int year)
: startDate(0), endDate(0)
{
tm tm;
memset (&tm, 0, sizeof (tm));
tm.tm_mday = 1;
tm.tm_year = year;
time_t t = ::mktime(&tm);
int isDST, day, hour, min;
for (day = 0; day < 365; day++)
{
t += 60 * 60 * 24;
isDST = ::localtime(&t)->tm_isdst;
if (startDate == 0)
{
if (isDST > 0)
{
t -= 60 * 60 * 24;
for (hour = 0; hour < 24; hour++)
{
t += 60 * 60;
isDST = ::localtime(&t)->tm_isdst;
if (isDST > 0)
{
t -= 60 * 60;
for (min = 0; min < 60; min++)
{
t += 60;
isDST = ::localtime(&t)->tm_isdst;
if (isDST > 0)
{
startDate = (int64_t)t * 1000;
break;
}
}
break;
}
}
}
}
else if (isDST == 0)
{
t -= 60 * 60 * 24;
for (hour = 0; hour < 24; hour++)
{
t += 60 * 60;
isDST = ::localtime(&t)->tm_isdst;
if (isDST == 0)
{
t -= 60 * 60;
for (min = 0; min < 60; min++)
{
t += 60;
isDST = ::localtime(&t)->tm_isdst;
if (isDST == 0)
{
endDate = (int64_t)t * 1000;
break;
}
}
break;
}
}
if (endDate != 0)
{
break;
}
}
}
}