Dates, instants et heures

Dates, instants et heures dans R

Il est courant de travailler avec des dates et des heures en analyse de données. Les dates et les heures servent également à étudier des tendances, la survie, et bien plus encore. Tout analyste de données doit savoir manipuler les variables de date et d'heure. En réalité, les variables de date et d'heure peuvent être traitées comme des variables numériques : chaque date/heure peut se voir attribuer une valeur numérique, qui peut ensuite être utilisée dans diverses opérations. Pour attribuer une valeur numérique à une date/un instant donné, une autre date doit servir de date de référence ou de point de départ. Dans R, cette date est fixée au 1970-01-01 00:00:00 GMT. Toute date/heure ultérieure peut alors être calculée comme le nombre de jours/heures/secondes écoulés depuis ce point de départ. Il est bien sûr possible de modifier la date de référence, mais c'est rarement nécessaire.

Pour travailler avec des dates et des heures comme variables numériques, R utilise des vecteurs atomiques de classe POSIXct ou POSIXt, qui sont en réalité des doubles. Bien que ces types de vecteurs soient effectivement des valeurs numériques, vous pouvez utiliser des chaînes de caractères pour les définir. Commençons par créer deux vecteurs atomiques contenant des dates :

## Nous créons deux vecteurs de caractères simples
birth_date <- c("1990-01-01", "1999-01-04", "2002-05-05", "2001-12-12")
death_date <- c("2005-02-02", "2009-11-14", "2018-01-01", "2011-11-09")

class(birth_date)
## [1] "character"
class(death_date)
## [1] "character"

R indique que les deux vecteurs sont de type character, comme nous nous y attendions. Convertissons ces vecteurs de caractères en vecteurs de dates à l'aide des fonctions disponibles dans base R (c'est-à-dire les fonctions de base de R) :

birth_date <- as.POSIXct(birth_date)
death_date <- as.POSIXct(death_date)
## Voir le résultat pour birth_date
birth_date
## [1] "1990-01-01 CET"  "1999-01-04 CET"  "2002-05-05 CEST" "2001-12-12 CET"
## Voir le résultat pour death_date
death_date
## [1] "2005-02-02 CET" "2009-11-14 CET" "2018-01-01 CET" "2011-11-09 CET"
## Vérifier la classe
class(birth_date)
## [1] "POSIXct" "POSIXt"
## Vérifier la classe
class(death_date)
## [1] "POSIXct" "POSIXt"

Nous pouvons calculer la différence de temps entre la naissance et le décès à l'aide de la fonction difftime() :

difftime(death_date, birth_date)
## Time differences in days
## [1] 5511.000 3967.000 5720.042 3619.000

5511.000 est la différence de temps entre le premier élément de birth_date (1990-01-01) et le premier élément de death_date (2005-02-02 CET). 3967.000 est la différence de temps entre le deuxième élément de birth_date (1999-01-04 CET) et le deuxième élément de death_date (2009-11-14 CET), et ainsi de suite.

R a converti les chaînes de caractères en dates-heures, avec les classes POSIXct et POSIXt. Avec POSIXct, chaque date est représentée par le nombre de secondes écoulées depuis 12:00 UTC (Universal Time Coordinated) le 1er janvier 1970. Mais difftime() calcule la différence de temps en jours, ce qui est un réglage par défaut. Vous pouvez le modifier. Si vous voulez par exemple la différence de temps en secondes, vous écrivez :

difftime(death_date, birth_date, units="secs")
## Time differences in secs
## [1] 476150400 342748800 494211600 312681600

Observez à nouveau la commande suivante :

## Résultat pour death_date
death_date
## [1] "2005-02-02 CET" "2009-11-14 CET" "2018-01-01 CET" "2011-11-09 CET"

La sortie montre que R a ajouté des fuseaux horaires ; CET correspond à l'heure d'Europe centrale. C'était quelque peu inattendu, et de fait les fonctions de base R pour la manipulation des dates et des heures peuvent être compliquées, voire problématiques. C'est pourquoi Garrett Grolemund, Hadley Wickham et Vitalie Spinu ont créé le package lubridate , qui rend la manipulation des dates et des heures très simple. Installons et chargeons le package :

