# Django 6.0.5 documentation

# Tidszoner

## Översikt

När stöd för tidszoner är aktiverat lagrar Django datetime-information i UTC i databasen, använder tidszonmedvetna datetime-objekt internt och konverterar dem till slutanvändarens tidszon i formulär. Mallar kommer att använda standardtidszonen, men detta kan uppdateras till slutanvändarens tidszon genom användning av filter och taggar.

Detta är praktiskt om dina användare bor i mer än en tidszon och du vill visa datatidsinformation enligt varje användares väggklocka.

Även om din webbplats bara är tillgänglig i en enda tidszon är det ändå bra att lagra data i UTC i databasen. Det främsta skälet är sommartid (DST). Många länder har ett system med sommartid, där klockorna ställs fram på våren och tillbaka på hösten. Om du arbetar med lokal tid kommer du sannolikt att stöta på fel två gånger om året, när övergångarna sker. Det här spelar förmodligen ingen roll för din blogg, men det är ett problem om du överfakturerar eller underfakturerar dina kunder med en timme, två gånger om året, varje år. Lösningen på det här problemet är att använda UTC i koden och endast använda lokal tid när du interagerar med slutanvändare.

Stöd för tidszoner är aktiverat som standard. För att inaktivera det, ange `USE_TZ = False` i din inställningsfil.

Tidszonsstöd använder `zoneinfo`, som är en del av Pythons standardbibliotek från Python 3.9.

Om du brottas med ett särskilt problem kan du börja med time zone FAQ.

## Koncept

### Naiva och medvetna datetime-objekt

Pythons `datetime.datetime`-objekt har ett `tzinfo`-attribut som kan användas för att lagra tidszoninformation, representerad som en instans av en underklass av `datetime.tzinfo`. När detta attribut är inställt och beskriver en förskjutning, är ett datetime-objekt medvetet. Annars är det naive.

Du kan använda `is_aware()` och `is_naive()` för att avgöra om datatider är medvetna eller naiva.

När stödet för tidszoner är avaktiverat använder Django naiva datetime-objekt i lokal tid. Detta är tillräckligt för många användningsfall. I det här läget skulle du skriva: för att få aktuell tid:

    import datetime

    now = datetime.datetime.now()

När stöd för tidszoner är aktiverat (`USE_TZ=True`) använder Django tidszonsmedvetna datetime-objekt. Om din kod skapar datetime-objekt bör de också vara medvetna. I det här läget blir exemplet ovan:

    from django.utils import timezone

    now = timezone.now()

Varning

Att hantera medvetna datetime-objekt är inte alltid intuitivt. Till exempel fungerar inte `tzinfo`-argumentet i standard datetime-konstruktören tillförlitligt för tidszoner med DST. Att använda UTC är i allmänhet säkert; om du använder andra tidszoner bör du granska `zoneinfo`-dokumentationen noggrant.

Observera

Pythons `datetime.time`-objekt har också ett `tzinfo`-attribut, och PostgreSQL har en matchande `tid med tidszon`-typ. Men som PostgreSQL: s dokument uttrycker det, den här typen ”uppvisar egenskaper som leder till tvivelaktig användbarhet”.

Django stöder endast naiva tidsobjekt och kommer att ge upphov till ett undantag om du försöker spara ett medvetet tidsobjekt, eftersom en tidszon för en tid utan något associerat datum inte är meningsfullt.

### Tolkning av naiva datetime-objekt

När `USE_TZ` är `True`, accepterar Django fortfarande naiva datetime-objekt, för att bevara bakåtkompatibilitet. När databaslagret tar emot ett sådant försöker det göra det medvetet genom att tolka det i default time zone och ger en varning.

Under DST-övergångar finns det tyvärr vissa datatider som inte existerar eller som är tvetydiga. Det är därför du alltid bör skapa medvetna datetime-objekt när stöd för tidszoner är aktiverat. (Se `Using ZoneInfo section of the zoneinfo docs` för exempel på användning av attributet `fold` för att ange den förskjutning som ska gälla för en datatid under en övergång till sommartid)

