2010-11-15 25 views
1

J'essaye de porter une application de C# à Python. L'application permet à l'utilisateur de choisir son format date/heure en utilisant C# String.Format DateTime formatting. La mise en forme datetime de Python n'est même pas proche de la même, donc je dois sauter mon code à travers quelques cerceaux.Format datetime Python comme C# String.Format

Est-il possible d'analyser des chaînes comme Python comme yyyy-MM-dd HH-mm-ss au lieu de %Y-%m-%d %H-%M-%S?

Répondre

3

Vous pouvez obtenir une bonne distance en utilisant un remplacement simple pour convertir les chaînes de format.

_format_changes = (
    ('MMMM', '%B'), 
    ('MMM', '%b'), # note: the order in this list is critical 
    ('MM', '%m'), 
    ('M', '%m'), # note: no exact equivalent 
    # etc etc 
    ) 

def conv_format(s): 
    for c, p in _format_changes: 
     # s.replace(c, p) #### typo/braino 
     s = s.replace(c, p) 
    return s 

Je présume que vos "cerceaux" signifie quelque chose de similaire. Notez qu'il y a des complications:
(1) le format C# peut avoir du texte littéral entre guillemets simples (exemples dans le lien que vous avez cité)
(2) il permet probablement à un seul caractère d'être littéral en l'échappant avec (3) L'horloge de 12 ou 24 heures peut nécessiter un travail supplémentaire (je n'ai pas exploré la spécification C#, ce commentaire est basé sur un autre exercice similaire auquel j'ai participé).
Vous pouvez finir par écrire un compilateur et un interpréteur de byte-code pour contourner tous les pièges (comme M, F, FF, FFF, ...).

Une alternative à regarder utilise ctypes ou quelque chose de similaire pour appeler le C# RTL directement.

Mise à jour Le code original était trop simpliste et avait une faute de frappe. Le nouveau code suivant montre comment résoudre certains problèmes (comme le texte littéral, et s'assurer qu'un littéral % dans l'entrée ne rend pas strftime mécontent). Il n'essaie pas de donner des réponses précises là où il n'y a pas de conversion directe (M, F, etc.). Les endroits où une exception peut être soulevée sont notés, mais le code fonctionne sur la base du laissez-faire.

_format_changes = (
    ('yyyy', '%Y'), ('yyy', '%Y'), ('yy', '%y'),('y', '%y'), 
    ('MMMM', '%B'), ('MMM', '%b'), ('MM', '%m'),('M', '%m'), 
    ('dddd', '%A'), ('ddd', '%a'), ('dd', '%d'),('d', '%d'), 
    ('HH', '%H'), ('H', '%H'), ('hh', '%I'), ('h', '%I'), 
    ('mm', '%M'), ('m', '%M'), 
    ('ss', '%S'), ('s', '%S'), 
    ('tt', '%p'), ('t', '%p'), 
    ('zzz', '%z'), ('zz', '%z'), ('z', '%z'), 
    ) 

def cnv_csharp_date_fmt(in_fmt): 
    ofmt = "" 
    fmt = in_fmt 
    while fmt: 
     if fmt[0] == "'": 
      # literal text enclosed in '' 
      apos = fmt.find("'", 1) 
      if apos == -1: 
       # Input format is broken. 
       apos = len(fmt) 
      ofmt += fmt[1:apos].replace("%", "%%") 
      fmt = fmt[apos+1:] 
     elif fmt[0] == "\\": 
      # One escaped literal character. 
      # Note graceful behaviour when \ is the last character. 
      ofmt += fmt[1:2].replace("%", "%%") 
      fmt = fmt[2:] 
     else: 
      # This loop could be done with a regex "(yyyy)|(yyy)|etc". 
      for intok, outtok in _format_changes: 
       if fmt.startswith(intok): 
        ofmt += outtok 
        fmt = fmt[len(intok):] 
        break 
      else: 
       # Hmmmm, what does C# do here? 
       # What do *you* want to do here? 
       # I'll just emit one character as literal text 
       # and carry on. Alternative: raise an exception. 
       ofmt += fmt[0].replace("%", "%%") 
       fmt = fmt[1:] 
    return ofmt 

Testée dans la mesure suivante:

>>> from cnv_csharp_date_fmt import cnv_csharp_date_fmt as cv 
>>> cv("yyyy-MM-dd hh:mm:ss") 
'%Y-%m-%d %I:%M:%S' 
>>> cv("3pcts %%% yyyy-MM-dd hh:mm:ss") 
'3pc%p%S %%%%%% %Y-%m-%d %I:%M:%S' 
>>> cv("'3pcts' %%% yyyy-MM-dd hh:mm:ss") 
'3pcts %%%%%% %Y-%m-%d %I:%M:%S' 
>>> cv(r"3pc\t\s %%% yyyy-MM-dd hh:mm:ss") 
'3pcts %%%%%% %Y-%m-%d %I:%M:%S' 
>>> 
+0

+1. Dérivé de la réponse de J V, mais plus clairement formaté et plus clairement expliqué. –

+0

@Steven Rumbalski: Dérivé de sa réponse initiale, qui ne contenait que la remarque "juste exécuter quelques remplacements", sans code, ce dernier étant évidemment ajouté avant que la période "ne pas enregistrer les modifications" de SO expire. –

+0

Par cerceaux Je voulais dire que j'ai une deuxième zone de texte cachée dans laquelle j'utilise mes événements de changement de zone de clic/de zone de texte pour ajouter le format Python. C'est salissant, et faire le double du travail semble-t-il, mais ça marche. Votre réponse, cependant, donne l'impression que cela serait possible. Comment gère-t-il le texte si tout est écrasé sans espaces ni délimiteurs? Exemple: 'yyyyMMddHHmmss' Je n'ai pas regardé beaucoup dans la chaîne remplacer docs, mais je suppose que je devrais. – Micheal

2

Il suffit de lancer quelques remplace d'abord:

replacelist = [["yyyy","%Y"], ["MM","%m"]] # Etc etc 
for replacer in replacelist: 
    string.replace(replacer[0],replacer[1]) 
+1

Que feriez-vous à propos de ceux qui ne correspondent pas? Par exemple C# 's M est le nombre du mois sans zéros de tête. Python n'a pas d'option de format d'heure pour cela. –

+1

Je l'utiliserais mais avec des tuples – aaronasterling

+3

Aussi, assurez-vous de remplacer «yyyy» avant de remplacer «yyy». –

0

Je crains que vous ne pouvez pas. strftime() appelle la fonction strftime() de la bibliothèque C sous-jacente, qui à son tour prend les directives de formatage exactement sous la forme% X. Vous devrez écrire quelques lignes de code pour faire une conversion.