2
votes

Comment obtenir des différences de temps avec une sortie comportant plusieurs unités

Bonjour,

J'ai deux colonnes de date dans as.POSIXct au format AAAA-MM-JJ HH: MM: SS. J'aimerais connaître la différence entre les deux, affichée au format Jours Heures: Secondes. Voici quelques données factices:

ab$time_difference<-difftime(ab$b, ab$a,units=c("days","hours","seconds"))

Ce qui donne ce bloc de données:

ab$time_difference<-difftime(ab$b, ab$a)
ab
                            a                       b   time_difference
     2018-03-20 11:52:25 AST 2018-04-09 18:39:38 AST  486.786944 hours
     2018-03-20 12:51:25 AST 2018-06-23 19:13:14 AST 2286.363611 hours
     2018-03-20 14:19:04 AST 2018-03-20 23:23:03 AST    9.066389 hours
     2018-03-21 14:12:12 AST 2018-05-10 21:29:28 AST 1207.287778 hours
     2018-03-21 12:09:22 AST 2018-03-22 03:17:23 AST   15.133611 hours
     2018-03-21 15:28:01 AST 2018-05-12 00:19:39 AST 1232.860556 hours

Je voudrais faire la différence entre a et b, ou soustrayez le temps a du temps b pour obtenir une sortie de X jours X heures: X secondes.

J'ai utilisé difftime ci-dessous, ainsi que les unités définies différemment:

                        a                       b
 2018-03-20 11:52:25 AST 2018-04-09 18:39:38 AST
 2018-03-20 12:51:25 AST 2018-06-23 19:13:14 AST
 2018-03-20 14:19:04 AST 2018-03-20 23:23:03 AST
 2018-03-21 14:12:12 AST 2018-05-10 21:29:28 AST
 2018-03-21 12:09:22 AST 2018-03-22 03:17:23 AST
 2018-03-21 15:28:01 AST 2018-05-12 00:19:39 AST

J'ai également essayé ce qui suit:

    a<-c("2018-03-20 11:52:25 AST", "2018-03-20 12:51:25 AST", "2018-03-20 14:19:04 AST",
"2018-03-21 14:12:12 AST", "2018-03-21 12:09:22 AST", "2018-03-21 15:28:01 AST")

b<-c("2018-04-09 18:39:38 AST", "2018-06-23 19:13:14 AST", "2018-03-20 23:23:03 AST",
     "2018-05-10 21:29:28 AST", "2018-03-22 03:17:23 AST", "2018-05-12 00:19:39 AST")

ab<-data.frame(a,b)

Mais obtenez l'erreur que 'units' doit avoir une longueur de 1. Y a-t-il une commande différente que je devrais utiliser, ou y a-t-il un moyen pour difftime de produire une différence de temps plus exacte? p >

Merci!


0 commentaires

4 Réponses :


3
votes

La bibliothèque hms peut fournir une assistance ici:

Fmt <- function(x) UseMethod("Fmt")
Fmt.difftime <- function(x) {
   units(x) <- "secs"
   x <- unclass(x)
   NextMethod()
}
Fmt.default <- function(x) {
   y <- abs(x)
   sprintf("%s%02d:%02d:%02d:%02d", 
           ifelse(x < 0, "-", ""), # sign
           y %/% 86400,  # days
           y %% 86400 %/% 3600,  # hours 
           y %% 3600 %/% 60,  # minutes
           y %% 60 %/% 1) # seconds
}


a<-c("2018-03-20 11:52:25 AST", "2018-03-20 12:51:25 AST", "2018-03-20 14:19:04 AST",
     "2018-03-21 14:12:12 AST", "2018-03-21 12:09:22 AST", "2018-03-21 15:28:01 AST")

b<-c("2018-04-09 18:39:38 AST", "2018-06-23 19:13:14 AST", "2018-03-20 23:23:03 AST",
     "2018-05-10 21:29:28 AST", "2018-03-22 03:17:23 AST", "2018-05-12 00:19:39 AST")
ab<-data.frame(a,b)

#Passing two dates to  the function(s)
Fmt(as.POSIXct(ab$b)-as.POSIXct(ab$a))
#Passing a time difference in seconds
Fmt(difftime(ab$b, ab$a, units="secs"))

Voir cette question pour d'autres options: Sortie de difftime comme HH: MM: SS: mm dans R

Voici le code de la réponse ci-dessus pour votre problème:

XXX

La clé ici est d'exécuter le code pour les définitions de fonction au début de votre script afin que les fonctions soient alors disponibles pour utilisation.


3 commentaires

Merci, cela fonctionne en reformatant la colonne de décalage horaire en heures: minutes: secondes, mais je ne peux pas aussi la mettre en forme en jours. J'ai également examiné la question que vous avez liée et essayé d'utiliser la fonction, mais je ne comprends pas très bien comment l'utiliser, et je n'ai pas pu la faire reformater ma colonne de données.