I praktiken är detta sällan ett problem. Django ger dig medvetna datetime-objekt i modellerna och formulären, och oftast skapas nya datetime-objekt från befintliga genom `timedelta`-aritmetik. Den enda datatid som ofta skapas i applikationskoden är den aktuella tiden, och `timezone.now()` gör automatiskt rätt sak.

### Standardtidszon och aktuell tidszon

Standardtidszonen är den tidszon som definieras av inställningen `TIME_ZONE`.

Den aktuella tidszonen är den tidszon som används för rendering.

Du bör ställa in den aktuella tidszonen till slutanvändarens faktiska tidszon med `activate()`. Annars används standardtidszonen.

Observera

Som förklaras i dokumentationen av `TIME_ZONE`, ställer Django in miljövariabler så att dess process körs i standardtidszonen. Detta sker oberoende av värdet på `USE_TZ` och den aktuella tidszonen.

When `USE_TZ` is `True`, this is useful to preserve backwards-compatibility with applications that still rely on local time. However, as explained above, this isn’t entirely reliable, and you should always work with aware datetimes in UTC in your own code. For instance, use `fromtimestamp()` and set the `tz` parameter to `datetime.UTC`.

### Välja aktuell tidszon

Den aktuella tidszonen är motsvarigheten till den aktuella locale för översättningar. Det finns dock ingen motsvarighet till HTTP-headern `Accept-Language` som Django kan använda för att automatiskt bestämma användarens tidszon. Istället tillhandahåller Django funktioner för val av tidszon. Använd dem för att bygga den logik för val av tidszon som är vettig för dig.

De flesta webbplatser som bryr sig om tidszoner frågar användarna i vilken tidszon de bor och lagrar denna information i användarens profil. För anonyma användare använder de tidszonen för sin primära målgrupp eller UTC. `zoneinfo.available_timezones()` ger en uppsättning tillgängliga tidszoner som du kan använda för att bygga en karta från sannolika platser till tidszoner.

Här är ett exempel som lagrar den aktuella tidszonen i sessionen. (Det hoppar över felhanteringen helt för enkelhetens skull)

Lägg till följande middleware i `MIDDLEWARE`:

    import zoneinfo

    from django.utils import timezone

    class TimezoneMiddleware:
        def __init__(self, get_response):
            self.get_response = get_response

        def __call__(self, request):
            tzname = request.session.get("django_timezone")
            if tzname:
                timezone.activate(zoneinfo.ZoneInfo(tzname))
            else:
                timezone.deactivate()
            return self.get_response(request)

Skapa en vy som kan ställa in aktuell tidszon:

    from django.shortcuts import redirect, render

    # Prepare a map of common locations to timezone choices you wish to offer.
    common_timezones = {
        "London": "Europe/London",
        "Paris": "Europe/Paris",
        "New York": "America/New_York",
    }

    def set_timezone(request):
        if request.method == "POST":
            request.session["django_timezone"] = request.POST["timezone"]
            return redirect("/")
        else:
            return render(request, "template.html", {"timezones": common_timezones})

Inkludera ett formulär i `template.html` som kommer att `POST` till denna vy:

    {% load tz %}
    {% get_current_timezone as TIME_ZONE %}
    <form action="{% url 'set_timezone' %}" method="POST">
        {% csrf_token %}
        <label for="timezone">Time zone:</label>
        <select name="timezone">
            {% for city, tz in timezones.items %}
            <option value="{{ tz }}"{% if tz == TIME_ZONE %} selected{% endif %}>{{ city }}</option>
            {% endfor %}
        </select>
        <input type="submit" value="Set">
    </form>

## Tidszonmedveten inmatning i formulär

När du aktiverar stöd för tidszoner tolkar Django datatider som anges i formulär i aktuell tidszon och returnerar medvetna datatidsobjekt i `cleaned_data`.

Konverterade datumtider som inte existerar eller som är tvetydiga eftersom de faller i en DST-övergång kommer att rapporteras som ogiltiga värden.

