Différence entre str Et repr?

Quelle est la différence entre __str__ et __repr__ dans Python ?

2176
demandé sur martineau 2009-09-17 08:27:45

21 réponses

Alex résumé mais, étonnamment, était trop succinct.

tout d'abord, permettez-moi de réitérer les principaux points dans Alex's post :

  • L'implémentation par défaut est inutile (il est difficile de penser à celle qui ne le serait pas, mais ouais)
  • __repr__ l'objectif est d'être sans ambiguïté
  • __str__ l'objectif est d'être lisible
  • Conteneur __str__ utilise des objets contenus’ __repr__

l'implémentation par défaut est inutile

c'est surtout une surprise car les valeurs par défaut de Python ont tendance à être assez utiles. Toutefois, dans ce cas, ayant un défaut pour __repr__ qui agirait comme:

return "%s(%r)" % (self.__class__, self.__dict__)

aurait été trop dangereux (par exemple, trop facile d'entrer dans une récursion infinie si les objets se réfèrent les uns aux autres). Donc Python est viré. Notez qu'il y a un défaut qui est true: si __repr__ est défini, et __str__ ne l'est pas, l'objet se comportera comme si __str__=__repr__ .

cela signifie, en termes simples: presque chaque objet que vous mettez en œuvre devrait avoir un __repr__ fonctionnel qui est utilisable pour comprendre l'objet. La mise en œuvre de __str__ est facultative: faites-le si vous avez besoin d'une fonctionnalité" pretty print " (par exemple, utilisé par un rapport générateur.)

le but de __repr__ est d'être sans ambiguïté

laissez - moi sortir et le dire-Je ne crois pas aux débogueurs. Je ne sais pas vraiment comment utiliser un débogueur, et je n'en ai jamais utilisé un sérieusement. En outre, je crois que la grande faille dans les débogueurs est leur nature fondamentale - la plupart des échecs que je corrige se sont produits il y a longtemps, dans une galaxie très lointaine. Cela signifie que je crois, avec des religieux ferveur, dans l'exploitation forestière. La journalisation est l'élément vital de tout système de serveur fire-and-forget décent. Python rend facile de se connecter: avec peut-être quelques enveloppements spécifiques au projet, tout ce dont vous avez besoin est un

log(INFO, "I am in the weird function and a is", a, "and b is", b, "but I got a null C — using default", default_c)

mais vous devez faire la dernière étape - assurez-vous que chaque objet que vous mettez en œuvre a un repr utile, de sorte que le code comme cela peut juste fonctionner. C'est pourquoi la chose "eval" apparaît: si vous avez assez d'informations pour eval(repr(c))==c , cela signifie que vous savez tout ce qu'il y a à savoir sur c . Si c'est assez facile, au moins dans un flou manière, le faire. Si non, assurez-vous que vous avez assez d'informations sur c de toute façon. J'utilise habituellement un format eval-like: "MyClass(this=%r,that=%r)" % (self.this,self.that) . Cela ne signifie pas que vous pouvez réellement construire MyClass, ou que ce sont les bons arguments du constructeur - mais c'est une forme utile pour exprimer "c'est tout ce que vous devez savoir à propos de cette instance".

Note: j'ai utilisé %r ci-dessus, pas %s . Vous avez toujours vous voulez utiliser le caractère de formatage repr() [ou %r , de façon équivalente] à l'intérieur de la mise en œuvre __repr__ , ou vous allez à l'encontre de l'objectif de repr. Vous voulez pouvoir différencier MyClass(3) et MyClass("3") .

le but de __str__ doit être lisible

en particulier, il n'est pas destiné à être sans ambiguïté - avis que str(3)==str("3") . De même, si vous mettez en œuvre une abstraction IP, ayant le str de ressembler à 192.168.1.1 est tout simplement parfait. Lors de la mise en œuvre d'un abstraction date/heure, la DOD peut être "2010/4/12 15:35:22", etc. Le but est de représenter de façon qu'un utilisateur, pas un programmeur, voudrais le lire. Couper des chiffres inutiles, prétendre être une autre classe - tant qu'elle soutient la lisibilité, c'est une amélioration.

Conteneur __str__ utilise des objets contenus’ __repr__

cela semble surprenant, n'est-ce pas? Il est un peu, mais comment lisible serait

[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]

be? Pas très. Plus précisément, les chaînes dans un conteneur trouveraient beaucoup trop facile de perturber sa représentation de chaîne. Face à l'ambiguïté, rappelez-vous, Python résiste à la tentation de le deviner. Si vous voulez le comportement ci-dessus lorsque vous imprimez une liste, juste

print "[" + ", ".join(l) + "]"

(vous pouvez probablement aussi trouver quoi faire à propos des dictionnaires.

résumé

mettre en Œuvre __repr__ pour toute la classe à mettre en œuvre. Cela devrait être une seconde nature. Implémenter __str__ si vous pensez qu'il serait utile d'avoir une version string qui se trompe du côté de plus de lisibilité en faveur de plus d'ambiguïté.

2232
répondu moshez 2018-06-19 12:00:22

Ma règle d'or: __repr__ est pour les développeurs", 151910920" est pour les clients.

378
répondu Ned Batchelder 2009-09-17 11:35:13

sauf si vous agissez spécifiquement pour assurer autrement, la plupart des classes n'ont pas de résultats utiles pour l'un ou l'autre:

>>> class Sic(object): pass
... 
>>> print str(Sic())
<__main__.Sic object at 0x8b7d0>
>>> print repr(Sic())
<__main__.Sic object at 0x8b7d0>
>>> 

comme vous voyez -- aucune différence, et aucune information au-delà de la classe et de l'objet id . Si vous remplacez uniquement l'un des deux...:

>>> class Sic(object): 
...   def __repr__(object): return 'foo'
... 
>>> print str(Sic())
foo
>>> print repr(Sic())
foo
>>> class Sic(object):
...   def __str__(object): return 'foo'
... 
>>> print str(Sic())
foo
>>> print repr(Sic())
<__main__.Sic object at 0x2617f0>
>>> 

comme vous le voyez, si vous outrepassez __repr__ , c'est aussi utilisé pour __str__ , mais pas vice versa.

autres informations cruciales à savoir: __str__ sur intégré le sur le conteneur utilise le __repr__ , PAS le __str__ , pour les éléments qu'il contient. Et, en dépit des mots sur le sujet trouvés dans les docs typiques, peu de gens dérange faire le __repr__ des objets être une chaîne que eval peut utiliser pour construire un objet égal (c'est juste trop dur, et ne pas savoir comment le module concerné a été effectivement importé rend en fait flat out impossible).

donc, mon conseil: se concentrer sur la fabrication __str__ raisonnablement lisible par l'homme, et __repr__ aussi sans ambiguïté que vous le pouvez, même si cela interfère avec l'objectif fuzzy inaccessible de faire __repr__ valeur retournée acceptable comme entrée à __eval__ !

326
répondu Alex Martelli 2009-09-17 04:49:40

__repr__ : la représentation de l'objet python habituellement eval le convertira de nouveau en cet objet

__str__ : est-ce que ce que vous pensez est cet objet sous forme de texte

p.ex.

>>> s="""w'o"w"""
>>> repr(s)
'\'w\\'o"w\''
>>> str(s)
'w\'o"w'
>>> eval(str(s))==s
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1
    w'o"w
       ^
SyntaxError: EOL while scanning single-quoted string
>>> eval(repr(s))==s
True
145
répondu Andrew Clark 2012-08-15 19:40:17

En bref, l'objectif de la __repr__ est d'être sans équivoque et __str__ lisible.

voici un bon exemple:

>>> import datetime
>>> today = datetime.datetime.now()
>>> str(today)
'2012-03-14 09:21:58.130922'
>>> repr(today)
'datetime.datetime(2012, 3, 14, 9, 21, 58, 130922)'

lire cette documentation pour repr:

repr(object)

renvoie une chaîne contenant une représentation imprimable d'un objet. Il s'agit de la même valeur obtenue par conversions (inverse). citation.) Il est parfois utile de pouvoir accéder à cette opération une fonction ordinaire. Pour de nombreux types, cette fonction fait une tentative pour retourner une chaîne qui donnerait un objet avec la même valeur lorsque le passé à eval() , sinon la représentation est une chaîne entre crochets qui contient le nom du type de l'objet avec des informations supplémentaires souvent, y compris le nom et adresse de l'objet. Une classe peut contrôler ce que cette fonction retourner pour ses instances en définissant une méthode __repr__() .

