Make writing a habit together! This is the 10th day of my participation in the “Gold Digging Day New Plan · April More text Challenge”. Click here for more details.

Container deployment is now very mature, and many of our services use container deployment, which is very easy to update and restore. However, one of the more troublesome issues is time zone handling, which is usually handled by injecting TZ environment variables. However, this kind of handling does not work in Django.

Timezone related configurations in Django

In Django’s settings.py configuration file, there are two parameters that depend on time and time zone: TIME_ZONE and USE_TZ. We expected Django to get the local time correctly when configured in settings.py, but it doesn’t. Let’s take a look at what these two Settings do.

USE_TZ=True

If USE_TZ is set to True, Django uses the system’s default timezone setting. The TIME_ZONE setting is essentially invalid, meaning it doesn’t work with or without a TIME_ZONE setting.

USE_TZ=False

If USE_TZ is set to False

  • TIME_ZONE set to None Django still uses the default time zone
  • If TIME_ZONE is set to another time zone
    1. On Windows, the TIME_ZONE setting is useless, and Django uses the native time
    2. For example, if USE_TZ = False, TIME_ZONE = ‘Asia/Shanghai’ is set, Shanghai UTC is used.

At this point, you might think the time is up, but it’s not, and we need to worry about the system time zone Settings.

The Settings of the middle area in the Linux container

USE_TZ = False, TIME_ZONE = ‘Asia/Shanghai’

The TZ=Asia/Shanghai environment variable is not injected

Enter the container to view the container time and time zone

The system time displays the UTC time zone, which is 08:15, 8 hours off

Go to your Django environment and check the time and time zone

Python manage.py shell from datetime import datetime.now() # datetime.datetime(2021, 10, 8, 8, 24, 8, 289230) from django.utils import timezone timezone.get_current_timezone_name() # output 'Asia/Shanghai'Copy the code

Inject the environment variable TZ=Asia/Shanghai

Enter the container to view the time and time zone

The system time is displayed as the Asia time zone, but the time is still UTC time. The actual local time is not displayed

Go to your Django environment and check the time and time zone

Python manage.py shell from datetime import datetime.now() # datetime.datetime(2021, 10, 8, 8, 24, 8, 289230) from django.utils import timezone timezone.get_current_timezone_name() # output 'Asia/Shanghai'Copy the code

As you can see, although the time zone has changed, the time is still UTC time, both in the container itself and in Django

To change the time zone in Linux, you need to modify the /etc/localtime file

Change the Time zone of a Linux container

The common practice is to copy the host’s /etc/localtime file to the container’s /etc/localtime file, but we found that the /etc/localtime file is actually a soft connection. The actual file is: /usr/share/zoneinfo/Asia/Shanghai

docker cp /usr/share/zoneinfo/Asia/Shanghai test:/etc/localtime
Copy the code

Without injecting the container with the TZ=Asia/Shanghai environment variable, we log in to the container and find that the system time of the container has been correctly retrieved to the local time and time zone

If the TZ=Asia/Shanghai environment variable is injected, even if the /etc/localtime file is replaced, only the time zone is changed and the time is still UTC

Go to your Django environment and check the time

Python manage.py shell from datetime import datetime.now() # datetime.datetime(2021, 10, 8, 8, 43, 43, 754698).Copy the code

The time in your Django environment is still UTC time, but the time in your Linux environment is still UTC time. Many people get a little crazy when they think the USE_TZ and TIME_ZONE Settings in settings.py are wrong. The reason is that the datetime library looks for the Asia/Shanghai file in /usr/share/zoneinfo/, which is not included in our image, so Django uses UTC. The solution is very simple: create /usr/share/zoneinfo/asia and copy files to this directory

# in containers (e.g., not the directory does not exist) mkdir -p/usr/share/zoneinfo/Asia # outside the container docker cp/usr/share/zoneinfo/Asia/Shanghai test:/usr/share/zoneinfo/Asia/ShanghaiCopy the code

Then log into the container and check the time in the Django environment

Python manage.py shell from datetime import datetime.now() # datetime.datetime(2021, 10, 8, 16, 49, 32, 57)Copy the code

Now the time is exactly right.

conclusion

For the container time zone problem, you are advised to install and set /etc/localtime during container creation. For example, add the following statement to the dockerfile

ADD /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai

RUN ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
Copy the code

This way our container does not need to worry about time zones when it is started. If the container is already made, mount the time zone file at startup

docker run -d -v /etc/localtime:/etc/localtime -v /usr/share/zoneinfo/Asia/Shanghai:/usr/share/zoneinfo/Asia/Shanghai imageName
Copy the code

This way is more troublesome. There is also a case that we now encounter, the service has been online, find the time problem, manually copy the two files into the container, and then restart the container

docker cp /usr/share/zoneinfo/Asia/Shanghai test:/etc/localtime
docker cp /usr/share/zoneinfo/Asia/Shanghai test:/usr/share/zoneinfo/Asia/Shanghai
docker restart test
Copy the code