SlideShare a Scribd company logo
Time-driven
applications
Piotr Horzycki
Team leader @ gwo.pl
phpCE 2017, Rawa Mazowiecka, Poland
What's time got to do with
web applications?
●
News, movies & other content
●
Voting systems
●
Subscriptions with time constraints
(like "Call For Papers":
https://github.com/opencfp/opencfp)
●
Discount systems
●
Reports, statistics
A very bad example...
class SuperMegaFancyPromotionController
{
public function showAction()
{
if (time() > 1496268000) {
$this->showForm();
} elseif (time() < 1490997600 && time() > 1488322800) {
$this->showWarning();
} else {
/* ... */
}
}
}
This code:
- is hard to read
- cannot be easily tested (see uopz extension)
- is not reusable
- must be modified even if somebody wants to change the dates (hardcoding)
Date & time operations in PHP
●
date(), time(), strtotime(), strftime()...
●
DateTime
●
DateInterval
●
DatePeriod
●
DateTimeZone
UNIX timestamps
●
A signed integer; a number of seconds since the "epoch"
– 1970-01-01 Coordinated Universal Time (UTC)
●
On 32-bit systems, the maximum supported year was 2038
●
On 64-bit systems, PHP 7 works beyond the year 2038:
$ php -r "echo strtotime('1939-09-01');"
-957315600
$ php -r "echo strtotime('2049-09-01');"
2514063600
Why use functions if we have
classes?
function getNextMonthAsRSSDate(DateTimeImmutable $date): string
{
$nextMonth = $date->add(new DateInterval('P1M'));
return $nextMonth->format(DateTime::RSS);
}
function getNextMonthAsRSSDate(int $date): string
{
$nextMonth = mktime(
date('H', $date), date('i', $date),
date('s', $date), date('n', $date) + 1
);
return date('D, d M Y H:i:s O', $nextMonth);
}
DateTimeImmutable vs DateTime
PHP Manual on DateTimeImmutable:
„This class behaves the same as DateTime except it never modifies itself but
returns a new object instead.”
Thus, DateTimeImmutable is a value object, known from DDD.
$now = new DateTime();
$nextMonth = $now->add(new DateInterval('P1M'));
/* $now and $nextMonth are pointers to the same object;
* we need two separate value objects! */
debug_zval_dump($now);
debug_zval_dump($nextMonth);
Timezones are tricky
●
Your server has its local time, your users have their
own local time
●
Daylight Saving Time works differently in different
countries
●
Timezones are not always shifted by whole hours
(like +8:45 in Australia)
●
Solution: store all dates in Coordinated Universal
Time – and convert back to local time in the
presentation layer
Intervals
$june = new DateTimeImmutable('2017-06-01Z');
$november = new DateTimeImmutable('2017-11-01Z');
echo $november
->diff($june) // returns DateInterval
->format('%r%m') . ' months' . PHP_EOL;
// Output: -5 months
Creating intervals in ISO 8601 syntax
$interval = new DateInterval('P1Y2M3DT4H5M6S');
$interval = new DateInterval('P0001-02-03T04:05:06');
=
1 year, 2 months, 3 days,
4 hours, 5 minutes and 6 seconds
Periods
function printSchoolYearMondays()
{
$start = new DateTimeImmutable('2017-09-01Z');
$end = new DateTimeImmutable('2018-06-30T23:59:59Z');
$interval = DateInterval::createFromDateString('next monday');
$period = new DatePeriod(
$start,
$interval,
$end,
DatePeriod::EXCLUDE_START_DATE
);
foreach ($period as $date) {
// $date is immutable if $start is too
echo $date->format('l, Y-m-d') . PHP_EOL;
}
}
Date ranges in MySQL
SELECT *
FROM news
WHERE
YEAR(published_at) = 2017 AND MONTH(published_at) = 11;
SELECT *
FROM news
WHERE
published_at BETWEEN '2017-11-01' AND '2017-11-30 23:59:59';
SELECT *
FROM news
WHERE
published_at LIKE '2017-11-%';
class MonthPeriod
{
public function getStart()
{
return new
DateTimeImmutable('first day of this month midnight');
}
public function getEnd()
{
return new
DateTimeImmutable('first day of next month midnight -1 second');
}
}
define('SQL_DATETIME', 'Y-m-d H:i:s');
$period = new MonthPeriod();
echo $period->getStart()->format(SQL_DATETIME) . PHP_EOL;
echo $period->getEnd()->format(SQL_DATETIME) . PHP_EOL;
// Output:
// 2017-11-01 00:00:00
// 2017-11-30 23:59:59
These two values are ready to be bound into a BETWEEN … AND … statement.
Remember about tests!
class MonthPeriod
{
private $now;
public function __construct(DateTimeImmutable $now)
{
$this->now = $now;
}
public function getStart()
{
return $this->now->modify('first day of this month midnight');
}
public function getEnd()
{
return $this->now->modify('first day of next month midnight -1 second');
}
}
class MonthPeriodTest extends PHPUnitFrameworkTestCase
{
/** @dataProvider getDateRanges */
public function testMonth(
string $today,
string $expectedStartDay,
string $expectedEndDay
) {
$now = new DateTimeImmutable($today);
$period = new MonthPeriod($now);
$expectedStart = new DateTimeImmutable($expectedStartDay);
$expectedEnd = new DateTimeImmutable($expectedEndDay);
$this->assertEquals($expectedStart, $period->getStart());
$this->assertEquals($expectedEnd, $period->getEnd());
}
public function getDateRanges()
{
return [
'November' => [
'2017-11-11Z', '2017-11-01 00:00:00Z', '2017-11-30 23:59:59Z'
],
'Leap year' => [
'2016-02-11Z', '2016-02-01 00:00:00Z', '2016-02-29 23:59:59Z'
],
];
}
}
Date and time arithmetic pitfalls
$lastDayOfJanuary = new DateTimeImmutable('2016-01-31Z');
echo $lastDayOfJanuary
->modify('+1 month')
->format('Y-m-d') . PHP_EOL;
echo $lastDayOfJanuary
->modify('last day of next month')
->format('Y-m-d') . PHP_EOL;
// Output:
// 2016-03-02
// 2016-02-29
More: http://php.net/manual/en/datetime.examples-arithmetic.php
More: Michał Pipa, Data i czas dla programistów (https://youtu.be/ZRoEVJlxPlo)
A bad example, once again...
class SuperMegaFancyPromotionController()
{
public function showAction()
{
if (time() > 1496268000) {
$this->showForm();
} elseif (time() < 1490997600 && time() > 1488322800) {
$this->showWarning();
} else {
/* ... */
}
}
}
Let's rewrite that legacy code...
class PromotionTimelineTest extends PHPUnitFrameworkTestCase
{
public function testIsActive()
{
$now = new DateTimeImmutable('2017-05-01T00:00:00Z');
$opening = $now;
$closing = $opening->add(new DateInterval('P2M'));
$timeline = new PromotionTimeline($now, $opening, $closing);
$this->assertTrue($timeline->isActive());
}
}
...starting from a test
Testing the exceptions
class PromotionTimelineTest extends PHPUnitFrameworkTestCase
{
/* ... */
/**
* @expectedException InvalidArgumentException
*/
public function testInvalidArguments()
{
$now = new DateTimeImmutable('2017-05-01T00:00:00Z');
$opening = $now;
$closing = $opening->sub(new DateInterval('PT1S'));
new PromotionTimeline($now, $opening, $closing);
}
}
class PromotionTimeline
{
private $now;
private $openingDate;
private $closingDate;
public function __construct(
DateTimeImmutable $now,
DateTimeImmutable $openingDate,
DateTimeImmutable $closingDate
) {
if ($openingDate >= $closingDate) {
throw new InvalidArgumentException('The opening date must be
earlier than the closing date');
}
$this->now = $now;
$this->openingDate = $openingDate;
$this->closingDate = $closingDate;
}
public function isActive()
{
return
($this->now >= $this->openingDate) &&
($this->now < $this->closingDate);
}
}
What might come next?
●
Early-bird tickets
●
Reminders
●
Last-minute tickets
●
Individual coupons valid until ...
●
Black Friday
●
...
Expect the unexpected!
Remember the Strategy pattern!
●
Let's say we develop a hotel booking platform
●
Ordinary users have to check out at a fixed
hour specified by the hotel
●
But the premium users have extra time!
Old-fashioned way...
$hotel = Hotel::find(['name' => 'Ossa']);
$user = User::find(['login' => 'test']);
if ($user->isPremium()) {
$checkout = $hotel->getCheckoutTime()->add(new DateInterval('P2H'));
} else {
$checkout = $hotel->getCheckoutTime();
}
echo 'Checkout at ' . $checkout->format('H:i');
interface CheckoutStrategyInterface
{
public function getCheckoutTime();
}
class User
{
private $checkoutStrategy;
public function __construct(CheckoutStrategyInterface $checkoutStrategy)
{
$this->checkoutStrategy = $checkoutStrategy;
}
public function getCheckoutTime()
{
return $this->checkoutStrategy->getCheckoutTime();
}
}
Doing it the flexible way
class StandardCheckoutStrategy implements CheckoutStrategyInterface
{
private $checkout;
public function __construct(DateTimeImmutable $checkout)
{
$this->checkout = $checkout;
}
public function getCheckoutTime()
{
return $this->checkout;
}
}
class ExtendedCheckoutStrategy extends StandardCheckoutStrategy
{
private $extension;
public function __construct(
DateTimeImmutable $checkout,
DateInterval $extension
) {
parent::__construct($checkout);
$this->extension = $extension;
}
public function getCheckoutTime()
{
return $this->checkout->add($this->extension);
}
}
Why do we create so many
classes?
●
A class should be modified only for a single
reason
●
Single-responsibility principle
●
Flexibility: loose coupling, high cohesion
●
You never know what business
brings next
●
But don't over-engineer!
Distributed systems
●
Servers in multiple timezones? Oops...
●
Date synchronization via Network Time Protocol
●
Time events
●
A lot of fun :)
Thank you!
piotr.horzycki@gmail.com
twitter.com/phorzycki
github.com/phorzycki/datetime_examples

More Related Content

What's hot

Pratik Bakane C++
Pratik Bakane C++Pratik Bakane C++
Pratik Bakane C++
pratikbakane
 
Double linked list
Double linked listDouble linked list
Double linked list
Sayantan Sur
 
C++ TUTORIAL 3
C++ TUTORIAL 3C++ TUTORIAL 3
C++ TUTORIAL 3
Farhan Ab Rahman
 
The Ring programming language version 1.5.4 book - Part 78 of 185
The Ring programming language version 1.5.4 book - Part 78 of 185The Ring programming language version 1.5.4 book - Part 78 of 185
The Ring programming language version 1.5.4 book - Part 78 of 185
Mahmoud Samir Fayed
 
How to send a mail from utl smtp or from back end
How to send a mail from utl smtp or from back endHow to send a mail from utl smtp or from back end
How to send a mail from utl smtp or from back end
Manju Nath
 
Advanced Java Practical File
Advanced Java Practical FileAdvanced Java Practical File
Advanced Java Practical FileSoumya Behera
 
Pratik Bakane C++
Pratik Bakane C++Pratik Bakane C++
Pratik Bakane C++
pratikbakane
 
C++ TUTORIAL 8
C++ TUTORIAL 8C++ TUTORIAL 8
C++ TUTORIAL 8
Farhan Ab Rahman
 
Single linked list
Single linked listSingle linked list
Single linked list
Sayantan Sur
 
Pratik Bakane C++
Pratik Bakane C++Pratik Bakane C++
Pratik Bakane C++
pratikbakane
 
Circular linked list
Circular linked listCircular linked list
Circular linked list
Sayantan Sur
 
C++ TUTORIAL 5
C++ TUTORIAL 5C++ TUTORIAL 5
C++ TUTORIAL 5
Farhan Ab Rahman
 
C++ TUTORIAL 10
C++ TUTORIAL 10C++ TUTORIAL 10
C++ TUTORIAL 10
Farhan Ab Rahman
 
Programa en C++ ( escriba 3 números y diga cual es el mayor))
Programa en C++ ( escriba 3 números y diga cual es el mayor))Programa en C++ ( escriba 3 números y diga cual es el mayor))
Programa en C++ ( escriba 3 números y diga cual es el mayor))Alex Penso Romero
 
