Ticket #17738: 17738.diff

File 17738.diff, 12.7 KB (added by Aymeric Augustin, 13 years ago)
  • docs/topics/i18n/timezones.txt

     
    66
    77.. versionadded:: 1.4
    88
     9.. _time-zones-overview:
     10
    911Overview
    1012========
    1113
     
    4446    controls if Django should activate format localization. See
    4547    :doc:`/topics/i18n/formatting` for more details.
    4648
     49If you're stumbling on a particular problem, start with the :ref:`time zone
     50FAQ <time-zones-faq>`.
     51
    4752Concepts
    4853========
    4954
     
    132137The **default time zone** is the time zone defined by the :setting:`TIME_ZONE`
    133138setting.
    134139
    135 When pytz_ is available, Django loads the definition of the default time zone
    136 from the `tz database`_. This is the most accurate solution. Otherwise, it
    137 relies on the difference between local time and UTC, as reported by the
    138 operating system, to compute conversions. This is less reliable, especially
    139 around DST transitions.
    140 
    141140The **current time zone** is the time zone that's used for rendering.
    142141
    143 You should set it to the end user's actual time zone with
     142You should set the current time zone to the end user's actual time zone with
    144143:func:`~django.utils.timezone.activate`. Otherwise, the default time zone is
    145144used.
    146145
     
    173172Most websites who care about time zones just ask users in which time zone they
    174173live and store this information in the user's profile. For anonymous users,
    175174they use the time zone of their primary audience or UTC. pytz_ provides
    176 helpers, like a list of time zones per country, that you can use to pre-select
     175helpers_, like a list of time zones per country, that you can use to pre-select
    177176the most likely choices.
    178177
    179178Here's an example that stores the current timezone in the session. (It skips
     
    217216        <input type="submit" value="Set" />
    218217    </form>
    219218
     219.. _time-zones-in-forms:
     220
    220221Time zone aware input in forms
    221222==============================
    222223
     
    464465Or, if they're small enough, you can simply edit them to add the UTC offset
    465466that matches your :setting:`TIME_ZONE` to each serialized datetime.
    466467
     468.. _time-zones-faq:
     469
     470FAQ
     471===
     472
     473Setup
     474-----
     475
     4761. **I don't need multiple time zones. Should I enable time zone support?**
     477
     478   Yes. When time-zone support is enabled, Django uses a more accurate model
     479   of local time. This shields you from subtle and unreproducible bugs around
     480   DST transitions. Remember that your website runs 24/7!
     481
     482   In this regard, time zones is comparable to ``unicode`` in Python. At first
     483   it's hard. You get encoding and decoding errors. Then you learn the rules.
     484   And some problems disappear -- you never get mangled output again when your
     485   application receives non-ASCII input.
     486
     487   When you enable time zone support, you'll encounter some errors because
     488   you're using naive datetimes where Django expects aware datetimes. Such
     489   errors show up when running tests and they're easy to fix. You'll quickly
     490   learn how to avoid invalid operations.
     491
     492   On the other hand, bugs caused by the lack of time zone support are much
     493   harder to prevent, diagnose and fix. Anything that involves scheduled tasks
     494   or datetime arithmetic is a candidate for subtle bugs that will bite you
     495   only once or twice a year.
     496
     497   For these reasons, time zone support is enabled by default in new projects,
     498   and you should keep it unless you have a very good reason not to.
     499
     5002. **I've enabled time zone support, am I safe?**
     501
     502   Maybe. You're better protected from DST-related bugs, but you can still
     503   shoot yourself into the foot by carelessly turning naive datetimes into
     504   aware datetimes, and vice-versa.
     505
     506   If your application connects to other systems, for instance if it queries
     507   a webservice, make sure datetimes are properly specified. To transmit
     508   datetimes safely, their representation should include the UTC offset, or
     509   their values should be in UTC (or both!).
     510
     511   Finally, our calendar system contains interesting traps for computers::
     512
     513       >>> import datetime
     514       >>> def substract_one_year(value):       # DON'T DO THAT!
     515       ...     return value.replace(year=value.year - 1)
     516       >>> one_year_before(datetime.datetime(2012, 3, 1, 10, 0))
     517       datetime.datetime(2011, 3, 1, 10, 0)
     518       >>> one_year_before(datetime.datetime(2012, 2, 29, 10, 0))
     519       Traceback (most recent call last):
     520       ...
     521       ValueError: day is out of range for month
     522
     523   (To implement this function, you must decide whether 2012-02-29 minus
     524   one year is 2011-02-28 or 2011-03-01, which depends on your business
     525   requirements.)
     526
     5273. **Should I install pytz?**
     528
     529   Yes. Django has a policy of not requiring external dependencies, and for
     530   this reason pytz_ is optional. However, it's much safer to install it.
     531
     532   As soon as you activate time zone support, Django needs a definition of the
     533   default time zone. When pytz is available, Django loads this definition
     534   from the `tz database`_. This is the most accurate solution. Otherwise, it
     535   relies on the difference between local time and UTC, as reported by the
     536   operating system, to compute conversions. This is less reliable, especially
     537   around DST transitions.
     538
     539   Furthermore, if you want to support users in more than one time zone, pytz
     540   is the reference for time zone definitions.
     541
     542Troubleshooting
     543---------------
     544
     5451. **My application crashes with** ``TypeError: can't compare offset-naive``
     546   ``and offset-aware datetimes`` **-- what's wrong?**
     547
     548   First, don't panic. Then, let's reproduce this error, simply by comparing a
     549   naive and an aware datetime::
     550
     551       >>> import datetime
     552       >>> from django.utils import timezone
     553       >>> datetime.datetime.utcnow().replace(tzinfo=timezone.utc) == datetime.datetime.utcnow()
     554       Traceback (most recent call last):
     555       ...
     556       TypeError: can't compare offset-naive and offset-aware datetimes
     557
     558   If you encounter this error, most likely, your code is comparing:
     559
     560   - a datetime provided by Django, for instance a value read from a form or
     561     a model field: since you enabled time zone support, it is aware;
     562   - a datetime generated by your code, which is naive (or you wouldn't be
     563     reading this).
     564
     565   Generally, the correct solution is to change your code to use an aware
     566   datetime instead.
     567
     568   If you're writing a pluggable application that's expected to work
     569   independently of the value of :setting:`USE_TZ`, you may find
     570   :func:`django.utils.timezone.now` useful. This function returns the current
     571   date and time as a naive datetime when ``USE_TZ = False`` and as an aware
     572   datetime when ``USE_TZ = True``. You can add or substract
     573   :class:`datetime.timedelta` as needed.
     574
     5752. **I see lots of** ``RuntimeWarning: DateTimeField received a naive
     576   datetime`` ``(YYYY-MM-DD HH:MM:SS)`` ``while time zone support is active``
     577   **-- is it bad?**
     578
     579   When time zone support is enabled, the database layer expects to receive
     580   only aware datetimes from your code. This warning occurs when it receives a
     581   naive datetime. This indicates that you haven't finished porting your code
     582   for time zone support. Please refer to the :ref:`migration guide
     583   <time-zones-migration-guide>` for tips on this process.
     584
     585   In the meantime, for backwards compatibility, the datetime is considered to
     586   be in the default time zone, which is generally what you expect.
     587
     5883. ``now.date()`` **is yesterday! (or tomorrow)**
     589
     590   If you've always used naive datetimes, you probably believe that you can
     591   convert a datetime to a date by calling its :meth:`~datetime.datetime.date`
     592   method. You also consider that a :class:`~datetime.date` is a lot like a
     593   :class:`~datetime.datetime`, except that it's less accurate.
     594
     595   None of this is true in a time zone aware environment::
     596
     597       >>> import datetime
     598       >>> import pytz
     599       >>> paris_tz = pytz.timezone("Europe/Paris")
     600       >>> new_york_tz = pytz.timezone("America/New_York")
     601       >>> paris = paris_tz.localize(datetime.datetime(2012, 3, 3, 1, 30))
     602       # This is the correct way to convert between time zones with pytz.
     603       >>> new_york = new_york_tz.normalize(paris.astimezone(new_york_tz))
     604       >>> paris == new_york, paris.date() == new_york.date()
     605       (True, False)
     606       >>> paris - new_york, paris.date() - new_york.date()
     607       (datetime.timedelta(0), datetime.timedelta(1))
     608       >>> paris
     609       datetime.datetime(2012, 3, 3, 1, 30, tzinfo=<DstTzInfo 'Europe/Paris' CET+1:00:00 STD>)
     610       >>> new_york
     611       datetime.datetime(2012, 3, 2, 19, 30, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>)
     612
     613   As this example shows, the same datetime has a different date, depending on
     614   the time zone in which it is representend. But the real problem is more fundamental.
     615
     616   A datetime represents a **point in time**. It's absolute: it doesn't depend
     617   on anything (barring relativistic effects). On the contrary, a date is a
     618   **calendaring concept**. It's a period of time whose bounds depend on the
     619   time zone in which the date is considered. As you can see, these two
     620   concepts are fundamentally different and converting a datetime to a date
     621   isn't a deterministic operation.
     622
     623   What does this mean in practice?
     624
     625   Generally, you should avoid converting a :class:`~datetime.datetime` to
     626   :class:`~datetime.date`. For instance, you can use the :tfilter:`date`
     627   template filter to only show the date part of a datetime. This filter will
     628   convert the datetime into the current time zone before formatting it,
     629   ensuring the results appear correct for the user.
     630
     631   If you really need to do the conversion yourself, you must ensure the
     632   datetime is converted to the appropriate time zone first. Usually, this
     633   will be the current timezone::
     634
     635       >>> from django.utils import timezone
     636       >>> timezone.activate(pytz.timezone("Asia/Singapore"))
     637       # For this example, we just set the time zone to Singapore, but here's how
     638       # you would obtain the current time zone in the general case.
     639       >>> current_tz = timezone.get_current_timezone()
     640       # Again, this is the correct way to convert between time zones with pytz.
     641       >>> local = current_tz.normalize(paris.astimezone(current_tz))
     642       >>> local
     643       datetime.datetime(2012, 3, 3, 8, 30, tzinfo=<DstTzInfo 'Asia/Singapore' SGT+8:00:00 STD>)
     644       >>> local.date()
     645       datetime.date(2012, 3, 3)
     646
     647Usage
     648-----
     649
     6501. **I have this string** ``"2012-02-21 10:28:45"`` **and I know it's in the**
     651   ``"Europe/Helsinki"`` **time zone. How do I turn that into an aware
     652   datetime?**
     653
     654   This is exactly what pytz_ is for.
     655
     656       >>> from django.utils.dateparse import parse_datetime
     657       >>> naive = parse_datetime("2012-02-21 10:28:45")
     658       >>> import pytz
     659       >>> pytz.timezone("Europe/Helsinki").localize(naive)
     660       datetime.datetime(2012, 2, 21, 10, 28, 45, tzinfo=<DstTzInfo 'Europe/Helsinki' EET+2:00:00 STD>)
     661
     662   Note that ``localize`` is a pytz extension to the :class:`~datetime.tzinfo`
     663   API. Also, you may want to catch :exc:`~pytz.InvalidTimeError`. The
     664   documentation of pytz contains `more examples`_; you should review it
     665   before attempting to manipulate aware datetimes.
     666
     6672. **How can I obtain the current time in the local time zone?**
     668
     669   Well, the first question is, do you really need to?
     670
     671   You should only use local time when you're interacting with humans, and the
     672   template layer provides :ref:`filters and tags <time-zones-in-templates>`
     673   to convert datetimes to the time zone of your choice.
     674
     675   Furthermore, Python knows how to compare aware datetimes, taking into
     676   account UTC offsets when necessary. It's much easier (and possibly faster)
     677   to write all your model and view code in UTC. So, in most circumstances,
     678   the datetime in UTC returned by :func:`django.utils.timezone.now` will be
     679   sufficient.
     680
     681   Now, if you really want the current time in the local time zone, here's
     682   the code::
     683
     684       >>> import datetime
     685       >>> from django.utils import timezone
     686       >>> datetime.datetime.now(tz=timezone.get_default_timezone())
     687       datetime.datetime(2012, 3, 3, 20, 10, 53, 873365, tzinfo=<DstTzInfo 'Europe/Paris' CET+1:00:00 STD>)
     688
     689   In this example, pytz_ is installed and :setting:`TIME_ZONE` is
     690   ``"Europe/Paris"``.
     691
     6923. **How can I see all available time zones?**
     693
     694   pytz_ provides helpers_, including a list of current time zones and a list
     695   of all available time zones -- some of which are only of historical
     696   interest.
     697
    467698.. _pytz: http://pytz.sourceforge.net/
     699.. _more examples: http://pytz.sourceforge.net/#example-usage
    468700.. _these issues: http://pytz.sourceforge.net/#problems-with-localtime
     701.. _helpers: http://pytz.sourceforge.net/#helpers
    469702.. _tz database: http://en.wikipedia.org/wiki/Tz_database
Back to Top