/** * @dataProvider provideValidTimestampDifferences * @covers MWTimestamp::diff */ public function testDiff($timestamp1, $timestamp2, $expected) { $timestamp1 = new MWTimestamp($timestamp1); $timestamp2 = new MWTimestamp($timestamp2); $diff = $timestamp1->diff($timestamp2); $this->assertEquals($expected, $diff->format('%D %H %I %S')); }
/** * Get the footer with user information (when joined, how * many edits/uploads, visit user page and talk page) * @return string */ protected function getUserFooterData() { $fromDate = $this->targetUser->getRegistration(); $ts = new MWTimestamp(wfTimestamp(TS_UNIX, $fromDate)); $diff = $ts->diff(new MWTimestamp()); if ($fromDate === null) { // User was registered in pre-historic times when registration wasn't recorded $msg = 'mobile-frontend-profile-footer-ancient'; $units = 0; $fromDate = '20010115000000'; // No users before that date } elseif ($diff->y) { $msg = 'mobile-frontend-profile-footer-years'; $units = $diff->y; } elseif ($diff->m) { $msg = 'mobile-frontend-profile-footer-months'; $units = $diff->m; } else { $msg = 'mobile-frontend-profile-footer-days'; $units = $diff->d; } $editCount = $this->targetUser->getEditCount(); $uploadCount = $this->userInfo->countRecentUploads($fromDate); // Ensure that the upload count is compatible with the i18n message if ($uploadCount > 500) { $uploadCount = 500; } $username = $this->targetUser->getName(); return array('editsSummary' => $this->msg($msg, $username)->numParams($units, $editCount, $uploadCount)->parse(), 'linkUserPage' => Linker::link($this->targetUser->getUserPage(), $this->msg('mobile-frontend-profile-userpage-link', $username)->escaped()), 'linkTalk' => $this->getTalkLink()); }
/** * Convert an MWTimestamp into a pretty human-readable timestamp using * the given user preferences and relative base time. * * @see Language::getHumanTimestamp * @param MWTimestamp $ts Timestamp to prettify * @param MWTimestamp $relativeTo Base timestamp * @param User $user User preferences to use * @return string Human timestamp * @since 1.26 */ private function getHumanTimestampInternal(MWTimestamp $ts, MWTimestamp $relativeTo, User $user) { $diff = $ts->diff($relativeTo); $diffDay = (bool) ((int) $ts->timestamp->format('w') - (int) $relativeTo->timestamp->format('w')); $days = $diff->days ?: (int) $diffDay; if ($diff->invert || $days > 5 && $ts->timestamp->format('Y') !== $relativeTo->timestamp->format('Y')) { // Timestamps are in different years: use full timestamp // Also do full timestamp for future dates /** * @todo FIXME: Add better handling of future timestamps. */ $format = $this->getDateFormatString('both', $user->getDatePreference() ?: 'default'); $ts = $this->sprintfDate($format, $ts->getTimestamp(TS_MW)); } elseif ($days > 5) { // Timestamps are in same year, but more than 5 days ago: show day and month only. $format = $this->getDateFormatString('pretty', $user->getDatePreference() ?: 'default'); $ts = $this->sprintfDate($format, $ts->getTimestamp(TS_MW)); } elseif ($days > 1) { // Timestamp within the past week: show the day of the week and time $format = $this->getDateFormatString('time', $user->getDatePreference() ?: 'default'); $weekday = self::$mWeekdayMsgs[$ts->timestamp->format('w')]; // Messages: // sunday-at, monday-at, tuesday-at, wednesday-at, thursday-at, friday-at, saturday-at $ts = wfMessage("{$weekday}-at")->inLanguage($this)->params($this->sprintfDate($format, $ts->getTimestamp(TS_MW)))->text(); } elseif ($days == 1) { // Timestamp was yesterday: say 'yesterday' and the time. $format = $this->getDateFormatString('time', $user->getDatePreference() ?: 'default'); $ts = wfMessage('yesterday-at')->inLanguage($this)->params($this->sprintfDate($format, $ts->getTimestamp(TS_MW)))->text(); } elseif ($diff->h > 1 || $diff->h == 1 && $diff->i > 30) { // Timestamp was today, but more than 90 minutes ago: say 'today' and the time. $format = $this->getDateFormatString('time', $user->getDatePreference() ?: 'default'); $ts = wfMessage('today-at')->inLanguage($this)->params($this->sprintfDate($format, $ts->getTimestamp(TS_MW)))->text(); // From here on in, the timestamp was soon enough ago so that we can simply say // XX units ago, e.g., "2 hours ago" or "5 minutes ago" } elseif ($diff->h == 1) { // Less than 90 minutes, but more than an hour ago. $ts = wfMessage('hours-ago')->inLanguage($this)->numParams(1)->text(); } elseif ($diff->i >= 1) { // A few minutes ago. $ts = wfMessage('minutes-ago')->inLanguage($this)->numParams($diff->i)->text(); } elseif ($diff->s >= 30) { // Less than a minute, but more than 30 sec ago. $ts = wfMessage('seconds-ago')->inLanguage($this)->numParams($diff->s)->text(); } else { // Less than 30 seconds ago. $ts = wfMessage('just-now')->text(); } return $ts; }
/** * Handler for GetHumanTimestamp hook. * Converts the given time into a human-friendly relative format, for * example, '6 days ago', 'In 10 months'. * * @param string &$output The output timestamp * @param MWTimestamp $timestamp The current (user-adjusted) timestamp * @param MWTimestamp $relativeTo The relative (user-adjusted) timestamp * @param User $user User whose preferences are being used to make timestamp * @param Language $lang Language that will be used to render the timestamp * @return bool False means the timestamp was overridden so stop further * processing. True means the timestamp was not overridden. */ public static function onGetHumanTimestamp(&$output, $timestamp, $relativeTo, $user, $lang) { // Map PHP's DateInterval property codes to CLDR unit names. $units = array('s' => 'second', 'i' => 'minute', 'h' => 'hour', 'd' => 'day', 'm' => 'month', 'y' => 'year'); // Get the difference between the two timestamps (as a DateInterval object). $timeDifference = $timestamp->diff($relativeTo); // Figure out if the timestamp is in the future or the past. if ($timeDifference->invert) { $tense = 'future'; } else { $tense = 'past'; } // Figure out which unit (days, months, etc.) it makes sense to display // the timestamp in, and get the number of that unit to use. $unit = null; foreach ($units as $code => $testUnit) { $testNumber = $timeDifference->format('%' . $code); if (intval($testNumber) > 0) { $unit = $testUnit; $number = $testNumber; } } // If it occurred less than 1 second ago, output 'just now' message. if (!$unit) { $output = wfMessage('just-now')->inLanguage($lang)->text(); return false; } // Get the CLDR time unit strings for the user's language. // If no strings are returned, abandon the timestamp override. $timeUnits = TimeUnits::getUnits($lang->getCode()); if (!$timeUnits) { return true; } // Figure out which grammatical number to use. // If the template doesn't exist, fall back to 'other' as the default. $grammaticalNumber = $lang->getPluralRuleType($number); $timeUnitKey = "{$unit}-{$tense}-{$grammaticalNumber}"; if (!isset($timeUnits[$timeUnitKey])) { $timeUnitKey = "{$unit}-{$tense}-other"; } // Not all languages have translations for everything if (!isset($timeUnits[$timeUnitKey])) { return true; } // Select the appropriate template for the timestamp. $timeUnit = $timeUnits[$timeUnitKey]; // Replace the placeholder with the number. $output = str_replace('{0}', $lang->formatNum($number), $timeUnit); return false; }
function execute() { global $wgVersion, $wgLang, $wgAllowSchemaUpdates; if (!$wgAllowSchemaUpdates && !($this->hasOption('force') || $this->hasOption('schema') || $this->hasOption('noschema'))) { $this->error("Do not run update.php on this wiki. If you're seeing this you should\n" . "probably ask for some help in performing your schema updates or use\n" . "the --noschema and --schema options to get an SQL file for someone\n" . "else to inspect and run.\n\n" . "If you know what you are doing, you can continue with --force\n", true); } $this->fileHandle = null; if (substr($this->getOption('schema'), 0, 2) === "--") { $this->error("The --schema option requires a file as an argument.\n", true); } elseif ($this->hasOption('schema')) { $file = $this->getOption('schema'); $this->fileHandle = fopen($file, "w"); if ($this->fileHandle === false) { $err = error_get_last(); $this->error("Problem opening the schema file for writing: {$file}\n\t{$err['message']}", true); } } $wgLang = Language::factory('en'); define('MW_UPDATER', true); $this->output("MediaWiki {$wgVersion} Updater\n\n"); wfWaitForSlaves(5); // let's not kill databases, shall we? ;) --tor if (!$this->hasOption('skip-compat-checks')) { $this->compatChecks(); } else { $this->output("Skipping compatibility checks, proceed at your own risk (Ctrl+C to abort)\n"); wfCountdown(5); } // Check external dependencies are up to date if (!$this->hasOption('skip-external-dependencies')) { $composerLockUpToDate = $this->runChild('CheckComposerLockUpToDate'); $composerLockUpToDate->execute(); } else { $this->output("Skipping checking whether external dependencies are up to date, proceed at your own risk\n"); } # Attempt to connect to the database as a privileged user # This will vomit up an error if there are permissions problems $db = wfGetDB(DB_MASTER); $this->output("Going to run database updates for " . wfWikiID() . "\n"); if ($db->getType() === 'sqlite') { $this->output("Using SQLite file: '{$db->getDbFilePath()}'\n"); } $this->output("Depending on the size of your database this may take a while!\n"); if (!$this->hasOption('quick')) { $this->output("Abort with control-c in the next five seconds " . "(skip this countdown with --quick) ... "); wfCountDown(5); } $time1 = new MWTimestamp(); $shared = $this->hasOption('doshared'); $updates = array('core', 'extensions'); if (!$this->hasOption('schema')) { if ($this->hasOption('noschema')) { $updates[] = 'noschema'; } $updates[] = 'stats'; } $updater = DatabaseUpdater::newForDb($db, $shared, $this); $updater->doUpdates($updates); foreach ($updater->getPostDatabaseUpdateMaintenance() as $maint) { $child = $this->runChild($maint); // LoggedUpdateMaintenance is checking the updatelog itself $isLoggedUpdate = is_a($child, 'LoggedUpdateMaintenance'); if (!$isLoggedUpdate && $updater->updateRowExists($maint)) { continue; } $child->execute(); if (!$isLoggedUpdate) { $updater->insertUpdateRow($maint); } } $updater->setFileAccess(); if (!$this->hasOption('nopurge')) { $updater->purgeCache(); } $time2 = new MWTimestamp(); $timeDiff = $time2->diff($time1); $this->output("\nDone in " . $timeDiff->format("%i:%S") . ".\n"); }