Voici la documentation pour str:

str(object='')

retourner une corde contenant un joli imprimable représentation d'un objet. Pour les cordes, ceci renvoie la corde m'. La différence avec repr(object) est que str(object) ne fait pas toujours essayer de retourner une chaîne qui est acceptable pour eval() ; son le but est de retourner une chaîne imprimable. Si aucun argument n'est donné, renvoie la chaîne vide, '' .

118
répondu bitoffdev 2013-10-28 00:23:46

Quelle est la différence entre __str__ et __repr__ en Python?

__str__ ("dunder (double-underscore) string") et __repr__ ("dunder-repper" pour "representation") sont deux méthodes spéciales qui renvoient des chaînes basées sur l'état de l'objet.

__repr__ fournit un comportement de sauvegarde si __str__ est manquant.

Donc on devrait d'abord écrire un __repr__ qui vous permet de réinstenter un objet équivalent à partir de la chaîne de caractères qu'il renvoie, par exemple en utilisant eval ou en le tapant dans caractère pour caractère dans un shell Python.

à tout moment plus tard, on peut écrire un __str__ pour une représentation en chaîne lisible par l'utilisateur de l'instance, quand on le juge nécessaire.

__str__

si vous imprimez un objet, ou le passez à format , str.format , ou str , alors si un __str__ la méthode est définie, cette méthode sera appelée, sinon, __repr__ sera utilisé.