## Commencez par installer lubridate
install.packages("lubridate")

## Chargez le package afin de pouvoir utiliser ses fonctions
library(lubridate)
## Attaching package: 'lubridate'
## The following object is masked from 'package:base':
##
##     date

Lubridate stocke les dates sous forme de nombre de jours écoulés depuis le 1970-01-01. Vous pouvez obtenir la date correspondant à 18000 jours après le 1970-01-01 avec la commande suivante :

as_date(18000)
## [1] "2019-04-14"

18000 jours après le 1970-01-01, nous arrivons à la date du 2019-04-04.

Stockons quelques valeurs de date avec lubridate. Lubridate propose de nombreuses fonctions pour cela. Le principe d'utilisation de ces fonctions est le suivant :

  • Identifiez l'ordre de l'année (y), du mois (m), du jour (d), de l'heure (h), des minutes (m) et des secondes (s) dans la chaîne de date.
  • Utilisez la fonction appropriée, dont l'ordre des éléments correspond à vos données.

Exemple :

  • Nous avons des dates au format « 1990-01-01 », ce qui signifie que le format est « YYYY-MM-DD ». L'ordre est donc Y, M, D.
  • La fonction lubridate appropriée s'appelle ymd().
  • La fonction ymd() crée un vecteur de dates à partir de votre chaîne.

Testons-la en créant un data frame de 3 personnes, comprenant leur nom, leur date de naissance, la date de leur opération et leur date de décès. Toutes les dates seront écrites avec des séparateurs différents afin de vérifier si la fonction ymd() sait interpréter différentes variantes de dates :

## Créer nos vecteurs (variables)
names <- c("David", "Mohammed", "Christina")
birth <- ymd("1990-01-01", "1999-01-04", "2002-05-05")
operation <- ymd("1990.01.01", "1999.01.04", "2002.05.05")
death <- ymd("2005/02/02", "2009/11/14", "2018/01/01")

## Combiner les vecteurs en un data frame
my_data <- data.frame(names, birth, operation, death)

## Afficher le data frame
my_data
##       names      birth  operation      death
## 1     David 1990-01-01 1990-01-01 2005-02-02
## 2  Mohammed 1999-01-04 1999-01-04 2009-11-14
## 3 Christina 2002-05-05 2002-05-05 2018-01-01

Comme vous pouvez le voir dans la sortie ci-dessus, R a reconnu les différentes formes de dates. Modifions maintenant l'ordre de l'année, du mois et du jour. Ce faisant, nous devons changer de fonction et utiliser une fonction qui comprend dans quel ordre l'année, le mois et le jour apparaissent dans la chaîne :

## Chaîne de date dans l'ordre jour, mois et année
dmy("30-01-2000", "25-12-2001")
## [1] "2000-01-30" "2001-12-25"
## Chaîne de date dans l'ordre mois, jour, année
mdy("12-25-1999", "09-29-2004")
## [1] "1999-12-25" "2004-09-29"
## Chaîne de date dans l'ordre année, mois jour
ymd("20181230", "20191129")
## [1] "2018-12-30" "2019-11-29"

Là encore, R a interprété les dates correctement. Lubridate contient bien d'autres fonctions pour manipuler les dates. Vous pouvez télécharger l'aide-mémoire (cheat sheet) de lubridate.

Dans l'exemple suivant, nous allons stocker une date qui comprend une heure. Pour l'interpréter correctement, nous utilisons une fonction qui sait aussi gérer h (heures), m (minutes) et s (secondes) :

ymd_hms("2011-06-04 12:00:00")
## [1] "2011-06-04 12:00:00 UTC"

Vous pouvez voir que R a attribué à la date le fuseau horaire UTC. R sait gérer environ 600 fuseaux horaires, pour lesquels il dispose d'informations sur le fuseau horaire, l'heure d'été et les variations historiques du calendrier de la zone. R attribue un fuseau horaire par vecteur. Vous pouvez obtenir la liste de tous les fuseaux horaires en exécutant la commande suivante (seuls les 20 premiers fuseaux horaires sont affichés, pour gagner de la place) :

