Existe-t-il un moyen de déshumaniser une chaîne de durée comme suit pour obtenir l'horodatage utc réel?
Par exemple: "1.hour.ago 25.minute.ago 1.second.ago" reconvertir ven, 18 oct 2019 16:09:10 UTC +00: 00
les informations du site l'a comme "il y a 17h 21m 1s" besoin de le convertir en db datetime utc je parviens à le faire:
"17h 21m 1s ago".gsub("h", '.hour.ago').gsub("m", '.minute.ago').gsub("s ago", '.second.ago')
# ==> "17.hour.ago 21.minute.ago 1.second.ago"
Mais comment supprimer la partie de chaîne et la convertir en méthode datetime ? L'essai de l'analyse datetime n'a pas fonctionné.
3 Réponses :
Je suppose que les heures, les minutes et les secondes sont séquentielles.
def time_from_string(time_in_string)
time_info = time_in_string.scan(/\d+/).map(&:to_i)
time_in_seconds = time_info.zip([3600, 60, 1]).sum{ |x, y| x * y }
Time.now - time_in_seconds.seconds
end
p time_from_string(time_in_string)
#=> 2019-10-18 21:37:10 +0300
En tant que méthode:
time_in_string = "1.hour.ago 25.minute.ago 1.second.ago"
time_info = time_in_string.scan(/\d+/).map(&:to_i)
#=> [1, 25, 1]
time_in_seconds = time_info.zip([3600, 60, 1]).sum{ |x, y| x * y }
=> 5101
Time.now
#=> 2019-10-18 22:56:14 +0300
Time.now - time_in_seconds.seconds
#=> 2019-10-18 21:31:13 +0300
En supposant que vous travaillez avec le format "Il y a 17h 21m 1s" , vous pouvez utiliser Time # advance pour faire le travail:
def when_was(string)
time = Time.now.utc
string.split(/\s+/).each do |part|
case (part)
when /\A(\d+)h\z/
time = time.advance(hours: -$1.to_i)
when /\A(\d+)m\z/
time = time.advance(minutes: -$1.to_i)
when /\A(\d+)s\z/
time = time.advance(seconds: -$1.to_i)
end
end
time
end
p when_was("17h 21m 1s ago")
# => 2019-10-18 01:31:36 UTC
Vous pouvez également le faire avec Time.now.utc - 17.hours - 21.minutes - 1.second mais cela implique une distribution dynamique avec send code> donc c'est plus compliqué.
En supposant que vous puissiez aller avec time.advance (string.match (/ (? :(? plutôt qu'une déclaration de cas
@engineersmnky Je parie que vous pourriez! C'est une alternative intéressante.
Une solution pré-packagée utilisant chronic_duration gem:
require 'chronic_duration'
time_in_seconds = ChronicDuration.parse('17h 21m 1s ago')
p Time.now - time_in_seconds # => 2019-10-18 03:50:47 +0200
Il peut comprendre m , min , etc. hors de la boîte.
ChronicDuration :: parse prendra-t-il l'argument "1.hour.ago 25.minute.ago 1.second.ago" ? Sinon, vous devez évidemment faire une simple conversion. J'espère que cette méthode est moins susceptible de renvoyer de faux positifs (renvoyant le temps en secondes lorsque l'argument ne représente clairement pas une heure) que la méthode notoire Date :: parse : Date.parse " Je peux aller à l'opéra, toi? " # => # .
@CarySwoveland: Non, il se confond avec les points entre les chiffres et les unités de temps. Vous devez utiliser Time.now - ChronicDuration.parse ("17.hour.ago 21.minute.ago 1.second.ago" .gsub (/\./, ''))
Cela vaut peut-être la peine de mentionner que dans votre réponse, plutôt que dans un commentaire, comme "1.hour.ago 25.minute.ago 1.second.ago" est vraisemblablement une donnée.
Cela n'a rien à voir avec les rails.
"1.hour.ago 25.minute.ago 1.second.ago"n'est pas la façon dont Rails ou Ruby fonctionne, et cela n'a rien à voir avec la chaîne"17h 21m 1s ago". Cette chaîne serait générée à partir d'un seul appel àtime_ago_in_wordsavec un seul horodatage, pas trois objets de durée séparés, et la sortie detime_ago_in_wordsest totalement différente.D'intérêt possible:
nécessite 'matrice'; arr = "1.hour.ago 25.minute.ago 1.second.ago" .scan (/ \ d + /). map (&: to_i) # => [1, 25, 1]; time_in_seconds = Vecteur [* arr] .inner_product Vector [3600, 60, 1] # => 5105.@CarySwoveland sans la dépendance ajoutée
arr.zip ([3600,60,1]). Reduction (0) {| m, a | m + = a.reduce (: *)}Qu'est-ce que
"1.hour.ago 25.minute.ago 1.second.ago"? Vous n'avez probablement pas à analyser une chaîne comme celle-là, n'est-ce pas?