__repr__

la méthode __repr__ est appelée par la fonction repr et est ce qui se répercute sur votre shell python quand il évalue une expression qui renvoie un objet.

Puisqu'il fournit une sauvegarde pour __str__ , si vous pouvez n'en écrire qu'un, en commençant par __repr__

Voici l'aide intégrée sur repr :

repr(...)
    repr(object) -> string

    Return the canonical string representation of the object.
    For most object types, eval(repr(object)) == object.

C'est-à-dire, pour la plupart des objets, si vous tapez ce qui est imprimé par repr , vous devriez pouvoir créer un objet équivalent. mais ce n'est pas l'implémentation par défaut.

mise en œuvre par défaut de __repr__

l'objet par défaut __repr__ est ( C source Python ) quelque chose comme:

def __repr__(self):
    return '<{0}.{1} object at {2}>'.format(
      self.__module__, type(self).__name__, hex(id(self)))

qui signifie par défaut que vous imprimerez le module d'où provient l'objet, le nom de classe et la représentation hexadécimale de son emplacement en mémoire-par exemple:

<__main__.Foo object at 0x7f80665abdd0>

cette information n'est pas très utile, mais il n'y a aucun moyen de déduire comment on pourrait créer avec précision une représentation canonique d'une instance donnée, et c'est mieux que rien, au moins nous disant comment nous pourrions l'identifier de façon unique dans la mémoire.

comment __repr__ peut-il être utile?

regardons à quel point il peut être utile, en utilisant le shell Python et les objets datetime . Tout d'abord, nous devons importer le datetime module:

import datetime

si nous appelons datetime.now dans le shell, nous verrons tout ce dont nous avons besoin pour recréer un objet datetime équivalent. Il est créé par le datetime __repr__ :

>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)

si nous imprimons un objet datetime, nous voyons un format agréable lisible par l'homme (en fait, ISO). Ceci est implémenté par __str__ de datetime:

>>> print(datetime.datetime.now())
2015-01-24 20:05:44.977951

il est simple de recréer l'objet que nous avons perdu parce que nous ne l'avons pas assigné à une variable en copiant et collant à partir de la sortie __repr__ , puis en l'imprimant, et nous l'obtenons dans la même sortie lisible par l'homme que l'autre objet:

>>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(the_past)
2015-01-24 20:05:36.491180

comment les mettre en œuvre?

pendant que vous développez, vous voudrez être en mesure de reproduire des objets dans le même état, si possible. Ceci, par exemple, est la façon dont l'objet datetime définit __repr__ ( Python source ). Il est assez complexe, parce que de tous les attributs nécessaires pour reproduire un tel objet:

