On Linux, I need to find the currently configured timezone as an Olson location. I want my (C or C++) code to be portable to as many Linux systems as possible.
For e
There is no standard c or c++ function for this. However, GNU libc has an extention. its struct tm
has two extra members:
long tm_gmtoff; /* Seconds east of UTC */
const char *tm_zone; /* Timezone abbreviation */
This means that if you use one of the functions which populates a struct tm
(such as localtime
or gmtime
) you can use these extra fields. This is of course only if you are using GNU libc (and a sufficiently recent version of it).
Also many systems have a int gettimeofday(struct timeval *tv, struct timezone *tz);
function (POSIX) which will fill in a struct timezone
. This has the following fields:
struct timezone {
int tz_minuteswest; /* minutes west of Greenwich */
int tz_dsttime; /* type of DST correction */
};
Not exactly what you asked for, but close...
I've been working on a free, open source C++11/14 library which addresses this question in a single line of code:
std::cout << date::current_zone()->name() << '\n';
It is meant to be portable across all recent flavors of Linux, macOS and Windows. For me this program outputs:
America/New_York
If you download this library, and it doesn't work you, bug reports are welcome.
FWIW, RHEL/Fedora/CentOS have /etc/sysconfig/clock
:
ZONE="Europe/Brussels"
UTC=true
ARC=false
Pretty late in the day, but I was looking for something similar and found that ICU library has the provision to get the Olson timezone ID: http://userguide.icu-project.org/datetime/timezone
It is now installed on most linux distributions (install the libicu-dev package or equivalent). Code:
#include <unicode/timezone.h>
#include <iostream>
using namespace U_ICU_NAMESPACE;
int main() {
TimeZone* tz = TimeZone::createDefault();
UnicodeString us;
tz->getID(us);
std::string s;
us.toUTF8String(s);
std::cout << "Current timezone ID: " << s << '\n';
delete tz;
return 0;
}
And to get the abbreviated/POSIX timezone names (should also work on Windows):
#include <time.h>
int main() {
time_t ts = 0;
struct tm t;
char buf[16];
::localtime_r(&ts, &t);
::strftime(buf, sizeof(buf), "%z", &t);
std::cout << "Current timezone (POSIX): " << buf << std::endl;
::strftime(buf, sizeof(buf), "%Z", &t);
std::cout << "Current timezone: " << buf << std::endl;
Here's code that works for most versions of Linux.
#include <iostream>
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
using namespace std;
void main()
{
char filename[256];
struct stat fstat;
int status;
status = lstat("/etc/localtime", &fstat);
if (S_ISLNK(fstat.st_mode))
{
cout << "/etc/localtime Is a link" << endl;
int nSize = readlink("/etc/localtime", filename, 256);
if (nSize > 0)
{
filename[nSize] = 0;
cout << " linked filename " << filename << endl;
cout << " Timezone " << filename + 20 << endl;
}
}
else if (S_ISREG(fstat.st_mode))
cout << "/etc/localtime Is a file" << endl;
}
On Linux, I need to find the current timezone as an Olson location. I want my (C or C++) code to be portable to as many Linux systems as possible.
If you want to be portable, then use only GMT internally. Due to multi-user heritge, *NIX system clock is normally is in GMT and there is no system wide timezone - because different users connected to the system might be living in different timezones.
The user specific timezone is reflected in TZ
environment variable and you might need to use that only when converting internal date/time into the user readable form. Otherwise, localtime()
takes care of it automatically for you.