VLSI Sequential Circuits II
VLSI Sequential Circuits IIVLSI Sequential Circuits II
VLSI Sequential Circuits IIGouthaman V
 
Numerical Methods in C
Numerical Methods in CNumerical Methods in C
Numerical Methods in C
Ambili Baby
 
Binary Search Tree
Binary Search TreeBinary Search Tree
Binary Search Treeraviahuja11
 
Pratik Bakane C++
Pratik Bakane C++Pratik Bakane C++
Pratik Bakane C++
pratikbakane
 
DATASTRUCTURES PPTS PREPARED BY M V BRAHMANANDA REDDY
DATASTRUCTURES PPTS PREPARED BY M V BRAHMANANDA REDDYDATASTRUCTURES PPTS PREPARED BY M V BRAHMANANDA REDDY
DATASTRUCTURES PPTS PREPARED BY M V BRAHMANANDA REDDYMalikireddy Bramhananda Reddy
 
Ejercicios
EjerciciosEjercicios
Ejerciciosleonharo
 

What's hot (20)

Pratik Bakane C++
Pratik Bakane C++Pratik Bakane C++
Pratik Bakane C++
 
Double linked list
Double linked listDouble linked list
Double linked list
 
C++ TUTORIAL 3
C++ TUTORIAL 3C++ TUTORIAL 3
C++ TUTORIAL 3
 
