Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix dst and utcOffset handling for Dublin time zone #3509

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions Foundation/include/Poco/Timezone.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,24 @@ class Foundation_API Timezone
static int utcOffset();
/// Returns the offset of local time to UTC, in seconds.
/// local time = UTC + utcOffset() + dst().

static int dst();
/// Returns the daylight saving time offset in seconds if
/// daylight saving time is in use.
/// local time = UTC + utcOffset() + dst().


#if !defined(POCO_OS_FAMILY_WINDOWS)
static int utcOffset(const Poco::Timestamp& timestamp);
/// Returns the offset of local time to UTC
/// for the given time, in seconds.
/// local time = UTC + utcOffset() + dst().

static int dst(const Poco::Timestamp& timestamp);
/// Returns the daylight saving time offset in seconds if
/// daylight saving time is in use for the given time.
/// local time = UTC + utcOffset() + dst().
#endif

static bool isDst(const Timestamp& timestamp);
/// Returns true if daylight saving time is in effect
/// for the given time. Depending on the operating system
Expand Down
6 changes: 3 additions & 3 deletions Foundation/src/LocalDateTime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ void LocalDateTime::determineTzd(bool adjust)
if (!localtime_r(&epochTime, &broken))
throw Poco::SystemException("cannot get local time");
#endif
_tzd = (Timezone::utcOffset() + ((broken.tm_isdst == 1) ? 3600 : 0));
_tzd = (Timezone::utcOffset() + Timezone::dst(_dateTime.timestamp()));
#endif
adjustForTzd();
}
Expand Down Expand Up @@ -307,8 +307,8 @@ std::time_t LocalDateTime::dstOffset(int& dstOffset) const
#else
local = std::mktime(&broken);
#endif
dstOffset = (broken.tm_isdst == 1) ? 3600 : 0;

dstOffset = (broken.tm_isdst == 1) ? Timezone::dst(_dateTime.timestamp()) : 0;
return local;
}

Expand Down
54 changes: 32 additions & 22 deletions Foundation/src/Timezone_UNIX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,16 @@ class TZInfo
{
tzset();
}

int timeZone()
{
Poco::FastMutex::ScopedLock lock(_mutex);

#if defined(__APPLE__) || defined(__FreeBSD__) || defined (__OpenBSD__) || POCO_OS == POCO_OS_ANDROID // no timezone global var
std::time_t now = std::time(NULL);
struct std::tm t;
gmtime_r(&now, &t);
std::time_t utc = std::mktime(&t);
return now - utc;
#elif defined(__CYGWIN__)
tzset();
return -_timezone;
static long gmtOffset(const struct std::tm& t)
{
#if defined(__CYGWIN__)
return t.__TM_GMTOFF;
#else
tzset();
return -timezone;
return t.tm_gmtoff;
#endif
}

const char* name(bool dst)
{
Poco::FastMutex::ScopedLock lock(_mutex);
Expand All @@ -64,19 +54,39 @@ class TZInfo
static TZInfo tzInfo;


int Timezone::utcOffset(const Poco::Timestamp& timestamp)
{
std::time_t time = timestamp.epochTime();
struct std::tm local;
if (!localtime_r(&time, &local))
throw Poco::SystemException("cannot get UTC offset");
struct std::tm utc;
gmtime_r(&time, &utc);
std::time_t utctime = std::mktime(&utc);
return time - utctime;
}


int Timezone::utcOffset()
{
return tzInfo.timeZone();
return utcOffset(Poco::Timestamp());
}


int Timezone::dst()
{
std::time_t now = std::time(NULL);
struct std::tm t;
if (!localtime_r(&now, &t))
return dst(Poco::Timestamp());
}


int Timezone::dst(const Poco::Timestamp& timestamp)
{
std::time_t time = timestamp.epochTime();
struct std::tm local;
if (!localtime_r(&time, &local))
throw Poco::SystemException("cannot get local time DST offset");
return t.tm_isdst == 1 ? 3600 : 0;
long dst = TZInfo::gmtOffset(local) - utcOffset(timestamp);
return local.tm_isdst == 1 ? dst : 0;
}


Expand Down
30 changes: 30 additions & 0 deletions Foundation/testsuite/src/LocalDateTimeTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,35 @@ void LocalDateTimeTest::testTimezone()
#endif
}

void LocalDateTimeTest::testTimezone2()
{
#if defined(POCO_OS_FAMILY_UNIX)
std::vector<std::string> timezones = {
"/usr/share/zoneinfo/America/Los_Angeles",
"/usr/share/zoneinfo/Europe/London",
"/usr/share/zoneinfo/Europe/Dublin", // special winter time of Ireland
"/usr/share/zoneinfo/Europe/Prague",
};

std::cout << "\n";

for (const std::string& tz : timezones) {
setenv("TZ", tz.c_str(), 1); // POSIX-specific
std::vector<LocalDateTime> times = {
LocalDateTime(2022, 06, 29), // summer period
LocalDateTime(2022, 01, 29), // winter period
};
for (const LocalDateTime& ldt : times) {
std::time_t t = ldt.timestamp().epochTime();
std::tm then;
then = *std::localtime(&t);
assertTrue (then.tm_gmtoff == ldt.tzd());
}
unsetenv("TZ");
}
#endif
}


void LocalDateTimeTest::setUp()
{
Expand All @@ -473,6 +502,7 @@ CppUnit::Test* LocalDateTimeTest::suite()
CppUnit_addTest(pSuite, LocalDateTimeTest, testArithmetics2);
CppUnit_addTest(pSuite, LocalDateTimeTest, testSwap);
CppUnit_addTest(pSuite, LocalDateTimeTest, testTimezone);
CppUnit_addTest(pSuite, LocalDateTimeTest, testTimezone2);

return pSuite;
}
1 change: 1 addition & 0 deletions Foundation/testsuite/src/LocalDateTimeTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class LocalDateTimeTest: public CppUnit::TestCase
void testArithmetics2();
void testSwap();
void testTimezone();
void testTimezone2();

void setUp();
void tearDown();
Expand Down