def __repr__(self):
    """Convert to formal string, for repr()."""
    L = [self._year, self._month, self._day, # These are never zero
         self._hour, self._minute, self._second, self._microsecond]
    if L[-1] == 0:
        del L[-1]
    if L[-1] == 0:
        del L[-1]
    s = ", ".join(map(str, L))
    s = "%s(%s)" % ('datetime.' + self.__class__.__name__, s)
    if self._tzinfo is not None:
        assert s[-1:] == ")"
        s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
    return s

si vous voulez que votre objet ait une représentation plus lisible, vous pouvez implémenter __str__ suivant. Voici comment l'objet datetime ( source Python ) implémente __str__ , ce qu'il fait facilement car il a déjà une fonction pour l'afficher au format ISO:

def __str__(self):
    "Convert to string, for str()."
    return self.isoformat(sep=' ')

Set __repr__ = __str__ ?

c'est une critique d'une autre réponse ici qui suggère de mettre __repr__ = __str__ .

réglage __repr__ = __str__ est stupide - __repr__ est un repli pour __str__ et un __repr__ , écrits pour l'usage des développeurs dans le débogage, devraient être écrits avant d'écrire un __str__ .

Vous avez besoin d'un __str__ seulement quand vous avez besoin d'une représentation textuelle de l'objet.

Conclusion

définir __repr__ pour les objets que vous écrivez de sorte que vous et d'autres développeurs ont un exemple reproductible lorsque vous l'utilisez que vous développez. Définir __str__ quand vous avez besoin d'un lisible par l'homme représentation sous forme de chaîne.

89
répondu Aaron Hall 2017-02-25 20:05:23

outre toutes les réponses données, je voudrais ajouter quelques points : -

1) __repr__() est invoqué lorsque vous écrivez simplement le nom de l'objet sur la console Python interactive et appuyez sur Entrée.

2) __str__() est invoqué lorsque vous utilisez object with print statement.

3) si __str__ est manquant, alors imprimer et toute fonction utilisant str() invoque __repr__() de l'objet.

4) __str__() de conteneurs, lorsqu'il est invoqué exécutera __repr__() méthode de ses éléments contenus.

5) str() appelé dans __str__() pourrait potentiellement se reproduire sans un cas de base, et erreur sur la profondeur de récursion maximale.

6) __repr__() peut appeler repr() qui tentera d'éviter la récursion infinie automatiquement, en remplaçant un objet déjà représenté par ... .

14
répondu Mangu Singh Rajpurohit 2018-06-05 07:47:41

À la page 358 du livre script Python pour le calcul de la science par Hans Petter Langtangen, il indique clairement que

  • le __repr__ vise une représentation en chaîne complète de l'objet;
  • le __str__ est de retourner une belle corde pour l'impression.

donc, je préfère les comprendre comme

  • repr = reproduire
  • str = chaîne de caractères (représentation)

du point de vue de l'utilisateur bien que ce soit un malentendu que j'ai fait en apprenant python.

un petit mais bon exemple est également donné sur la même page comme suit:

exemple

In [38]: str('s')
Out[38]: 's'

In [39]: repr('s')
Out[39]: "'s'"

In [40]: eval(str('s'))
Traceback (most recent call last):

  File "<ipython-input-40-abd46c0c43e7>", line 1, in <module>
    eval(str('s'))

  File "<string>", line 1, in <module>

NameError: name 's' is not defined


In [41]: eval(repr('s'))
Out[41]: 's'
13
répondu Yong Yang 2018-01-29 05:47:49

En toute honnêteté, eval(repr(obj)) n'est jamais utilisé. Si vous vous trouvez à l'utiliser, vous devez arrêter, car eval est dangereux, et les chaînes de caractères sont un moyen très inefficace de sérialiser vos objets (utilisez pickle à la place).