## Tidszonmedveten utdata i mallar

När du aktiverar stöd för tidszoner konverterar Django medvetna datetime-objekt till aktuell tidszon när de återges i mallar. Detta beter sig väldigt mycket som format localization.

Varning

Django konverterar inte naiva datetime-objekt, eftersom de kan vara tvetydiga och eftersom din kod aldrig bör producera naiva datetimes när tidszonsstöd är aktiverat. Du kan dock tvinga fram konvertering med de mallfilter som beskrivs nedan.

Omvandling till lokal tid är inte alltid lämplig - du kanske genererar utdata för datorer snarare än för människor. Följande filter och taggar, som tillhandahålls av malltaggbiblioteket `tz`, gör att du kan kontrollera tidszonskonverteringarna.

### Malltaggar

#### `lokaltid`

Aktiverar eller inaktiverar konvertering av medvetna datetime-objekt till den aktuella tidszonen i det block som ingår.

Denna tagg har exakt samma effekter som inställningen `USE_TZ` när det gäller mallmotorn. Den tillåter en mer finkornig kontroll av konverteringen.

För att aktivera eller avaktivera konvertering för ett mallblock, använd:

    {% load tz %}

    {% localtime on %}
        {{ value }}
    {% endlocaltime %}

    {% localtime off %}
        {{ value }}
    {% endlocaltime %}

Observera

Värdet på `USE_TZ` respekteras inte inuti ett `{% localtime %}` block.

#### `tidszon`

Ställer in eller tar bort den aktuella tidszonen i det block som ingår. När den aktuella tidszonen inte är inställd gäller standardtidszonen.

    {% load tz %}

    {% timezone "Europe/Paris" %}
        Paris time: {{ value }}
    {% endtimezone %}

    {% timezone None %}
        Server time: {{ value }}
    {% endtimezone %}

#### `hämta aktuell tidszon`

Du kan få namnet på den aktuella tidszonen med hjälp av taggen `get_current_timezone`:

    {% get_current_timezone as TIME_ZONE %}

Alternativt kan du aktivera kontextprocessorn `tz()` och använda kontextvariabeln `TIME_ZONE`.

### Mallfilter

Dessa filter accepterar både medvetna och naiva datatider. För konverteringsändamål antar de att naiva datatider är i standardtidszonen. De returnerar alltid medvetna datatider.

#### `lokaltid`

Tvingar fram konvertering av ett enskilt värde till aktuell tidszon.

Till exempel:

    {% load tz %}

    {{ value|localtime }}

#### `utc`

Tvingar fram konvertering av ett enskilt värde till UTC.

Till exempel:

    {% load tz %}

    {{ value|utc }}

#### `tidszon`

Tvingar fram konvertering av ett enskilt värde till en godtycklig tidszon.

Argumentet måste vara en instans av en `tzinfo`-underklass eller ett tidszonnamn.

Till exempel:

    {% load tz %}

    {{ value|timezone:"Europe/Paris" }}

## Migrationsguide

Så här gör du för att migrera ett projekt som startades innan Django stödde tidszoner.

### Databas

#### PostgreSQL

PostgreSQL-backend lagrar datatider som `` tidsstämpel med tidszon``. I praktiken betyder det att den konverterar datatider från anslutningens tidszon till UTC vid lagring och från UTC till anslutningens tidszon vid hämtning.

Som en följd av detta, om du använder PostgreSQL, kan du växla mellan `USE_TZ = False` och `USE_TZ = True` fritt. Databasanslutningens tidszon kommer att ställas in till `DATABASE-TIME_ZONE` respektive `UTC`, så att Django får korrekta datatider i alla fall. Du behöver inte utföra några datakonverteringar.

Inställningar för tidszon

Den `tidszon` som har konfigurerats för anslutningen i `DATABASES` skiljer sig från den allmänna `TIME_ZONE`-inställningen.

#### Övriga databaser

