2016-05-20 5 views
0

J'importe des données à partir d'un fichier CSV et je souhaite autoriser mon utilisateur à spécifier le format d'une colonne DateTime. Plutôt que de leur permettre de taper une chaîne de format et de gérer la peine de valider l'entrée, je prévoyais de leur donner une boîte de sélection qui répertorie toutes les options de format (par exemple %m/%d/%Y, etc ...). Quelqu'un a mentionné qu'une gemme existe déjà qui énumérera tous les formats DateTime raisonnables, mais j'ai été incapable de le trouver. Comment puis-je obtenir une liste des formats DateTime disponibles pour l'affichage?Ruby: Liste des options de format DateTime

+0

Bienvenue chez SO. «Les questions qui nous demandent de recommander ou de trouver un livre, un outil, une bibliothèque de logiciels, un didacticiel ou autre ressource hors site sont hors sujet pour Stack Overflow, car elles ont tendance à attirer les réponses avisées et le spam. //meta.stackoverflow.com/questions/254393) et ce qui a été fait jusqu'à présent pour le résoudre. " –

Répondre

1

Vous pourriez être intéressé par une autre alternative. J'ai dû faire quelque chose de similaire il n'y a pas si longtemps, et supporter des formats de dates presque arbitraires. En fin de compte, nous avons détecté 29 formats distincts (tous les États-Unis et le Canada) de toutes les sources de données (fichiers CSV) que nous avons pris en charge.

je suis venu avec cette classe pour analyser et mettre en cache le résultat:

class DateParser 
    @@date_cache = {} 

    def self.is_date?(date) 
    return self.match_digital_date?(date) || self.match_instance_date?(date) 
    end 

    def self.parse_date(date) 
    return nil if date.blank? 
    return date if date.instance_of?(Date) 

    date = date.to_s 
    cached_date = @@date_cache[date] 

    return cached_date if !cached_date.nil? 

    match = self.match_instance_date?(date) 

    if !match.nil? 
     month_str = match[1].upcase 
     day = match[2].to_i 
     year = match[3].to_i 
     year += (year < 20) ? 2000 : 1900 if year < 1600 

     month = ['JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC'].find_index {|mon| mon == month_str } 
     cached_date = Date.new(year, month+1, day) if !month.nil? 
    else 
     scrubbed_date = date.gsub(/^([0-9]+)[\/-]+([0-9]+)[\/-]+00$/, '\\1/\\2/2000') 
     begin 
     parsed = Chronic.parse(scrubbed_date) 
     rescue 
     parsed = nil 
     end 
     return nil if parsed.nil? 

     cached_date = parsed.to_date 
    end 

    @@date_cache[date] = cached_date 
    return cached_date 
    end 

private 

    # Matches dates in these formats 
    # : 2015-01-13 
    # : 01-13-2015 
    # : 01-13-15 
    # : 13-01-15 
    # : 01/13/2015 
    # : 01/13/15 
    # : 13/01/15 
    def self.match_digital_date?(date) 
    return /^([0-9]+)[\/-]+([0-9]+)[\/-]+([0-9]+)$/.match(date) 
    end 

    def self.match_instance_date?(date) 
    return /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d+)\/(\d+)/i.match(date) 
    end 
end 

Il utilise le Chronic gem pour faire partie de l'analyse de ce jour, à partir d'une correspondance initiale de regex pour choisir le chemin d'analyse syntaxique, ainsi comme certains correctifs nécessaires que nous avons rencontrés en cours de route. L'exactitude et la rapidité étaient les principaux objectifs de cette approche. La mise en cache des résultats a permis d'accélérer le traitement des dates du fichier CSV de 5X ou plus dans la plupart des cas.

Si vous ne voulez pas demander à l'utilisateur quel format il a utilisé et si vous voulez simplement consommer les dates que vous choisissez, cela devrait vous donner ce dont vous avez besoin.

1

Consultez la classe DateTime. Il fait partie de la bibliothèque standard, pas une gemme externe. Vous aurez besoin de require date pour l'utiliser.

Voici quelques exemples dans irb; notez qu'avec strftime vous avez beaucoup de flexibilité et devrez spécifier votre propre chaîne de format.

2.3.0 :007 > dt = DateTime.now 
=> #<DateTime: 2016-05-21T03:16:51+08:00 ((2457529j,69411s,139202000n),+28800s,2299161j)> 
2.3.0 :008 > dt.iso8601 
=> "2016-05-21T03:16:51+08:00" 
2.3.0 :009 > dt.xmlschema 
=> "2016-05-21T03:16:51+08:00" 
2.3.0 :010 > dt.jisx0301 
=> "H28.05.21T03:16:51+08:00" 
2.3.0 :011 > dt.rfc3339 
=> "2016-05-21T03:16:51+08:00" 
2.3.0 :012 > dt.httpdate 
=> "Fri, 20 May 2016 19:16:51 GMT" 
2.3.0 :013 > dt.strftime('%Y-%m-%dT%H:%M:%S%z') 
=> "2016-05-21T03:16:51+0800"