The Ring programming language version 1.5.4 book - Part 78 of 185
The Ring programming language version 1.5.4 book - Part 78 of 185The Ring programming language version 1.5.4 book - Part 78 of 185
The Ring programming language version 1.5.4 book - Part 78 of 185
 
How to send a mail from utl smtp or from back end
How to send a mail from utl smtp or from back endHow to send a mail from utl smtp or from back end
How to send a mail from utl smtp or from back end
 
Advanced Java Practical File
Advanced Java Practical FileAdvanced Java Practical File
Advanced Java Practical File
 
Pratik Bakane C++
Pratik Bakane C++Pratik Bakane C++
Pratik Bakane C++
 
C++ TUTORIAL 8
C++ TUTORIAL 8C++ TUTORIAL 8
C++ TUTORIAL 8
 
Single linked list
Single linked listSingle linked list
Single linked list
 
Pratik Bakane C++
Pratik Bakane C++Pratik Bakane C++
Pratik Bakane C++
 
Circular linked list
Circular linked listCircular linked list
Circular linked list
 
C++ TUTORIAL 5
C++ TUTORIAL 5C++ TUTORIAL 5
C++ TUTORIAL 5
 
C++ TUTORIAL 10
C++ TUTORIAL 10C++ TUTORIAL 10
C++ TUTORIAL 10
 
Programa en C++ ( escriba 3 números y diga cual es el mayor))
Programa en C++ ( escriba 3 números y diga cual es el mayor))Programa en C++ ( escriba 3 números y diga cual es el mayor))
Programa en C++ ( escriba 3 números y diga cual es el mayor))
 
VLSI Sequential Circuits II
VLSI Sequential Circuits IIVLSI Sequential Circuits II
VLSI Sequential Circuits II
 
Numerical Methods in C
Numerical Methods in CNumerical Methods in C
Numerical Methods in C
 
Binary Search Tree
Binary Search TreeBinary Search Tree
Binary Search Tree
 
Pratik Bakane C++
Pratik Bakane C++Pratik Bakane C++
Pratik Bakane C++
 
DATASTRUCTURES PPTS PREPARED BY M V BRAHMANANDA REDDY
DATASTRUCTURES PPTS PREPARED BY M V BRAHMANANDA REDDYDATASTRUCTURES PPTS PREPARED BY M V BRAHMANANDA REDDY
DATASTRUCTURES PPTS PREPARED BY M V BRAHMANANDA REDDY
 
Ejercicios
EjerciciosEjercicios
Ejercicios
 

Similar to Time-driven applications