Andra backends lagrar datatider utan tidszoninformation. Om du byter från `USE_TZ = False` till `USE_TZ = True`, måste du konvertera dina data från lokal tid till UTC - vilket inte är deterministiskt om din lokala tid har DST.

### Kod

Det första steget är att lägga till `USE_TZ = True` i din inställningsfil. Vid denna punkt bör saker och ting mestadels fungera. Om du skapar naiva datetime-objekt i din kod, gör Django dem medvetna när det behövs.

Dessa konverteringar kan dock misslyckas vid DST-övergångar, vilket innebär att du inte får alla fördelar med tidszonsstöd ännu. Dessutom kommer du sannolikt att stöta på några problem eftersom det är omöjligt att jämföra en naiv datatid med en medveten datatid. Eftersom Django nu ger dig medvetna datatider kommer du att få undantag när du jämför en datatid som kommer från en modell eller ett formulär med en naiv datatid som du har skapat i din kod.

Så det andra steget är att omarbeta din kod varhelst du instansierar datetime-objekt för att göra dem medvetna. Detta kan göras stegvis. `django.utils.timezone` definierar några praktiska hjälpmedel för kompatibilitetskod: `now()`, `is_aware()`, `is_naive()`, `make_aware()`, och `make_naive()`.

Slutligen, för att hjälpa dig att hitta kod som behöver uppgraderas, ger Django en varning när du försöker spara en naiv datatid i databasen:

    RuntimeWarning: DateTimeField ModelName.field_name received a naive
    datetime (2012-01-01 00:00:00) while time zone support is active.

Under utvecklingsarbetet kan du omvandla sådana varningar till undantag och få en spårning genom att lägga till följande i din inställningsfil:

    import warnings

    warnings.filterwarnings(
        "error",
        r"DateTimeField .* received a naive datetime",
        RuntimeWarning,
        r"django\.db\.models\.fields",
    )

### Fixturer

Vid serialisering av en medveten datatid inkluderas UTC-offset, så här:

    "2011-09-01T13:20:30+03:00"

Medan det för en naiv datatid inte är:

    "2011-09-01T13:20:30"

För modeller med `DateTimeField` gör denna skillnad det omöjligt att skriva en fixtur som fungerar både med och utan stöd för tidszoner.

Fixturer som genererats med `USE_TZ = False`, eller före Django 1.4, använder det ”naiva” formatet. Om ditt projekt innehåller sådana fixturer kommer du att se `RuntimeWarning` när du laddar dem efter att du har aktiverat stöd för tidszoner. För att bli av med varningarna måste du konvertera dina fixturer till ”aware”-formatet.

Du kan regenerera fixturer med `loaddata` och sedan `dumpdata`. Eller, om de är tillräckligt små, kan du redigera dem för att lägga till UTC-offset som matchar din `TIME_ZONE` till varje serialiserad datatid.

## FAQ

### Setup

1. Jag behöver inte flera tidszoner. Ska jag aktivera stöd för tidszoner?

   Ja, det stämmer. När stöd för tidszoner är aktiverat använder Django en mer exakt modell av lokal tid. Detta skyddar dig från subtila och icke reproducerbara buggar kring övergångar till sommartid (DST).

   När du aktiverar stöd för tidszoner kommer du att stöta på vissa fel eftersom du använder naiva datatider där Django förväntar sig medvetna datatider. Sådana fel dyker upp när man kör tester. Du kommer snabbt att lära dig hur du undviker ogiltiga operationer.

   Å andra sidan är buggar som orsakas av avsaknad av stöd för tidszoner mycket svårare att förebygga, diagnostisera och åtgärda. Allt som involverar schemalagda uppgifter eller datatidsaritmetik är en kandidat för subtila buggar som bara kommer att bita dig en eller två gånger om året.

   Av dessa skäl är stöd för tidszoner aktiverat som standard i nya projekt, och du bör behålla det om du inte har en mycket god anledning att inte göra det.