Merci pour la réponse et éditez @ Dave2e. J'ai exécuté le code, mais continue à recevoir le message d'erreur "Erreur dans * tmp * $ diffs: l'opérateur $ n'est pas valide pour les vecteurs atomiques". J'ai essayé is.atomic et j'ai obtenu TRUE pour chaque colonne. Selon cette question, une erreur stackoverflow.com/questions/23299684/... Je dois utiliser Fmt (as.POSIXct (ab [" b "]) - as.POSIXct (ab [" a "]), cependant J'obtiens alors l'erreur "ne sais pas comment convertir 'tag_final [" last_pos "]' en classe" POSIXct ". Quand je fais str (ab), cela indique que ces colonnes sont dans POSIXct. Que me manque-t-il ici?


Si les colonnes sont de classe POSIXct, alors elles sont toutes prêtes pour un objet date-heure et vous devez utiliser la fonction difftime . Si vous citez les noms de colonnes, vous devrez utiliser des doubles crochets Fmt (as.POSIXct (ab [["b"]]) - as.POSIXct (ab [["a"]])



1
votes
require(lubridate)

a<-c("2018-03-20 11:52:25 AST", "2018-03-20 12:51:25 AST", "2018-03-20 14:19:04 AST",
     "2018-03-21 14:12:12 AST", "2018-03-21 12:09:22 AST", "2018-03-21 15:28:01 AST")

b<-c("2018-04-09 18:39:38 AST", "2018-06-23 19:13:14 AST", "2018-03-20 23:23:03 AST",
     "2018-05-10 21:29:28 AST", "2018-03-22 03:17:23 AST", "2018-05-12 00:19:39 AST")

# Make df
ab <- data.frame(a = as.POSIXct(a),b = as.POSIXct(b),stringsAsFactors = FALSE)

# Time diff
ab$time_difference <- ab$b - ab$a
ab$time_difference <- as.duration(ab$time_difference)
ab$time_difference 

1 2018-03-20 11:52:25 2018-04-09 18:39:38   1752433s (~2.9 weeks)
2 2018-03-20 12:51:25 2018-06-23 19:13:14 8230909s (~13.61 weeks)
3 2018-03-20 14:19:04 2018-03-20 23:23:03    32639s (~9.07 hours)
4 2018-03-21 14:12:12 2018-05-10 21:29:28  4346236s (~7.19 weeks)
5 2018-03-21 12:09:22 2018-03-22 03:17:23   54481s (~15.13 hours)
6 2018-03-21 15:28:01 2018-05-12 00:19:39  4438298s (~7.34 weeks)

1 commentaires

Comment un décalage horaire du même jour est-il égal à -785104d -7H -7M 0S ?



2
votes

Puisque vous souhaitez des jours, des heures, des minutes, des secondes, nous pouvons obtenir ce résultat avec le package lubridate :

> as.period(timespan, unit = "day")
[1] "20d 6H 47M 13S" "95d 6H 21M 49S" "9H 3M 59S"      "50d 7H 17M 16S"
[5] "15H 8M 1S"      "51d 8H 51M 38S"

Si vous le souhaitez, nous pouvons convertir des mois à jours en spécifiant la mise en forme comme suit:

a<-c("2018-03-20 11:52:25 AST", "2018-03-20 12:51:25 AST", "2018-03-20 14:19:04 AST",
 "2018-03-21 14:12:12 AST", "2018-03-21 12:09:22 AST", "2018-03-21 15:28:01 AST")

b<-c("2018-04-09 18:39:38 AST", "2018-06-23 19:13:14 AST", "2018-03-20 23:23:03 AST",
 "2018-05-10 21:29:28 AST", "2018-03-22 03:17:23 AST", "2018-05-12 00:19:39 AST")

a = as.POSIXct(a)
b = as.POSIXct(b)

library(lubridate)
timespan = interval(ymd_hms(ab[,1]), ymd_hms(ab[,2]))
> as.period(timespan)
[1] "20d 6H 47M 13S"    "3m 3d 6H 21M 49S"  "9H 3M 59S"         "1m 19d 7H 17M 16S"
[5] "15H 8M 1S"         "1m 20d 8H 51M 38S"


7 commentaires

Utiliser un objet period pour cela semble être une idée loin d'être idéale - " Parce que les périodes n'ont pas de longueur fixe, ils ne peuvent pas être convertis avec précision depuis et vers des objets Duration "


Je vous remercie. La deuxième valeur de la sortie a 3m et 21 M ... Est-ce que les minuscules m représentent des millisecondes? Si oui, existe-t-il un moyen de supprimer les millisecondes?


Le «m» minuscule représente des mois (puisque la différence entre les dates est si grande).


Ah, je vois, merci. Étant donné que les jours en mois varient, existe-t-il un moyen de faire passer les mois par défaut à jours? Donc, ma sortie serait juste des jours, des heures, des minutes, des secondes?


@ElizabethSmith: Oui, nous pouvons changer des mois en jours en spécifiant le formatage. J'ai édité ma réponse et ajouté un peu de code à la fin pour ce faire.


Merci beaucoup! C'est exactement ce que je recherche!


@ElizabethSmith: Je suis contente d'avoir pu aider :)



1
votes

Utilisez sprintf et l'arithmétique modulaire:

# first, be sure to specify units in difftime, or it will internally
#   choose units for each row
# using 'secs' here since it's the lowest common denominator
# wrapping as.double() to remove the class attribute which will
#   screw up dispatch to Ops below
ab$time_difference <- as.double(difftime(ab$b, ab$a, units = 'secs'))

#  3600 =   60*60 seconds in an hour;
# 86400 = 3600*24 seconds in a day
ab$hms = with(ab, sprintf('%d days; %d hours; %d seconds',
                          time_difference %/% 86400L,
                          (time_difference %% 86400L) %/% 3600L,
                          time_difference %% 3600L))
ab$hms
# [1] "20 days; 6 hours; 2833 seconds" "95 days; 6 hours; 1309 seconds"
# [3] "0 days; 9 hours; 239 seconds"   "50 days; 7 hours; 1036 seconds"
# [5] "0 days; 15 hours; 481 seconds"  "51 days; 8 hours; 3098 seconds"

J'ai choisi un format de sortie particulièrement verbeux juste pour l'illustration; les blocs de construction sont là pour rouler les vôtres, bien sûr, en gardant à l'esprit que vous devez remplacer % d par % 02d (par exemple) à gauche- 0 -pad la sortie à 2 chiffres.


0 commentaires