{"id":976,"date":"2018-10-01T09:35:02","date_gmt":"2018-10-01T07:35:02","guid":{"rendered":"http:\/\/perso.ens-lyon.fr\/lise.vaudor\/?p=976"},"modified":"2018-10-01T09:35:02","modified_gmt":"2018-10-01T07:35:02","slug":"gerer-des-dates-avec-lubridate-un-jeu-denfant","status":"publish","type":"post","link":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/gerer-des-dates-avec-lubridate-un-jeu-denfant\/","title":{"rendered":"G\u00e9rer des dates avec lubridate: un jeu d&rsquo;enfant"},"content":{"rendered":"<p><img decoding=\"async\" src=\"..\/..\/lise.vaudor\/Rfigures\/lubridate\/Lise_Vaudor_headband-1.png\" alt=\"\" \/><\/p>\n<p><img decoding=\"async\" src=\"..\/..\/lise.vaudor\/Rfigures\/lubridate\/lubridate_jeu_d_enfant.jpg\" alt=\"\" \/><\/p>\n<p>Voil\u00e0 d\u00e9j\u00e0 2-3 ans que je recommande \u00e0 qui veut m&rsquo;entendre le package <code>lubridate<\/code> pour travailler avec des dates. En effet, travailler avec des dates, <em>\u00e0 la base<\/em>, ce n&rsquo;est pas \u00e9vident. Des op\u00e9rations a priori simples, comme ordonner les vecteurs, calculer des diff\u00e9rences, arrondir des valeurs, peuvent devenir compliqu\u00e9es d\u00e8s que le vecteur en question est de classe <code>date<\/code>. Cela avait d&rsquo;ailleurs fait l&rsquo;objet de mon <a href=\"http:\/\/perso.ens-lyon.fr\/lise.vaudor\/dates\/\">tout premier billet de blog<\/a> (\u00e9motion! nostalgie!) que j&rsquo;avais r\u00e9dig\u00e9 du temps o\u00f9 je ne connaissais pas encore <code>lubridate<\/code> -ni <code>ggplot2<\/code>, du reste-. Autant vous dire qu&rsquo;\u00e0 cette \u00e9poque, travailler avec des dates, c&rsquo;\u00e9tait <em>carr\u00e9ment la louse<\/em>.<\/p>\n<p>Heureusement, le progr\u00e8s ayant parfois du bon, le <code>tidyverse<\/code> et <code>lubridate<\/code> sont pass\u00e9s par l\u00e0: maintenant, travailler avec des dates, c&rsquo;est <em>fingers in the nose<\/em>. D&rsquo;autant que RStudio a publi\u00e9 r\u00e9cemment une <a href=\"https:\/\/github.com\/rstudio\/cheatsheets\/raw\/master\/lubridate.pdf\">cheatsheet lubridate<\/a>, qui, comme toujours, est <strong>tr\u00e8s bien construite et illustr\u00e9e<\/strong>.<\/p>\n<p>Allez hop, commen\u00e7ons donc par charger le package:<\/p>\n<pre><code>library(lubridate)\n<\/code><\/pre>\n<h1>Transformer une cha\u00eene de caract\u00e8res en date<\/h1>\n<p>Avant toute autre chose, les fonctions du package <code>lubridate<\/code> facilitent de mani\u00e8re d\u00e9concertante la transformation d&rsquo;un vecteur de classe <strong>cha\u00eene de caract\u00e8res<\/strong> en un vecteur de classe <strong>date<\/strong>.<\/p>\n<p>Pour ce faire, il suffit d&rsquo;indiquer quels sont les <strong>\u00e9l\u00e9ments renseign\u00e9s<\/strong> dans la cha\u00eene de caract\u00e8res (et dans quel <strong>ordre<\/strong>). C&rsquo;est le <strong>nom de la fonction<\/strong> qui remplit cet office.<\/p>\n<p>Par exemple, je veux faire comprendre \u00e0 R les \u00e9l\u00e9ments qui composent la cha\u00eene de caract\u00e8res \u00ab\u00a011 avril 2019\u00a0\u00bb: je vais donc lui indiquer que les \u00e9l\u00e9ments sont le jour (<strong>d<\/strong> comme day) le mois (<strong>m<\/strong> comme month) et l&rsquo;ann\u00e9e (<strong>y<\/strong> comme year):<\/p>\n<pre><code>\"11 avril 2019\"\n\n## [1] \"11 avril 2019\"\n\nclass(\"11 avril 2019\")\n\n## [1] \"character\"\n\njourJ &lt;- dmy(\"11 avril 2019\")\nclass(jourJ)\n\n## [1] \"Date\"\n\njourJ\n\n## [1] \"2019-04-11\"\n<\/code><\/pre>\n<p>Vous avez vu? la transformation s&rsquo;est faite sans probl\u00e8me (et \u00e0 partir d&rsquo;une date en fran\u00e7ais, s&rsquo;il-vous-pla\u00eet!). Par ailleurs, la fonction <code>dmy<\/code> aurait tr\u00e8s bien pu s&rsquo;accomoder de mises en formes diff\u00e9rentes (par exemple \u00ab\u00a011th of April, 2019\u00a0\u00bb ou \u00ab\u00a011\/04\/2019\u00a0\u00bb), pour aboutir au m\u00eame r\u00e9sultat.<\/p>\n<p>Sur ce m\u00eame principe, le package <code>lubridate<\/code> comprend un grand nombre de fonctions capables de prendre en entr\u00e9e <strong>dates<\/strong> et <strong>heures<\/strong>, selon des mises en formes vari\u00e9es. Note pour la suite: quand on a des vecteurs qui regroupent \u00e0 la fois la date et l&rsquo;heure (comme \u00ab\u00a011\/04\/2019 14h37\u00a0\u00bb par exemple) on parle de \u00ab\u00a0<strong>date-time<\/strong>\u00ab\u00a0.<\/p>\n<p>Quelques exemples:<\/p>\n<pre><code>ymd(\"2019\/04_11\")\n\n## [1] \"2019-04-11\"\n\nymd_hm(\"2019.04.11 14h37\")\n\n## [1] \"2019-04-11 14:37:00 UTC\"\n\nymd_hms(\"20190407143752\")\n\n## [1] \"2019-04-07 14:37:52 UTC\"\n\nhms(\"14h37min52s\")\n\n## [1] \"14H 37M 52S\"\n<\/code><\/pre>\n<h1>R\u00e9cup\u00e9rer les \u00e9l\u00e9ments des dates<\/h1>\n<p>Maintenant que l&rsquo;on sait faire comprendre \u00e0 R de quelle mani\u00e8re interpr\u00e9ter une cha\u00eene de caract\u00e8res en tant que date-time, on va pouvoir r\u00e9aliser quelques op\u00e9rations simples.<\/p>\n<p>Pour commencer, on peut essayer d&rsquo;<strong>isoler un des \u00e9l\u00e9ments<\/strong> de la date-time (juste l&rsquo;ann\u00e9e, ou juste le mois, ou juste l&rsquo;heure, etc.).<\/p>\n<p>L\u00e0 encore, c&rsquo;est \u00e0 travers le <strong>nom de la fonction utilis\u00e9e<\/strong> que l&rsquo;on va sp\u00e9cifier quel est l&rsquo;\u00e9l\u00e9ment qui nous int\u00e9resse.<\/p>\n<pre><code>t &lt;- ymd_hms(\"2019.04.11 14h37min52s\")\ndate(t)\n\n## [1] \"2019-04-11\"\n\nhour(t)\n\n## [1] 14\n\nminute(t)\n\n## [1] 37\n\nsecond(t)\n\n## [1] 52\n<\/code><\/pre>\n<h1>Arrondir<\/h1>\n<p>On peut \u00e9galement arrondir une date, vers le haut (<code>ceiling_date()<\/code>), vers le bas (<code>floor_date()<\/code>), ou vers le plus proche (<code>round_date()<\/code>):<\/p>\n<pre><code>t &lt;- ymd_hms(\"2019.04.11 14h37min52s\")\nceiling_date(t,\"hour\")\n\n## [1] \"2019-04-11 15:00:00 UTC\"\n\nfloor_date(t,\"hour\")\n\n## [1] \"2019-04-11 14:00:00 UTC\"\n\nround_date(t,\"hour\")\n\n## [1] \"2019-04-11 15:00:00 UTC\"\n<\/code><\/pre>\n<p>Evidemment, on peut choisir \u00e0 quelle <strong>unit\u00e9<\/strong> se fait cet arrondi:<\/p>\n<pre><code>t &lt;- ymd_hms(\"2019.04.11 14h37min52s\")\nround_date(t,\"minute\")\n\n## [1] \"2019-04-11 14:38:00 UTC\"\n\nround_date(t,\"hour\")\n\n## [1] \"2019-04-11 15:00:00 UTC\"\n\nround_date(t,\"day\")\n\n## [1] \"2019-04-12 UTC\"\n\nround_date(t,\"month\")\n\n## [1] \"2019-04-01 UTC\"\n\nround_date(t,\"year\")\n\n## [1] \"2019-01-01 UTC\"\n<\/code><\/pre>\n<h1>P\u00e9riodes ou dur\u00e9es<\/h1>\n<pre><code>t1 &lt;- dmy(\"17\/07\/2018\")\nt2 &lt;- dmy(\"17\/04\/2019\")\ndiff &lt;- t2-t1\n<\/code><\/pre>\n<p>L&rsquo;objet <code>diff<\/code> nous renseigne sur la \u00ab\u00a0diff\u00e9rence de temps\u00a0\u00bb entre t1 et t2. Il s&rsquo;agit d&rsquo;un objet de classe <code>difftime<\/code> (classe qui n&rsquo;est pas sp\u00e9cifiquement li\u00e9e \u00e0 l&rsquo;usage de <code>lubridate<\/code>).<\/p>\n<p>Cette \u00ab\u00a0diff\u00e9rence de temps\u00a0\u00bb peut \u00eatre trait\u00e9e de diff\u00e9rentes mani\u00e8res par <code>lubridate<\/code>. On peut en effet consid\u00e9rer cette diff\u00e9rence en terme de <strong>p\u00e9riode<\/strong> ou en terme de <strong>dur\u00e9e<\/strong>.<\/p>\n<p>On le sp\u00e9cifie de la mani\u00e8re suivante:<\/p>\n<pre><code>as.duration(diff)\n\n## [1] \"23673600s (~39.14 weeks)\"\n\nas.period(diff)\n\n## [1] \"274d 0H 0M 0S\"\n<\/code><\/pre>\n<p>Bon, \u00e0 ce stade, \u00e0 part en terme d&rsquo;affichage, on ne voit pas forc\u00e9ment bien la nuance entre les deux&#8230; L&rsquo;id\u00e9e, c&rsquo;est que la dur\u00e9e correspond plut\u00f4t \u00e0 une diff\u00e9rence de temps \u00ab\u00a0<strong>physique<\/strong>\u00a0\u00bb (c&rsquo;est \u00e0 dire le nombre exact de secondes correspondant \u00e0 un intervalle de temps) tandis que la p\u00e9riode correspond \u00e0 une diff\u00e9rence de temps \u00ab\u00a0<strong>sociale<\/strong>\u00ab\u00a0.<\/p>\n<p>Par exemple, quand Patrick Bruel dit \u00ab\u00a0On s&rsquo;\u00e9tait dit rendez-vous dans 10 ans, m\u00eame jour m\u00eame heure, m\u00eame pomme\u00a0\u00bb, on peut supposer qu&rsquo;il parle d&rsquo;un \u00e9coulement \u00ab\u00a0social\u00a0\u00bb du temps.<\/p>\n<p>Ainsi, partant d&rsquo;une prise de rendez-vous le 4\/02\/1991, on arriverait \u00e0 un prochain rendez-vous le:<\/p>\n<pre><code>t0=dmy_h(\"4\/02\/1991 21h\")\nt0+years(10)\n\n## [1] \"2001-02-04 21:00:00 UTC\"\n<\/code><\/pre>\n<p>soit, \u00e9galement, un 4\/02. Alors que si on avait voulu que 10 ans <em>stricto sensu<\/em> se soient \u00e9coul\u00e9s, cela aurait abouti \u00e0 un rendez-vous quelques jours plus t\u00f4t, du fait des ann\u00e9es bissextiles ayant eu lieu dans l&rsquo;intervalle:<\/p>\n<pre><code>t0+dyears(10)\n\n## [1] \"2001-02-01 21:00:00 UTC\"\n<\/code><\/pre>\n<h1>Calculs arithm\u00e9tiques avec des p\u00e9riodes ou dur\u00e9es<\/h1>\n<p>Dans la partie pr\u00e9c\u00e9dente, nous avons d\u00e9j\u00e0 vu qu&rsquo;il \u00e9tait possible de r\u00e9aliser des op\u00e9rations arithm\u00e9tiques sur des dates. Quelle que soit l&rsquo;op\u00e9ration r\u00e9alis\u00e9e, il faut bien garder en t\u00eate la distinction entre p\u00e9riode et dur\u00e9e! Les p\u00e9riodes correspondent au fonctions <code>xxx()<\/code> (par exemple <code>days()<\/code> ou <code>months()<\/code>) tandis que les dur\u00e9es correspondent aux fonctions <code>dxxx()<\/code> (par exemple <code>ddays()<\/code> ou <code>dyears()<\/code>)<\/p>\n<pre><code>t1+months(9) # t1 + 9 mois\n\n## [1] \"2019-04-17\"\n\nt1+ddays(268) # t1 + exactement 268 jours\n\n## [1] \"2019-04-11\"\n\nddays(268)\/dweeks(1) # combien de semaines (exactement) pour 268 jours?\n\n## [1] 38.28571\n\nt2-dweeks(3) # t2 - (exactement) 3 semaines\n\n## [1] \"2019-03-27\"\n<\/code><\/pre>\n<p>Notez que ces fonctions vous permettent \u00e9galement de cr\u00e9er des <strong>s\u00e9ries<\/strong> \u00e0 intervalle de temps r\u00e9gulier:<\/p>\n<pre><code>t1+months(1:9)\n\n## [1] \"2018-08-17\" \"2018-09-17\" \"2018-10-17\" \"2018-11-17\" \"2018-12-17\" \"2019-01-17\" \"2019-02-17\" \"2019-03-17\" \"2019-04-17\"\n\nnow()+minutes(seq(0,30,by=10))\n\n## [1] \"2018-09-10 11:29:33 CEST\" \"2018-09-10 11:39:33 CEST\" \"2018-09-10 11:49:33 CEST\" \"2018-09-10 11:59:33 CEST\"\n<\/code><\/pre>\n<h1>Intervalles de temps<\/h1>\n<p>Une autre mani\u00e8re d&rsquo;envisager l&rsquo;analyse d&rsquo;un jeu de donn\u00e9es comprenant des dates est de travailler sur des <strong>intervalles<\/strong> de temps.<\/p>\n<p>Pour transformer deux dates en intervalle de temps avec <code>lubridate<\/code>, on a deux solutions (la fonction <code>interval()<\/code>, ou l&rsquo;op\u00e9rateur <code>%--%<\/code>. Dans les deux cas, on obtient le m\u00eame r\u00e9sultat:<\/p>\n<pre><code>itv &lt;- interval(t1,t2)\nitv &lt;- t1 %--% t2\n\nitv\n\n## [1] 2018-07-17 UTC--2019-04-17 UTC\n<\/code><\/pre>\n<p>Disposer d&rsquo;un intervalle, cela permet de r\u00e9aliser certaines op\u00e9rations, comme (par exemple) d\u00e9terminer si une date (ou une \u00ab\u00a0date-time\u00a0\u00bb) donn\u00e9e fait partie de l&rsquo;intervalle:<\/p>\n<pre><code>Noel &lt;- dmy(\"25\/12\/2018\")\nNoel %within% itv\n\n## [1] TRUE\n\nsitv=int_diff(t1+months(1:9))\n<\/code><\/pre>\n<p>Une des op\u00e9rations \u00e0 mon sens les plus utiles en lien avec ces intervalles, c&rsquo;est ainsi de permettre de <strong>replacer l&rsquo;occurrence d&rsquo;un ou plusieurs \u00e9v\u00e9nements dans des intervalles de temps<\/strong>:<\/p>\n<pre><code>sitv\n\n## [1] 2018-08-17 UTC--2018-09-17 UTC 2018-09-17 UTC--2018-10-17 UTC 2018-10-17 UTC--2018-11-17 UTC 2018-11-17 UTC--2018-12-17 UTC 2018-12-17 UTC--2019-01-17 UTC 2019-01-17 UTC--2019-02-17 UTC 2019-02-17 UTC--2019-03-17 UTC 2019-03-17 UTC--2019-04-17 UTC\n\nNoel %within% sitv \n\n## [1] FALSE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE\n<\/code><\/pre>\n<h1>Conclusion<\/h1>\n<p>Je suis loin d&rsquo;avoir couvert toutes les possibilit\u00e9s de <code>lubridate<\/code> (par exemple je n&rsquo;ai rien dit sur les fuseaux horaires, sur les formats <code>date<\/code> et <code>time<\/code> qui correspondent \u00e0 un nombre de jours), mais j&rsquo;esp\u00e8re n\u00e9anmoins vous avoir convaincu (si le besoin s&rsquo;en faisait ressentir) qu&rsquo;<strong>on ne saurait s&rsquo;en passer pour travailler sur des donn\u00e9es temporelles<\/strong>!<\/p>\n<p><!-- De plus, ceux qui liront attentivement auront peut-\u00eatre le plaisir de deviner \u00e0 partir des indices subtils que j'ai diss\u00e9min\u00e9s dans ce billet quel est la nature de l'\u00e9v\u00e9nement qui se pr\u00e9pare pour [entre le 11 et le 17 avril], selon mes estimations :-). --><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Voil\u00e0 d\u00e9j\u00e0 2-3 ans que je recommande \u00e0 qui veut m&rsquo;entendre le package lubridate pour travailler avec des dates. En effet, travailler avec des dates, \u00e0 la base, ce n&rsquo;est pas \u00e9vident. Des op\u00e9rations a priori simples, comme ordonner les vecteurs, calculer des diff\u00e9rences, arrondir des valeurs, peuvent devenir compliqu\u00e9es d\u00e8s que le vecteur en question est de classe date. Cela avait d&rsquo;ailleurs fait l&rsquo;objet de mon tout premier billet.. <a href=\"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/gerer-des-dates-avec-lubridate-un-jeu-denfant\/\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-976","post","type-post","status-publish","format-standard","hentry","category-tous-les-posts"],"_links":{"self":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts\/976","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/comments?post=976"}],"version-history":[{"count":5,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts\/976\/revisions"}],"predecessor-version":[{"id":994,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/posts\/976\/revisions\/994"}],"wp:attachment":[{"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/media?parent=976"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/categories?post=976"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/perso.ens-lyon.fr\/lise.vaudor\/wp-json\/wp\/v2\/tags?post=976"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}