2. Jag har aktiverat tidszonsstöd. Är jag säker?

   Ja, kanske det. Du är bättre skyddad från DST-relaterade buggar, men du kan fortfarande skjuta dig själv i foten genom att slarvigt förvandla naiva datatider till medvetna datatider och vice versa.

   Om din applikation ansluter till andra system - t.ex. om den frågar en webbtjänst - måste du se till att datatiderna är korrekt angivna. För att överföra datatider på ett säkert sätt bör deras representation inkludera UTC-offset, eller så bör deras värden vara i UTC (eller båda!).

   Slutligen innehåller vårt kalendersystem intressanta undantagsfall. Till exempel kan man inte alltid subtrahera ett år direkt från ett givet datum:

       >>> import datetime
       >>> def one_year_before(value):  # Wrong example.
       ...     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

   För att implementera en sådan funktion korrekt måste du bestämma om 2012-02-29 minus ett år är 2011-02-28 eller 2011-03-01, vilket beror på dina affärskrav.

3. Hur interagerar jag med en databas som lagrar datatider i lokal tid?

   Ställ in alternativet `TIME_ZONE` till lämplig tidszon för den här databasen i inställningen `DATABASES`.

   Detta är användbart för att ansluta till en databas som inte stöder tidszoner och som inte hanteras av Django när `USE_TZ` är `True`.

### Felsökning

1. Mitt program kraschar med `TypeError: can't compare offset-naive` `and offset-aware datetimes` **– what’s wrong? **

   Låt oss återskapa detta fel genom att jämföra en naiv och en medveten datetime:

       >>> from django.utils import timezone
       >>> aware = timezone.now()
       >>> naive = timezone.make_naive(aware)
       >>> naive == aware
       Traceback (most recent call last):
       ...
       TypeError: can't compare offset-naive and offset-aware datetimes

   Om du stöter på detta fel är det troligt att din kod jämför dessa två saker:

   - en datatid som tillhandahålls av Django - till exempel ett värde som läses från ett formulär eller ett modellfält. Eftersom du aktiverade stöd för tidszoner är den medveten.

   - en datatid som genereras av din kod, vilket är naivt (annars skulle du inte läsa det här).

   I allmänhet är den korrekta lösningen att ändra din kod så att den använder en medveten datetime istället.

   Om du skriver en pluggbar applikation som förväntas fungera oberoende av värdet på `USE_TZ`, kan du tycka att `django.utils.timezone.now()` är användbar. Denna funktion returnerar aktuellt datum och tid som en naiv datatid när `USE_TZ = False` och som en medveten datatid när `USE_TZ = True`. Du kan lägga till eller dra ifrån `datetime.timedelta` efter behov.

2. Jag ser massor av `RuntimeWarning: DateTimeField received a naive datetime` `(YYYY-MM-DD HH:MM:SS)` `while time zone support is active` **– är det dåligt? **

   När stöd för tidszoner är aktiverat förväntar sig databaslagret att endast medvetna datatider tas emot från din kod. Denna varning visas när den tar emot en naiv datetime. Detta indikerar att du inte har slutfört portningen av din kod för stöd för tidszoner. Se migreringsguide för tips om den här processen.

   Under tiden, för bakåtkompatibilitet, anses datatiden vara i standardtidszonen, vilket i allmänhet är vad du förväntar dig.