OlsonNames()
##   [1] "Africa/Abidjan"                   "Africa/Accra"
##   [3] "Africa/Addis_Ababa"               "Africa/Algiers"
##   [5] "Africa/Asmara"                    "Africa/Asmera"
##   [7] "Africa/Bamako"                    "Africa/Bangui"
##   [9] "Africa/Banjul"                    "Africa/Bissau"
##  [11] "Africa/Blantyre"                  "Africa/Brazzaville"
##  [13] "Africa/Bujumbura"                 "Africa/Cairo"
##  [15] "Africa/Casablanca"                "Africa/Ceuta"
##  [17] "Africa/Conakry"                   "Africa/Dakar"
##  [19] "Africa/Dar_es_Salaam"             "Africa/Djibouti"

Créons un vecteur de dates en fixant le fuseau horaire sur la zone Pacifique des États-Unis :

ymd_hms("2011-06-04 12:00:00", tz="US/Pacific")
## [1] "2011-06-04 12:00:00 PDT"

Calculer des intervalles de temps dans R

Créons quelques données comprenant 3 individus et leurs dates de naissance et de décès :

## Créer les vecteurs
names <- c("David", "Mohammed")
birth <- ymd("1990-01-01", "1999-01-04")
death <- ymd("2005/02/02", "2009/11/14")

## Combiner les vecteurs en un data frame
my_data <- data.frame(names, birth, death)

## Afficher le data frame
my_data
##      names      birth      death
## 1    David 1990-01-01 2005-02-02
## 2 Mohammed 1999-01-04 2009-11-14

Nous voulons créer une nouvelle variable/un nouveau vecteur/une nouvelle colonne dans notre data frame my_data. Cette nouvelle variable, que nous appelons dayslived, doit correspondre à la différence de temps entre la date de naissance et la date de décès.

## Calculer la différence de temps par soustraction
my_data$dayslived <- my_data$death-my_data$birth

## Afficher les données
my_data
##      names      birth      death dayslived
## 1    David 1990-01-01 2005-02-02 5511 days
## 2 Mohammed 1999-01-04 2009-11-14 3967 days

Nous pouvons utiliser la fonction interval() pour définir un intervalle de temps, qui pourra ensuite servir à diverses comparaisons. Créons une variable d'intervalle de temps et appelons-la time_interval :

my_data$time_interval <- interval(my_data$birth, my_data$death)
my_data

Le résultat est le même, ce que vous pouvez vérifier vous-même.

Voyons si David et Mohammed ont vécu pendant la Seconde Guerre mondiale.

## Définir le début de la Seconde Guerre mondiale :
ww2start    <- ymd_hms("1939-01-01 00:00:00")
## Définir la fin de la Seconde Guerre mondiale :
ww2end      <- ymd_hms("1945-12-31 00:00:00")
## Définir un intervalle de temps
ww2interval <- interval(ww2start, ww2end)

#Vérifier si les intervalles de temps se chevauchent (c'est-à-dire si David et Mohammed ont vécu pendant la Seconde Guerre mondiale) :
int_overlaps(my_data$time_interval, ww2interval)
## 1  FALSE
## 2  FALSE

Il semble qu'aucun des deux n'ait vécu pendant la Seconde Guerre mondiale, puisque le résultat est FALSE pour David comme pour Mohammed.

Durées

Une durée est la différence de temps entre deux instants. Avec lubridate, on calcule des durées en soustrayant des dates, comme le montre l'exemple :

ymd("2018-01-01") - ymd("1999-01-04")
## Time difference of 6937 days

Périodes

Vous pouvez ajouter ou soustraire des périodes à l'aide de fonctions simples, comme suit :

ymd(20110101) + years(1)
## [1] "2012-01-01"
ymd(20110101) + months(12)
## [1] "2012-01-01"
ymd(20110101) - days(2)
## [1] "2010-12-30"
ymd(20110101) - seconds(2000)
## [1] "2010-12-31 23:26:40 UTC"