1
votes

Comment déshumaniser le temps passé d'humaniser les chaînes en Ruby?

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é.


4 commentaires

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_words avec un seul horodatage, pas trois objets de durée séparés, et la sortie de time_ago_in_words est 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?


3 Réponses :


1
votes

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


0 commentaires

2
votes

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é.


2 commentaires

En supposant que vous puissiez aller avec time.advance (string.match (/ (? :(? \ d +) d \ s)? (? :(? \ ‌ d +) h \ s )? (?: (? \ d +) m \ s)? (?: (? \ d +) s) /). named_‌ capture.transform_v‌ alues ​​{| v | - v.to_i}) plutôt qu'une déclaration de cas


@engineersmnky Je parie que vous pourriez! C'est une alternative intéressante.



2
votes

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.


3 commentaires

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.