The olson parser is feature complete and ready for people to start playing with it. The entry point is the olson_todst($filename) function.
This commit is contained in:
+158
-50
@@ -14,16 +14,14 @@ function olson_todst ($filename) {
|
||||
$zones = olson_simple_zone_parser($filename);
|
||||
$rules = olson_simple_rule_parser($filename);
|
||||
|
||||
if (function_exists('memory_get_usage')) {
|
||||
trigger_error("We are consuming memory: " . get_memory_usage());
|
||||
}
|
||||
$mdl_zones = array();
|
||||
|
||||
/**
|
||||
*** To translate the combined Zone & Rule changes
|
||||
*** in the Olson files to the Moodle single ruleset
|
||||
*** format, wwe need to trasverse every year and see
|
||||
*** format, we need to trasverse every year and see
|
||||
*** if either the Zone or the relevant Rule has a
|
||||
*** change. It's yuck but it yealds a rationalized
|
||||
*** change. It's yuck but it yields a rationalized
|
||||
*** set of data, which is arguably simpler.
|
||||
***
|
||||
*** Also note that I am starting at the epoch (1970)
|
||||
@@ -35,47 +33,129 @@ function olson_todst ($filename) {
|
||||
$maxyear = $maxyear['tm_year'] + 1900 + 10;
|
||||
|
||||
foreach ($zones as $zname=>$zbyyear) { // loop over zones
|
||||
// loop over years
|
||||
$lastyear = NULL;
|
||||
$lastzone = NULL;
|
||||
$lastrule = NULL;
|
||||
$lastzonerule = NULL;
|
||||
/**
|
||||
*** Loop over years, only adding a rule when zone or rule
|
||||
*** have changed. All loops preserver the last seen vars
|
||||
*** until there's an explicit decision to delete them
|
||||
***
|
||||
**/
|
||||
|
||||
// find the last pre 1970 zone entry
|
||||
for ($y = 1970 ; $y >0 ; $y--) {
|
||||
// clean the slate for a new zone
|
||||
$zone = NULL;
|
||||
$rule = NULL;
|
||||
|
||||
//
|
||||
// Find the pre 1970 zone rule entries
|
||||
//
|
||||
for ($y = 1970 ; $y > 0 ; $y--) {
|
||||
if (array_key_exists((string)$y, $zbyyear )) { // we have a zone entry for the year
|
||||
$lastyear = $y;
|
||||
$zentry = $zbyyear[$y];
|
||||
$lastzone = $zentry;
|
||||
print "$zname pre1970 is $y\n";
|
||||
$zone = $zbyyear[$y];
|
||||
// print "Zone $zname pre1970 is in $y\n";
|
||||
break; // Perl's last -- get outta here
|
||||
}
|
||||
}
|
||||
|
||||
for ($y = 1970 ; $y < $maxyear ; $y++) {
|
||||
/// force it to string to avoid PHP
|
||||
/// thinking of a positional array
|
||||
if (array_key_exists((string)$y, $zbyyear )) { // we have a zone entry for the year
|
||||
$lastyear = $y;
|
||||
$zentry = $zbyyear[$y];
|
||||
$lastzone = $zentry;
|
||||
|
||||
print "$zname $y $zentry[rule]\n";
|
||||
if (!empty($zone['rule'])) {
|
||||
$rule = NULL;
|
||||
for ($y = 1970 ; $y > 0 ; $y--) {
|
||||
if (array_key_exists((string)$y, $rules[$zone['rule']] )) { // we have a rule entry for the year
|
||||
$rule = $rules[$zone['rule']][$y];
|
||||
// print "Rule $rule[name] pre1970 is $y\n";
|
||||
break; // Perl's last -- get outta here
|
||||
}
|
||||
|
||||
}
|
||||
if (empty($rule)) {
|
||||
// Colombia and a few others refer to rules before they exist
|
||||
// Perhaps we should comment out this warning...
|
||||
// trigger_error("Cannot find rule in $zone[rule] <= 1970");
|
||||
$rule = array();
|
||||
}
|
||||
// has a tz entry
|
||||
// has a rule entry
|
||||
} else {
|
||||
// no DST this year!
|
||||
$rule = array();
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
$zones = getzones
|
||||
foreach $zones as $zone
|
||||
foreach $year
|
||||
offset & rule(rulename/yearstart) ... is it the same as last?
|
||||
|
||||
// Prepare to insert the base 1970 zone+rule
|
||||
if (!empty($rule)) {
|
||||
// merge the two arrays into the moodle rule
|
||||
unset($rule['name']); // warning: $rule must NOT be a reference!
|
||||
unset($rule['year']);
|
||||
$mdl_tz = array_merge($zone, $rule);
|
||||
|
||||
//fix (de)activate_time (AT) field to be GMT
|
||||
$mdl_tz['activate_time'] = olson_parse_at($mdl_tz['activate_time'], 'set', $mdl_tz['gmtoff']);
|
||||
$mdl_tz['deactivate_time'] = olson_parse_at($mdl_tz['deactivate_time'], 'reset', $mdl_tz['gmtoff']);
|
||||
} else {
|
||||
// just a simple zone
|
||||
$mdl_tz = $zone;
|
||||
}
|
||||
|
||||
// Fix the from year to 1970
|
||||
$mdl_tz['from'] = 1970;
|
||||
$mdl_tz['from_timestamp'] = 0;
|
||||
|
||||
// add to the array
|
||||
$mdl_zones[] = $mdl_tz;
|
||||
|
||||
///
|
||||
/// 1970 onwards
|
||||
///
|
||||
for ($y = 1970 ; $y < $maxyear ; $y++) {
|
||||
$changed = false;
|
||||
///
|
||||
/// We create a "zonerule" entry if either zone or rule change...
|
||||
///
|
||||
/// force $y to string to avoid PHP
|
||||
/// thinking of a positional array
|
||||
///
|
||||
if (array_key_exists((string)$y, $zbyyear)) { // we have a zone entry for the year
|
||||
$changed = true;
|
||||
$zone = $zbyyear[(string)$y];
|
||||
}
|
||||
if (!empty($zone['rule'])){
|
||||
if (array_key_exists((string)$y, $rules[$zone['rule']])) {
|
||||
$changed = true;
|
||||
$rule = $rules[$zone['rule']][(string)$y];
|
||||
}
|
||||
} else {
|
||||
$rule = array();
|
||||
}
|
||||
|
||||
if ($changed) {
|
||||
// print "CHANGE YEAR $y Zone $zone[name] Rule $zone[rule]\n";
|
||||
if (!empty($rule)) {
|
||||
// merge the two arrays into the moodle rule
|
||||
unset($rule['name']);
|
||||
unset($rule['year']);
|
||||
$mdl_tz = array_merge($zone, $rule);
|
||||
|
||||
//fix (de)activate_time (AT) field to be GMT
|
||||
$mdl_tz['activate_time'] = olson_parse_at($mdl_tz['activate_time'], 'set', $mdl_tz['gmtoff']);
|
||||
$mdl_tz['deactivate_time'] = olson_parse_at($mdl_tz['deactivate_time'], 'reset', $mdl_tz['gmtoff']);
|
||||
} else {
|
||||
// just a simple zone
|
||||
$mdl_tz = $zone;
|
||||
}
|
||||
|
||||
// start-of-year timestamp
|
||||
// TODO: perhaps should consider the current DST rule
|
||||
$mdl_tz['from_timestamp'] = gmmktime(0, 0, 0, 1, 1, $mdl_tz['from'], 0) + $mdl_tz['gmtoff'] * 60 ;
|
||||
if ($mdl_tz['from_timestamp'] < 0) {
|
||||
$mdl_tz['from_timestamp'] = 0;
|
||||
}
|
||||
$mdl_zones[] = $mdl_tz;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
if (function_exists('memory_get_usage')) {
|
||||
trigger_error("We are consuming this much memory: " . get_memory_usage());
|
||||
}
|
||||
*/
|
||||
|
||||
return $mdl_zones;
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +219,7 @@ function olson_simple_rule_parser ($filename) {
|
||||
|
||||
// now reformat it a bit to match Moodle's DST table
|
||||
$moodle_rules = array();
|
||||
foreach ($rules as $family => $rulesbyyear) {
|
||||
foreach ($rules as $rule => $rulesbyyear) {
|
||||
foreach ($rulesbyyear as $year => $rulesthisyear) {
|
||||
|
||||
if(!isset($rulesthisyear['reset'])) {
|
||||
@@ -182,7 +262,7 @@ function olson_simple_rule_parser ($filename) {
|
||||
trigger_error('Unknown month: '.$in);
|
||||
}
|
||||
|
||||
$moodle_rule['family'] = $name;
|
||||
$moodle_rule['name'] = $name;
|
||||
$moodle_rule['year'] = $year;
|
||||
$moodle_rule['apply_offset'] = $save; // time offset
|
||||
|
||||
@@ -222,7 +302,7 @@ function olson_simple_rule_parser ($filename) {
|
||||
$moodle_rule['deactivate_index'] = $on['index'];
|
||||
$moodle_rule['deactivate_day'] = $on['day'];
|
||||
|
||||
$moodle_rules[$moodle_rule['family']][$moodle_rule['year']] = $moodle_rule;
|
||||
$moodle_rules[$moodle_rule['name']][$moodle_rule['year']] = $moodle_rule;
|
||||
//print_object($moodle_rule);
|
||||
}
|
||||
|
||||
@@ -271,8 +351,12 @@ function olson_simple_zone_parser ($filename) {
|
||||
*** continuation lines, we shift the "until" from the previous field
|
||||
*** into this line's "from".
|
||||
***
|
||||
*** If a RULES field contains a time instead of a rule we discard it
|
||||
*** I have no idea of how to create a DST rule out of that
|
||||
*** (what are the start/end times?)
|
||||
***
|
||||
*** We remove "until" from the data we keep, but preserve
|
||||
*** it in $lastzone
|
||||
*** it in $lastzone.
|
||||
*/
|
||||
if (preg_match('/^Zone/', $line)) { // a new zone
|
||||
$line = trim($line);
|
||||
@@ -327,6 +411,11 @@ function olson_simple_zone_parser ($filename) {
|
||||
if ($zone['rule'] === '-') { // cleanup empty rules
|
||||
$zone['rule'] = '';
|
||||
}
|
||||
if (preg_match('/:/',$zone['rule'])) {
|
||||
// we are not handling direct SAVE rules here
|
||||
// discard it
|
||||
$zone['rule'] = '';
|
||||
}
|
||||
|
||||
$zones[$zone['name']][(string)$zone['from']] = $zone;
|
||||
}
|
||||
@@ -380,7 +469,10 @@ function olson_parse_offset ($offset) {
|
||||
function olson_parse_on ($on) {
|
||||
|
||||
$rule = array();
|
||||
$days = array('sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3, 'thu' => 4, 'fri' => 5, 'sat' => 6);
|
||||
$days = array('sun' => 0, 'mon' => 1,
|
||||
'tue' => 2, 'wed' => 3,
|
||||
'thu' => 4, 'fri' => 5,
|
||||
'sat' => 6);
|
||||
|
||||
if(is_numeric($on)) {
|
||||
$rule['index'] = $on;
|
||||
@@ -417,7 +509,7 @@ function olson_parse_on ($on) {
|
||||
|
||||
|
||||
/***
|
||||
*** olson_parse_at($at)
|
||||
*** olson_parse_at($at, $set, $gmtoffset)
|
||||
***
|
||||
*** see `man zic`. This function translates
|
||||
***
|
||||
@@ -438,20 +530,36 @@ function olson_parse_on ($on) {
|
||||
*/
|
||||
function olson_parse_at ($at, $set = 'set', $gmtoffset) {
|
||||
|
||||
list($hours, $mins) = explode(':', $at);
|
||||
|
||||
if ( !empty($matches[0]) && ( $matches[0] === 'u'
|
||||
|| $matches[0] === 'g'
|
||||
|| $matches[0] === 'z' )) {
|
||||
return sprintf('%02d:%02d', $hours, $mins);
|
||||
// find the time "signature";
|
||||
$sig = '';
|
||||
if (preg_match('/\w$/', $at, $matches)) {
|
||||
$sig = $matches[0];
|
||||
$at = substr($at, 0, strlen($at)-1); // chop
|
||||
}
|
||||
|
||||
// try and fetch the trailing alpha char if present
|
||||
if (empty($matches[0]) || $matches[0] === 'w') {
|
||||
// wall clock
|
||||
list($hours, $mins) = explode(':', $at);
|
||||
|
||||
// GMT -- return as is!
|
||||
if ( !empty($sig) && ( $sig === 'u'
|
||||
|| $sig === 'g'
|
||||
|| $sig === 'z' )) {
|
||||
return $at;
|
||||
}
|
||||
|
||||
// Wall clock
|
||||
if (empty($sig) || $sig === 'w') {
|
||||
if ($set !== 'set'){ // wall clock is on DST, assume by 1hr
|
||||
$hours = $hours-1;
|
||||
}
|
||||
$sig = 's';
|
||||
}
|
||||
|
||||
// Standard time
|
||||
if (!empty($sig) && $sig === 's') {
|
||||
$mins = $mins + $hours*60 + $gmtoffset;
|
||||
$hours = $mins / 60;
|
||||
$hours = (int)$hours;
|
||||
$mins = abs($mins % 60);
|
||||
return sprintf('%02d:%02d', $hours, $mins);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user