par conséquent, je recommande le réglage __repr__ = __str__ . La raison en est que str(list) appelle repr sur les éléments (je considère que c'est l'un des plus gros défauts de conception de Python qui n'a pas été abordé par Python 3). Un le repr réel ne sera probablement pas très utile comme la sortie de print [your, objects] .

pour qualifier ceci, d'après mon expérience, le cas d'utilisation le plus utile de la fonction repr est de mettre une chaîne dans une autre chaîne (en utilisant le formatage de chaîne). De cette façon, vous n'avez pas à vous soucier d'échapper à des citations ou quoi que ce soit. Mais notez qu'il n'y a pas de eval qui se passe ici.

11
répondu asmeurer 2015-04-14 00:30:54

pour le dire simplement:

__str__ est utilisé pour montrer une représentation en chaîne de votre objet à lire facilement par d'autres.

__repr__ est utilisé pour montrer une représentation en chaîne de l'objet .

disons que je veux créer une classe Fraction où la représentation string d'une fraction est '(1/2) ' et l'objet (Classe Fraction) doit être représenté comme 'Fraction (1,2) '

pour que nous puissions créer une classe de Fraction simple:

class Fraction:
    def __init__(self, num, den):
        self.__num = num
        self.__den = den

    def __str__(self):
        return '(' + str(self.__num) + '/' + str(self.__den) + ')'

    def __repr__(self):
        return 'Fraction (' + str(self.__num) + ',' + str(self.__den) + ')'



f = Fraction(1,2)
print('I want to represent the Fraction STRING as ' + str(f)) # (1/2)
print('I want to represent the Fraction OBJECT as ', repr(f)) # Fraction (1,2)
10
répondu Zer0 2016-07-28 04:08:32

à Partir de http://pyref.infogami.com/__str__ par effbot:

__str__ " calcule la représentation de chaîne "informelle" d'un objet. Ceci diffère de __repr__ en ce qu'il n'est pas nécessaire que ce soit une expression valide de Python: une représentation plus pratique ou concise peut être utilisée à la place."

9
répondu Casebash 2017-10-27 22:09:05

Un aspect qui manque dans les autres réponses. C'est vrai qu'en général, le modèle est:

  • le But de __str__ : lisible par l'homme
  • but de __repr__ : non ambigu, peut-être lisible par machine via eval

malheureusement, cette différenciation est imparfaite, car le REPL Python et aussi IPython utilisent __repr__ pour imprimer des objets dans une console REPL (voir questions connexes pour Python et IPython ). Ainsi, les projets qui sont ciblés pour le travail sur console interactive (par exemple, Numpy ou Pandas) ont commencé à ignorer les règles ci-dessus et à fournir une implémentation __repr__ lisible par l'humain à la place.

6
répondu bluenote10 2017-05-26 12:33:51

str - Crée un nouvel objet string à partir de l'objet donné.

repr - renvoie la représentation canonique de l'objet.

les différences:

str ():

  • rend l'objet lisible
  • génère la sortie pour l'utilisateur final

repr ():

  • a besoin d'un code qui reproduit l'objet
  • génère la sortie pour le développeur
5
répondu Inconnu 2016-12-04 16:18:48

excellentes réponses couvrent déjà la différence entre __str__ et __repr__ , qui pour moi se résume à la première étant lisible même par un utilisateur final, et le dernier étant aussi utile que possible pour les développeurs. Étant donné que, je trouve que l'implémentation par défaut de __repr__ échoue souvent à atteindre cet objectif parce qu'il omet informations utiles aux développeurs.

Pour cette raison, si j'ai un assez simple __str__ , je généralement juste essayer d'obtenir le meilleur des deux mondes avec quelque chose comme:

def __repr__(self):
    return '{0} ({1})'.format(object.__repr__(self), str(self))
4
répondu orome 2018-04-25 19:35:20
>>> print(decimal.Decimal(23) / decimal.Decimal("1.05"))
21.90476190476190476190476190
>>> decimal.Decimal(23) / decimal.Decimal("1.05")
Decimal('21.90476190476190476190476190')

quand print() est appelé sur le résultat de décimal.Décimal(23) / décimal.Décimal ("1.05") le nombre brut est imprimé; cette sortie est en string form qui peut être atteint avec __str __(). Si nous entrons simplement l'expression nous obtenons une décimale.Sortie décimale-cette sortie est dans la forme de représentation qui peut être réalisée avec __repr __(). Tous les objets Python ont deux formes de sortie. La forme de chaîne de caractères est conçue pour être lisible par l'homme. La forme de représentation est conçue pour produire une sortie qui, si elle était transmise à un interpréteur Python, produirait (si possible) à nouveau l'objet représenté

3
répondu BattleDrum 2015-07-15 10:30:35

une chose importante à garder à l'esprit est que le conteneur __str__ utilise des objets contenus __repr__ .

>>> from datetime import datetime
>>> from decimal import Decimal
>>> print (Decimal('52'), datetime.now())
(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 51, 26, 185000))
>>> str((Decimal('52'), datetime.now()))
"(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 52, 22, 176000))"

