hack datetime instances cannot be assigned new attributes define a subclass in order to define new attributes in dotimezone template filters convert a datetime to local time in the active time zone this only makes sense within a localtime off block convert a datetime to utc convert a datetime to local time in a given time zone the argument must be an instance of a tzinfo subclass or a time zone name naive datetimes are assumed to be in local time in the default time zone obtain a timezoneaware datetime filters must never raise exceptionsm so catch everything obtain a tzinfo instance hack the converttolocaltime flag will prevent automatic conversion of the value to local time template tags template node class used by localtimetag template node class used by timezonetag template node class used by getcurrenttimezonetag force or prevent conversion of datetime objects to local time regardless of the value of settings usetz sample usage localtime off valueinutc endlocaltime enable a given time zone just for this block the timezone argument must be an instance of a tzinfo subclass a time zone name or none if it is none the default time zone is used within the block sample usage timezone europeparis it is now in paris endtimezone store the name of the current time zone in the context usage getcurrenttimezone as timezone this will fetch the currently active time zone and put its name into the timezone context variable token splitcontents isn t useful here because this tag doesn t accept variable as arguments hack datetime instances cannot be assigned new attributes define a subclass in order to define new attributes in do_timezone template filters convert a datetime to local time in the active time zone this only makes sense within a localtime off block convert a datetime to utc convert a datetime to local time in a given time zone the argument must be an instance of a tzinfo subclass or a time zone name naive datetimes are assumed to be in local time in the default time zone obtain a timezone aware datetime filters must never raise exceptionsm so catch everything obtain a tzinfo instance hack the convert_to_local_time flag will prevent automatic conversion of the value to local time template tags template node class used by localtime_tag template node class used by timezone_tag template node class used by get_current_timezone_tag force or prevent conversion of datetime objects to local time regardless of the value of settings use_tz sample usage localtime off value_in_utc endlocaltime enable a given time zone just for this block the timezone argument must be an instance of a tzinfo subclass a time zone name or none if it is none the default time zone is used within the block sample usage timezone europe paris it is now in paris endtimezone store the name of the current time zone in the context usage get_current_timezone as time_zone this will fetch the currently active time zone and put its name into the time_zone context variable token split_contents isn t useful here because this tag doesn t accept variable as arguments
import zoneinfo
from datetime import datetime
from datetime import timezone as datetime_timezone
from datetime import tzinfo

from django.template import Library, Node, TemplateSyntaxError
from django.utils import timezone

register = Library()




class datetimeobject(datetime):
    pass





@register.filter
def localtime(value):
    
    return do_timezone(value, timezone.get_current_timezone())


@register.filter
def utc(value):
    
    return do_timezone(value, datetime_timezone.utc)


@register.filter("timezone")
def do_timezone(value, arg):
    
    if not isinstance(value, datetime):
        return ""

    
    try:
        if timezone.is_naive(value):
            default_timezone = timezone.get_default_timezone()
            value = timezone.make_aware(value, default_timezone)
    
    except Exception:
        return ""

    
    if isinstance(arg, tzinfo):
        tz = arg
    elif isinstance(arg, str):
        try:
            tz = zoneinfo.ZoneInfo(arg)
        except zoneinfo.ZoneInfoNotFoundError:
            return ""
    else:
        return ""

    result = timezone.localtime(value, tz)

    
    
    result = datetimeobject(
        result.year,
        result.month,
        result.day,
        result.hour,
        result.minute,
        result.second,
        result.microsecond,
        result.tzinfo,
    )
    result.convert_to_local_time = False
    return result





class LocalTimeNode(Node):
    

    def __init__(self, nodelist, use_tz):
        self.nodelist = nodelist
        self.use_tz = use_tz

    def render(self, context):
        old_setting = context.use_tz
        context.use_tz = self.use_tz
        output = self.nodelist.render(context)
        context.use_tz = old_setting
        return output


class TimezoneNode(Node):
    

    def __init__(self, nodelist, tz):
        self.nodelist = nodelist
        self.tz = tz

    def render(self, context):
        with timezone.override(self.tz.resolve(context)):
            output = self.nodelist.render(context)
        return output


class GetCurrentTimezoneNode(Node):
    

    def __init__(self, variable):
        self.variable = variable

    def render(self, context):
        context[self.variable] = timezone.get_current_timezone_name()
        return ""


@register.tag("localtime")
def localtime_tag(parser, token):
    
    bits = token.split_contents()
    if len(bits) == 1:
        use_tz = True
    elif len(bits) > 2 or bits[1] not in ("on", "off"):
        raise TemplateSyntaxError("%r argument should be 'on' or 'off'" % bits[0])
    else:
        use_tz = bits[1] == "on"
    nodelist = parser.parse(("endlocaltime",))
    parser.delete_first_token()
    return LocalTimeNode(nodelist, use_tz)


@register.tag("timezone")
def timezone_tag(parser, token):
    
    bits = token.split_contents()
    if len(bits) != 2:
        raise TemplateSyntaxError("'%s' takes one argument (timezone)" % bits[0])
    tz = parser.compile_filter(bits[1])
    nodelist = parser.parse(("endtimezone",))
    parser.delete_first_token()
    return TimezoneNode(nodelist, tz)


@register.tag("get_current_timezone")
def get_current_timezone_tag(parser, token):
    
    
    
    args = token.contents.split()
    if len(args) != 3 or args[1] != "as":
        raise TemplateSyntaxError(
            "'get_current_timezone' requires 'as variable' (got %r)" % args
        )
    return GetCurrentTimezoneNode(args[2])