Getting Windows Time Zone Information (C++/MFC) - c++

I’m trying to:
Get a list of the time zone names as they appear in when the user selects a time zone from the Windows Control Panel (e.g., “(UTC-08:00) Pacific Time (US & Canada)”).
I’m doing that by reading “CurrentVersion\Time Zones” section of the registry which works well.
Get the currently selected time zone as a string.
I can get the current time zone using GetTimeZoneInformation(), but the names don’t match the list of time zones retrieved from “CurrentVersion\Time Zones” section of the registry. For example, Pacific time appears as “(UTC-08:00) Pacific Time (US & Canada)” in the list of time zones, but GetTimeZoneInformation() contains the strings “Pacific Standard Time” and “Pacific Daylight Time”. I need to find a name that corresponds to the “CurrentVersion\Time Zones” names so I can select it from a list.
Get the current offset (in minutes) between UTC and any other time zone based on the string name.
I can retrieve the offset from UTC in timeZoneInformation.Bias, but that’s only for the currently selected time zone. I need to know the “bias” from any zone as listed in the registry (e.g., “(UC-07:00) Mountain Time (US & Canada)” while adjusting for the daylight savings if in effect.

Microsoft chooses to put the string you want in a different area, some strings are non trivial to retrieve. But parts of your question can be answered with the information you have already.
In CurrentVersion\Time Zones, yes are the names of the zones.
Inside that key are the values for some of the parts you want.
re: “(UTC-08:00) Pacific Time (US & Canada)”
This is in the registry value "Display" under the zone name you have.
There are more strings in a resource DLL, specified by the values "MUI_Display", "MUI_Std" and "MUI_Dlt". It is usually something like "#tzres.dll,-220"
To get these strings you will need to load that resource DLL into memory and fetch those specific resources as UNICODE strings.
re: Offset in minutes of any timezone.
Also inside the registry key you have (the time zone name) is a value called "TZI".
This is a binary blob that (according to the MSDN) looks like this:
typedef struct _REG_TZI_FORMAT
{
LONG Bias;
LONG StandardBias;
LONG DaylightBias;
SYSTEMTIME StandardDate;
SYSTEMTIME DaylightDate;
} REG_TZI_FORMAT;
Where the various BIAS are in minutes, using the equation UTC = local + theBias and theBias is either Bias + StandardBias or Bias + DaylightBias depending on the date in question. The two SYSTEMTIME values describe the transition dates.

TimeZoneInfo.Bias
TIME_ZONE_INFORMATION structure - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725481(v=vs.85).aspx
SetTimeZoneInformation function - http://msdn.microsoft.com/en-us/library/windows/desktop/ms724944(v=vs.85).aspx
// Get the local system time.
SYSTEMTIME LocalTime = { 0 };
GetSystemTime( &LocalTime );
// Get the timezone info.
TIME_ZONE_INFORMATION TimeZoneInfo;
GetTimeZoneInformation( &TimeZoneInfo );
// Convert local time to UTC.
SYSTEMTIME GmtTime = { 0 };
TzSpecificLocalTimeToSystemTime( &TimeZoneInfo,
&LocalTime,
&GmtTime );
// GMT = LocalTime + TimeZoneInfo.Bias
// TimeZoneInfo.Bias is the difference between local time
// and GMT in minutes.
// Local time expressed in terms of GMT bias.
float TimeZoneDifference = -( float(TimeZoneInfo.Bias) / 60 );
CString csLocalTimeInGmt;
csLocalTimeInGmt.Format( _T("%ld:%ld:%ld + %2.1f Hrs"),
GmtTime.wHour,
GmtTime.wMinute,
GmtTime.wSecond,
TimeZoneDifference );
TimeZoneInfo Class - http://msdn.microsoft.com/en-us/library/bb396389
Determine Daylight Savings Time - http://www.metatrader4.com/forum/2155

Related

C++ declare zoned_time for 1 PM today east coast time

I'm looking for how to declare a time for a configurable number of minutes before 1 pm east coast time on the day of running the program. I've found ways to get a fixed time of the timezone such as:
chrono::zoned_time onePmEastCoastTime ("New York/New York", chrono::sys_days{ 2022y / chrono::April/ 15d } + 13h );
How can I declare a configurable time that will match a specific timezone?
It sounds like you want to specify the time in terms of local time as opposed to UTC. The key to this is in the use of local_days vs sys_days.
sys_days is a count of days in UTC.
local_days is a count of days in some local time that can be subsequently paired with a timezone.
Maybe you are looking for:
chrono::minutes m = ...
chrono::zoned_time onePmEastCoastTime{"America/New_York",
chrono::local_days{ 2022y / chrono::April/ 15d } + 13h - m};

How boost local_date_time can use time zone database for a given timezone offset?

I was trying to understand how Boost::date_time::local_date_time support timezone specific calculations (e.g. : dst etc). I found some information on this link :http://www.boost.org/doc/libs/1_55_0/doc/html/date_time/local_time.html
In the following code, we establish time zone pointer for New York and Phoenix :
tz_database tz_db;
tz_db.load_from_file("date_time_zonespec.csv");
time_zone_ptr nyc_tz = tz_db.time_zone_from_region("America/New_York");
time_zone_ptr phx_tz(new posix_time_zone("MST-07:00:00"));
How can we define the time zone ptr for a region for which we have only the time zone offset (for example -7:00:00) and not the name as string (e.g. America/New York)? I need precise calculation of timestamps in various timezones.

C++ timegm conversion DST to a certain timezone at a given time in the future?

I need an accurate conversion in my class from UTC time to local time of a given timezone, with or without DST in effect. My problem is, that when I use struct tm I have to provide the tm_isdst member, or leave it -1 to be determined automatically.
from mktime(3) - linux man page:
"The value specified in the tm_isdst field informs mktime() whether or not daylight saving time (DST) is in effect for the time supplied in the tm structure:
a positive value means DST is in effect;
zero means that DST is not in effect;
and a negative value means that mktime() should (use timezone information and system databases to) attempt to determine whether DST is in effect at the specified time.
Now here's my problem. I'm working with exchanges from all over the globe (from Chicago, New York, Sao Paolo, Melbourne, Buenos Aires, Johannesburg, Shanghai, Seoul ...). I have a table with the name of each timezone for each of the exchanges: for example Africa/Johannesburg, America/Chicago, America/Winnipeg.
The data I'm working on is expiration for some given futures and options financial instruments. The data I'm receiving is always in UTC, and I need to convert to the local time of the exchange.
Long story short, my current implementation is adding 1 extra hour to the expiration time of those assets that should not have the DST in effect (for example an instrument that expires in December and local time is America/Chicago, should add -360 minutes offset and DST 0, while another one which expires in June in the same timezone should have -360 timezone offset +60 DST offset, which would be -300 offset to the UTC timestamp. What I'm currently having the problem with, for example for the month of December I get 9:30 AM instead of 8:30 AM as the UTC timestamp contains the dst offset already.
Here is my function for doing the conversion, which is obviously broken:
#ifdef WIN32
#define timegm _mkgmtime
#endif
SimpleDateTime BusinessDateCalculator::UTC2TZ(const SimpleDateTime& utcDateTime, const int tz_utc_offset, const int tz_dst)
{
struct tm stm;
memset(&stm, 0, sizeof(stm));
stm.tm_year = utcDateTime.getYear() - 1900;
stm.tm_mon = utcDateTime.getMonth() - 1;
stm.tm_mday = utcDateTime.getDay();
stm.tm_hour = utcDateTime.getHour();
stm.tm_min = utcDateTime.getMinute();
stm.tm_sec = utcDateTime.getSecond();
stm.tm_isdst = -1; //see note at the top of this file
time_t tt = timegm( &stm );
tt += (tz_utc_offset + tz_dst) * 60;
struct tm ntm;
memset(&ntm, 0, sizeof(ntm));
gmtime_r( &tt, &ntm );
return SimpleDateTime(ntm.tm_year + 1900, ntm.tm_mon + 1, ntm.tm_mday, ntm.tm_hour, ntm.tm_min, ntm.tm_sec, utcDateTime.getMillisecond());
}
Where SimpleDateTime is a date-time class with additional functionality, like conversion from different date/time formats (SQL, FIX, Timeonly, DateOnly).
I have the timezone information of a certain exchange available at all time. My question can I provide the timezone name somehow, and let the timegm perform a database search and determine whether in the America/Chicago timezone the DST is or is not in effect on 2014-12-19 and accordingly not add the extra 60 minutes to the UTC time, and on the same date for example in the southern hemisphere timezone America/Sao_Paulo it is in effect until 16 Feb 2015, and for this timestamp it should add 60 minutes to get the correct local time for the given date.
When you refer to a time zone by it's IANA identifier (eg "America/Chicago") - that already includes all of the DST information and full history of the time zone. At least, it does in the original source data in the IANA time zone database.
You mentioned Boost (in comments). While Boost does have support for these types of identifiers, it makes the mistake of assuming that they are permanently fixed in time. That is not true, as time zones of the world change their offsets and DST rules all the time. Consider that the USA changed its DST rules in 2007, and that Russia is changing its time zones significantly later this year (Oct. 2014). If you look at the Boost time zone data file, you'll see that its format strips away all of the history and just maps each identifier to a single set of rules. For this reason, I recommend you do not use Boost for local time zone conversions.
Instead, consider using ICU. Among other things, it includes time zone conversion functions, and uses the full copy of the IANA time zone database. You can read more here, and see sample code here. I'm not particularly skilled in C++, but it would appear that you can use ICU's Calendar class to project a UTC time to a local time in a particular time zone.
Another option would be to use the time zone functions built in to the GNU C library. It also uses the full time zone database. There's a simple example of converting UTC tor local time using an IANA/Olson identifier on this site, which I have also posted below:
/*
C source code example: Convert UTC to local time zone, considering daylight
savings. Uses mktime(), gmtime() and localtime(). Works for dates between
years 1902 and 2037. Should compile and run with any recent GNU C if your
tzdata is healthy. Written by Robert Larsson http://rl.se
Code put in public domain; do what you want with it.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define DESTZONE "TZ=Europe/Stockholm" // Our destination time zone
int main(void)
{
struct tm i;
time_t stamp; // Can be negative, so works before 1970
putenv("TZ=UTC"); // Begin work in Greenwich …
i.tm_year = 2009-1900; // Populate struct members with
i.tm_mon = 8-1; // the UTC time details, we use
i.tm_mday = 29; // 29th August, 2009 12:34:56
i.tm_hour = 12; // in this example
i.tm_min = 34;
i.tm_sec = 56;
stamp = mktime(&i); // Convert the struct to a Unix timestamp
putenv(DESTZONE); // Switch to destination time zone
printf("UTC : %s", asctime(gmtime(&stamp)));
printf("Local: %s", asctime(localtime(&stamp)));
return 0; // That’s it, folks.
}

How to check whether day light savings enabled for the given UTC offset?

I need to determine whether day light savings enabled for a given UTC offset in Linux(Redhat).
I get input such as UTC+05:30.
I checked the usage of zdump command. When used with time zone name, we can check the value of isdst in the output to determine the status of daylight-savings.
zdump -v /usr/share/zoneinfo/Asia/Kolkata | grep 2013
As above, zdump requires zone name. It doesn't accept UTC offset.
I also tried localtime function as below.
time_t currtime;
struct tm * timeinfo;
timeinfo = localtime ( &currtime );
time_t local = mktime( timeinfo );
cout<<timeinfo->tm_isdst<<endl;
The above code works when time zone name is set in date time settings. It doesn't work if system is using UTC time. I used gmtime instead of localtime when UTC time is used.
Please let me know if there is any way to determine whether dst is enabled or not using UTC offset.
This is in general not possible. UTC+05:30 might be used by many countries, each with a different daylight savings time policy.
UTC offset isn't enough to determine whether DST is enabled, as some jurisdictions don't use DST. Furthermore, those that do have different schedules for when it goes into effect (e.g., places in the southern hemisphere vs. places in the northern hemisphere). What you need is an up to date table that has the time zone names that use DST and when DST starts and stops for each.

Convert historical time to GMT

I need to convert some string times in the format "2011061411322100" into GMT - my first attempt is below. However, the problem is that the times are coming from another PC and is a historical time. So I am not getting the times in real time so I cannot simply get the GMT from the local time on the box that my code is running.
The problem is that if my code is running during a time change, the time change will have occurred on my box but not on the remote box where I am getting the times. I can however, query the box to get the current time at any time.
So, to give more detail:
I start the job on a remote box
The job completes
I get some times related to the job running
I convert the time to GMT
If a time change (daylight savings) occurs between 1. and 2. I am screwed. My GMT conversion will break. I guess after 2) I need to get the current Remote Box time and see if there is a difference of >58 mins and then apply that to the conversion. But I cannot figure out a reliable method of doing this.
string GMTConverter::strToGMT(const string& timeToConvert)
{
// Set time zone from TZ environment variable.
_tzset();
struct tm tmTime;
//2011 06 14 11 32 21 00
// (strToInt is just a wrapper for atoi)
int year = strToint(timeToConvert.substr(0, 4) );
int month = strToint(timeToConvert.substr(4, 2) );
int day = strToint(timeToConvert.substr(6, 2) );
int hour = strToint(timeToConvert.substr(8, 2) );
int min = strToint(timeToConvert.substr(10, 2) );
int sec = strToint(timeToConvert.substr(12, 2) );
cout<<"Time after parsing: "<<year<<"/"<<month<<"/"<<day<<" "<<hour<<":"<<min<<":"<<sec<<endl;
// add to tm struct and return
tmTime.tm_hour = hour;
tmTime.tm_min = min;
tmTime.tm_sec = sec;
tmTime.tm_mday = day;
tmTime.tm_mon = (month-1);
tmTime.tm_year = (year - 1900);
cout <<"Time in TM: "<<tmTime.tm_year<<"/"<<tmTime.tm_mon<<"/"<<tmTime.tm_mday<<" "<<tmTime.tm_hour<<":"<<tmTime.tm_min<<":"<<tmTime.tm_sec<<endl;
char currDateTime[64];
// For logging
strftime(currDateTime, 63, "%c", &tmTime);
cout <<"Actual time:"<<currDateTime<<endl;
time_t remotePCTime = mktime( &tmTime );
struct tm *gmt = gmtime( &remotePCTime );
cout << "gmt = " << asctime( gmt ) << endl;
char datebuf_2[12];
char timebuf_2[13];
strftime( datebuf_2, 13, "%Y-%m-%d\0", gmt );
strftime( timebuf_2, 13, "%H:%M:%S\0", gmt );
return string(datebuf_2) + "T" + string(timebuf_2) + "." + string("000");
}
The obvious reliable solution would be to use UTC (which has no daylight savings) for the time stamp you're sending over. Using any time system that has inherent ambiguity (there is one hour of overlap each year where you can get the same time stamps on a different time) will make it impossible to have a fool-proof method, since information is lost.
If you have no control over the time format that the remote machine is sending, you can only try to extrapolate from the information that you do have, for instance, if the end time is lower than the start time, add one hour. This again introduces ambiguity if the job took longer than one hour, but at least time won't move backwards.
Time change appears twice a year - why should you bother? Anyway, can't you change the time format to include the time change event? Or check if job is done during time change by comparing to some fixed time and date at which time change appears?
Get the local time in UTC at the start and end of the remote job. Get the remote job time and covert to UTC at the start and end of the job. Convert the collection "historic" times to GMT/UTC as stated in your original post. Keep this data together in a struct or class and give additional start end times a clear name like LocalDLSValidation etc
We must now checkfor following scenarios:
1. Start and end time delta between Local and Remote is within allowed threshold(50mins?)
This the gold case. No modification is required to our collection of historical times
2. Local start/end time and remote time delta is outside threshold.
This is the second simplest case. It means that we can + or - hour to our entire collection of times.
3.Local start time and remote time delta is within threshold. But end is outside.
This is our worst case scenario as it means change has occurred in the middle of our job. If the job lasts less than hour then it will be easy to see which times in our collection need to be + or - one hour.
If it is greater than 1 hour....mmmmm. This is where we run into problems.
4. Start time between local and remote is different but end time is different
According to use case in OP this should not occur.