| .. _time-zones: |
| |
| ========== |
| Time zones |
| ========== |
| |
| .. versionadded:: 1.4 |
| |
| .. _time-zones-overview: |
| |
| Overview |
| ======== |
| |
| When support for time zones is enabled, Django stores date and time |
| information in UTC in the database, uses time-zone-aware datetime objects |
| internally, and translates them to the end user's time zone in templates and |
| forms. |
| |
| This is handy if your users live in more than one time zone and you want to |
| display date and time information according to each user's wall clock. |
| |
| Even if your Web site is available in only one time zone, it's still good |
| practice to store data in UTC in your database. One main reason is Daylight |
| Saving Time (DST). Many countries have a system of DST, where clocks are moved |
| forward in spring and backward in autumn. If you're working in local time, |
| you're likely to encounter errors twice a year, when the transitions happen. |
| (The pytz_ documentation discusses `these issues`_ in greater detail.) This |
| probably doesn't matter for your blog, but it's a problem if you over-bill or |
| under-bill your customers by one hour, twice a year, every year. The solution |
| to this problem is to use UTC in the code and use local time only when |
| interacting with end users. |
| |
| Time zone support is disabled by default. To enable it, set :setting:`USE_TZ = |
| True <USE_TZ>` in your settings file. Installing pytz_ is highly recommended, |
| but not mandatory. It's as simple as: |
| |
| .. code-block:: bash |
| |
| $ sudo pip install pytz |
| |
| .. note:: |
| |
| The default :file:`settings.py` file created by :djadmin:`django-admin.py |
| startproject <startproject>` includes :setting:`USE_TZ = True <USE_TZ>` |
| for convenience. |
| |
| .. note:: |
| |
| There is also an independent but related :setting:`USE_L10N` setting that |
| controls whether Django should activate format localization. See |
| :doc:`/topics/i18n/formatting` for more details. |
| |
| If you're wrestling with a particular problem, start with the :ref:`time zone |
| FAQ <time-zones-faq>`. |
| |
| Concepts |
| ======== |
| |
| Naive and aware datetime objects |
| -------------------------------- |
| |
| Python's :class:`datetime.datetime` objects have a ``tzinfo`` attribute that |
| can be used to store time zone information, represented as an instance of a |
| subclass of :class:`datetime.tzinfo`. When this attribute is set and describes |
| an offset, a datetime object is **aware**. Otherwise, it's **naive**. |
| |
| You can use :func:`~django.utils.timezone.is_aware` and |
| :func:`~django.utils.timezone.is_naive` to determine whether datetimes are |
| aware or naive. |
| |
| When time zone support is disabled, Django uses naive datetime objects in local |
| time. This is simple and sufficient for many use cases. In this mode, to obtain |
| the current time, you would write:: |
| |
| import datetime |
| |
| now = datetime.datetime.now() |
| |
| When time zone support is enabled, Django uses time-zone-aware datetime |
| objects. If your code creates datetime objects, they should be aware too. In |
| this mode, the example above becomes:: |
| |
| import datetime |
| from django.utils.timezone import utc |
| |
| now = datetime.datetime.utcnow().replace(tzinfo=utc) |
| |
| .. note:: |
| |
| :mod:`django.utils.timezone` provides a |
| :func:`~django.utils.timezone.now()` function that returns a naive or |
| aware datetime object according to the value of :setting:`USE_TZ`. |
| |
| .. warning:: |
| |
| Dealing with aware datetime objects isn't always intuitive. For instance, |
| the ``tzinfo`` argument of the standard datetime constructor doesn't work |
| reliably for time zones with DST. Using UTC is generally safe; if you're |
| using other time zones, you should review the `pytz`_ documentation |
| carefully. |
| |
| .. note:: |
| |
| Python's :class:`datetime.time` objects also feature a ``tzinfo`` |
| attribute, and PostgreSQL has a matching ``time with time zone`` type. |
| However, as PostgreSQL's docs put it, this type "exhibits properties which |
| lead to questionable usefulness". |
| |
| Django only supports naive time objects and will raise an exception if you |
| attempt to save an aware time object. |
| |
| .. _naive-datetime-objects: |
| |
| Interpretation of naive datetime objects |
| ---------------------------------------- |
| |
| When :setting:`USE_TZ` is ``True``, Django still accepts naive datetime |
| objects, in order to preserve backwards-compatibility. When the database layer |
| receives one, it attempts to make it aware by interpreting it in the |
| :ref:`default time zone <default-current-time-zone>` and raises a warning. |
| |
| Unfortunately, during DST transitions, some datetimes don't exist or are |
| ambiguous. In such situations, pytz_ raises an exception. Other |
| :class:`~datetime.tzinfo` implementations, such as the local time zone used as |
| a fallback when pytz_ isn't installed, may raise an exception or return |
| inaccurate results. That's why you should always create aware datetime objects |
| when time zone support is enabled. |
| |
| In practice, this is rarely an issue. Django gives you aware datetime objects |
| in the models and forms, and most often, new datetime objects are created from |
| existing ones through :class:`~datetime.timedelta` arithmetic. The only |
| datetime that's often created in application code is the current time, and |
| :func:`timezone.now() <django.utils.timezone.now>` automatically does the |
| right thing. |
| |
| .. _default-current-time-zone: |
| |
| Default time zone and current time zone |
| --------------------------------------- |
| |
| The **default time zone** is the time zone defined by the :setting:`TIME_ZONE` |
| setting. |
| |
| The **current time zone** is the time zone that's used for rendering. |
| |
| You should set the current time zone to the end user's actual time zone with |
| :func:`~django.utils.timezone.activate`. Otherwise, the default time zone is |
| used. |
| |
| .. note:: |
| |
| As explained in the documentation of :setting:`TIME_ZONE`, Django sets |
| environment variables so that its process runs in the default time zone. |
| This happens regardless of the value of :setting:`USE_TZ` and of the |
| current time zone. |
| |
| When :setting:`USE_TZ` is ``True``, this is useful to preserve |
| backwards-compatibility with applications that still rely on local time. |
| However, :ref:`as explained above <naive-datetime-objects>`, this isn't |
| entirely reliable, and you should always work with aware datetimes in UTC |
| in your own code. For instance, use |
| :meth:`~datetime.datetime.utcfromtimestamp` instead of |
| :meth:`~datetime.datetime.fromtimestamp` -- and don't forget to set |
| ``tzinfo`` to :data:`~django.utils.timezone.utc`. |
| |
| Selecting the current time zone |
| ------------------------------- |
| |
| The current time zone is the equivalent of the current :term:`locale <locale |
| name>` for translations. However, there's no equivalent of the |
| ``Accept-Language`` HTTP header that Django could use to determine the user's |
| time zone automatically. Instead, Django provides :ref:`time zone selection |
| functions <time-zone-selection-functions>`. Use them to build the time zone |
| selection logic that makes sense for you. |
| |
| Most Web sites that care about time zones just ask users in which time zone they |
| live and store this information in the user's profile. For anonymous users, |
| they use the time zone of their primary audience or UTC. pytz_ provides |
| helpers_, like a list of time zones per country, that you can use to pre-select |
| the most likely choices. |
| |
| Here's an example that stores the current timezone in the session. (It skips |
| error handling entirely for the sake of simplicity.) |
| |
| Add the following middleware to :setting:`MIDDLEWARE_CLASSES`:: |
| |
| from django.utils import timezone |
| |
| class TimezoneMiddleware(object): |
| def process_request(self, request): |
| tz = request.session.get('django_timezone') |
| if tz: |
| timezone.activate(tz) |
| |
| Create a view that can set the current timezone:: |
| |
| import pytz |
| from django.shortcuts import redirect, render |
| |
| def set_timezone(request): |
| if request.method == 'POST': |
| request.session['django_timezone'] = pytz.timezone(request.POST['timezone']) |
| return redirect('/') |
| else: |
| return render(request, 'template.html', {'timezones': pytz.common_timezones}) |
| |
| Include a form in ``template.html`` that will ``POST`` to this view: |
| |
| .. code-block:: html+django |
| |
| {% load tz %} |
| <form action="{% url 'set_timezone' %}" method="POST"> |
| {% csrf_token %} |
| <label for="timezone">Time zone:</label> |
| <select name="timezone"> |
| {% for tz in timezones %} |
| <option value="{{ tz }}"{% if tz == TIME_ZONE %} selected="selected"{% endif %}>{{ tz }}</option> |
| {% endfor %} |
| </select> |
| <input type="submit" value="Set" /> |
| </form> |
| |
| .. _time-zones-in-forms: |
| |
| Time zone aware input in forms |
| ============================== |
| |
| When you enable time zone support, Django interprets datetimes entered in |
| forms in the :ref:`current time zone <default-current-time-zone>` and returns |
| aware datetime objects in ``cleaned_data``. |
| |
| If the current time zone raises an exception for datetimes that don't exist or |
| are ambiguous because they fall in a DST transition (the timezones provided by |
| pytz_ do this), such datetimes will be reported as invalid values. |
| |
| .. _time-zones-in-templates: |
| |
| Time zone aware output in templates |
| =================================== |
| |
| When you enable time zone support, Django converts aware datetime objects to |
| the :ref:`current time zone <default-current-time-zone>` when they're rendered |
| in templates. This behaves very much like :doc:`format localization |
| </topics/i18n/formatting>`. |
| |
| .. warning:: |
| |
| Django doesn't convert naive datetime objects, because they could be |
| ambiguous, and because your code should never produce naive datetimes when |
| time zone support is enabled. However, you can force conversion with the |
| template filters described below. |
| |
| Conversion to local time isn't always appropriate -- you may be generating |
| output for computers rather than for humans. The following filters and tags, |
| provided by the ``tz`` template tag library, allow you to control the time zone |
| conversions. |
| |
| Template tags |
| ------------- |
| |
| .. templatetag:: localtime |
| |
| localtime |
| ~~~~~~~~~ |
| |
| Enables or disables conversion of aware datetime objects to the current time |
| zone in the contained block. |
| |
| This tag has exactly the same effects as the :setting:`USE_TZ` setting as far |
| as the template engine is concerned. It allows a more fine grained control of |
| conversion. |
| |
| To activate or deactivate conversion for a template block, use:: |
| |
| {% load tz %} |
| |
| {% localtime on %} |
| {{ value }} |
| {% endlocaltime %} |
| |
| {% localtime off %} |
| {{ value }} |
| {% endlocaltime %} |
| |
| .. note:: |
| |
| The value of :setting:`USE_TZ` isn't respected inside of a |
| ``{% localtime %}`` block. |
| |
| .. templatetag:: timezone |
| |
| timezone |
| ~~~~~~~~ |
| |
| Sets or unsets the current time zone in the contained block. When the current |
| time zone is unset, the default time zone applies. |
| |
| :: |
| |
| {% load tz %} |
| |
| {% timezone "Europe/Paris" %} |
| Paris time: {{ value }} |
| {% endtimezone %} |
| |
| {% timezone None %} |
| Server time: {{ value }} |
| {% endtimezone %} |
| |
| .. templatetag:: get_current_timezone |
| |
| get_current_timezone |
| ~~~~~~~~~~~~~~~~~~~~ |
| |
| When the ``django.core.context_processors.tz`` context processor is |
| enabled -- by default, it is -- each :class:`~django.template.RequestContext` |
| contains a ``TIME_ZONE`` variable that provides the name of the current time |
| zone. |
| |
| If you don't use a :class:`~django.template.RequestContext`, you can obtain |
| this value with the ``get_current_timezone`` tag:: |
| |
| {% get_current_timezone as TIME_ZONE %} |
| |
| Template filters |
| ---------------- |
| |
| These filters accept both aware and naive datetimes. For conversion purposes, |
| they assume that naive datetimes are in the default time zone. They always |
| return aware datetimes. |
| |
| .. templatefilter:: localtime |
| |
| localtime |
| ~~~~~~~~~ |
| |
| Forces conversion of a single value to the current time zone. |
| |
| For example:: |
| |
| {% load tz %} |
| |
| {{ value|localtime }} |
| |
| .. templatefilter:: utc |
| |
| utc |
| ~~~ |
| |
| Forces conversion of a single value to UTC. |
| |
| For example:: |
| |
| {% load tz %} |
| |
| {{ value|utc }} |
| |
| .. templatefilter:: timezone |
| |
| timezone |
| ~~~~~~~~ |
| |
| Forces conversion of a single value to an arbitrary timezone. |
| |
| The argument must be an instance of a :class:`~datetime.tzinfo` subclass or a |
| time zone name. If it is a time zone name, pytz_ is required. |
| |
| For example:: |
| |
| {% load tz %} |
| |
| {{ value|timezone:"Europe/Paris" }} |
| |
| .. _time-zones-migration-guide: |
| |
| Migration guide |
| =============== |
| |
| Here's how to migrate a project that was started before Django supported time |
| zones. |
| |
| Database |
| -------- |
| |
| PostgreSQL |
| ~~~~~~~~~~ |
| |
| The PostgreSQL backend stores datetimes as ``timestamp with time zone``. In |
| practice, this means it converts datetimes from the connection's time zone to |
| UTC on storage, and from UTC to the connection's time zone on retrieval. |
| |
| As a consequence, if you're using PostgreSQL, you can switch between ``USE_TZ |
| = False`` and ``USE_TZ = True`` freely. The database connection's time zone |
| will be set to :setting:`TIME_ZONE` or ``UTC`` respectively, so that Django |
| obtains correct datetimes in all cases. You don't need to perform any data |
| conversions. |
| |
| Other databases |
| ~~~~~~~~~~~~~~~ |
| |
| Other backends store datetimes without time zone information. If you switch |
| from ``USE_TZ = False`` to ``USE_TZ = True``, you must convert your data from |
| local time to UTC -- which isn't deterministic if your local time has DST. |
| |
| Code |
| ---- |
| |
| The first step is to add :setting:`USE_TZ = True <USE_TZ>` to your settings |
| file and install pytz_ (if possible). At this point, things should mostly |
| work. If you create naive datetime objects in your code, Django makes them |
| aware when necessary. |
| |
| However, these conversions may fail around DST transitions, which means you |
| aren't getting the full benefits of time zone support yet. Also, you're likely |
| to run into a few problems because it's impossible to compare a naive datetime |
| with an aware datetime. Since Django now gives you aware datetimes, you'll get |
| exceptions wherever you compare a datetime that comes from a model or a form |
| with a naive datetime that you've created in your code. |
| |
| So the second step is to refactor your code wherever you instantiate datetime |
| objects to make them aware. This can be done incrementally. |
| :mod:`django.utils.timezone` defines some handy helpers for compatibility |
| code: :func:`~django.utils.timezone.now`, |
| :func:`~django.utils.timezone.is_aware`, |
| :func:`~django.utils.timezone.is_naive`, |
| :func:`~django.utils.timezone.make_aware`, and |
| :func:`~django.utils.timezone.make_naive`. |
| |
| Finally, in order to help you locate code that needs upgrading, Django raises |
| a warning when you attempt to save a naive datetime to the database:: |
| |
| RuntimeWarning: DateTimeField received a naive datetime (2012-01-01 00:00:00) while time zone support is active. |
| |
| During development, you can turn such warnings into exceptions and get a |
| traceback by adding the following to your settings file:: |
| |
| import warnings |
| warnings.filterwarnings( |
| 'error', r"DateTimeField received a naive datetime", |
| RuntimeWarning, r'django\.db\.models\.fields') |
| |
| Fixtures |
| -------- |
| |
| When serializing an aware datetime, the UTC offset is included, like this:: |
| |
| "2011-09-01T13:20:30+03:00" |
| |
| For a naive datetime, it obviously isn't:: |
| |
| "2011-09-01T13:20:30" |
| |
| For models with :class:`~django.db.models.DateTimeField`\ s, this difference |
| makes it impossible to write a fixture that works both with and without time |
| zone support. |
| |
| Fixtures generated with ``USE_TZ = False``, or before Django 1.4, use the |
| "naive" format. If your project contains such fixtures, after you enable time |
| zone support, you'll see :exc:`~exceptions.RuntimeWarning`\ s when you load |
| them. To get rid of the warnings, you must convert your fixtures to the "aware" |
| format. |
| |
| You can regenerate fixtures with :djadmin:`loaddata` then :djadmin:`dumpdata`. |
| Or, if they're small enough, you can simply edit them to add the UTC offset |
| that matches your :setting:`TIME_ZONE` to each serialized datetime. |
| |
| .. _time-zones-faq: |
| |
| FAQ |
| === |
| |
| Setup |
| ----- |
| |
| 1. **I don't need multiple time zones. Should I enable time zone support?** |
| |
| Yes. When time zone support is enabled, Django uses a more accurate model |
| of local time. This shields you from subtle and unreproducible bugs around |
| Daylight Saving Time (DST) transitions. |
| |
| In this regard, time zones are comparable to ``unicode`` in Python. At first |
| it's hard. You get encoding and decoding errors. Then you learn the rules. |
| And some problems disappear -- you never get mangled output again when your |
| application receives non-ASCII input. |
| |
| When you enable time zone support, you'll encounter some errors because |
| you're using naive datetimes where Django expects aware datetimes. Such |
| errors show up when running tests and they're easy to fix. You'll quickly |
| learn how to avoid invalid operations. |
| |
| On the other hand, bugs caused by the lack of time zone support are much |
| harder to prevent, diagnose and fix. Anything that involves scheduled tasks |
| or datetime arithmetic is a candidate for subtle bugs that will bite you |
| only once or twice a year. |
| |
| For these reasons, time zone support is enabled by default in new projects, |
| and you should keep it unless you have a very good reason not to. |
| |
| 2. **I've enabled time zone support. Am I safe?** |
| |
| Maybe. You're better protected from DST-related bugs, but you can still |
| shoot yourself in the foot by carelessly turning naive datetimes into aware |
| datetimes, and vice-versa. |
| |
| If your application connects to other systems -- for instance, if it queries |
| a Web service -- make sure datetimes are properly specified. To transmit |
| datetimes safely, their representation should include the UTC offset, or |
| their values should be in UTC (or both!). |
| |
| Finally, our calendar system contains interesting traps for computers:: |
| |
| >>> import datetime |
| >>> def one_year_before(value): # DON'T DO THAT! |
| ... return value.replace(year=value.year - 1) |
| >>> one_year_before(datetime.datetime(2012, 3, 1, 10, 0)) |
| datetime.datetime(2011, 3, 1, 10, 0) |
| >>> one_year_before(datetime.datetime(2012, 2, 29, 10, 0)) |
| Traceback (most recent call last): |
| ... |
| ValueError: day is out of range for month |
| |
| (To implement this function, you must decide whether 2012-02-29 minus |
| one year is 2011-02-28 or 2011-03-01, which depends on your business |
| requirements.) |
| |
| 3. **Should I install pytz?** |
| |
| Yes. Django has a policy of not requiring external dependencies, and for |
| this reason pytz_ is optional. However, it's much safer to install it. |
| |
| As soon as you activate time zone support, Django needs a definition of the |
| default time zone. When pytz is available, Django loads this definition |
| from the `tz database`_. This is the most accurate solution. Otherwise, it |
| relies on the difference between local time and UTC, as reported by the |
| operating system, to compute conversions. This is less reliable, especially |
| around DST transitions. |
| |
| Furthermore, if you want to support users in more than one time zone, pytz |
| is the reference for time zone definitions. |
| |
| Troubleshooting |
| --------------- |
| |
| 1. **My application crashes with** ``TypeError: can't compare offset-naive`` |
| ``and offset-aware datetimes`` **-- what's wrong?** |
| |
| Let's reproduce this error by comparing a naive and an aware datetime:: |
| |
| >>> import datetime |
| >>> from django.utils import timezone |
| >>> naive = datetime.datetime.utcnow() |
| >>> aware = naive.replace(tzinfo=timezone.utc) |
| >>> naive == aware |
| Traceback (most recent call last): |
| ... |
| TypeError: can't compare offset-naive and offset-aware datetimes |
| |
| If you encounter this error, most likely your code is comparing these two |
| things: |
| |
| - a datetime provided by Django -- for instance, a value read from a form or |
| a model field. Since you enabled time zone support, it's aware. |
| - a datetime generated by your code, which is naive (or you wouldn't be |
| reading this). |
| |
| Generally, the correct solution is to change your code to use an aware |
| datetime instead. |
| |
| If you're writing a pluggable application that's expected to work |
| independently of the value of :setting:`USE_TZ`, you may find |
| :func:`django.utils.timezone.now` useful. This function returns the current |
| date and time as a naive datetime when ``USE_TZ = False`` and as an aware |
| datetime when ``USE_TZ = True``. You can add or subtract |
| :class:`datetime.timedelta` as needed. |
| |
| 2. **I see lots of** ``RuntimeWarning: DateTimeField received a naive |
| datetime`` ``(YYYY-MM-DD HH:MM:SS)`` ``while time zone support is active`` |
| **-- is that bad?** |
| |
| When time zone support is enabled, the database layer expects to receive |
| only aware datetimes from your code. This warning occurs when it receives a |
| naive datetime. This indicates that you haven't finished porting your code |
| for time zone support. Please refer to the :ref:`migration guide |
| <time-zones-migration-guide>` for tips on this process. |
| |
| In the meantime, for backwards compatibility, the datetime is considered to |
| be in the default time zone, which is generally what you expect. |
| |
| 3. ``now.date()`` **is yesterday! (or tomorrow)** |
| |
| If you've always used naive datetimes, you probably believe that you can |
| convert a datetime to a date by calling its :meth:`~datetime.datetime.date` |
| method. You also consider that a :class:`~datetime.date` is a lot like a |
| :class:`~datetime.datetime`, except that it's less accurate. |
| |
| None of this is true in a time zone aware environment:: |
| |
| >>> import datetime |
| >>> import pytz |
| >>> paris_tz = pytz.timezone("Europe/Paris") |
| >>> new_york_tz = pytz.timezone("America/New_York") |
| >>> paris = paris_tz.localize(datetime.datetime(2012, 3, 3, 1, 30)) |
| # This is the correct way to convert between time zones with pytz. |
| >>> new_york = new_york_tz.normalize(paris.astimezone(new_york_tz)) |
| >>> paris == new_york, paris.date() == new_york.date() |
| (True, False) |
| >>> paris - new_york, paris.date() - new_york.date() |
| (datetime.timedelta(0), datetime.timedelta(1)) |
| >>> paris |
| datetime.datetime(2012, 3, 3, 1, 30, tzinfo=<DstTzInfo 'Europe/Paris' CET+1:00:00 STD>) |
| >>> new_york |
| datetime.datetime(2012, 3, 2, 19, 30, tzinfo=<DstTzInfo 'America/New_York' EST-1 day, 19:00:00 STD>) |
| |
| As this example shows, the same datetime has a different date, depending on |
| the time zone in which it is represented. But the real problem is more |
| fundamental. |
| |
| A datetime represents a **point in time**. It's absolute: it doesn't depend |
| on anything. On the contrary, a date is a **calendaring concept**. It's a |
| period of time whose bounds depend on the time zone in which the date is |
| considered. As you can see, these two concepts are fundamentally different, |
| and converting a datetime to a date isn't a deterministic operation. |
| |
| What does this mean in practice? |
| |
| Generally, you should avoid converting a :class:`~datetime.datetime` to |
| :class:`~datetime.date`. For instance, you can use the :tfilter:`date` |
| template filter to only show the date part of a datetime. This filter will |
| convert the datetime into the current time zone before formatting it, |
| ensuring the results appear correctly. |
| |
| If you really need to do the conversion yourself, you must ensure the |
| datetime is converted to the appropriate time zone first. Usually, this |
| will be the current timezone:: |
| |
| >>> from django.utils import timezone |
| >>> timezone.activate(pytz.timezone("Asia/Singapore")) |
| # For this example, we just set the time zone to Singapore, but here's how |
| # you would obtain the current time zone in the general case. |
| >>> current_tz = timezone.get_current_timezone() |
| # Again, this is the correct way to convert between time zones with pytz. |
| >>> local = current_tz.normalize(paris.astimezone(current_tz)) |
| >>> local |
| datetime.datetime(2012, 3, 3, 8, 30, tzinfo=<DstTzInfo 'Asia/Singapore' SGT+8:00:00 STD>) |
| >>> local.date() |
| datetime.date(2012, 3, 3) |
| |
| Usage |
| ----- |
| |
| 1. **I have a string** ``"2012-02-21 10:28:45"`` **and I know it's in the** |
| ``"Europe/Helsinki"`` **time zone. How do I turn that into an aware |
| datetime?** |
| |
| This is exactly what pytz_ is for. |
| |
| >>> from django.utils.dateparse import parse_datetime |
| >>> naive = parse_datetime("2012-02-21 10:28:45") |
| >>> import pytz |
| >>> pytz.timezone("Europe/Helsinki").localize(naive, is_dst=None) |
| datetime.datetime(2012, 2, 21, 10, 28, 45, tzinfo=<DstTzInfo 'Europe/Helsinki' EET+2:00:00 STD>) |
| |
| Note that ``localize`` is a pytz extension to the :class:`~datetime.tzinfo` |
| API. Also, you may want to catch ``pytz.InvalidTimeError``. The |
| documentation of pytz contains `more examples`_. You should review it |
| before attempting to manipulate aware datetimes. |
| |
| 2. **How can I obtain the local time in the current time zone?** |
| |
| Well, the first question is, do you really need to? |
| |
| You should only use local time when you're interacting with humans, and the |
| template layer provides :ref:`filters and tags <time-zones-in-templates>` |
| to convert datetimes to the time zone of your choice. |
| |
| Furthermore, Python knows how to compare aware datetimes, taking into |
| account UTC offsets when necessary. It's much easier (and possibly faster) |
| to write all your model and view code in UTC. So, in most circumstances, |
| the datetime in UTC returned by :func:`django.utils.timezone.now` will be |
| sufficient. |
| |
| For the sake of completeness, though, if you really want the local time |
| in the current time zone, here's how you can obtain it:: |
| |
| >>> from django.utils import timezone |
| >>> timezone.localtime(timezone.now()) |
| datetime.datetime(2012, 3, 3, 20, 10, 53, 873365, tzinfo=<DstTzInfo 'Europe/Paris' CET+1:00:00 STD>) |
| |
| In this example, pytz_ is installed and the current time zone is |
| ``"Europe/Paris"``. |
| |
| 3. **How can I see all available time zones?** |
| |
| pytz_ provides helpers_, including a list of current time zones and a list |
| of all available time zones -- some of which are only of historical |
| interest. |
| |
| .. _pytz: http://pytz.sourceforge.net/ |
| .. _more examples: http://pytz.sourceforge.net/#example-usage |
| .. _these issues: http://pytz.sourceforge.net/#problems-with-localtime |
| .. _helpers: http://pytz.sourceforge.net/#helpers |
| .. _tz database: http://en.wikipedia.org/wiki/Tz_database |