1
0
mirror of https://github.com/flarum/core.git synced 2025-08-04 15:37:51 +02:00

I think we're finally good with the timezone stuff now?

MySQL's UNIX_TIMESTAMP function interprets the date using MySQL's
configured timezone, which we don't want (may be misconfigured etc).
Instead, now we do the conversion to a timestamp on the PHP side. Then
JavaScript is given the offset between UTC and the configure timezone
so it can work out how to display the data.
This commit is contained in:
Toby Zerner
2017-12-11 22:42:51 +10:30
parent 6857d32d22
commit d56b792a9d
3 changed files with 77 additions and 34 deletions

View File

@@ -36,7 +36,15 @@ System.register('flarum/statistics/components/StatisticsWidget', ['flarum/compon
value: function init() {
babelHelpers.get(StatisticsWidget.prototype.__proto__ || Object.getPrototypeOf(StatisticsWidget.prototype), 'init', this).call(this);
var today = new Date().setHours(0, 0, 0, 0) / 1000;
// Create a Date object which represents the start of the day in the
// configured timezone. To do this we convert a UTC time into that timezone,
// reset to the first hour of the day, and then convert back into UTC time.
// We'll be working with seconds rather than milliseconds throughout too.
var today = new Date();
today.setTime(today.getTime() + app.data.statistics.utcOffset * 1000);
today.setUTCHours(0, 0, 0, 0);
today.setTime(today.getTime() - app.data.statistics.utcOffset * 1000);
today = today / 1000;
this.entities = ['users', 'discussions', 'posts'];
this.periods = {
@@ -135,6 +143,7 @@ System.register('flarum/statistics/components/StatisticsWidget', ['flarum/compon
return;
}
var offset = app.data.statistics.utcOffset;
var period = this.periods[this.selectedPeriod];
var periodLength = period.end - period.start;
var labels = [];
@@ -145,12 +154,12 @@ System.register('flarum/statistics/components/StatisticsWidget', ['flarum/compon
var label = void 0;
if (period.step < 86400) {
label = moment.unix(i).format('h A');
label = moment.unix(i + offset).utc().format('h A');
} else {
label = moment.unix(i).format('D MMM');
label = moment.unix(i + offset).utc().format('D MMM');
if (period.step > 86400) {
label += ' - ' + moment.unix(i + period.step - 1).format('D MMM');
label += ' - ' + moment.unix(i + offset + period.step - 1).utc().format('D MMM');
}
}
@@ -173,7 +182,7 @@ System.register('flarum/statistics/components/StatisticsWidget', ['flarum/compon
y_axis_mode: 'span',
is_series: 1,
show_dots: 0,
colors: ['rgba(0, 0, 0, 0.1)', app.forum.attribute('themePrimaryColor')]
colors: ['rgba(127, 127, 127, 0.2)', app.forum.attribute('themePrimaryColor')]
});
} else {
context.chart.update_values(datasets, labels);
@@ -200,12 +209,12 @@ System.register('flarum/statistics/components/StatisticsWidget', ['flarum/compon
}, {
key: 'getPeriodCount',
value: function getPeriodCount(entity, period) {
var daily = app.data.statistics[entity].daily;
var timed = app.data.statistics[entity].timed;
var count = 0;
for (var day in daily) {
if (day >= period.start && day < period.end) {
count += daily[day];
for (var time in timed) {
if (time >= period.start && time < period.end) {
count += timed[time];
}
}

View File

@@ -19,7 +19,15 @@ export default class StatisticsWidget extends DashboardWidget {
init() {
super.init();
const today = new Date().setHours(0, 0, 0, 0) / 1000;
// Create a Date object which represents the start of the day in the
// configured timezone. To do this we convert a UTC time into that timezone,
// reset to the first hour of the day, and then convert back into UTC time.
// We'll be working with seconds rather than milliseconds throughout too.
let today = new Date();
today.setTime(today.getTime() + app.data.statistics.utcOffset * 1000);
today.setUTCHours(0, 0, 0, 0);
today.setTime(today.getTime() - app.data.statistics.utcOffset * 1000);
today = today / 1000;
this.entities = ['users', 'discussions', 'posts'];
this.periods = {
@@ -91,6 +99,7 @@ export default class StatisticsWidget extends DashboardWidget {
return;
}
const offset = app.data.statistics.utcOffset;
const period = this.periods[this.selectedPeriod];
const periodLength = period.end - period.start;
const labels = [];
@@ -101,12 +110,12 @@ export default class StatisticsWidget extends DashboardWidget {
let label;
if (period.step < 86400) {
label = moment.unix(i).format('h A');
label = moment.unix(i + offset).utc().format('h A');
} else {
label = moment.unix(i).format('D MMM');
label = moment.unix(i + offset).utc().format('D MMM');
if (period.step > 86400) {
label += ' - ' + moment.unix(i + period.step - 1).format('D MMM');
label += ' - ' + moment.unix(i + offset + period.step - 1).utc().format('D MMM');
}
}
@@ -132,7 +141,7 @@ export default class StatisticsWidget extends DashboardWidget {
y_axis_mode: 'span',
is_series: 1,
show_dots: 0,
colors: ['rgba(0, 0, 0, 0.1)', app.forum.attribute('themePrimaryColor')]
colors: ['rgba(127, 127, 127, 0.2)', app.forum.attribute('themePrimaryColor')]
});
} else {
context.chart.update_values(datasets, labels);
@@ -155,12 +164,12 @@ export default class StatisticsWidget extends DashboardWidget {
}
getPeriodCount(entity, period) {
const daily = app.data.statistics[entity].daily;
const timed = app.data.statistics[entity].timed;
let count = 0;
for (const day in daily) {
if (day >= period.start && day < period.end) {
count += daily[day];
for (const time in timed) {
if (time >= period.start && time < period.end) {
count += timed[time];
}
}

View File

@@ -49,7 +49,10 @@ class AddStatisticsData
*/
public function addStatisticsData(ConfigureWebApp $event)
{
$event->view->setVariable('statistics', $this->getStatistics());
$event->view->setVariable('statistics', array_merge(
$this->getStatistics(),
['utcOffset' => $this->getUTCOffset()]
));
}
private function getStatistics()
@@ -63,40 +66,62 @@ class AddStatisticsData
return array_map(function ($entity) {
return [
'total' => $entity[0]->count(),
'daily' => $this->getDailyCounts($entity[0], $entity[1])
'timed' => $this->getTimedCounts($entity[0], $entity[1])
];
}, $entities);
}
private function getDailyCounts(Builder $query, $column)
private function getTimedCounts(Builder $query, $column)
{
// Calculate the offset between the server timezone (which is used for
// dates stored in the database) and the user's timezone (set via the
// settings table). We will use this to adjust dates before aggregating
// daily/hourly statistics.
// settings table). We will use this to make sure we aggregate the
// daily/hourly statistics according to the user's timezone.
$offset = $this->getTimezoneOffset();
return $query
$results = $query
->selectRaw(
'UNIX_TIMESTAMP(
DATE_FORMAT(
@date := DATE_ADD('.$column.', INTERVAL ? SECOND), -- correct for timezone
IF(@date > ?, \'%Y-%m-%d %H:00:00\', \'%Y-%m-%d\') -- if within the last 48 hours, group by hour
)
) as period',
'DATE_FORMAT(
@date := DATE_ADD('.$column.', INTERVAL ? SECOND), -- correct for timezone
IF(@date > ?, \'%Y-%m-%dT%H:00:00\', \'%Y-%m-%dT00:00:00\') -- if within the last 48 hours, group by hour
) as time_group',
[$offset, new DateTime('-48 hours')]
)
->selectRaw('COUNT(id) as count')
->where($column, '>', new DateTime('-24 months'))
->groupBy('period')
->lists('count', 'period');
->groupBy('time_group')
->lists('count', 'time_group');
// Now that we have the aggregated statistics, convert each point in
// time into a UNIX timestamp .
$displayTimezone = $this->getDisplayTimezone();
$timed = [];
$results->each(function ($count, $time) use (&$timed, $displayTimezone) {
$time = new DateTime($time, $displayTimezone);
$timed[$time->getTimestamp()] = $count;
});
return $timed;
}
private function getTimezoneOffset()
{
$dataTimezone = new DateTimeZone(date_default_timezone_get());
$displayTimezone = new DateTimeZone($this->settings->get('flarum-statistics.timezone', date_default_timezone_get()));
return $displayTimezone->getOffset(new DateTime('now', $dataTimezone));
return $this->getDisplayTimezone()->getOffset(new DateTime('now', $dataTimezone));
}
private function getUTCOffset()
{
$utcTimezone = new DateTimeZone('UTC');
return $this->getDisplayTimezone()->getOffset(new DateTime('now', $utcTimezone));
}
private function getDisplayTimezone()
{
return new DateTimeZone($this->settings->get('flarum-statistics.timezone', date_default_timezone_get()));
}
}