Python favorise sans ambiguïté sur la lisibilité , le __str__ appel d'un tuple appelle les objets contenus " __repr__ , le " formel " représentation d'un objet. Bien que la représentation formelle est plus difficile à lire qu'un informel, il est sans ambiguïté et plus robuste contre les bugs.

3
répondu zangw 2015-11-16 03:02:21
"A basic requirement for a Python object is to provide usable 
 string   representations of itself, one used for debugging and
 logging, another for presentation to end users. That is why the  
 special methods __repr__ and __str__ exist in the data model."

du livre: Fluent Python

3
répondu Ijaz Khan 2017-04-04 12:35:08

en un mot:

class Demo:
  def __repr__(self):
    return 'repr'
  def __str__(self):
    return 'str'

demo = Demo()
print(demo) # use __str__, output 'str' to stdout

s = str(demo) # __str__ is used, return 'str'
r = repr(demo) # __repr__ is used, return 'repr'

import logging
logger = logging.getLogger(logging.INFO)
logger.info(demo) # use __str__, output 'str' to stdout

from pprint import pprint, pformat
pprint(demo) # use __repr__, output 'repr' to stdout
result = pformat(demo) # use __repr__, result is string which value is 'str'
2
répondu ShadowWalker 2018-04-16 09:28:38

Comprendre __str__ et __repr__ intuitivement et de manière permanente les distinguer.

__str__ retourner la chaîne de caractères corps déguisé d'un objet donné pour lisibilité d'yeux

__repr__ retourner le corps de chair réel d'un objet donné (retourner lui-même) pour identifier sans ambiguïté.

voir dans un exemple

In [30]: str(datetime.datetime.now())
Out[30]: '2017-12-07 15:41:14.002752'
Disguised in string form

comme __repr__

In [32]: datetime.datetime.now()
Out[32]: datetime.datetime(2017, 12, 7, 15, 43, 27, 297769)
Presence in real body which allows to be manipulated directly.

nous pouvons faire une opération arithmétique sur __repr__ résultats commodément.

In [33]: datetime.datetime.now()
Out[33]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521)
In [34]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521) - datetime.datetime(2
    ...: 017, 12, 7, 15, 43, 27, 297769)
Out[34]: datetime.timedelta(0, 222, 443752)

si s'applique l'opération sur __str__

In [35]: '2017-12-07 15:43:14.002752' - '2017-12-07 15:41:14.002752'
TypeError: unsupported operand type(s) for -: 'str' and 'str'

ne renvoie que l'erreur.

autre exemple.

In [36]: str('string_body')
Out[36]: 'string_body' # in string form

In [37]: repr('real_body')
Out[37]: "'real_body'" #its real body hide inside

espérons que cela vous aidera à construire des bases concrètes pour explorer plus de réponses.

1
répondu JawSaw 2018-01-02 10:36:32

tellement plus clair de blog

str est comme toString. créé pour que vous puissiez imprimer les données repr , c'est comme sérialiser, ou de la saumure. Comment puis-je recréer cet objet si je dois le faire en utilisant eval ()

>>> import datetime
>>> now = datetime.datetime.now() 
>>> str(now)
'2015-04-04 20:51:31.766862'
>>> repr(now)
'datetime.datetime(2015, 4, 4, 20, 51, 31, 766862)'
>>mydate = eval(repr(now))
1
répondu Mickey Perlstein 2018-04-01 13:32:34

__repr__ est utilisé partout, sauf par print et str lorsqu'un __str__ est défini

0
répondu trthhrtz 2018-05-08 08:49:10