Upgrade to Pro — share decks privately, control downloads, hide ads and more …

La génération de dates en PHP

La génération de dates en PHP

Par Kevin Nadin / @kevinjhappy
Pour le Forum PHP 2017

F4140d07ad6cd1ddd512cde434ae4412?s=128

Kevin Nadin

October 26, 2017
Tweet

Other Decks in Programming

Transcript

  1. La génération de dates en PHP Par Kevin Nadin, conférencier

    Padawan / - Forum PHP 2017 @kevinjhappy
  2. Vraiment ?? Une présentation sur les dates ?? Oui, les

    dates sont piégeuses! Il y a beaucoup de possibilités de les générer, et elles peuvent vous causer des soucis...
  3. Nous allons voir de suite : 1. La fonction date

    (forcément) 2. La fonction mktime 3. La fonction strtotime 4. L'objet DateTime 5. L'objet DateTimeZone 6. L'objet DateInterval 7. Des exemples d'utilisation
  4. La fonction date()

  5. Commençons avec les bases : La première fonction à laquelle

    on pense, évidemment Elle l'a été pour moi pour en générer php.net: fonction date
  6. $testDate = date('Y-m-d'); echo $testDate; // 2017-05-26 $testDate = date('Y-m-d

    H:i:s'); echo $testDate; // 2017-05-26 16:25:08
  7. Les dates avec un timestamp date() accepte un timestamp comme

    second paramètre string date ( string $format [, int $timestamp = time() ] )
  8. Timestamps ?? Un timestamp unix est le nombre de secondes

    écoulées depuis le 1er Janvier 1970 sans fuseau horaire Vient des normes de l'IEEE qui ont standardisé cette date en marquant le début de l'ère UNIX
  9. La fonction mktime()

  10. Prends en entrée 6 paramètres : Attention à leur ordre

    ! 1. Heures 2. Minutes 3. Secondes 4. Mois 5. Jours 6. Années
  11. $hour = 0; $minute = 0; $second = 0; $month

    = 10; $day = 24; $year = 2016; $timestamp = mktime($hour, $minute, $second, $month, $day, $year); $myDate = date('Y-m-d', $timestamp); echo $myDate; // 2016-10-24
  12. mktime semble un peu moisi... Ouais c'est vrai, cela peut

    être très compliqué. Mais cela peut apporter une précision chirurgicale
  13. // I want to get the last day of last

    month, we are the 26th May 2017 $month = date('m') - 1; $year = date('Y'); // get the timestamp of last month $timestampLastMonth = mktime(0, 0, 0, $month, 1, $year); // get the last day of the month, so the 30th April $lastDayOfTheMonth = date('t', $timestampLastMonth); $timestampLastDayOfLastMonth = mktime( 0, 0, 0, $month, $lastDayOfTheMonth, $year ); // I have the correct timestamp, I can call the function date $lastDayOfLastMonth = date('Y-m-d', $timestampLastDayOfLastMonth); echo $lastDayOfLastMonth; // 2017-04-30
  14. // I want to get the last day of last

    month, we are the 26th May 2017 // made in one line $lastDayOfLastMonth = date( 'Y-m-d', mktime( 0, 0, 0, date('m') - 1, date('t', mktime( 0, 0, 0, date('m') - 1, 1, date('Y') )), date('Y') ) ); // => 2017-04-30
  15. None
  16. Comportement à connaitre Si j'essaye de mettre le 33 janvier

    echo date('Y-m-d', mktime(0, 0, 0, 1, 33, 2017)); // 2017-02-02 Cela va prendre la date du 31 janvier + 2 jours
  17. None
  18. La fonction strtotime()

  19. Supposons, nous sommes le 2017-05-26 : $firstDayOfLastMonth = date('Y-m-d', strtotime("first

    day of last month")); // => 2017-04-01 $lastDayOfLastMonth = date('Y-m-d', strtotime("last Day of Last Month")); // => 2017-04-30 $lastSunday = date('Y-m-d', strtotime("last Sunday")); // => 2017-05-21 $mondayOfLastWeek = date('Y-m-d', strtotime("last Monday of Last Week")); // => 2017-05-15
  20. Alors strtotime est bien ? Ouais, c'est pas mal du

    tout ! Il faut faire attention à la "magie" de la fonction Certaines dates ne peuvent pas être faites avec php.net : Formats relatifs
  21. // WARNING !! first Specific day of last week //

    will not give you what you want $date = date('Y-m-d', strtotime("First Monday of Last Week")); // => 2017-04-24 // WARNING !! if you are the 31th, Last month will give you // the day one of this month $timeThirtyOneOctober = mktime(0,0,0,10,31,2017); $wrongDate = date('Y-m-d', strtotime("Last Month", $timeThirtyOneOctober)); // => 2017-10-01 // Only way to get it right is by using this $goodDate = date('Y-m-d', strtotime( "Last Day of Last Month", $timeThirtyOneOctober )); // => 2017-09-30
  22. // WARNING, some sentences may seem ok but do not

    work at all $wrongDate = date('Y-m-d', strtotime("Monday of Last Week")); // => 1970-01-01 // You can't construct with strtotime the 13th of this month $dayThirteenOfThisMonth = date( 'Y-m-d', mktime(0, 0, 0, date('m'), 13, date('Y')) ); // => 2017-05-13
  23. None
  24. L'objet DateTime

  25. Ah ben enfin on discute !! On peut oublier les

    chapitres précédents !
  26. Yeah !!

  27. Hum... NON !! Parce que les comportements sont les mêmes

    !
  28. $firstDayOfThisMonth = new \DateTime('first day of this month'); echo $firstDayOfThisMonth->format('Y-m-d');

    // 2017-05-01 $dayFifteenOfThisMonth = new \DateTime(); $dayFifteenOfThisMonth->setTime(0, 0, 0); $dayFifteenOfThisMonth->setDate( (int) $dayFifteenOfThisMonth->format('Y'), (int) $dayFifteenOfThisMonth->format('m'), 15 ); echo $dayFifteenOfThisMonth->format('Y-m-d'); // 2017-05-15
  29. Et les pièges sont les mêmes !

  30. // first Specific day of last Week // Today is

    2017-05-26 $date = new DateTime("First Monday of Last Week"); echo $date->format('Y-m-d') ; // 2017-04-24 // sentences that may seems ok but does not work at all $wrongDate = new DateTime("Monday of Last Week"); echo $wrongDate->format('Y-m-d'); // Fatal error: Uncaught Exception: DateTime::__construct(): // Failed to parse time string (Monday of Last Week)
  31. // WARNING !! if you are the 31th, Last month

    will give you // the day one of this month $lastMonthDate = new DateTime("2017-10-31"); $lastMonthDate->modify('Last Month'); echo $lastMonthDate->format('Y-m-d'); // 2017-10-01 // Only way to get it right is by using this $lastMonthDate = new DateTime("2017-10-31"); $lastMonthDate->modify('Last Day of Last Month'); echo $lastMonthDate->format('Y-m-d'); // 2017-09-30
  32. Petite parenthèse : correction possible avec la librairie Carbon //Taking

    the last month of a 31th of this month $date = Carbon::createFromDate(2016, 10, 31); Carbon::useMonthsOverflow(false); $date->subMonth(1); echo $date->format('Y-m-d'); // 2016-09-30
  33. Parlons aussi de DateTimeImmutable Même utilisation que DateTime() Di érence

    : ne peut pas être modi é une fois créé. Toute modi cation renvoit un nouvel objet
  34. $date = new DateTimeImmutable("2017-05-26"); $newDate = $date->setDate(2017, 07, 12); echo

    $date->format('Y-m-d'), " <=> ", $newDate->format('Y-m-d'); // 2017-05-26 <=> 2017-07-12
  35. Une fonction en plus : DateTimeImmutable::createFromMutable // create a specific

    date $date = new DateTime('2017-09-15'); $myNewDate = DateTimeImmutable::createFromMutable($date); echo $myNewDate->format('Y-m-d'); // 2017-09-15
  36. L'objet DateTimeZone

  37. Toujours penser et faire attention avec le fuseau horaire Par

    défaut con gurez le serveur à UTC Pensez à sauvegarder celui des dates reçues N'oubliez pas de l'appliquer lorsque vous communiquez
  38. // set a date with a Timezone $date = new

    DateTime('2017-05-01', new DateTimeZone('Europe/Paris')); echo "Europe/Paris " , $date->format('Y-m-d H:i:s P'); // Europe/Paris 2017-05-01 00:00:00 +02:00 $date->setDate(2017, 01, 01); echo "Europe/Paris en hiver " , $date->format('Y-m-d H:i:s P'); // Europe/Paris en hiver 2017-01-01 00:00:00 +01:00 $date->setTimezone(new DateTimeZone('Australia/Sydney')); echo "Australia/Sydney " , $date->format(\DateTime::ISO8601); // Australia/Sydney 2017-01-01T10:00:00+1100
  39. Fuseaux Horaires possibles php.net => timezones : Attention à celles

    qui sont listés dans la catégorie "Autres" comme Japan, Turkey, etc... Wikipedia.org => list timezones
  40. // set a date with a Timezone in number of

    hours $date = new DateTime('2017-05-01', new DateTimeZone('+02:00')); echo "UTC + 2 hours " , $date->format('Y-m-d H:i:sP') ; // UTC + 2 hours 2017-05-01 00:00:00+02:00 $utcDate = new DateTime('2017-05-01', new DateTimeZone('UTC')); echo "UTC date " , $utcDate->format('Y-m-d H:i:sP'); // UTC date 2017-05-01 00:00:00+00:00
  41. Et bien sûr... des pièges ! // today in Paris,

    let's try to get the location of the timezone $dateInParis = new DateTime('now', new \DateTimeZone('Europe/Paris')); print_r($dateInParis->getTimezone()->getLocation()); /*Array ( [country_code] => FR [latitude] => 48.86666 [longitude] => 2.33333 [comments] => )*/ // now if we received this date in string format $newDateInParis = new DateTime($dateInParis->format('Y-m-d H:i:sP')); var_dump($newDateInParis->getTimezone()->getLocation()); // bool(false)
  42. Pour éviter ce piège // today in Paris, let's try

    to get the location of the timezone $dateInParis = new DateTime('now', new \DateTimeZone('Europe/Paris')); $newDateInParis = new DateTime( $dateInParis->format('Y-m-d H:i:s'), $dateInParis->getTimezone() ); print_r($newDateInParis->getTimezone()->getLocation()); /* Array ( [country_code] => FR [latitude] => 48.86666 [longitude] => 2.33333 [comments] => )*/
  43. l'object DateInterval

  44. Cela permet de définir une période Seulement 2 fonctions, assez

    similaires En utilisation DateTime->diff, cela donnera un intervale
  45. new DateInterval('P2Y4DT6H8M') Quelle est cette chose ?????? Le P est

    pour "Period", on précise des années aux jours Le T est pour "Time", on précise des heures aux secondes Dans notre exemple ci dessus : P: 2Year 4Day T: 6Hour 8Minute
  46. // set a date Interval $dateInterval = new DateInterval('P2Y4DT6H8M'); echo

    $dateInterval->format('%y years, %d days and %h hours, %i minutes'); // 2 years, 4 days and 6 hours, 8 minutes // equals to : $dateInterval = DateInterval::createFromDateString( '2 year + 4 day + 6 hour + 8 minutes' ); echo $dateInterval->format('%y years, %d days and %h hours, %i minutes'); // 2 years, 4 days and 6 hours, 8 minutes
  47. Quelques situations rencontrés

  48. Demande simple : extraire les 10 derniers jours // we

    set default dates, today is 2017-05-29 $endDate = new DateTime(); $startDate = new DateTime(); // substract 10 days with the object DateInterval $startDate->sub(new DateInterval('P10D')); // or you can use Date Interval with regular string $startDate->sub(new DateInterval::createFromDateString('10 Days')); // or you can use the construct if you don't like DateInterval $startDate = new DateTime("now - 10 days"); // startDate = 2017-05-19 , endDate = 2017-05-29
  49. Demande : extraire la dernière demi-semaine, soit du lundi au

    mercredi, ou du jeudi au dimanche // If today is between Monday to Wednesday, // We want to get dates from last Thursday to last Sunday $today = new DateTime(); // 'N' indicate the day number, Monday = 1, Tuesday = 2 ... Sunday = 7 if ($today->format('N') < 4 ){ $startDate = new DateTime('Last Thursday'); $endDate = new DateTime('Last Sunday'); } // else, today is between Thursday to Sunday, // we want to get dates from Last Monday to Last Wednesday else { $startDate = new DateTime('Last Monday'); $endDate = new DateTime('Last Wednesday'); }
  50. Demande: extraire la dernière semaine, mais si la semaine est

    à cheval entre 2 mois, il faut prendre le 1er jour du mois // We need to check If the Last Monday is in the last month $lastMondayDate = new DateTime('Last Monday'); $lastDayOfLastMonthDate = new DateTime('Last Day of Last Month'); // if the last monday is indeed in the past month, // we take the first day of this month if ($lastMondayDate->format('m') === $lastDayOfLastMonthDate->format('m')){ $startDate = new DateTime('First Day of This Month'); } // else we take the last monday else{ $startDate = $lastMondayDate ; } // in both cases, end date is the Last Sunday $endDate = new DateTime('Last Sunday');
  51. Que se passe-t-il si je fais ceci ?? // Today

    is 2017-05-29 $date = new DateTime("first day of last month"); echo $date->format('Y-m-d') , ' => '; $date->setDate(2013, 2, 3); echo $date->format('Y-m-d');
  52. Executons ça sur 3v4l.org

  53. // Today is : 2017-05-29 $date = new DateTime("first day

    of last month"); echo $date->format('Y-m-d') , ' => '; $date->setDate(2013, 2, 3); echo $date->format('Y-m-d'); // in PHP 7.0.17 - 7.0.19, 7.1.3 - 7.2.0rc2 // 2017-04-01 => 2013-02-03 // in PHP 5.6.0 - 5.6.30, 7.0.0 - 7.0.16, 7.1.0 - 7.1.2 // 2017-04-01 => 2013-02-01
  54. None
  55. Whoa, c'est fort problématique ! Le comportement n'est pas le

    même en fonction de la version de PHP Le problème est le même avec certaines autres phrases
  56. // Anoter Exemple, we create with Last day of this

    month $date = new DateTime("last day of this month"); echo $date->format('Y-m-d') , ' => '; $date->setDate(2012, 2, 03); echo $date->format('Y-m-d'); // in PHP 7.0.17 - 7.0.19, 7.1.3 - 7.2.0rc2 // 2017-05-31 => 2012-02-03 // in PHP 5.6.0 - 5.6.30, 7.0.0 - 7.0.16, 7.1.0 - 7.1.2 // 2017-05-31 => 2012-02-29 Finalement il a calculé le dernier jour de Février 2012 (année bissextile)
  57. Mon conseil: Ne le faites pas ! En tout cas

    pas avant un bon moment ! Si vous travaillez sur une version inférieure à 7.1.3, cela risque de ne pas marcher...
  58. Conclusion

  59. Avec les bonnes pratiques d'aujourd'hui DateTimeImmutable avec DateTimeZone sont les

    plus utilisés Les fonctions date() avec des timestamps étaient surtout utilisées en procédural
  60. Attention !! Ne créez jamais de dates avec une chaine

    de caractères sans les avoir testées dans plusieurs situations ! Par exemple: au 31 Janvier, sur une année Bissextile, etc... Gardez en tête qu'un comportement sur une version de PHP ne marchera pas forcément sur une autre faketime : modi e la date du système pour l'application
  61. Pour simplifier...

  62. Des questions ??

  63. Merci ;)