Switch from DateTime to DateTimeImmutable across codebase

This commit is contained in:
Alex Cabal 2024-04-13 14:05:14 -05:00
parent 92c647f2b1
commit e55fecaaa2
35 changed files with 102 additions and 99 deletions

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\date; use function Safe\date;
/** /**
@ -12,8 +12,8 @@ use function Safe\date;
class Artist extends Accessor{ class Artist extends Accessor{
public ?int $ArtistId = null; public ?int $ArtistId = null;
public ?string $Name = null; public ?string $Name = null;
public ?datetime $Created = null; public ?DateTimeImmutable $Created = null;
public ?datetime $Updated = null; public ?DateTimeImmutable $Updated = null;
protected ?int $_DeathYear = null; protected ?int $_DeathYear = null;
protected ?string $_UrlName = null; protected ?string $_UrlName = null;
protected ?string $_Url = null; protected ?string $_Url = null;
@ -82,7 +82,7 @@ class Artist extends Accessor{
// ******* // *******
public function Validate(): void{ public function Validate(): void{
$now = new DateTime('now', new DateTimeZone('UTC')); $now = new DateTimeImmutable();
$thisYear = intval($now->format('Y')); $thisYear = intval($now->format('Y'));
$error = new Exceptions\ValidationException(); $error = new Exceptions\ValidationException();

View file

@ -1,7 +1,7 @@
<? <?
use Exceptions\InvalidUrlException; use Exceptions\InvalidUrlException;
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\apcu_cache_info; use function Safe\apcu_cache_info;
use function Safe\copy; use function Safe\copy;
@ -40,8 +40,8 @@ class Artwork extends Accessor{
public ?int $ArtistId = null; public ?int $ArtistId = null;
public ?int $CompletedYear = null; public ?int $CompletedYear = null;
public bool $CompletedYearIsCirca = false; public bool $CompletedYearIsCirca = false;
public ?DateTime $Created = null; public ?DateTimeImmutable $Created = null;
public ?DateTime $Updated = null; public ?DateTimeImmutable $Updated = null;
public ?string $EbookUrl = null; public ?string $EbookUrl = null;
public ?int $SubmitterUserId = null; public ?int $SubmitterUserId = null;
public ?int $ReviewerUserId = null; public ?int $ReviewerUserId = null;
@ -356,7 +356,7 @@ class Artwork extends Accessor{
} }
} }
$now = new DateTime('now', new DateTimeZone('UTC')); $now = new DateTimeImmutable();
$thisYear = intval($now->format('Y')); $thisYear = intval($now->format('Y'));
$error = new Exceptions\ValidationException(); $error = new Exceptions\ValidationException();
@ -680,7 +680,7 @@ class Artwork extends Accessor{
$this->Validate($imagePath, true); $this->Validate($imagePath, true);
$this->Created = new DateTime(); $this->Created = new DateTimeImmutable();
$tags = []; $tags = [];
foreach($this->Tags as $artworkTag){ foreach($this->Tags as $artworkTag){
@ -745,7 +745,7 @@ class Artwork extends Accessor{
// Manually set the updated timestamp, because if we only update the image and nothing else, the row's // Manually set the updated timestamp, because if we only update the image and nothing else, the row's
// updated timestamp won't change automatically. // updated timestamp won't change automatically.
$this->Updated = new DateTime('now', new DateTimeZone('UTC')); $this->Updated = new DateTimeImmutable();
$this->_ImageUrl = null; $this->_ImageUrl = null;
$this->_ThumbUrl = null; $this->_ThumbUrl = null;
$this->_Thumb2xUrl = null; $this->_Thumb2xUrl = null;

View file

@ -1,10 +1,10 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\file_get_contents; use function Safe\file_get_contents;
class AtomFeed extends Feed{ class AtomFeed extends Feed{
public string $Id; public string $Id;
public ?DateTime $Updated = null; public ?DateTimeImmutable $Updated = null;
public ?string $Subtitle = null; public ?string $Subtitle = null;
/** /**
@ -39,7 +39,7 @@ class AtomFeed extends Feed{
// Did we actually update the feed? If so, write to file and update the index // Did we actually update the feed? If so, write to file and update the index
if($this->HasChanged($this->Path)){ if($this->HasChanged($this->Path)){
// Files don't match, save the file // Files don't match, save the file
$this->Updated = new DateTime(); $this->Updated = new DateTimeImmutable();
$this->Save(); $this->Save();
return true; return true;
} }

View file

@ -1,10 +1,10 @@
<? <?
// Auto-included by Composer in composer.json to satisfy PHPStan // Auto-included by Composer in composer.json to satisfy PHPStan
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\define; use function Safe\define;
$now = new DateTime('now', new DateTimeZone('UTC')); $now = new DateTimeImmutable();
$nowPd = new DateTime('now', new DateTimeZone('America/Juneau')); // Latest continental US time zone $nowPd = new DateTimeImmutable('now', new DateTimeZone('America/Juneau')); // Latest continental US time zone
const SITE_STATUS_LIVE = 'live'; const SITE_STATUS_LIVE = 'live';
const SITE_STATUS_DEV = 'dev'; const SITE_STATUS_DEV = 'dev';
@ -94,7 +94,7 @@ const ARTWORK_UPLOADS_LOG_FILE_PATH = '/var/log/local/artwork-uploads.log'; // M
define('PD_YEAR', intval($nowPd->format('Y')) - 96); define('PD_YEAR', intval($nowPd->format('Y')) - 96);
define('PD_STRING', 'January 1, ' . (PD_YEAR + 1)); define('PD_STRING', 'January 1, ' . (PD_YEAR + 1));
define('DONATION_HOLIDAY_ALERT_ON', $now > new DateTime('November 15, ' . $now->format('Y'), new DateTimeZone('UTC')) || $now < new DateTime('January 7, ' . $now->add(new DateInterval('P1Y'))->format('Y'), new DateTimeZone('UTC'))); define('DONATION_HOLIDAY_ALERT_ON', $now > new DateTimeImmutable('November 15, ' . $now->format('Y')) || $now < new DateTimeImmutable('January 7, ' . $now->add(new DateInterval('P1Y'))->format('Y')));
define('DONATION_ALERT_ON', DONATION_HOLIDAY_ALERT_ON || rand(1, 4) == 2); define('DONATION_ALERT_ON', DONATION_HOLIDAY_ALERT_ON || rand(1, 4) == 2);
// Controls the progress bar donation dialog // Controls the progress bar donation dialog

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\preg_match; use function Safe\preg_match;
use function Safe\posix_getpwuid; use function Safe\posix_getpwuid;
@ -199,7 +199,7 @@ class DbConnection{
switch($metadata[$i]['native_type'] ?? null){ switch($metadata[$i]['native_type'] ?? null){
case 'DATETIME': case 'DATETIME':
case 'TIMESTAMP': case 'TIMESTAMP':
$object->{$metadata[$i]['name']} = new DateTime($row[$i], new DateTimeZone('UTC')); $object->{$metadata[$i]['name']} = new DateTimeImmutable($row[$i], new DateTimeZone('UTC'));
break; break;
case 'LONG': case 'LONG':

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\file_get_contents; use function Safe\file_get_contents;
use function Safe\filesize; use function Safe\filesize;
use function Safe\json_encode; use function Safe\json_encode;
@ -67,8 +67,8 @@ class Ebook{
public $Contributors = []; public $Contributors = [];
public ?string $ContributorsHtml = null; public ?string $ContributorsHtml = null;
public string $TitleWithCreditsHtml = ''; public string $TitleWithCreditsHtml = '';
public DateTime $Created; public DateTimeImmutable $Created;
public DateTime $Updated; public DateTimeImmutable $Updated;
public string $TextUrl; public string $TextUrl;
public string $TextSinglePageUrl; public string $TextSinglePageUrl;
public ?string $TextSinglePageSizeNumber = null; public ?string $TextSinglePageSizeNumber = null;
@ -222,12 +222,12 @@ class Ebook{
$date = $xml->xpath('/package/metadata/dc:date') ?: []; $date = $xml->xpath('/package/metadata/dc:date') ?: [];
if($date !== false && sizeof($date) > 0){ if($date !== false && sizeof($date) > 0){
$this->Created = new DateTime((string)$date[0]); $this->Created = new DateTimeImmutable((string)$date[0]);
} }
$modifiedDate = $xml->xpath('/package/metadata/meta[@property="dcterms:modified"]') ?: []; $modifiedDate = $xml->xpath('/package/metadata/meta[@property="dcterms:modified"]') ?: [];
if($modifiedDate !== false && sizeof($modifiedDate) > 0){ if($modifiedDate !== false && sizeof($modifiedDate) > 0){
$this->Updated = new DateTime((string)$modifiedDate[0]); $this->Updated = new DateTimeImmutable((string)$modifiedDate[0]);
} }
// Get SE tags // Get SE tags

View file

@ -22,7 +22,7 @@ class ValidationException extends AppException{
public function Add(\Exception $exception, bool $isFatal = false): void{ public function Add(\Exception $exception, bool $isFatal = false): void{
if(is_a($exception, static::class)){ if(is_a($exception, static::class)){
// Type hint for linter // Type hint for linter
/** @var ValidationException $exception */ /** @var ValidationException $childException */
foreach($exception->Exceptions as $childException){ foreach($exception->Exceptions as $childException){
$this->Add($childException); $this->Add($childException);
} }

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\apcu_fetch; use function Safe\apcu_fetch;
use function Safe\exec; use function Safe\exec;
use function Safe\filemtime; use function Safe\filemtime;
@ -432,7 +432,7 @@ class Library{
private static function FillBulkDownloadObject(string $dir, string $downloadType, string $urlRoot): stdClass{ private static function FillBulkDownloadObject(string $dir, string $downloadType, string $urlRoot): stdClass{
$obj = new stdClass(); $obj = new stdClass();
$now = new DateTime('now', new DateTimeZone('UTC')); $now = new DateTimeImmutable();
// The count of ebooks in each file is stored as a filesystem attribute // The count of ebooks in each file is stored as a filesystem attribute
$obj->EbookCount = exec('attr -g se-ebook-count ' . escapeshellarg($dir)) ?: null; $obj->EbookCount = exec('attr -g se-ebook-count ' . escapeshellarg($dir)) ?: null;
@ -479,7 +479,7 @@ class Library{
$obj->ZipFiles[] = $zipFile; $obj->ZipFiles[] = $zipFile;
} }
$obj->Updated = new DateTime('@' . filemtime($files[0])); $obj->Updated = new DateTimeImmutable('@' . filemtime($files[0]));
$obj->UpdatedString = $obj->Updated->format('M j'); $obj->UpdatedString = $obj->Updated->format('M j');
// Add a period to the abbreviated month, but not if it's May (the only 3-letter month) // Add a period to the abbreviated month, but not if it's May (the only 3-letter month)
$obj->UpdatedString = preg_replace('/^(.+?)(?<!May) /', '\1. ', $obj->UpdatedString); $obj->UpdatedString = preg_replace('/^(.+?)(?<!May) /', '\1. ', $obj->UpdatedString);
@ -546,7 +546,7 @@ class Library{
foreach($dirs as $dir){ foreach($dirs as $dir){
$obj = self::FillBulkDownloadObject($dir, 'months', '/months'); $obj = self::FillBulkDownloadObject($dir, 'months', '/months');
$date = new DateTime($obj->Label . '-01'); $date = new DateTimeImmutable($obj->Label . '-01');
$year = $date->format('Y'); $year = $date->format('Y');
$month = $date->format('F'); $month = $date->format('F');

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\fopen; use function Safe\fopen;
use function Safe\fwrite; use function Safe\fwrite;
use function Safe\fclose; use function Safe\fclose;
@ -33,7 +33,7 @@ class Log{
return; return;
} }
$now = new DateTime('now', new DateTimeZone('UTC')); $now = new DateTimeImmutable();
fwrite($fp, $now->format('Y-m-d H:i:s') . "\t" . $this->RequestId . "\t" . $text . "\n"); fwrite($fp, $now->format('Y-m-d H:i:s') . "\t" . $this->RequestId . "\t" . $text . "\n");
fclose($fp); fclose($fp);

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
/** /**
* @property User $User * @property User $User
@ -10,7 +10,7 @@ class NewsletterSubscription extends Accessor{
public bool $IsSubscribedToSummary = false; public bool $IsSubscribedToSummary = false;
public bool $IsSubscribedToNewsletter = false; public bool $IsSubscribedToNewsletter = false;
public ?int $UserId = null; public ?int $UserId = null;
public DateTime $Created; public DateTimeImmutable $Created;
protected $_User; protected $_User;
protected $_Url = null; protected $_Url = null;
@ -44,7 +44,7 @@ class NewsletterSubscription extends Accessor{
} }
$this->UserId = $this->User->UserId; $this->UserId = $this->User->UserId;
$this->Created = new DateTime(); $this->Created = new DateTimeImmutable();
try{ try{
Db::Query(' Db::Query('

View file

@ -1,6 +1,4 @@
<? <?
use Safe\DateTime;
class OpdsAcquisitionFeed extends OpdsFeed{ class OpdsAcquisitionFeed extends OpdsFeed{
public bool $IsCrawlable; public bool $IsCrawlable;

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\file_put_contents; use function Safe\file_put_contents;
class OpdsFeed extends AtomFeed{ class OpdsFeed extends AtomFeed{
@ -24,7 +24,7 @@ class OpdsFeed extends AtomFeed{
// METHODS // METHODS
// ******* // *******
protected function SaveUpdated(string $entryId, DateTime $updated): void{ protected function SaveUpdated(string $entryId, DateTimeImmutable $updated): void{
// Only save the updated timestamp for the given entry ID in this file // Only save the updated timestamp for the given entry ID in this file
foreach($this->Entries as $entry){ foreach($this->Entries as $entry){
if($entry instanceof OpdsNavigationEntry){ if($entry instanceof OpdsNavigationEntry){
@ -50,7 +50,7 @@ class OpdsFeed extends AtomFeed{
if($this->HasChanged($this->Path)){ if($this->HasChanged($this->Path)){
// Files don't match, save the file and update the parent navigation feed with the last updated timestamp // Files don't match, save the file and update the parent navigation feed with the last updated timestamp
$this->Updated = new DateTime(); $this->Updated = new DateTimeImmutable();
if($this->Parent !== null){ if($this->Parent !== null){
$this->Parent->SaveUpdated($this->Id, $this->Updated); $this->Parent->SaveUpdated($this->Id, $this->Updated);

View file

@ -1,15 +1,17 @@
<? <?
use Safe\DateTimeImmutable;
class OpdsNavigationEntry{ class OpdsNavigationEntry{
public string $Id; public string $Id;
public string $Url; public string $Url;
public string $Rel; public string $Rel;
public string $Type; public string $Type;
public ?DateTime $Updated = null; public ?DateTimeImmutable $Updated = null;
public string $Description; public string $Description;
public string $Title; public string $Title;
public string $SortTitle; public string $SortTitle;
public function __construct(string $title, string $description, string $url, ?DateTime $updated, string $rel, string $type){ public function __construct(string $title, string $description, string $url, ?DateTimeImmutable $updated, string $rel, string $type){
$this->Id = SITE_URL . $url; $this->Id = SITE_URL . $url;
$this->Url = $url; $this->Url = $url;
$this->Rel = $rel; $this->Rel = $rel;

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\file_get_contents; use function Safe\file_get_contents;
class OpdsNavigationFeed extends OpdsFeed{ class OpdsNavigationFeed extends OpdsFeed{
@ -25,7 +25,7 @@ class OpdsNavigationFeed extends OpdsFeed{
foreach($xml->xpath('//entry') ?: [] as $existingEntry){ foreach($xml->xpath('//entry') ?: [] as $existingEntry){
foreach($this->Entries as $entry){ foreach($this->Entries as $entry){
if($entry->Id == $existingEntry->id){ if($entry->Id == $existingEntry->id){
$entry->Updated = new DateTime($existingEntry->updated); $entry->Updated = new DateTimeImmutable($existingEntry->updated);
} }
} }
} }

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
/** /**
* @property User $User * @property User $User
@ -10,8 +10,8 @@ class Patron extends Accessor{
public bool $IsAnonymous; public bool $IsAnonymous;
public ?string $AlternateName = null; public ?string $AlternateName = null;
public bool $IsSubscribedToEmails; public bool $IsSubscribedToEmails;
public ?DateTime $Created = null; public ?DateTimeImmutable $Created = null;
public ?DateTime $Ended = null; public ?DateTimeImmutable $Ended = null;
// ******* // *******
@ -19,7 +19,7 @@ class Patron extends Accessor{
// ******* // *******
public function Create(): void{ public function Create(): void{
$this->Created = new DateTime(); $this->Created = new DateTimeImmutable();
Db::Query(' Db::Query('
INSERT into Patrons (Created, UserId, IsAnonymous, AlternateName, IsSubscribedToEmails) INSERT into Patrons (Created, UserId, IsAnonymous, AlternateName, IsSubscribedToEmails)
values(?, values(?,

View file

@ -1,11 +1,13 @@
<? <?
use Safe\DateTimeImmutable;
/** /**
* @property User $User * @property User $User
*/ */
class Payment extends Accessor{ class Payment extends Accessor{
public int $PaymentId; public int $PaymentId;
public ?int $UserId = null; public ?int $UserId = null;
public DateTime $Created; public DateTimeImmutable $Created;
public int $ChannelId; public int $ChannelId;
public string $TransactionId; public string $TransactionId;
public float $Amount; public float $Amount;

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\usort; use function Safe\usort;
/** /**
@ -15,9 +15,9 @@ class Poll extends Accessor{
public string $Name; public string $Name;
public string $UrlName; public string $UrlName;
public string $Description; public string $Description;
public DateTime $Created; public DateTimeImmutable $Created;
public DateTime $Start; public DateTimeImmutable $Start;
public DateTime $End; public DateTimeImmutable $End;
protected ?string $_Url = null; protected ?string $_Url = null;
protected $_PollItems = null; protected $_PollItems = null;
protected $_PollItemsByWinner = null; protected $_PollItemsByWinner = null;
@ -85,7 +85,7 @@ class Poll extends Accessor{
// ******* // *******
public function IsActive(): bool{ public function IsActive(): bool{
$now = new DateTime(); $now = new DateTimeImmutable();
if( ($this->Start !== null && $this->Start > $now) || ($this->End !== null && $this->End < $now)){ if( ($this->Start !== null && $this->Start > $now) || ($this->End !== null && $this->End < $now)){
return false; return false;
} }

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
/** /**
* @property User $User * @property User $User
@ -8,7 +8,7 @@ use Safe\DateTime;
*/ */
class PollVote extends Accessor{ class PollVote extends Accessor{
public int $UserId; public int $UserId;
public DateTime $Created; public DateTimeImmutable $Created;
public ?int $PollItemId = null; public ?int $PollItemId = null;
protected ?User $_User = null; protected ?User $_User = null;
protected ?PollItem $_PollItem = null; protected ?PollItem $_PollItem = null;
@ -98,7 +98,7 @@ class PollVote extends Accessor{
} }
$this->Validate(); $this->Validate();
$this->Created = new DateTime(); $this->Created = new DateTimeImmutable();
Db::Query(' Db::Query('
INSERT into PollVotes (UserId, PollItemId, Created) INSERT into PollVotes (UserId, PollItemId, Created)
values (?, values (?,

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\file_get_contents; use function Safe\file_get_contents;
use function Safe\filesize; use function Safe\filesize;
use function Safe\preg_replace; use function Safe\preg_replace;
@ -27,7 +27,7 @@ class RssFeed extends Feed{
protected function GetXmlString(): string{ protected function GetXmlString(): string{
if($this->XmlString === null){ if($this->XmlString === null){
$feed = Template::RssFeed(['url' => $this->Url, 'description' => $this->Description, 'title' => $this->Title, 'entries' => $this->Entries, 'updated' => (new DateTime())->format('r')]); $feed = Template::RssFeed(['url' => $this->Url, 'description' => $this->Description, 'title' => $this->Title, 'entries' => $this->Entries, 'updated' => (new DateTimeImmutable())->format('r')]);
$this->XmlString = $this->CleanXmlString($feed); $this->XmlString = $this->CleanXmlString($feed);
} }

View file

@ -2,7 +2,7 @@
use Exceptions\InvalidLoginException; use Exceptions\InvalidLoginException;
use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Uuid;
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\strtotime; use function Safe\strtotime;
/** /**
@ -12,7 +12,7 @@ use function Safe\strtotime;
class Session extends Accessor{ class Session extends Accessor{
public int $UserId; public int $UserId;
protected ?User $_User = null; protected ?User $_User = null;
public DateTime $Created; public DateTimeImmutable $Created;
public string $SessionId; public string $SessionId;
public ?string $_Url = null; public ?string $_Url = null;
@ -53,7 +53,7 @@ class Session extends Accessor{
else{ else{
$uuid = Uuid::uuid4(); $uuid = Uuid::uuid4();
$this->SessionId = $uuid->toString(); $this->SessionId = $uuid->toString();
$this->Created = new DateTime(); $this->Created = new DateTimeImmutable();
Db::Query(' Db::Query('
INSERT into Sessions (UserId, SessionId, Created) INSERT into Sessions (UserId, SessionId, Created)
values (?, values (?,

View file

@ -1,6 +1,6 @@
<? <?
use Ramsey\Uuid\Uuid; use Ramsey\Uuid\Uuid;
use Safe\DateTime; use Safe\DateTimeImmutable;
/** /**
* @property Array<Payment> $Payments * @property Array<Payment> $Payments
@ -12,7 +12,7 @@ class User extends Accessor{
public int $UserId; public int $UserId;
public ?string $Name = null; public ?string $Name = null;
public ?string $Email = null; public ?string $Email = null;
public DateTime $Created; public DateTimeImmutable $Created;
public string $Uuid; public string $Uuid;
public ?string $PasswordHash = null; public ?string $PasswordHash = null;
protected ?bool $_IsRegistered = null; protected ?bool $_IsRegistered = null;
@ -78,7 +78,7 @@ class User extends Accessor{
public function Create(?string $password = null): void{ public function Create(?string $password = null): void{
$uuid = Uuid::uuid4(); $uuid = Uuid::uuid4();
$this->Uuid = $uuid->toString(); $this->Uuid = $uuid->toString();
$this->Created = new DateTime(); $this->Created = new DateTimeImmutable();
$this->PasswordHash = null; $this->PasswordHash = null;
if($password !== null){ if($password !== null){

View file

@ -2,7 +2,7 @@
<? <?
require_once('/standardebooks.org/web/lib/Core.php'); require_once('/standardebooks.org/web/lib/Core.php');
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\getopt; use function Safe\getopt;
use function Safe\mkdir; use function Safe\mkdir;
use function Safe\preg_replace; use function Safe\preg_replace;
@ -11,7 +11,7 @@ function SortByUpdatedDesc($a, $b){
return $b->Updated <=> $a->Updated; return $b->Updated <=> $a->Updated;
} }
function SaveFeed(Feed $feed, bool $force, ?string $label = null, ?string $labelSort = null, DateTime $now = null): void{ function SaveFeed(Feed $feed, bool $force, ?string $label = null, ?string $labelSort = null, DateTimeImmutable $now = null): void{
$updateAttrs = false; $updateAttrs = false;
if($force){ if($force){
@ -31,7 +31,7 @@ function SaveFeed(Feed $feed, bool $force, ?string $label = null, ?string $label
} }
} }
function CreateOpdsCollectionFeed(string $name, string $url, string $description, array $collections, array $ebooks, DateTime $now, string $webRoot, OpdsNavigationFeed $opdsRoot, bool $force): void{ function CreateOpdsCollectionFeed(string $name, string $url, string $description, array $collections, array $ebooks, DateTimeImmutable $now, string $webRoot, OpdsNavigationFeed $opdsRoot, bool $force): void{
$collator = collator_create('en_US'); // Used for sorting letters with diacritics like in author names $collator = collator_create('en_US'); // Used for sorting letters with diacritics like in author names
usort($collections, function($a, $b) use($collator){ return $collator->compare($a['sortedname'], $b['sortedname']); }); usort($collections, function($a, $b) use($collator){ return $collator->compare($a['sortedname'], $b['sortedname']); });
@ -108,7 +108,7 @@ usort($allEbooks, 'SortByUpdatedDesc');
usort($newestEbooks, function($a, $b){ return $b->Created <=> $a->Created; }); usort($newestEbooks, function($a, $b){ return $b->Created <=> $a->Created; });
$newestEbooks = array_slice($newestEbooks, 0, $ebooksPerNewestEbooksFeed); $newestEbooks = array_slice($newestEbooks, 0, $ebooksPerNewestEbooksFeed);
$now = new DateTime(); $now = new DateTimeImmutable();
// Create OPDS feeds // Create OPDS feeds
$opdsRootEntries = [ $opdsRootEntries = [

View file

@ -16,7 +16,7 @@ use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Firefox\FirefoxDriver; use Facebook\WebDriver\Firefox\FirefoxDriver;
use Facebook\WebDriver\Firefox\FirefoxOptions; use Facebook\WebDriver\Firefox\FirefoxOptions;
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\file_get_contents; use function Safe\file_get_contents;
use function Safe\preg_replace; use function Safe\preg_replace;
use function Safe\putenv; use function Safe\putenv;
@ -44,7 +44,7 @@ $lastSeenTransactionId = null;
$firstTransactionId = null; $firstTransactionId = null;
$transactionFilePath = '/tmp/last-fa-donation'; $transactionFilePath = '/tmp/last-fa-donation';
$transactionIds = []; $transactionIds = [];
$now = new DateTime('now', new DateTimeZone('UTC')); $now = new DateTimeImmutable();
$today = $now->format('n/j/Y'); $today = $now->format('n/j/Y');
$faItemsPerPage = 20; // How many items are on a full page of FA results? $faItemsPerPage = 20; // How many items are on a full page of FA results?

View file

@ -9,7 +9,7 @@ use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Firefox\FirefoxDriver; use Facebook\WebDriver\Firefox\FirefoxDriver;
use Facebook\WebDriver\Firefox\FirefoxOptions; use Facebook\WebDriver\Firefox\FirefoxOptions;
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\preg_match; use function Safe\preg_match;
use function Safe\preg_replace; use function Safe\preg_replace;
use function Safe\putenv; use function Safe\putenv;
@ -31,8 +31,8 @@ $capabilities->setCapability(FirefoxOptions::CAPABILITY, $firefoxOptions);
$driver = null; $driver = null;
$log = new Log(DONATIONS_LOG_FILE_PATH); $log = new Log(DONATIONS_LOG_FILE_PATH);
$lastMonth = (new DateTime())->sub(new DateInterval('P45D')); // 45 days, a 15 day grace period before Patrons Circle members are dropped off $lastMonth = (new DateTimeImmutable())->sub(new DateInterval('P45D')); // 45 days, a 15 day grace period before Patrons Circle members are dropped off
$lastYear = (new DateTime())->sub(new DateInterval('P1Y')); $lastYear = (new DateTimeImmutable())->sub(new DateInterval('P1Y'));
$faUsername = get_cfg_var('se.secrets.fractured_atlas.username'); $faUsername = get_cfg_var('se.secrets.fractured_atlas.username');
$faPassword = get_cfg_var('se.secrets.fractured_atlas.password'); $faPassword = get_cfg_var('se.secrets.fractured_atlas.password');
@ -152,7 +152,7 @@ try{
$payment->User = null; $payment->User = null;
} }
$payment->Created = DateTime::createFromFormat('n/j/Y', trim($detailsRow->findElement(WebDriverBy::xpath('//td[preceding-sibling::th[normalize-space(.) = "Created"]]'))->getText())); $payment->Created = DateTimeImmutable::createFromFormat('n/j/Y', trim($detailsRow->findElement(WebDriverBy::xpath('//td[preceding-sibling::th[normalize-space(.) = "Created"]]'))->getText()));
$payment->IsRecurring = sizeof($headerRow->findElements(WebDriverBy::xpath('//td[contains(., "Recurring")]'))) > 0; $payment->IsRecurring = sizeof($headerRow->findElements(WebDriverBy::xpath('//td[contains(., "Recurring")]'))) > 0;
$payment->Amount = floatval(str_replace('$', '', trim($detailsRow->findElement(WebDriverBy::xpath('//td[preceding-sibling::th[normalize-space(.) = "Total Amount"]]'))->getText()))); $payment->Amount = floatval(str_replace('$', '', trim($detailsRow->findElement(WebDriverBy::xpath('//td[preceding-sibling::th[normalize-space(.) = "Total Amount"]]'))->getText())));
$payment->Fee = floatval(str_replace('$', '', trim($detailsRow->findElement(WebDriverBy::xpath('//td[preceding-sibling::th[normalize-space(.) = "Fee"]]'))->getText()))); $payment->Fee = floatval(str_replace('$', '', trim($detailsRow->findElement(WebDriverBy::xpath('//td[preceding-sibling::th[normalize-space(.) = "Fee"]]'))->getText())));

View file

@ -2,12 +2,14 @@
<? <?
require_once('/standardebooks.org/web/lib/Core.php'); require_once('/standardebooks.org/web/lib/Core.php');
use Safe\DateTimeImmutable;
// Get a list of payments that are within 1 year / 45 days of today, and deactivate Patrons Circle members // Get a list of payments that are within 1 year / 45 days of today, and deactivate Patrons Circle members
// who aren't in that list. // who aren't in that list.
// We give a 15 day grace period to Patrons Circle members because sometimes FA can be delayed in charging. // We give a 15 day grace period to Patrons Circle members because sometimes FA can be delayed in charging.
$now = new DateTime(); $now = new DateTimeImmutable();
$lastYear = new DateTime('-1 year'); $lastYear = new DateTimeImmutable('-1 year');
$expiredPatrons = Db::Query(' $expiredPatrons = Db::Query('
SELECT * from Patrons SELECT * from Patrons
@ -38,7 +40,7 @@ if(sizeof($expiredPatrons) > 0){
preg_match_all('/<dc:date>(.+?)<\/dc:date>/iu', $metadata, $matches); preg_match_all('/<dc:date>(.+?)<\/dc:date>/iu', $metadata, $matches);
if(sizeof($matches) > 0){ if(sizeof($matches) > 0){
$created = new DateTime($matches[1][0]); $created = new DateTimeImmutable($matches[1][0]);
if($created >= $lastYear){ if($created >= $lastYear){
$ebooksThisYear++; $ebooksThisYear++;
} }

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
$artwork = $artwork ?? null; $artwork = $artwork ?? null;
@ -10,7 +10,7 @@ if($artwork === null){
$isEditForm = $isEditForm ?? false; $isEditForm = $isEditForm ?? false;
$now = new DateTime('now', new DateTimeZone('America/Juneau')); // Latest continental US time zone $now = new DateTimeImmutable('now', new DateTimeZone('America/Juneau')); // Latest continental US time zone
?> ?>
<fieldset> <fieldset>
<legend>Artist details</legend> <legend>Artist details</legend>

View file

@ -1,8 +1,9 @@
<? <?
use Safe\DateTimeImmutable;
$start = new DateTime(DONATION_DRIVE_COUNTER_START); $start = new DateTimeImmutable(DONATION_DRIVE_COUNTER_START);
$end = new DateTime(DONATION_DRIVE_COUNTER_END); $end = new DateTimeImmutable(DONATION_DRIVE_COUNTER_END);
$now = new DateTime(); $now = new DateTimeImmutable();
// Hide the alert if the user has closed it // Hide the alert if the user has closed it
if(!DONATION_DRIVE_COUNTER_ON || ($autoHide ?? $_COOKIE['hide-donation-alert'] ?? false) || $now > $end){ if(!DONATION_DRIVE_COUNTER_ON || ($autoHide ?? $_COOKIE['hide-donation-alert'] ?? false) || $now > $end){

View file

@ -1,14 +1,14 @@
<? <?
use Safe\DateTimeImmutable;
$start = new DateTime(DONATION_DRIVE_START); $start = new DateTimeImmutable(DONATION_DRIVE_START);
$end = new DateTime(DONATION_DRIVE_END); $end = new DateTimeImmutable(DONATION_DRIVE_END);
$now = new DateTimeImmutable();
$totalCurrent = 0; $totalCurrent = 0;
$baseTarget = 50; $baseTarget = 50;
$stretchCurrent = 0; $stretchCurrent = 0;
$stretchTarget = 20; $stretchTarget = 20;
$now = new DateTime();
// Hide the alert if the user has closed it // Hide the alert if the user has closed it
if(!DONATION_DRIVE_ON || ($autoHide ?? $_COOKIE['hide-donation-alert'] ?? false) || $GLOBALS['User'] !== null || $now > $end){ if(!DONATION_DRIVE_ON || ($autoHide ?? $_COOKIE['hide-donation-alert'] ?? false) || $GLOBALS['User'] !== null || $now > $end){
return; return;

View file

@ -1,6 +1,4 @@
<? <?
use Safe\DateTime;
// Note that the XSL stylesheet gets stripped during `se clean` when we generate the feed. // Note that the XSL stylesheet gets stripped during `se clean` when we generate the feed.
// `se clean` will also start adding empty namespaces everywhere if we include the stylesheet declaration first. // `se clean` will also start adding empty namespaces everywhere if we include the stylesheet declaration first.
// We have to add it programmatically when saving the feed file. // We have to add it programmatically when saving the feed file.

View file

@ -297,7 +297,7 @@ catch(Exceptions\EbookNotFoundException){
<ol> <ol>
<? foreach($ebook->GitCommits as $commit){ ?> <? foreach($ebook->GitCommits as $commit){ ?>
<li> <li>
<time datetime="<?= $commit->Created->format(DateTime::RFC3339) ?>"><?= $commit->Created->format('M j, Y') ?></time> <time datetime="<?= $commit->Created->format(DateTimeImmutable::RFC3339) ?>"><?= $commit->Created->format('M j, Y') ?></time>
<p><a href="<?= Formatter::EscapeHtml($ebook->GitHubUrl) ?>/commit/<?= Formatter::EscapeHtml($commit->Hash) ?>"><?= Formatter::EscapeHtml($commit->Message) ?></a></p> <p><a href="<?= Formatter::EscapeHtml($ebook->GitHubUrl) ?>/commit/<?= Formatter::EscapeHtml($commit->Hash) ?>"><?= Formatter::EscapeHtml($commit->Message) ?></a></p>
</li> </li>
<? } ?> <? } ?>

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
$ebooks = []; $ebooks = [];
@ -25,7 +25,7 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?xml-stylesheet href=\"" . S
<title>Search Results</title> <title>Search Results</title>
<subtitle>Results for <?= Formatter::EscapeXml($query) ?>”.</subtitle> <subtitle>Results for <?= Formatter::EscapeXml($query) ?>”.</subtitle>
<icon><?= SITE_URL ?>/images/logo.png</icon> <icon><?= SITE_URL ?>/images/logo.png</icon>
<updated><?= (new Datetime())->Format('Y-m-d\TH:i:s\Z') ?></updated> <updated><?= (new DateTimeImmutable())->Format('Y-m-d\TH:i:s\Z') ?></updated>
<author> <author>
<name>Standard Ebooks</name> <name>Standard Ebooks</name>
<uri><?= SITE_URL ?></uri> <uri><?= SITE_URL ?></uri>

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
$ebooks = []; $ebooks = [];
@ -26,7 +26,7 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?xml-stylesheet href=\"". SI
<title>Search Results</title> <title>Search Results</title>
<subtitle>Results for <?= Formatter::EscapeXml($query) ?>”.</subtitle> <subtitle>Results for <?= Formatter::EscapeXml($query) ?>”.</subtitle>
<icon><?= SITE_URL ?>/images/logo.png</icon> <icon><?= SITE_URL ?>/images/logo.png</icon>
<updated><?= (new Datetime())->Format('Y-m-d\TH:i:s\Z') ?></updated> <updated><?= (new DateTimeImmutable())->Format('Y-m-d\TH:i:s\Z') ?></updated>
<author> <author>
<name>Standard Ebooks</name> <name>Standard Ebooks</name>
<uri><?= SITE_URL ?></uri> <uri><?= SITE_URL ?></uri>

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
$ebooks = []; $ebooks = [];
@ -24,7 +24,7 @@ print("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<?xml-stylesheet href=\"" . S
<description>Results for <?= Formatter::EscapeXml($query) ?>”.</description> <description>Results for <?= Formatter::EscapeXml($query) ?>”.</description>
<language>en-US</language> <language>en-US</language>
<copyright>https://creativecommons.org/publicdomain/zero/1.0/</copyright> <copyright>https://creativecommons.org/publicdomain/zero/1.0/</copyright>
<lastBuildDate><?= (new DateTime())->format('r') ?></lastBuildDate> <lastBuildDate><?= (new DateTimeImmutable())->format('r') ?></lastBuildDate>
<docs>http://blogs.law.harvard.edu/tech/rss</docs> <docs>http://blogs.law.harvard.edu/tech/rss</docs>
<atom:link href="<?= SITE_URL ?>/feeds/rss/all?query=<?= urlencode($query) ?>" rel="self" type="application/rss+xml"/> <atom:link href="<?= SITE_URL ?>/feeds/rss/all?query=<?= urlencode($query) ?>" rel="self" type="application/rss+xml"/>
<atom:link href="<?= SITE_URL ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml" /> <atom:link href="<?= SITE_URL ?>/ebooks/opensearch" rel="search" type="application/opensearchdescription+xml" />

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
$poll = new Poll(); $poll = new Poll();
$canVote = true; // Allow non-logged-in users to see the 'vote' button $canVote = true; // Allow non-logged-in users to see the 'vote' button
@ -7,7 +7,7 @@ $canVote = true; // Allow non-logged-in users to see the 'vote' button
try{ try{
$poll = Poll::GetByUrlName(HttpInput::Str(GET, 'pollurlname')); $poll = Poll::GetByUrlName(HttpInput::Str(GET, 'pollurlname'));
if(!$poll->IsActive() && $poll->End !== null && $poll->End < new DateTime()){ if(!$poll->IsActive() && $poll->End !== null && $poll->End < new DateTimeImmutable()){
// If the poll ended, redirect to the results // If the poll ended, redirect to the results
header('Location: ' . $poll->Url . '/votes'); header('Location: ' . $poll->Url . '/votes');
exit(); exit();
@ -47,7 +47,7 @@ catch(Exceptions\AppException){
<a href="<?= $poll->Url ?>/votes" class="button">View results</a> <a href="<?= $poll->Url ?>/votes" class="button">View results</a>
</p> </p>
<? }else{ ?> <? }else{ ?>
<? if($poll->Start !== null && $poll->Start > new DateTime()){ ?> <? if($poll->Start !== null && $poll->Start > new DateTimeImmutable()){ ?>
<p class="center-notice">This poll opens on <?= $poll->Start->format('F j, Y g:i a') ?>.</p> <p class="center-notice">This poll opens on <?= $poll->Start->format('F j, Y g:i a') ?>.</p>
<? }else{ ?> <? }else{ ?>
<p class="center-notice">This poll closed on <?= $poll->End->format('F j, Y g:i a') ?>.</p> <p class="center-notice">This poll closed on <?= $poll->End->format('F j, Y g:i a') ?>.</p>

View file

@ -1,5 +1,5 @@
<? <?
use Safe\DateTime; use Safe\DateTimeImmutable;
use function Safe\file_get_contents; use function Safe\file_get_contents;
use function Safe\preg_match; use function Safe\preg_match;
use function Safe\preg_replace; use function Safe\preg_replace;