3. `now.date()` är igår! (eller imorgon)

   Om du alltid har använt naiva datetider tror du förmodligen att du kan konvertera en datetime till ett datum genom att anropa dess `date()`-metod. Du tror också att en `date` är ungefär som en `datetime`, förutom att den är mindre exakt.

   Inget av detta är sant i en miljö som är medveten om tidszoner:

       >>> import datetime
       >>> import zoneinfo
       >>> paris_tz = zoneinfo.ZoneInfo("Europe/Paris")
       >>> new_york_tz = zoneinfo.ZoneInfo("America/New_York")
       >>> paris = datetime.datetime(2012, 3, 3, 1, 30, tzinfo=paris_tz)
       # This is the correct way to convert between time zones.
       >>> new_york = 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=zoneinfo.ZoneInfo(key='Europe/Paris'))
       >>> new_york
       datetime.datetime(2012, 3, 2, 19, 30, tzinfo=zoneinfo.ZoneInfo(key='America/New_York'))

   Som exemplet visar har samma datatid olika datum beroende på i vilken tidszon den representeras. Men det verkliga problemet är mer grundläggande.

   En datatid representerar en punkt i tiden. Den är absolut: den är inte beroende av någonting. Tvärtom är ett datum ett kalendrerande begrepp. Det är en tidsperiod vars gränser beror på den tidszon i vilken datumet betraktas. Som du kan se är dessa två begrepp fundamentalt olika, och att konvertera en datetime till ett datum är inte en deterministisk operation.

   Vad innebär detta i praktiken?

   Generellt sett bör du undvika att konvertera en `datetime` till `date`. Du kan t.ex. använda mallfiltret `date` för att bara visa datumdelen av en datatid. Det här filtret konverterar datatiden till aktuell tidszon innan den formateras, vilket säkerställer att resultaten visas korrekt.

   Om du verkligen behöver göra konverteringen själv måste du först se till att datatiden konverteras till rätt tidszon. Vanligtvis kommer detta att vara den aktuella tidszonen:

       >>> from django.utils import timezone
       >>> timezone.activate(zoneinfo.ZoneInfo("Asia/Singapore"))
       # For this example, we 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()
       >>> local = paris.astimezone(current_tz)
       >>> local
       datetime.datetime(2012, 3, 3, 8, 30, tzinfo=zoneinfo.ZoneInfo(key='Asia/Singapore'))
       >>> local.date()
       datetime.date(2012, 3, 3)

4. ** Jag får ett fel** ”``Är tidszondefinitioner för din databas installerade? ``”

   Om du använder MySQL, se avsnittet Definitioner av tidszoner i MySQL Notes för instruktioner om hur du läser in tidszonsdefinitioner.

### Användning

1. Jag har en sträng `"2012-02-21 10:28:45"` och jag vet att den är i `"Europa/Helsingfors"` tidszonen. Hur förvandlar jag det till en medveten datatid?

   Här måste du skapa den nödvändiga `ZoneInfo`-instansen och koppla den till den naiva datatiden:

       >>> import zoneinfo
       >>> from django.utils.dateparse import parse_datetime
       >>> naive = parse_datetime("2012-02-21 10:28:45")
       >>> naive.replace(tzinfo=zoneinfo.ZoneInfo("Europe/Helsinki"))
       datetime.datetime(2012, 2, 21, 10, 28, 45, tzinfo=zoneinfo.ZoneInfo(key='Europe/Helsinki'))

2. Hur får jag fram den lokala tiden i den aktuella tidszonen?

   Den första frågan är om du verkligen behöver göra det?

   Du bör bara använda lokal tid när du interagerar med människor, och mallskiktet tillhandahåller filter och taggar för att konvertera datatider till den tidszon du väljer.

   Dessutom vet Python hur man jämför medvetna datatider och tar hänsyn till UTC-offset när det behövs. Det är mycket enklare (och möjligen snabbare) att skriva all din modell- och vykod i UTC. Så under de flesta omständigheter kommer datatiden i UTC som returneras av `django.utils.timezone.now()` att vara tillräcklig.

   Men om du verkligen vill ha den lokala tiden i den aktuella tidszonen kan du få den så här, för fullständighetens skull:

       >>> from django.utils import timezone
       >>> timezone.localtime(timezone.now())
       datetime.datetime(2012, 3, 3, 20, 10, 53, 873365, tzinfo=zoneinfo.ZoneInfo(key='Europe/Paris'))

   I detta exempel är den aktuella tidszonen `"Europa/Paris"`.

3. Hur kan jag se alla tillgängliga tidszoner?

   `zoneinfo.available_timezones()` ger en uppsättning av alla giltiga nycklar för IANA-tidszoner som är tillgängliga för ditt system. Se dokumentationen för användningsöverväganden.