tzfile format : handling of istd and isgmt - timezone

I'm trying to parse the tzfile (Olson) format on a Unix system. In the tzfile(5) man page it states the following:
Then there are tzh_ttisstdcnt standard/wall indicators, each stored
as a one-byte value; they tell whether the transition times
associated with local time types were specified as standard time or
wall clock time, and are used when a timezone file is used in
handling POSIX-style timezone environment variables.
Finally, there are tzh_ttisgmtcnt UTC/local indicators, each stored
as a one-byte value; they tell whether the transition times
associated with local time types were specified as UTC or local time,
and are used when a timezone file is used in handling POSIX-style
timezone environment variables.
Does this mean I can ignore isstd and isgmt and still get the correct times? In spot checking, this seems to be the case but in digging around in the C source files, I see unix makes some adjustments dependant on these values.

As requested above, I asked on the mailing list. The answer was to look in the code. So the relevant code is in zic.c (zone compiler) and glib's tzfile.c. Source code for both can be found on github at the time of this wring. The relevant code for zic.c is
switch (lowerit(*ep)) {
case 's': /* Standard */
rp->r_todisstd = true;
rp->r_todisgmt = false;
*ep = '\0';
break;
case 'w': /* Wall */
rp->r_todisstd = false;
rp->r_todisgmt = false;
*ep = '\0';
break;
case 'g': /* Greenwich */
case 'u': /* Universal */
case 'z': /* Zulu */
rp->r_todisstd = true;
rp->r_todisgmt = true;
*ep = '\0';
break;
Which says there are 3 possible cases: isstd = true && isgmt = false, both false and both true. So to see what is done with these flags, the relevant code in tzfile.c is
if (trans_type->isgmt)
/* The transition time is in GMT. No correction to apply. */ ;
else if (isdst && !trans_type->isstd)
/* The type says this transition is in "local wall clock time", and
wall clock time as of the previous transition was DST. Correct
for the difference between the rule's DST offset and the user's
DST offset. */
transitions[i] += dstoff - rule_dstoff;
else
/* This transition is in "local wall clock time", and wall clock
time as of this iteration is non-DST. Correct for the
difference between the rule's standard offset and the user's
standard offset. */
transitions[i] += stdoff - rule_stdoff;
So this seems to say that if isgmt is true we can ignore everything else. If it is false then if the previous transition was DST and the current one is not standard (i.e. case 'w' above, as it's also not gmt) apply the dst offset (the last one found in the file). Otherwise apply the standard offset.
Which seems to mean that glibc ignores the offsets in the individual tt_types and case 's'. I looked in localtime.c in the tz package and it worked the same way.
I can only conclude from all this that most of the information in the tzfile isn't actually used anywhere. Some of this may be due to POSIX requirements. If anyone can expand on the details below, please do. It would be nice to have this behaviour documented somewhere on the internet besides in C source code.

Related

Why is this basic MQL4-code taking so much time to load up on my MT4?

I am learning MQL4 language and am using this Code to plot a Simple moving Average, the Code works fine, but when I load it up on my MT4 it takes a lot of time, am I missing something ?
int start() // Special function start()
{
int i, // Bar index
n, // Formal parameter
Counted_bars; // Number of counted bars
// Sum of Low values for period
// --------------------------------------------------------------------
Counted_bars=IndicatorCounted(); // Number of counted bars
i=Bars-Counted_bars-1; // Index of the first uncounted
while(i>=0) // Loop for uncounted bars
{
Buf_0[i]=(iMA(Symbol(),PERIOD_M5,200,i,MODE_EMA,PRICE_HIGH,0);
i--; // Calculating index of the next bar
}
// --------------------------------------------------------------------
return; // Exit the special funct. start()
}
// --------------------------------------------------------------------
Q : am I missing something?
No, this is a standard feature to process all the Bars back, towards the earliest parts of the history.
If your intentions require a minimum setup-time, it is possible to "shorten" the re-painted part of the history to just, say, last week, not going all the way back all the Bars-number of Bars a few years back, as all that data have been stored in the OHLCV-history database.
That "shortened"-part of the history will this way become as long as your needs can handle and not a single bar "longer".
Hooray, The Problem was solved.
BONUS PART :
Given your code instructs to work with EMA, not SMA, there is one more vector of attack onto the shortest possible time.
For EMA, any next Bar value will become a product of alfa * High[next] added to a previously known as EMA[next+1]
Where a constant alfa = 2. / ( N_period + 1 ) is known and constant across the whole run of the history processed.
This approach helped me gain about ~20-30 [us] FASTER processing for a 20-cell Price-vector, when using this algorithmic shortcut on an array of float32-values compared to cell-by-cell processing. Be sure to benchmark the code for your use-case and may polish further tricks with using different call-signatures of iHigh() instead of accessing an array of High[]-s for any potential speedups, if in utmost need to shave-off any further [us] possible.

Is there a simple code to get time zone from Etcetera area

I know that The etc area time zone boundaries are meridians 15° apart with Longitude;
eg:
ETC/GMT (-7,7)
ETC/GMT -1 (7,15)
...
so i need write a code with a switch or a if-else format;
Is there a simple and pretty code to get it with just a single parmeter "longitude"?
Thanks

How to get OHLC prices for a historic bar in MQL4?

I'm getting a bit stuck with a piece of mql4 code. Esentially, I need to access and store the OHLC prices of a historic bar back in time maximum 30 days back from current date. This is how I am currently doing it.
input int referenceDay=1;
static double reference;
if ( Day() == referenceDay ) reference = Open[0];
This is working fine until the point I either add to the code which, it then resets the reference back to 0. I am looking for a way to be able to access the history on each new candle and store the price for the referenceDay.
The objective is that whenever the EA is loaded to the chart, it automatically goes into the history and updates the reference price to be used on this trading day without having to wait for the entire month's iteration in real time.
The objective is that whenever the EA is loaded to the chart, it automatically goes into the history and updates the reference price
So far so good.
Once EA gets loaded,
the definition of static double reference; sets the initial value of reference == 0.;
next, the call to Day() sets the rules:
int Day(); returns the current day of the month, which is not the "today"'s-day, but the day of month of the so called last known server time. Given the EA was loaded on Sunday afternoon, or Monday morning, before the Market was opened, the "last known server time" is still Friday ... remember, the Server-side datetime rules ( so, if trading on APAC or Australia / New Zealand TimeZone servers, additional gymnastics are in place ).
So, as the code continues - in all such cases, when the input int referenceDay value will accidentally != the last known server time Day(), your ( just ) initialised variable reference will remain == 0.
Surprised?
May test it:
static double reference = EMPTY; // .SET EXPLICIT INITIALISER
if ( Day() == referenceDay )
{ reference = Open[0];
print( reference,
"AFTER Day() MATCHED referenceDay" // THIS NEED NOT HAPPEN
);
}
else
{ print( reference,
"ON( ",Day(), " ) ",
"AFTER Day() DID NOT MATCH referenceDay = ",
referenceDay
}
May redefine the assignment strategy, using:
input int referenceDAYinput = 1;
int referenceDAYnDaysBACK = max( 0, // FUSED
Day() - referenceDAYinput
);
static double referenceLEVEL = iOpen( _Symbol,
PERIOD_D1,
referenceDAYnDaysBACK
);
This code snippet certainly does not strive to be the complete solution, but shows the mechanics for achieving the desired objective.
Your actual code will have to solve how many Trading days - which is needed to address the TimeSeries-indexing logic of MetaTrader Terminal 4 platofrm -- ( not just the Calendar days ) -- there were in between the referenceDAYinput and the "last known server time"-Day(), but your are this close to have this done.

Why is the gettimeofday timezone wrong?

Both ftime and gettimeofday are returning 0 for the current timezone in Ubuntu 16. The timezone is set correctly in the date and time settings provided by Ubuntu. There is no TZ env variable set.
I don't want to just "fix" it because this is production software used in many different contexts. So I just want a reliable way of programmatically getting the timezone (and preferably the current DST offset as well).
My attempts so far:
#if 0
timeb tbTime;
ftime(&tbTime);
int CurTz = -tbTime.timezone;
#else
struct timeval tv;
struct timezone tz;
int r = gettimeofday(&tv, &tz);
if (r)
return NO_ZONE;
int CurTz = tz.tz_minuteswest;
#endif
The 'date' command is working:
matthew#mallen-ubuntu:~$ date +%Z
AEDT
matthew#mallen-ubuntu:~$ date +%z
+1100
I could just spawn a process to call "date", but that seems very heavy handed when some API calls are available.
On GNU/Linux, the second argument of gettimeofday is quite useless and should always be NULL. The manual page for gettimeofday says this:
The use of the timezone structure is obsolete; the tz argument should normally be specified as NULL.
Even on non-Linux systems, the tz_dsttime has useless semantics (e.g., it reports that India uses DST because it did so for a brief period about seventy years ago).
If you need to obtain the time zone for the current time, you need to use localtime or localtime_r and examine the broken-down time structure it produces (and not global variables such as daylight). The struct tm members you are probably interested are tm_isdst, tm_gmtoff, and perhaps tm_zone. The latter two are glibc extensions.

How to properly parse timezone codes

In the example bellow the result is always "[date] 05:00:00 +0000 UTC" regardless the timezone you choose for the parseAndPrint function. What is wrong with this code? The time should change depending on the timezone you choose. (Go Playground servers are apparently configured in UTC timezone).
http://play.golang.org/p/wP207BWYEd
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
parseAndPrint(now, "BRT")
parseAndPrint(now, "EDT")
parseAndPrint(now, "UTC")
}
func parseAndPrint(now time.Time, timezone string) {
test, err := time.Parse("15:04:05 MST", fmt.Sprintf("05:00:00 %s", timezone))
if err != nil {
fmt.Println(err)
return
}
test = time.Date(
now.Year(),
now.Month(),
now.Day(),
test.Hour(),
test.Minute(),
test.Second(),
test.Nanosecond(),
test.Location(),
)
fmt.Println(test.UTC())
}
When you Parse a time, you are parsing it in your current location, which is OK as long as that's what you're expecting, and the timezone abbreviation is known from within your location.
If you can forgo timezones, it's far easier to normalize all the times you're dealing with into UTC.
The next easiest is handling everything with explicit offsets, like -05:00.
If you want to deal with times originating in other timezones, you need to use time.Location. You can load Locations from the local timezone db with time.LoadLocation, and parse times there with time.ParseInLocation.
Question: How to properly parse time with abbreviated timezone names like UTC, CET, BRT, etc.?
Answer: You better should not. As JimB and others in this question Why doesn't Go's time.Parse() parse the timezone identifier? carefully suggest, you can expect that Go correctly parses only two timezones: UTC and the local one.
What they don't make quite explicit is that you can't expect Go to correctly parse time with any other timezone. At least that is so in my personal experience (go1.16.1, Ubuntu 20.04).
Also, abbreviated timezones are ambiguous. IST could mean India Standard Time, Irish Standard Time or Israel Standard Time. There's no way to disambiguate unless you know zone location, and, if you know location, you should use time.ParseInLocation.
If this is user input and you have control, you should change format requirements for users to input time with explicit offsets as JimB is also suggesting in their answer. Make sure you don't forget about minutes, i.e. use -0700, -07:00, Z0700 or Z07:00 but not -07 or Z07 in layout. Not all offsets are whole hours. For instance, Inidia Standard Time is UTC+5:30.
If you have no other choice and forced to parse such times, you can do something like that:
func parseTimeWithTimezone(layout, value string) (time.Time, error) {
tt, err := time.Parse(layout, value)
if err != nil {
return time.Time{}, err
}
loc := tt.Location()
zone, offset := tt.Zone()
// Offset will be 0 if timezone is not recognized (or UTC, but that's ok).
// Read carefully https://pkg.go.dev/time#Parse
// In this case we'll try to load location from zone name.
// Timezones that are recognized: local, UTC, GMT, GMT-1, GMT-2, ..., GMT+1, GMT+2, ...
if offset == 0 {
// Make sure you have timezone database available in your system for
// time.LoadLocation to work. Read https://pkg.go.dev/time#LoadLocation
// about where Go looks for timezone database.
// Perhaps the simplest solution is to `import _ "time/tzdata"`, but
// note that it increases binary size by few hundred kilobytes.
// See https://golang.org/doc/go1.15#time/tzdata
loc, err = time.LoadLocation(zone)
if err != nil {
return time.Time{}, err // or `return tt, nil` if you more prefer
// the original Go semantics of returning time with named zone
// but zero offset when timezone is not recognized.
}
}
return time.ParseInLocation(layout, value, loc)
}
Note that zone names that aren't present as files in timezone database will fail parsing. These are quite many. You can see what is present by checking
contents of /usr/share/zoneinfo, /usr/share/lib/zoneinfo on your system,
contents of this file https://github.com/golang/go/blob/master/lib/time/zoneinfo.zip.

Resources