Added initial support for DST. Rules are defined in constants.php and are extensible.
--- a/includes/common.php Tue Sep 16 08:22:47 2008 -0400
+++ b/includes/common.php Sun Sep 21 09:01:27 2008 -0400
@@ -170,6 +170,10 @@
global $timezone;
$timezone = 0;
+// DST settings
+global $dst_params;
+$dst_params = array(0, 0, 0, 0, 60);
+
// Divert to CLI loader if running from CLI
if ( isset($argc) && isset($argv) )
{
@@ -390,7 +394,7 @@
// One quick security check...
if ( !is_valid_ip($_SERVER['REMOTE_ADDR']) )
{
- die('SECURITY: spoofed IP address');
+ die('SECURITY: spoofed IP address: ' . htmlspecialchars($_SERVER['REMOTE_ADDR']));
}
// All checks passed! Start the main components up.
--- a/includes/constants.php Tue Sep 16 08:22:47 2008 -0400
+++ b/includes/constants.php Sun Sep 21 09:01:27 2008 -0400
@@ -92,6 +92,12 @@
define('TOKEN_PARENTHRIGHT', 4);
define('TOKEN_NOT', 5);
+// DST constants
+define('FIRST_SUNDAY', 1);
+define('SECOND_SUNDAY', 2);
+define('THIRD_SUNDAY', 3);
+define('LAST_SUNDAY', 4);
+
//
// User types - don't touch these
//
@@ -617,3 +623,12 @@
0xFE => "COM", 0x01 => "TEM", 0x02 => "RES",
);
+// DST profiles
+global $dst_profiles;
+$dst_profiles = array(
+ 'off' => '0;0;0;0;60',
+ 'usa' => '3;' . SECOND_SUNDAY . ';11;' . FIRST_SUNDAY . ';60',
+ 'europe' => '3;' . LAST_SUNDAY . ';10;' . LAST_SUNDAY . ';60',
+ 'australia' => '10;' . LAST_SUNDAY . ';3;' . LAST_SUNDAY . ';60',
+ 'tasmania' => '10;' . FIRST_SUNDAY . ';3;' . LAST_SUNDAY . ';60'
+ );
--- a/includes/functions.php Tue Sep 16 08:22:47 2008 -0400
+++ b/includes/functions.php Sun Sep 21 09:01:27 2008 -0400
@@ -271,31 +271,117 @@
if ( !is_int($timestamp) && !is_double($timestamp) && strval(intval($timestamp)) !== $timestamp )
$timestamp = time();
- /*
- // List of valid characters for date()
- $date_chars = 'dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZFcrU';
- // Split them into an array
- $date_chars = enano_str_split($date_chars);
- // Emulate date() formatting by replacing date characters with their
- // percentage-signed counterparts, but not escaped characters which
- // shouldn't be parsed.
- foreach ( $date_chars as $char )
- {
- $string = str_replace($char, "%$char", $string);
- $string = str_replace("\\%$char", $char, $string);
- }
- */
-
// perform timestamp offset
global $timezone;
// it's gonna be in minutes, so multiply by 60 to offset the unix timestamp
$timestamp = $timestamp + ( $timezone * 60 );
+ // are we in DST?
+ global $dst_params;
+ if ( check_timestamp_dst($timestamp, $dst_params[0], $dst_params[1], $dst_params[2], $dst_params[3]) )
+ {
+ // offset for DST
+ $timestamp += ( $dst_params[4] * 60 );
+ }
+
// Let PHP do the work for us =)
return gmdate($string, $timestamp);
}
/**
+ * Determine if a timestamp is within DST.
+ * @param int Timestamp
+ * @param int Start month (1-12) of DST
+ * @param int Which Sunday DST starts on (*_SUNDAY constants)
+ * @param int End month of DST
+ * @param int Which Sunday DST ends on
+ * @return bool
+ */
+
+function check_timestamp_dst($time, $start_month, $start_sunday, $end_month, $end_sunday)
+{
+ static $sundays = array(FIRST_SUNDAY, SECOND_SUNDAY, THIRD_SUNDAY, LAST_SUNDAY);
+
+ // perform timestamp offset
+ global $timezone;
+ // it's gonna be in minutes, so multiply by 60 to offset the unix timestamp
+ $time = $time + ( $timezone * 60 );
+ $year = intval(gmdate('Y', $time));
+
+ // one-pass validation
+ if ( !in_array($start_sunday, $sundays) || !in_array($end_sunday, $sundays) ||
+ $start_month < 1 || $start_month > 12 || $end_month < 1 || $end_month > 12 )
+ return false;
+
+ // get timestamp of the selected sunday (start)
+ $dst_start = get_sunday_timestamp($start_month, $start_sunday, $year);
+ $dst_end = get_sunday_timestamp($end_month, $end_sunday, $year);
+
+ if ( $dst_start > $dst_end )
+ {
+ // start time is past the end time, this means we're in the southern hemisphere
+ // as a result, if we're within the range, DST is NOT in progress.
+ return !( $time >= $dst_start && $time <= $dst_end );
+ }
+
+ return $time >= $dst_start && $time <= $dst_end;
+}
+
+/**
+ * Returns a timestamp for the given *_SUNDAY index.
+ * @param int Month
+ * @param int Which Sunday (FIRST, SECOND, THIRD, or LAST)
+ * @param int Year that we're doing our calculations in
+ * @return int
+ */
+
+function get_sunday_timestamp($month, $sunday, $year)
+{
+ $days_in_month = array(
+ 1 => 31,
+ 2 => $year % 4 == 0 && ( $year % 100 != 0 || ( $year % 100 == 0 && $year % 400 == 0 ) ) ? 29 : 28,
+ 3 => 31,
+ 4 => 30,
+ 5 => 31,
+ 6 => 30,
+ 7 => 31,
+ 8 => 31,
+ 9 => 30,
+ 10 => 31,
+ 11 => 30,
+ 12 => 31
+ );
+
+ $result = mktime(0, 0, 0, $month, 1, $year);
+
+ // hack. allows a specific day of the month to be set instead of a sunday. not a good place to do this.
+ if ( is_string($sunday) && substr($sunday, -1) === 'd' )
+ {
+ $result += 86400 * ( intval($sunday) - 1);
+ return $result;
+ }
+
+ $tick = 0;
+ $days_remaining = $days_in_month[$month];
+ while ( true )
+ {
+ if ( date('D', $result) == 'Sun' )
+ {
+ $tick++;
+ if ( ( $tick == 1 && $sunday == FIRST_SUNDAY ) ||
+ ( $tick == 2 && $sunday == SECOND_SUNDAY ) ||
+ ( $tick == 3 && $sunday == THIRD_SUNDAY ) ||
+ ( $sunday == LAST_SUNDAY && $days_remaining < 7 ) )
+ break;
+ }
+ $days_remaining--;
+ $result += 86400;
+ }
+
+ return $result;
+}
+
+/**
* Tells you the title for the given page ID string
* @param string Page ID string (ex: Special:Administration)
* @param bool Optional. If true, and if the namespace turns out to be something other than Article, the namespace prefix will be prepended to the return value.
--- a/includes/sessions.php Tue Sep 16 08:22:47 2008 -0400
+++ b/includes/sessions.php Sun Sep 21 09:01:27 2008 -0400
@@ -473,7 +473,15 @@
}
}
$user = true;
+
+ // set timezone params
$GLOBALS['timezone'] = $userdata['user_timezone'];
+ $GLOBALS['dst_params'] = explode(';', $userdata['user_dst']);
+ foreach ( $GLOBALS['dst_params'] as &$parm )
+ {
+ if ( substr($parm, -1) != 'd' )
+ $parm = intval($parm);
+ }
// Set language
if ( !defined('ENANO_ALLOW_LOAD_NOLANG') )
@@ -1038,7 +1046,7 @@
// using a normal call to $db->sql_query to avoid failing on errors here
$query = $db->sql_query('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,' . "\n"
. ' u.reg_time,u.account_active,u.activation_key,u.user_lang,u.user_title,k.source_ip,k.time,k.auth_level,k.key_type,COUNT(p.message_id) AS num_pms,' . "\n"
- . ' u.user_timezone, x.* FROM '.table_prefix.'session_keys AS k' . "\n"
+ . ' u.user_timezone, u.user_dst, x.* FROM '.table_prefix.'session_keys AS k' . "\n"
. ' LEFT JOIN '.table_prefix.'users AS u' . "\n"
. ' ON ( u.user_id=k.user_id )' . "\n"
. ' LEFT JOIN '.table_prefix.'users_extra AS x' . "\n"
@@ -1051,7 +1059,7 @@
if ( !$query && ( defined('IN_ENANO_INSTALL') or defined('IN_ENANO_UPGRADE') ) )
{
- $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms, 1440 AS user_timezone, ' . SK_SHORT . ' AS key_type FROM '.table_prefix.'session_keys AS k
+ $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms, 1440 AS user_timezone, \'0;0;0;0;60\' AS user_dst, ' . SK_SHORT . ' AS key_type FROM '.table_prefix.'session_keys AS k
LEFT JOIN '.table_prefix.'users AS u
ON ( u.user_id=k.user_id )
LEFT JOIN '.table_prefix.'privmsgs AS p
@@ -2707,7 +2715,8 @@
if ( !$q )
$db->_die();
- $groups = array();
+ // The l10n engine takes care of this later.
+ $groups = array(1 => 'Everyone');
if ( $row = $db->fetchrow() )
{
@@ -2983,7 +2992,7 @@
{
if ( isset($perm2[$i]) )
{
- if ( $is_everyone && !$defaults_used[$i] )
+ if ( $is_everyone && isset($defaults_used[$i]) && $defaults_used[$i] === false )
continue;
// Decide precedence
if ( isset($defaults_used[$i]) )
--- a/install/schemas/mysql_stage2.sql Tue Sep 16 08:22:47 2008 -0400
+++ b/install/schemas/mysql_stage2.sql Sun Sep 21 09:01:27 2008 -0400
@@ -115,6 +115,7 @@
user_timezone int(12) UNSIGNED NOT NULL DEFAULT 0,
user_title varchar(64) DEFAULT NULL,
user_group mediumint(5) NOT NULL DEFAULT 1,
+ user_dst varchar(11) NOT NULL DEFAULT '0;0;0;0;60',
PRIMARY KEY (user_id)
) CHARACTER SET `utf8` COLLATE `utf8_bin`;
--- a/install/schemas/postgresql_stage2.sql Tue Sep 16 08:22:47 2008 -0400
+++ b/install/schemas/postgresql_stage2.sql Sun Sep 21 09:01:27 2008 -0400
@@ -115,6 +115,7 @@
user_timezone int NOT NULL DEFAULT 0,
user_title varchar(64) DEFAULT NULL,
user_group int NOT NULL DEFAULT 1,
+ user_dst varchar(11) NOT NULL DEFAULT '0;0;0;0;60',
CHECK (avatar_type IN ('jpg', 'png', 'gif', 'grv')),
PRIMARY KEY (user_id)
);
--- a/install/schemas/upgrade/1.1.4-1.1.5-mysql.sql Tue Sep 16 08:22:47 2008 -0400
+++ b/install/schemas/upgrade/1.1.4-1.1.5-mysql.sql Sun Sep 21 09:01:27 2008 -0400
@@ -1,2 +1,3 @@
ALTER TABLE {{TABLE_PREFIX}}session_keys ADD COLUMN key_type tinyint(1) NOT NULL DEFAULT 0;
UPDATE {{TABLE_PREFIX}}session_keys SET key_type = 2 WHERE auth_level > 2;
+ALTER TABLE {{TABLE_PREFIX}}users ADD COLUMN user_dst varchar(11) NOT NULL DEFAULT '0;0;0;0;60';
--- a/install/schemas/upgrade/1.1.4-1.1.5-postgresql.sql Tue Sep 16 08:22:47 2008 -0400
+++ b/install/schemas/upgrade/1.1.4-1.1.5-postgresql.sql Sun Sep 21 09:01:27 2008 -0400
@@ -1,3 +1,4 @@
ALTER TABLE {{TABLE_PREFIX}}session_keys ADD COLUMN key_type smallint NOT NULL DEFAULT 0;
UPDATE {{TABLE_PREFIX}}session_keys SET key_type = 2 WHERE auth_level > 2;
+ALTER TABLE {{TABLE_PREFIX}}users ADD COLUMN user_dst varchar(11) NOT NULL DEFAULT '0;0;0;0;60';
--- a/language/english/core.json Tue Sep 16 08:22:47 2008 -0400
+++ b/language/english/core.json Sun Sep 21 09:01:27 2008 -0400
@@ -692,7 +692,14 @@
title_13: '[UTC + 13] Tonga Time, Phoenix Islands Time',
title_14: '[UTC + 14] Line Island Time',
// This is a JSON string that lists all the timezones that are defined here.
- list: '{"n12":-12,"n11":-11,"n10":-10,"n9p5":-9.5,"n9":-9,"n8":-8,"n7":-7,"n6":-6,"n5":-5,"n4":-4,"n3p5":-3.5,"n3":-3,"n2":-2,"n1":-1,"0":0,"1":1,"2":2,"3":3,"3p5":3.5,"4":4,"4p5":4.5,"5":5,"5p5":5.5,"5p75":5.75,"6":6,"6p5":6.5,"7":7,"8":8,"8p75":8.75,"9":9,"9p5":9.5,"10":10,"10p5":10.5,"11":11,"11p5":11.5,"12":12,"12p75":12.75,"13":13,"14":14}'
+ list: '{"n12":-12,"n11":-11,"n10":-10,"n9p5":-9.5,"n9":-9,"n8":-8,"n7":-7,"n6":-6,"n5":-5,"n4":-4,"n3p5":-3.5,"n3":-3,"n2":-2,"n1":-1,"0":0,"1":1,"2":2,"3":3,"3p5":3.5,"4":4,"4p5":4.5,"5":5,"5p5":5.5,"5p75":5.75,"6":6,"6p5":6.5,"7":7,"8":8,"8p75":8.75,"9":9,"9p5":9.5,"10":10,"10p5":10.5,"11":11,"11p5":11.5,"12":12,"12p75":12.75,"13":13,"14":14}',
+
+ // DST profiles
+ dst_off: 'My region doesn\'t use DST',
+ dst_usa: 'United States: second Sunday of March to first Sunday of November',
+ dst_europe: 'Europe: last Sunday of March to last Sunday of October',
+ dst_australia: 'Australia (except Tasmania): last Sunday of October to last Sunday of March',
+ dst_tasmania: 'Tasmania: first Sunday of October to last Sunday of March'
},
etc: {
redirect_title: 'Redirecting...',
--- a/language/english/user.json Tue Sep 16 08:22:47 2008 -0400
+++ b/language/english/user.json Sun Sep 21 09:01:27 2008 -0400
@@ -308,6 +308,7 @@
publicinfo_field_changetheme: 'Change my theme...',
publicinfo_field_timezone: 'Time zone:',
publicinfo_field_timezone_hint: 'Select the time zone you live in and when Daylight Savings Time occurs, if at all.',
+ publicinfo_field_dst: 'Daylight saving time:',
publicinfo_field_usertitle_title: 'User title:',
publicinfo_field_usertitle_hint: 'This can be some text that will be displayed underneath your username.',
publicinfo_th_im: 'Instant messenger contact information',
--- a/plugins/SpecialUserPrefs.php Tue Sep 16 08:22:47 2008 -0400
+++ b/plugins/SpecialUserPrefs.php Sun Sep 21 09:01:27 2008 -0400
@@ -652,6 +652,22 @@
<td class="row2"><?php echo $lang->get('usercp_publicinfo_field_timezone'); ?><br /><small><?php echo $lang->get('usercp_publicinfo_field_timezone_hint'); ?></small></td>
<td class="row1"><?php echo $tz_select; ?></td>
</tr>
+ <tr>
+ <td class="row2"><?php echo $lang->get('usercp_publicinfo_field_dst'); ?></td>
+ <td class="row1">
+ <select name="dst">
+ <?php
+ global $dst_profiles, $dst_params;
+ $user_dst = implode(';', $dst_params);
+ foreach ( $dst_profiles as $region => $data )
+ {
+ $selected = ( $data === $user_dst ) ? ' selected="selected"' : '';
+ echo '<option value="' . $data . '"' . $selected . '>' . $lang->get("tz_dst_$region") . '</option>';
+ }
+ ?>
+ </select>
+ </td>
+ </tr>
<?php
if ( $session->get_permissions('custom_user_title') ):
?>