Why should we use SIMPLE FACTORY pattern even when we have one class only?
Why should we use SIMPLE FACTORY pattern even when we have one class only?Why should we use SIMPLE FACTORY pattern even when we have one class only?
Why should we use SIMPLE FACTORY pattern even when we have one class only?
Rafal Ksiazek
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy codeShriKant Vashishtha
 
Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13
Jason Lotito
 
Instruction1. Please read the two articles. (Kincheloe part 1 &.docx
Instruction1. Please read the two articles. (Kincheloe part 1 &.docxInstruction1. Please read the two articles. (Kincheloe part 1 &.docx
Instruction1. Please read the two articles. (Kincheloe part 1 &.docx
carliotwaycave
 
Broken windows de práticas ágeis
Broken windows de práticas ágeisBroken windows de práticas ágeis
Broken windows de práticas ágeis
Cecilia Fernandes
 
Advanced patterns in asynchronous programming
Advanced patterns in asynchronous programmingAdvanced patterns in asynchronous programming
Advanced patterns in asynchronous programming
Michael Arenzon
 
A Test of Strength
A Test of StrengthA Test of Strength
A Test of Strength
Chris Oldwood
 
Reactive programming every day
Reactive programming every dayReactive programming every day
Reactive programming every day
Vadym Khondar
 
Introduction to Zend Framework web services
Introduction to Zend Framework web servicesIntroduction to Zend Framework web services
Introduction to Zend Framework web services
Michelangelo van Dam
 
[232]TensorRT를 활용한 딥러닝 Inference 최적화
[232]TensorRT를 활용한 딥러닝 Inference 최적화[232]TensorRT를 활용한 딥러닝 Inference 최적화
[232]TensorRT를 활용한 딥러닝 Inference 최적화
NAVER D2
 
[232] TensorRT를 활용한 딥러닝 Inference 최적화
[232] TensorRT를 활용한 딥러닝 Inference 최적화[232] TensorRT를 활용한 딥러닝 Inference 최적화
[232] TensorRT를 활용한 딥러닝 Inference 최적화
NAVER D2
 
22-SE-77 OS_lab_labotary assignmnet#2.pdf
22-SE-77 OS_lab_labotary assignmnet#2.pdf22-SE-77 OS_lab_labotary assignmnet#2.pdf
22-SE-77 OS_lab_labotary assignmnet#2.pdf
EngTariq2
 
Code Generation in PHP - PHPConf 2015
Code Generation in PHP - PHPConf 2015Code Generation in PHP - PHPConf 2015
Code Generation in PHP - PHPConf 2015
Lin Yo-An
 
JavaScript Refactoring
JavaScript RefactoringJavaScript Refactoring
JavaScript Refactoring
Krzysztof Szafranek
 
PHP7 - Scalar Type Hints & Return Types
PHP7 - Scalar Type Hints & Return TypesPHP7 - Scalar Type Hints & Return Types
PHP7 - Scalar Type Hints & Return Types
Eric Poe
 
Zend framework service
Zend framework serviceZend framework service
Zend framework service
Michelangelo van Dam
 
Zend framework service
Zend framework serviceZend framework service
Zend framework service
Michelangelo van Dam
 
Dynamically Evolving Systems: Cluster Analysis Using Time
Dynamically Evolving Systems: Cluster Analysis Using TimeDynamically Evolving Systems: Cluster Analysis Using Time
Dynamically Evolving Systems: Cluster Analysis Using Time
Magnify Analytic Solutions
 
New Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian BergmannNew Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian Bergmanndpc
 

Similar to Time-driven applications (20)

Why should we use SIMPLE FACTORY pattern even when we have one class only?
Why should we use SIMPLE FACTORY pattern even when we have one class only?Why should we use SIMPLE FACTORY pattern even when we have one class only?
Why should we use SIMPLE FACTORY pattern even when we have one class only?
 
Working effectively with legacy code
Working effectively with legacy codeWorking effectively with legacy code
Working effectively with legacy code
 
Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13Load Testing with PHP and RedLine13
Load Testing with PHP and RedLine13
 
Instruction1. Please read the two articles. (Kincheloe part 1 &.docx
Instruction1. Please read the two articles. (Kincheloe part 1 &.docxInstruction1. Please read the two articles. (Kincheloe part 1 &.docx
Instruction1. Please read the two articles. (Kincheloe part 1 &.docx
 
Broken windows de práticas ágeis
Broken windows de práticas ágeisBroken windows de práticas ágeis
Broken windows de práticas ágeis
 
Advanced patterns in asynchronous programming
Advanced patterns in asynchronous programmingAdvanced patterns in asynchronous programming
Advanced patterns in asynchronous programming
 
A Test of Strength
A Test of StrengthA Test of Strength
A Test of Strength
 
Reactive programming every day
Reactive programming every dayReactive programming every day
Reactive programming every day
 
Introduction to Zend Framework web services
Introduction to Zend Framework web servicesIntroduction to Zend Framework web services
Introduction to Zend Framework web services
 
[232]TensorRT를 활용한 딥러닝 Inference 최적화
[232]TensorRT를 활용한 딥러닝 Inference 최적화[232]TensorRT를 활용한 딥러닝 Inference 최적화
[232]TensorRT를 활용한 딥러닝 Inference 최적화
 
[232] TensorRT를 활용한 딥러닝 Inference 최적화
[232] TensorRT를 활용한 딥러닝 Inference 최적화[232] TensorRT를 활용한 딥러닝 Inference 최적화
[232] TensorRT를 활용한 딥러닝 Inference 최적화
 
22-SE-77 OS_lab_labotary assignmnet#2.pdf
22-SE-77 OS_lab_labotary assignmnet#2.pdf22-SE-77 OS_lab_labotary assignmnet#2.pdf
22-SE-77 OS_lab_labotary assignmnet#2.pdf
 
Code Generation in PHP - PHPConf 2015
Code Generation in PHP - PHPConf 2015Code Generation in PHP - PHPConf 2015
Code Generation in PHP - PHPConf 2015
 
Event Sourcing & CQRS
Event Sourcing & CQRSEvent Sourcing & CQRS
Event Sourcing & CQRS
 
JavaScript Refactoring
JavaScript RefactoringJavaScript Refactoring
JavaScript Refactoring
 
PHP7 - Scalar Type Hints & Return Types
PHP7 - Scalar Type Hints & Return TypesPHP7 - Scalar Type Hints & Return Types
PHP7 - Scalar Type Hints & Return Types
 
Zend framework service
Zend framework serviceZend framework service
Zend framework service
 
Zend framework service
Zend framework serviceZend framework service
Zend framework service
 
Dynamically Evolving Systems: Cluster Analysis Using Time
Dynamically Evolving Systems: Cluster Analysis Using TimeDynamically Evolving Systems: Cluster Analysis Using Time
Dynamically Evolving Systems: Cluster Analysis Using Time
 
New Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian BergmannNew Features PHPUnit 3.3 - Sebastian Bergmann
New Features PHPUnit 3.3 - Sebastian Bergmann
 

More from Piotr Horzycki

Serial(ize) killers, czyli jak popsuliśmy API
Serial(ize) killers, czyli jak popsuliśmy APISerial(ize) killers, czyli jak popsuliśmy API
Serial(ize) killers, czyli jak popsuliśmy API
Piotr Horzycki
 
Mity, które blokują Twoją karierę
Mity, które blokują Twoją karieręMity, które blokują Twoją karierę
Mity, które blokują Twoją karierę
Piotr Horzycki
 
Architecture tests: Setting a common standard
Architecture tests: Setting a common standardArchitecture tests: Setting a common standard
Architecture tests: Setting a common standard
Piotr Horzycki
 
Software development myths that block your career
Software development myths that block your careerSoftware development myths that block your career
Software development myths that block your career
Piotr Horzycki
 
Software Composition Analysis in PHP
Software Composition Analysis in PHP Software Composition Analysis in PHP
Software Composition Analysis in PHP
Piotr Horzycki
 
How to count money with Java and not lose it
How to count money with Java and not lose itHow to count money with Java and not lose it
How to count money with Java and not lose it
Piotr Horzycki
 
How to count money using PHP and not lose money
How to count money using PHP and not lose moneyHow to count money using PHP and not lose money
How to count money using PHP and not lose money
Piotr Horzycki
 
New kids on the block: Conducting technical onboarding
New kids on the block: Conducting technical onboardingNew kids on the block: Conducting technical onboarding
New kids on the block: Conducting technical onboarding
Piotr Horzycki
 
Jak zacząć, aby nie żałować - czyli 50 twarzy PHP
Jak zacząć, aby nie żałować - czyli 50 twarzy PHPJak zacząć, aby nie żałować - czyli 50 twarzy PHP
Jak zacząć, aby nie żałować - czyli 50 twarzy PHP
Piotr Horzycki
 

More from Piotr Horzycki (9)

Serial(ize) killers, czyli jak popsuliśmy API
Serial(ize) killers, czyli jak popsuliśmy APISerial(ize) killers, czyli jak popsuliśmy API
Serial(ize) killers, czyli jak popsuliśmy API
 
Mity, które blokują Twoją karierę
Mity, które blokują Twoją karieręMity, które blokują Twoją karierę
Mity, które blokują Twoją karierę
 
Architecture tests: Setting a common standard
Architecture tests: Setting a common standardArchitecture tests: Setting a common standard
Architecture tests: Setting a common standard
 
Software development myths that block your career
Software development myths that block your careerSoftware development myths that block your career
Software development myths that block your career
 
Software Composition Analysis in PHP
Software Composition Analysis in PHP Software Composition Analysis in PHP
Software Composition Analysis in PHP
 
How to count money with Java and not lose it
How to count money with Java and not lose itHow to count money with Java and not lose it
How to count money with Java and not lose it
 
How to count money using PHP and not lose money
How to count money using PHP and not lose moneyHow to count money using PHP and not lose money
How to count money using PHP and not lose money
 
New kids on the block: Conducting technical onboarding
New kids on the block: Conducting technical onboardingNew kids on the block: Conducting technical onboarding
New kids on the block: Conducting technical onboarding
 
Jak zacząć, aby nie żałować - czyli 50 twarzy PHP
Jak zacząć, aby nie żałować - czyli 50 twarzy PHPJak zacząć, aby nie żałować - czyli 50 twarzy PHP
Jak zacząć, aby nie żałować - czyli 50 twarzy PHP
 

Recently uploaded

CME397 Surface Engineering- Professional Elective
CME397 Surface Engineering- Professional ElectiveCME397 Surface Engineering- Professional Elective
CME397 Surface Engineering- Professional Elective
karthi keyan
 
NUMERICAL SIMULATIONS OF HEAT AND MASS TRANSFER IN CONDENSING HEAT EXCHANGERS...
NUMERICAL SIMULATIONS OF HEAT AND MASS TRANSFER IN CONDENSING HEAT EXCHANGERS...NUMERICAL SIMULATIONS OF HEAT AND MASS TRANSFER IN CONDENSING HEAT EXCHANGERS...
NUMERICAL SIMULATIONS OF HEAT AND MASS TRANSFER IN CONDENSING HEAT EXCHANGERS...
ssuser7dcef0
 
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
zwunae
 
Gen AI Study Jams _ For the GDSC Leads in India.pdf
Gen AI Study Jams _ For the GDSC Leads in India.pdfGen AI Study Jams _ For the GDSC Leads in India.pdf
Gen AI Study Jams _ For the GDSC Leads in India.pdf
gdsczhcet
 
English lab ppt no titlespecENG PPTt.pdf
English lab ppt no titlespecENG PPTt.pdfEnglish lab ppt no titlespecENG PPTt.pdf
English lab ppt no titlespecENG PPTt.pdf
BrazilAccount1
 
DfMAy 2024 - key insights and contributions
DfMAy 2024 - key insights and contributionsDfMAy 2024 - key insights and contributions
DfMAy 2024 - key insights and contributions
gestioneergodomus
 
Planning Of Procurement o different goods and services
Planning Of Procurement o different goods and servicesPlanning Of Procurement o different goods and services
Planning Of Procurement o different goods and services
JoytuBarua2
 
NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...
NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...
NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...
Amil Baba Dawood bangali
 
weather web application report.pdf
weather web application report.pdfweather web application report.pdf
weather web application report.pdf
Pratik Pawar
 
6th International Conference on Machine Learning & Applications (CMLA 2024)
6th International Conference on Machine Learning & Applications (CMLA 2024)6th International Conference on Machine Learning & Applications (CMLA 2024)
6th International Conference on Machine Learning & Applications (CMLA 2024)
ClaraZara1
 
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdfHybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
fxintegritypublishin
 
一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理
一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理
一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理
bakpo1
 
Student information management system project report ii.pdf
Student information management system project report ii.pdfStudent information management system project report ii.pdf
Student information management system project report ii.pdf
Kamal Acharya
 
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
thanhdowork
 
ML for identifying fraud using open blockchain data.pptx
ML for identifying fraud using open blockchain data.pptxML for identifying fraud using open blockchain data.pptx
ML for identifying fraud using open blockchain data.pptx
Vijay Dialani, PhD
 
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
ydteq
 
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&BDesign and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Sreedhar Chowdam
 
Basic Industrial Engineering terms for apparel
Basic Industrial Engineering terms for apparelBasic Industrial Engineering terms for apparel
Basic Industrial Engineering terms for apparel
top1002
 
Hierarchical Digital Twin of a Naval Power System
Hierarchical Digital Twin of a Naval Power SystemHierarchical Digital Twin of a Naval Power System
Hierarchical Digital Twin of a Naval Power System
Kerry Sado
 
AP LAB PPT.pdf ap lab ppt no title specific
AP LAB PPT.pdf ap lab ppt no title specificAP LAB PPT.pdf ap lab ppt no title specific
AP LAB PPT.pdf ap lab ppt no title specific
BrazilAccount1
 

Recently uploaded (20)

CME397 Surface Engineering- Professional Elective
CME397 Surface Engineering- Professional ElectiveCME397 Surface Engineering- Professional Elective
CME397 Surface Engineering- Professional Elective
 
NUMERICAL SIMULATIONS OF HEAT AND MASS TRANSFER IN CONDENSING HEAT EXCHANGERS...
NUMERICAL SIMULATIONS OF HEAT AND MASS TRANSFER IN CONDENSING HEAT EXCHANGERS...NUMERICAL SIMULATIONS OF HEAT AND MASS TRANSFER IN CONDENSING HEAT EXCHANGERS...
NUMERICAL SIMULATIONS OF HEAT AND MASS TRANSFER IN CONDENSING HEAT EXCHANGERS...
 
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
一比一原版(IIT毕业证)伊利诺伊理工大学毕业证成绩单专业办理
 
Gen AI Study Jams _ For the GDSC Leads in India.pdf
Gen AI Study Jams _ For the GDSC Leads in India.pdfGen AI Study Jams _ For the GDSC Leads in India.pdf
Gen AI Study Jams _ For the GDSC Leads in India.pdf
 
English lab ppt no titlespecENG PPTt.pdf
English lab ppt no titlespecENG PPTt.pdfEnglish lab ppt no titlespecENG PPTt.pdf
English lab ppt no titlespecENG PPTt.pdf
 
DfMAy 2024 - key insights and contributions
DfMAy 2024 - key insights and contributionsDfMAy 2024 - key insights and contributions
DfMAy 2024 - key insights and contributions
 
Planning Of Procurement o different goods and services
Planning Of Procurement o different goods and servicesPlanning Of Procurement o different goods and services
Planning Of Procurement o different goods and services
 
NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...
NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...
NO1 Uk best vashikaran specialist in delhi vashikaran baba near me online vas...
 
weather web application report.pdf
weather web application report.pdfweather web application report.pdf
weather web application report.pdf
 
6th International Conference on Machine Learning & Applications (CMLA 2024)
6th International Conference on Machine Learning & Applications (CMLA 2024)6th International Conference on Machine Learning & Applications (CMLA 2024)
6th International Conference on Machine Learning & Applications (CMLA 2024)
 
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdfHybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
Hybrid optimization of pumped hydro system and solar- Engr. Abdul-Azeez.pdf
 
一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理
一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理
一比一原版(SFU毕业证)西蒙菲莎大学毕业证成绩单如何办理
 
Student information management system project report ii.pdf
Student information management system project report ii.pdfStudent information management system project report ii.pdf
Student information management system project report ii.pdf
 
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
RAT: Retrieval Augmented Thoughts Elicit Context-Aware Reasoning in Long-Hori...
 
ML for identifying fraud using open blockchain data.pptx
ML for identifying fraud using open blockchain data.pptxML for identifying fraud using open blockchain data.pptx
ML for identifying fraud using open blockchain data.pptx
 
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
一比一原版(UofT毕业证)多伦多大学毕业证成绩单如何办理
 
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&BDesign and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
Design and Analysis of Algorithms-DP,Backtracking,Graphs,B&B
 
Basic Industrial Engineering terms for apparel
Basic Industrial Engineering terms for apparelBasic Industrial Engineering terms for apparel
Basic Industrial Engineering terms for apparel
 
Hierarchical Digital Twin of a Naval Power System
Hierarchical Digital Twin of a Naval Power SystemHierarchical Digital Twin of a Naval Power System
Hierarchical Digital Twin of a Naval Power System
 
AP LAB PPT.pdf ap lab ppt no title specific
AP LAB PPT.pdf ap lab ppt no title specificAP LAB PPT.pdf ap lab ppt no title specific
AP LAB PPT.pdf ap lab ppt no title specific
 

Time-driven applications

  • 1. Time-driven applications Piotr Horzycki Team leader @ gwo.pl phpCE 2017, Rawa Mazowiecka, Poland
  • 2. What's time got to do with web applications? ● News, movies & other content ● Voting systems ● Subscriptions with time constraints (like "Call For Papers": https://github.com/opencfp/opencfp) ● Discount systems ● Reports, statistics
  • 3. A very bad example... class SuperMegaFancyPromotionController { public function showAction() { if (time() > 1496268000) { $this->showForm(); } elseif (time() < 1490997600 && time() > 1488322800) { $this->showWarning(); } else { /* ... */ } } } This code: - is hard to read - cannot be easily tested (see uopz extension) - is not reusable - must be modified even if somebody wants to change the dates (hardcoding)
  • 4. Date & time operations in PHP ● date(), time(), strtotime(), strftime()... ● DateTime ● DateInterval ● DatePeriod ● DateTimeZone
  • 5. UNIX timestamps ● A signed integer; a number of seconds since the "epoch" – 1970-01-01 Coordinated Universal Time (UTC) ● On 32-bit systems, the maximum supported year was 2038 ● On 64-bit systems, PHP 7 works beyond the year 2038: $ php -r "echo strtotime('1939-09-01');" -957315600 $ php -r "echo strtotime('2049-09-01');" 2514063600
  • 6. Why use functions if we have classes? function getNextMonthAsRSSDate(DateTimeImmutable $date): string { $nextMonth = $date->add(new DateInterval('P1M')); return $nextMonth->format(DateTime::RSS); } function getNextMonthAsRSSDate(int $date): string { $nextMonth = mktime( date('H', $date), date('i', $date), date('s', $date), date('n', $date) + 1 ); return date('D, d M Y H:i:s O', $nextMonth); }
  • 7. DateTimeImmutable vs DateTime PHP Manual on DateTimeImmutable: „This class behaves the same as DateTime except it never modifies itself but returns a new object instead.” Thus, DateTimeImmutable is a value object, known from DDD. $now = new DateTime(); $nextMonth = $now->add(new DateInterval('P1M')); /* $now and $nextMonth are pointers to the same object; * we need two separate value objects! */ debug_zval_dump($now); debug_zval_dump($nextMonth);
  • 8. Timezones are tricky ● Your server has its local time, your users have their own local time ● Daylight Saving Time works differently in different countries ● Timezones are not always shifted by whole hours (like +8:45 in Australia) ● Solution: store all dates in Coordinated Universal Time – and convert back to local time in the presentation layer
  • 9.
  • 10.
  • 11. Intervals $june = new DateTimeImmutable('2017-06-01Z'); $november = new DateTimeImmutable('2017-11-01Z'); echo $november ->diff($june) // returns DateInterval ->format('%r%m') . ' months' . PHP_EOL; // Output: -5 months
  • 12. Creating intervals in ISO 8601 syntax $interval = new DateInterval('P1Y2M3DT4H5M6S'); $interval = new DateInterval('P0001-02-03T04:05:06'); = 1 year, 2 months, 3 days, 4 hours, 5 minutes and 6 seconds
  • 13. Periods function printSchoolYearMondays() { $start = new DateTimeImmutable('2017-09-01Z'); $end = new DateTimeImmutable('2018-06-30T23:59:59Z'); $interval = DateInterval::createFromDateString('next monday'); $period = new DatePeriod( $start, $interval, $end, DatePeriod::EXCLUDE_START_DATE ); foreach ($period as $date) { // $date is immutable if $start is too echo $date->format('l, Y-m-d') . PHP_EOL; } }
  • 14. Date ranges in MySQL SELECT * FROM news WHERE YEAR(published_at) = 2017 AND MONTH(published_at) = 11; SELECT * FROM news WHERE published_at BETWEEN '2017-11-01' AND '2017-11-30 23:59:59'; SELECT * FROM news WHERE published_at LIKE '2017-11-%';
  • 15. class MonthPeriod { public function getStart() { return new DateTimeImmutable('first day of this month midnight'); } public function getEnd() { return new DateTimeImmutable('first day of next month midnight -1 second'); } } define('SQL_DATETIME', 'Y-m-d H:i:s'); $period = new MonthPeriod(); echo $period->getStart()->format(SQL_DATETIME) . PHP_EOL; echo $period->getEnd()->format(SQL_DATETIME) . PHP_EOL; // Output: // 2017-11-01 00:00:00 // 2017-11-30 23:59:59 These two values are ready to be bound into a BETWEEN … AND … statement.
  • 16. Remember about tests! class MonthPeriod { private $now; public function __construct(DateTimeImmutable $now) { $this->now = $now; } public function getStart() { return $this->now->modify('first day of this month midnight'); } public function getEnd() { return $this->now->modify('first day of next month midnight -1 second'); } }
  • 17. class MonthPeriodTest extends PHPUnitFrameworkTestCase { /** @dataProvider getDateRanges */ public function testMonth( string $today, string $expectedStartDay, string $expectedEndDay ) { $now = new DateTimeImmutable($today); $period = new MonthPeriod($now); $expectedStart = new DateTimeImmutable($expectedStartDay); $expectedEnd = new DateTimeImmutable($expectedEndDay); $this->assertEquals($expectedStart, $period->getStart()); $this->assertEquals($expectedEnd, $period->getEnd()); } public function getDateRanges() { return [ 'November' => [ '2017-11-11Z', '2017-11-01 00:00:00Z', '2017-11-30 23:59:59Z' ], 'Leap year' => [ '2016-02-11Z', '2016-02-01 00:00:00Z', '2016-02-29 23:59:59Z' ], ]; } }
  • 18. Date and time arithmetic pitfalls $lastDayOfJanuary = new DateTimeImmutable('2016-01-31Z'); echo $lastDayOfJanuary ->modify('+1 month') ->format('Y-m-d') . PHP_EOL; echo $lastDayOfJanuary ->modify('last day of next month') ->format('Y-m-d') . PHP_EOL; // Output: // 2016-03-02 // 2016-02-29 More: http://php.net/manual/en/datetime.examples-arithmetic.php More: Michał Pipa, Data i czas dla programistów (https://youtu.be/ZRoEVJlxPlo)
  • 19. A bad example, once again... class SuperMegaFancyPromotionController() { public function showAction() { if (time() > 1496268000) { $this->showForm(); } elseif (time() < 1490997600 && time() > 1488322800) { $this->showWarning(); } else { /* ... */ } } }
  • 20. Let's rewrite that legacy code... class PromotionTimelineTest extends PHPUnitFrameworkTestCase { public function testIsActive() { $now = new DateTimeImmutable('2017-05-01T00:00:00Z'); $opening = $now; $closing = $opening->add(new DateInterval('P2M')); $timeline = new PromotionTimeline($now, $opening, $closing); $this->assertTrue($timeline->isActive()); } } ...starting from a test
  • 21. Testing the exceptions class PromotionTimelineTest extends PHPUnitFrameworkTestCase { /* ... */ /** * @expectedException InvalidArgumentException */ public function testInvalidArguments() { $now = new DateTimeImmutable('2017-05-01T00:00:00Z'); $opening = $now; $closing = $opening->sub(new DateInterval('PT1S')); new PromotionTimeline($now, $opening, $closing); } }
  • 22. class PromotionTimeline { private $now; private $openingDate; private $closingDate; public function __construct( DateTimeImmutable $now, DateTimeImmutable $openingDate, DateTimeImmutable $closingDate ) { if ($openingDate >= $closingDate) { throw new InvalidArgumentException('The opening date must be earlier than the closing date'); } $this->now = $now; $this->openingDate = $openingDate; $this->closingDate = $closingDate; } public function isActive() { return ($this->now >= $this->openingDate) && ($this->now < $this->closingDate); } }
  • 23. What might come next? ● Early-bird tickets ● Reminders ● Last-minute tickets ● Individual coupons valid until ... ● Black Friday ● ... Expect the unexpected!
  • 24. Remember the Strategy pattern! ● Let's say we develop a hotel booking platform ● Ordinary users have to check out at a fixed hour specified by the hotel ● But the premium users have extra time!
  • 25. Old-fashioned way... $hotel = Hotel::find(['name' => 'Ossa']); $user = User::find(['login' => 'test']); if ($user->isPremium()) { $checkout = $hotel->getCheckoutTime()->add(new DateInterval('P2H')); } else { $checkout = $hotel->getCheckoutTime(); } echo 'Checkout at ' . $checkout->format('H:i');
  • 26. interface CheckoutStrategyInterface { public function getCheckoutTime(); } class User { private $checkoutStrategy; public function __construct(CheckoutStrategyInterface $checkoutStrategy) { $this->checkoutStrategy = $checkoutStrategy; } public function getCheckoutTime() { return $this->checkoutStrategy->getCheckoutTime(); } } Doing it the flexible way
  • 27. class StandardCheckoutStrategy implements CheckoutStrategyInterface { private $checkout; public function __construct(DateTimeImmutable $checkout) { $this->checkout = $checkout; } public function getCheckoutTime() { return $this->checkout; } }
  • 28. class ExtendedCheckoutStrategy extends StandardCheckoutStrategy { private $extension; public function __construct( DateTimeImmutable $checkout, DateInterval $extension ) { parent::__construct($checkout); $this->extension = $extension; } public function getCheckoutTime() { return $this->checkout->add($this->extension); } }
  • 29. Why do we create so many classes? ● A class should be modified only for a single reason ● Single-responsibility principle ● Flexibility: loose coupling, high cohesion ● You never know what business brings next ● But don't over-engineer!
  • 30. Distributed systems ● Servers in multiple timezones? Oops... ● Date synchronization via Network Time Protocol ● Time events ● A lot of fun :)