Django: Timezone

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
lunas
User
Beiträge: 87
Registriert: Samstag 2. Dezember 2006, 10:56

Django: Timezone

Beitragvon lunas » Montag 19. Januar 2009, 15:05

Hi,

gibt es eine Möglichkeit Zeiten von Django so zu ändern, dass eine vorher definierte Zeitzone für die Anzeige genutzt wird (oder die des Browser OS, wenn das übertragen werden sollte)? In settings.TIME_ZONE kann man zwar die Zeitzone einstellen, zu der Django automatisch sämtliche Zeitangaben konvertiert, aber das bringt mir nicht viel, da die Seite in verschiedenen Zeitzonen arbeiten soll und jeweils die lokale Zeit angezeigt werden soll (speichere sämtliche Zeitangaben in GMT).

Was ich nun nun bräuchte wäre evtl. ein (session-abhängiger) Filter, der zur richtigen Zeitzone konvertiert...

Irgendwelche Ideen?
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Beitragvon sma » Dienstag 20. Januar 2009, 08:50

Zeitzonen in Python erfordern erstmal ein neues Paket: pytz. Dummerweise kann Python in der Standardinstallation nicht mit Zeitzonen umgehen. Dann würde ich einfach in einem UserProfile den Benutzer seine Lieblingszeitzone einstellen lassen und diese dann über den in der Session gemerkten User zu berücksichtigen. Vielleicht hilft dir ja auch http://www.djangosnippets.org/snippets/183/ oder http://code.google.com/p/django-timezones/

Stefan
lunas
User
Beiträge: 87
Registriert: Samstag 2. Dezember 2006, 10:56

Beitragvon lunas » Freitag 30. Januar 2009, 18:27

Vielen Dank für den Hinweis. Den Filter konnte ich auch schon implementieren, aber so recht gefällt mir die Lösung noch nicht, da jedes mal das User Objekt im Template mitgegeben werden muss.

Code: Alles auswählen

from django import template

def user_timezone(value, user):
  # timezone conversion
  pass

register = template.Library()
register.filter('user_timezone', user_timezone)

Das kann zwar noch vereinfacht werden, damit man nicht jedes Mal bei der HttpResponse den user explizit mitgeben muss:

Code: Alles auswählen

# settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
    'mysite.processor_file_name.user'
)

# mysite/processor_file_name.py
def user(request):   
  return {'user':request.user }

aber trotzdem scheint mir das Übergeben des Users im Template überflüssig. Gibt es vielleicht die Möglichkeit den User, der das soeben generierte Template abfragt innerhalb der Filter-Funktion zu ermitteln?

Vielen Dank.
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Beitragvon Dauerbaustelle » Freitag 30. Januar 2009, 18:40

Hm. Du könntest einen Hack zusammenschrauben, aber toll wäre das auch nicht:

Code: Alles auswählen

# models
class YourModel:
    @property
    def usertime(self):
        return (self.timestamp, self.user)


Dann passiert zwar im Prinzip das Selbe, allerdings musst du nur noch `article.usertime|user_timezone` machen. Optional könntest du den Filter gleich in die Methode `usertime` einbauen, dann ist alles was du schreibst `article.usertime`. Oder so.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Beitragvon sma » Sonntag 1. Februar 2009, 10:25

Vielleicht ist es mit einem Custom-Tag einfacher? Z.B. {% usertime article.create_at %}. Der Tag hätte Zugriff auf den Kontext und könnte sich dort den per Request-Prozessor (dafür gibt es übrigens schon einen fertigen) in den Kontext eingetragenen User herausholen.

Stefan
tarak
User
Beiträge: 2
Registriert: Montag 9. Februar 2009, 16:15

Gegenfrage

Beitragvon tarak » Montag 9. Februar 2009, 16:56

Snippet 183 und django-timezones find ich auch nicht so gut. Vor allem wenn man sich das Alter des Snippets anschaut. An "Django-Timezones" wird zwar aktuell gebaut (siehe SVN-Repo), gefällt mir aber auch nicht so gut. Ich benutze "Django-Timezones" allerdings wegen des TimeZoneField. Bin zu faul das mit PyTZ selber zu machen.

Das gesamte User-Objekt mit in den Context zu packen finde ich, ehrlich gesagt, fragwürdig. Das schließt, soweit ich weiß, alle Relationen ein. Mit Kanonen auf Spatzen geschossen... Das Wort "Sicherheit" sei hier auch mal kurz erwähnt, nebenbei. Und vor allem braucht man nicht immer den User. Zudem: Spart DB-Abfragen...

Per Middleware kann man ja z.B. die Sprache nach den Einstellungen des Users einstellen... Da würde ich auch gleich die Zeitzone irgendwo hin packen. Allerdings unabhängig vom "User", in die Session meiner Meinung nach. Oder gleich in den Request, der ist ja immer verfügbar. Ob das so klug ist frag ich mich allerdings gerade auch.... Babeldjango macht allerdings genau das per Middleware und bringt auch Filter mit, um die Zeit ins rischdische Format zu formatieren. Locale = de-de, Datum = 01.12.2345

Bezüglich User-Einstellungen und Middleware würd ich nen Blick auf Pinax werfen. Im SVN unter so genannten "lokalen Applikationen" (glaub ich) findet man in einer App namens misc (oder woanders) eine LocaleMiddleware die bei jedem eingeloggtem User die Sprache einstellt...

Dann stellt sich da noch eine Frage: Wenn der User Zeiten oder Datum mit Zeitangaben (DATETIME oder TIME) in Formularen macht, denkt er doch bestimmt, dies innerhalb seiner Zeit-Zone zu machen. Was passiert dann bei der Verarbeitung? Will man in jeder View die Zeit von Hand anfassen und in die richtige Zeitzone konvertieren? Heiden-Arbeit bei größeren Projekten, oder?

Das zu lösen finde ich viel spannender!!!

Ich bin ja dafür, das Django das "unter der Haube" löst... Diskussion läuft da schon seit längerem. Dann hätte sich das Thema im Forum hier eh von selbst erledigt.
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

Re: Gegenfrage

Beitragvon apollo13 » Montag 9. Februar 2009, 20:14

tarak hat geschrieben:Das gesamte User-Objekt mit in den Context zu packen finde ich, ehrlich gesagt, fragwürdig. Das schließt, soweit ich weiß, alle Relationen ein. Mit Kanonen auf Spatzen geschossen... Das Wort "Sicherheit" sei hier auch mal kurz erwähnt, nebenbei. Und vor allem braucht man nicht immer den User. Zudem: Spart DB-Abfragen...


Das user object ist schon im Context! (zumindest so lang du http://docs.djangoproject.com/en/dev/re ... rs-request enablest). Zugriff hast du darauf über request.user. Django macht so oder so jeden request eine Db Abfrage für den User, und nein relations werden erst geladen wenn du auf sie zugreifst, ala request.user.groups...
Und nein Sicherheit braucht man hier nicht zu erwähnen...

Dann stellt sich da noch eine Frage: Wenn der User Zeiten oder Datum mit Zeitangaben (DATETIME oder TIME) in Formularen macht, denkt er doch bestimmt, dies innerhalb seiner Zeit-Zone zu machen. Was passiert dann bei der Verarbeitung? Will man in jeder View die Zeit von Hand anfassen und in die richtige Zeitzone konvertieren? Heiden-Arbeit bei größeren Projekten, oder?

Nein ist es normalerweise nicht, man schreibt sich 2,3 Funktionen und konvertiert dann einfach, im Grunde könnte schon das Feld im Formular diese Aufgabe übernehmen (def clean, anyone?). Und selbst bei Modelforms kannst du die Felder überschreiben, also ist das fast keine Arbeit.

Ich bin ja dafür, das Django das "unter der Haube" löst... Diskussion läuft da schon seit längerem. Dann hätte sich das Thema im Forum hier eh von selbst erledigt.

Wo? Link bitte.
tarak
User
Beiträge: 2
Registriert: Montag 9. Februar 2009, 16:15

Beitragvon tarak » Dienstag 10. Februar 2009, 14:49

Wo? Link bitte.


Gibt keinen bestimmten Link... Hab mir mit den Zeitzonen die selben Gedanken gemacht wie Lunas und herum gesucht. Mehrere Tage lang Mailinglisten gelesen, gegoogelt, etc... Ist mein "Gesamt-Eindruck" von der Problematik. Die Django-Entwickler sind sich des Problems bewusst, meiner Erinnerung nach war die Aussage da: Design decision needed (kann mich auch irren)...

Django macht so oder so jeden request eine Db Abfrage für den User


Kann man abstellen. Will jetzt hier nicht theoretisch werden. Ich bleib dabei, will mich nicht auf request.user verlassen. Zeitzonen gehen auch ohne eingeloggten user...

Danke für das klären meiner Frage wegen relations, Apollo13!!! Hat mir Arbeit gespart. (Ich fauler Hund, nimm's mir nicht übel...)

Sicher kann man da 2,3 Funktionen schreiben, reduziert das ganze auf wenige Zeilen in den Views oder in Forms, die wohl trotzdem alle geändert werden müssten, wenn sich die Funktion ändert, bsp.-weise ein Argument mehr, oder? Sowas ist absolut machbar, will ich nicht bestreiten, aber auch anfällig. Ich weiss dann immer, wo ich vor Monaten was gemacht hab, was ich mittlerweile schon wieder vergessen hab. Eigentlich benutz ich ja Django, um genau von sowas wegzukommen... By the way, I know "def clean", man...

Noch was: Django-Timezones bringt zwar ein TimeZoneField mit, aber das ist nur in Englisch. Wer sich das anschaut, der kann sich Gedanken über eine Übersetzung ins Deutsche machen.

Und Django-Timezones vom SVN ist z.Zt. strange (kaputt?), siehe

http://code.google.com/p/django-timezones/issues/detail?id=14

Comment 2 is von mir..
Benutzeravatar
jens
Moderator
Beiträge: 8458
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Beitragvon jens » Dienstag 24. November 2009, 15:34

Das mit der Zeitzone interessiert mich nun auch ein wenig... Denn die Zeiten sind auf meiner Webseite falsch ;)
Bei meinem Blog nutzte ich teilweise den template Filter "timesince"...

Aber wie kann man es richtig machen?

Eine Möglichkeit wäre es doch, alles in UTC zu speichern und beim Client per JS bzw. jQuery die zeiten zu korrigieren...

Dumm ist allerdings, das django von sich auf kein UTC verwendet, siehe auch:
http://www.python-forum.de/topic-13534.html
http://www.python-forum.de/topic-19956.html

EDIT: Ach, das Problem an "timesince" ist natürlich, das es quasi nicht cacheable ist.

Ich Frage mich warum django z.B. beim DateTimeField mit "auto_now" bzw. "auto_now_add" ein datetime.now() benutzt und kein datetime.utcnow()... Weiß jemand warum???
EDIT2: Hab es mal nachgefragt: http://groups.google.com/group/django-d ... ef33c88bf3

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Moderator
Beiträge: 8458
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Beitragvon jens » Dienstag 24. November 2009, 18:22

Geht dieser Template Filter auch einfacher (ein großer Teil ist von contrib/syndication/feeds.py):

Code: Alles auswählen

from datetime import datetime, timedelta

def _get_offset():
    now = datetime.now()
    utcnow = datetime.utcnow()

    # Must always subtract smaller time from larger time here.
    if utcnow > now:
        sign = -1
        tzDifference = (utcnow - now)
    else:
        sign = 1
        tzDifference = (now - utcnow)

    # Round the timezone offset to the nearest half hour.
    tzOffsetMinutes = sign * ((tzDifference.seconds / 60 + 15) / 30) * 30
    tzOffset = timedelta(minutes=tzOffsetMinutes)
    return tzOffset

_TZ_OFFSET = _get_offset()

def to_utc(value, arg=None):
    value = value - _TZ_OFFSET
    return value

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Moderator
Beiträge: 8458
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Beitragvon jens » Donnerstag 26. November 2009, 09:41

Offensichtlich ist django in der Sache nicht gut durchdacht. Sehr lesenswert: http://code.djangoproject.com/ticket/10587

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Beitragvon mkesper » Donnerstag 26. November 2009, 11:47

jens hat geschrieben:Eine Möglichkeit wäre es doch, alles in UTC zu speichern und beim Client per JS bzw. jQuery die zeiten zu korrigieren...

UN*X macht sowas schon seit 30 Jahren aus dem Grund, dass man sich anderenfalls schwer ins Knie schiessen kann. Genauso wie man Preise immer netto speichert gehören Uhrzeiten immer in UTC abgespeichert.
Benutzeravatar
jens
Moderator
Beiträge: 8458
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Beitragvon jens » Donnerstag 26. November 2009, 18:02

hab mir ein kleines "timezone info plugin" für PyLucid geschrieben: http://trac.pylucid.net/changeset/2436

Normalerweise sehen die Ausgaben so ähnlich aus:
[code=] server information
settings.TIME_ZONE
America/Chicago
TZ from os.environ
America/Chicago
datetime now
26. Nov. 2009, 10:56
datetime UTC now
26. Nov. 2009, 16:56
datetime to UTC (calculated with PyLucid template filter 'to_utc')
26. Nov. 2009, 16:56
UTC offset
-1 day, 18:00:00

Client information via JavaScript
Current time from JavaScript
Do 26 Nov 2009 17:53:30 CET
JavaScript timezone offset
-1 [/code]

Wenn man aber settings.TIME_ZONE="" macht, dann sieht das so aus:
[code=] server information
settings.TIME_ZONE
TZ from os.environ
datetime now
26. Nov. 2009, 16:48
datetime UTC now
26. Nov. 2009, 16:48
datetime to UTC (calculated with PyLucid template filter 'to_utc')
26. Nov. 2009, 16:48
UTC offset
0:00:00

Client information via JavaScript
Current time from JavaScript
Do 26 Nov 2009 17:48:54 CET
JavaScript timezone offset
-1 [/code]

Speichert django also Zeiten in UTC, wenn man TIME_ZONE="" setzt?
So sieht es zumindest aus, wenn man datetime.now() und datetime.utcnow() vergleicht.

Wenn das so ist, dann wäre das doch jetzt schon eine gute Lösung, oder nicht???

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Moderator
Beiträge: 8458
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Beitragvon jens » Montag 30. November 2009, 18:11

Hab mich dazu entschieden settings.TIME_ZONE auf "Europe/London" zu stellen, was Greenwich Mean Time bzw. GMT-0 ist. Das ist expliziter als einfach ein Leeren String zu übergeben ;)

Django sollte das in den Voreinstellung auch machen. Ist IMHO besser als "America/Chicago".

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Beitragvon mkesper » Dienstag 1. Dezember 2009, 11:45

Keine gute Idee, da Europe/London auch Daylight Saving Times beinhalten kann: http://www.timezoneconverter.com/cgi-bi ... ope/London

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder