Hướng dẫn python parse timezone - múi giờ phân tích cú pháp python

Tổng quan

Gần đây mình có làm việc nhiều với kiểu dữ liệu Datetime trong Python. Vấn đề mình gặp phải là xử lý nhiều loại time format khác nhau, chuyển hóa thành dạng Datetime, chuẩn hóa thời gian lưu trữ và lưu vào database. Và sau đây, mình sẽ viết bài chia sẻ về cách mình xử lý kiểu dữ liệu Datetime trong Python. Trong bài mình sẽ sử dụng Python 3 để xử lý kiểu dữ liệu Datetime.

Tips 1: Chuẩn hóa múi giờ sử dụng

Đầu tiên, cũng là quan trọng nhất, chuẩn hóa múi giờ sử dụng để convert các kiểu thời gian. Mình lựa chọn sử dụng chuẩn múi giờ UTC để chuẩn hóa thời gian cho cả hệ thống cũng như làm múi giờ chuẩn để xử lý các loại format thời gian khác nhau.

Tham khảo thêm về thời gian UTC tại

Tips 2: Convert String thành Datetime

Xử lý bằng hàm

import datetime
import pytz
from dateutil.parser import parse

# Dạng string time
date_string = '2019-03-21 03:41:16'

# Strptime
format = '%Y-%m-%d %H:%M:%S'
date_time_python = datetime.datetime.strptime(date_string, format)
8

import datetime
import pytz
from dateutil.parser import parse

# Dạng string time
date_string = '2019-03-20T03:41:16Z'

# Dạng datetime format
date_time_python = parse(date_string)

Xử lý bằng strptime

import datetime
import pytz
from dateutil.parser import parse

# Dạng string time
date_string = '2019-03-21 03:41:16'

# Strptime
format = '%Y-%m-%d %H:%M:%S'
date_time_python = datetime.datetime.strptime(date_string, format)

Lưu ý:

  • Các rất nhiều format time khác nhau nên để có thể chuyển từ string thành Datetime
    import datetime
    import pytz
    from dateutil.parser import parse
    
    # Dạng string time
    date_string = '2019-03-21 03:41:16'
    
    # Strptime
    format = '%Y-%m-%d %H:%M:%S'
    date_time_python = datetime.datetime.strptime(date_string, format)
    
    8 chỉ có thể xử lý một số dạng tiêu chuẩn, nếu khác dạng tiêu chuẩn phải hiểu ra cấu trúc time string để sử dụng hàm
    import datetime
    
    # Dạng datetime
    date_time_now = datetime.datetime.now()
    
    # Dạng timestamp
    timestamp_now = date_time_now.timestamp()
    
    0 để cắt chuỗi tạo Datetime
  • Nếu kiểu dữ liệu Datetime không rõ múi giờ thì được gọi là
    import datetime
    
    # Dạng datetime
    date_time_now = datetime.datetime.now()
    
    # Dạng timestamp
    timestamp_now = date_time_now.timestamp()
    
    1

Tips 3: Chuyển hóa kiểu Datetime sang Timestamp Python

Timestamp là kiểu thời gian thông dụng của hệ thông Unix, tìm hiểu thêm tại

import datetime

# Dạng datetime
date_time_now = datetime.datetime.now()

# Dạng timestamp
timestamp_now = date_time_now.timestamp()

Tips 4: Chuyển hóa kiểu native date sang UTC timezone

Kiểm tra kiểu timezone

import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())

Lưu ý: không sử dụng hàm replace, hàm replace sẽ chỉ thay đổi tzinfo không qui đổi thời gian từ múi giờ này sang múi giờ khác

Tips 5: Convert UTC sang timezone khác

Nếu bạn ở múi giờ Việt Nam (GMT + 7), tức nếu hiện tại là 8 giờ sáng (giờ Việt Nam) thì quy ra giờ UTC tức 1 giờ sáng (giờ UTC). Vậy nếu Datetime đang ở múi giờ UTC, ta phải convert nó sáng giờ Việt Nam

import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())

# Dạng 'Asia/Ho_Chi_Minh'

VN_TZ = pytz.timezone('Asia/Ho_Chi_Minh')
date_time_vntz_now = date_time_utc_now.astimezone(VN_TZ)
print(date_time_vntz_now.tzname())

Tips 6: Chuyên từ Timestamp sang Datetime

import datetime

date_time_now = datetime.datetime.now()
timestamp_now = date_time_now.timestamp()

# Convert timestamp thành dạng Datetime
timestamp_to_datetime = datetime.datetime.fromtimestamp(timestamp_now)

Tips 7: Convert Datetime sang ISO 8601

ISO 8601 là một tiêu chuẩn quốc tế, được đưa ra bởi Tổ chức tiêu chuẩn hóa quốc tế (ISO) lần đầu tiên năm 1988, mô tả quy cách viết ngày tháng và thời gian theo cách đơn giản nhất mà máy tính có thể hiểu được. Còn đối với Python ISO 8601 Datetime là string format time thông dụng.

import datetime

date_time_now = datetime.datetime.now()

# Convert Datetime thành dạng ISO 8601
iso_format = date_time_now.isoformat()

Nguồn

https://vi.wikipedia.org/wiki/Th%E1%BA%A3o_lu%E1%BA%ADn:M%C3%BAi_gi%E1%BB%9D

https://vi.wikipedia.org/wiki/Th%E1%BA%A3o_lu%E1%BA%ADn:M%C3%BAi_gi%E1%BB%9D


Thực hiện bởi cloud365.vn

Tổng quan

Gần đây mình có làm việc nhiều với kiểu dữ liệu Datetime trong Python. Vấn đề mình gặp phải là xử lý nhiều loại time format khác nhau, chuyển hóa thành dạng Datetime, chuẩn hóa thời gian lưu trữ và lưu vào database. Và sau đây, mình sẽ viết bài chia sẻ về cách mình xử lý kiểu dữ liệu Datetime trong Python. Trong bài mình sẽ sử dụng Python 3 để xử lý kiểu dữ liệu Datetime.

Nội dung chính ShowShow

  • Tổng quan
  • Tips 1: Chuẩn hóa múi giờ sử dụng
  • Tips 2: Convert String thành Datetime
  • Tips 3: Chuyển hóa kiểu Datetime sang Timestamp Python
  • Tips 4: Chuyển hóa kiểu native date sang UTC timezone
  • Tips 5: Convert UTC sang timezone khác
  • Tips 6: Chuyên từ Timestamp sang Datetime
  • Tips 7: Convert Datetime sang ISO 8601
  • Múi giờ (timezone) là gì?
  • Vậy ta lấy gì làm mốc?
  • Còn vấn đề nào khác?
  • Best practices
  • Convert timezone
  • Sử dụng UTC trong tính toán nội bộ
  • Không nên dùng offset-aware datetime

Tips 1: Chuẩn hóa múi giờ sử dụng

Tips 2: Convert String thành Datetime

Tips 3: Chuyển hóa kiểu Datetime sang Timestamp Python

Tips 2: Convert String thành Datetime

Tips 3: Chuyển hóa kiểu Datetime sang Timestamp Python

import datetime
import pytz
from dateutil.parser import parse

# Dạng string time
date_string = '2019-03-20T03:41:16Z'

# Dạng datetime format
date_time_python = parse(date_string)

Tips 4: Chuyển hóa kiểu native date sang UTC timezone

import datetime
import pytz
from dateutil.parser import parse

# Dạng string time
date_string = '2019-03-21 03:41:16'

# Strptime
format = '%Y-%m-%d %H:%M:%S'
date_time_python = datetime.datetime.strptime(date_string, format)

Tips 5: Convert UTC sang timezone khác

  • Tips 6: Chuyên từ Timestamp sang Datetime
  • Tips 7: Convert Datetime sang ISO 8601

Tips 3: Chuyển hóa kiểu Datetime sang Timestamp Python

Tips 4: Chuyển hóa kiểu native date sang UTC timezone

import datetime

# Dạng datetime
date_time_now = datetime.datetime.now()

# Dạng timestamp
timestamp_now = date_time_now.timestamp()

Tips 4: Chuyển hóa kiểu native date sang UTC timezone

Tips 5: Convert UTC sang timezone khác

import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())

Tips 6: Chuyên từ Timestamp sang Datetime

Tips 5: Convert UTC sang timezone khác

Tips 6: Chuyên từ Timestamp sang Datetime

import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())

# Dạng 'Asia/Ho_Chi_Minh'

VN_TZ = pytz.timezone('Asia/Ho_Chi_Minh')
date_time_vntz_now = date_time_utc_now.astimezone(VN_TZ)
print(date_time_vntz_now.tzname())

Tips 6: Chuyên từ Timestamp sang Datetime

import datetime

date_time_now = datetime.datetime.now()
timestamp_now = date_time_now.timestamp()

# Convert timestamp thành dạng Datetime
timestamp_to_datetime = datetime.datetime.fromtimestamp(timestamp_now)

Tips 7: Convert Datetime sang ISO 8601

Múi giờ (timezone) là gì?

import datetime

date_time_now = datetime.datetime.now()

# Convert Datetime thành dạng ISO 8601
iso_format = date_time_now.isoformat()

Vậy ta lấy gì làm mốc?

Còn vấn đề nào khác?

Còn vấn đề nào khác?


Best practices

Múi giờ (timezone) là gì?

Vậy ta lấy gì làm mốc?

import datetime
import pytz
from dateutil.parser import parse

# Dạng string time
date_string = '2019-03-21 03:41:16'

# Strptime
format = '%Y-%m-%d %H:%M:%S'
date_time_python = datetime.datetime.strptime(date_string, format)
4

Còn vấn đề nào khác?

Best practices

Convert timezone

Vậy ta lấy gì làm mốc?

Còn vấn đề nào khác?

Best practices

Còn vấn đề nào khác?

Best practices

  1. Convert timezone
  2. Sử dụng UTC trong tính toán nội bộ
  3. Không nên dùng offset-aware datetime

Đầu tiên, cũng là quan trọng nhất, chuẩn hóa múi giờ sử dụng để convert các kiểu thời gian. Mình lựa chọn sử dụng chuẩn múi giờ UTC để chuẩn hóa thời gian cho cả hệ thống cũng như làm múi giờ chuẩn để xử lý các loại format thời gian khác nhau.

import datetime
import pytz
from dateutil.parser import parse

# Dạng string time
date_string = '2019-03-21 03:41:16'

# Strptime
format = '%Y-%m-%d %H:%M:%S'
date_time_python = datetime.datetime.strptime(date_string, format)
5

Tham khảo thêm về thời gian UTC tại

import datetime
import pytz
from dateutil.parser import parse

# Dạng string time
date_string = '2019-03-21 03:41:16'

# Strptime
format = '%Y-%m-%d %H:%M:%S'
date_time_python = datetime.datetime.strptime(date_string, format)
6

Một là giờ ở UTC, một là giờ địa phương. Tuy nhiên nó lại không cho bạn biết múi giờ địa phương là gì cũng như với 2 giá trị

import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())
3 và
import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())
4 bạn không thể biết được cái nào có múi giờ UTC.

Thư viện còn cung cấp

import datetime

# Dạng datetime
date_time_now = datetime.datetime.now()

# Dạng timestamp
timestamp_now = date_time_now.timestamp()
9 object và
import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())
0 object. Và cả hai đều không có ý nghĩa gì nữa nếu dính líu đến timezone. Vì nếu chỉ
import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())
0 không thì không đủ hoặc nếu là
import datetime

# Dạng datetime
date_time_now = datetime.datetime.now()

# Dạng timestamp
timestamp_now = date_time_now.timestamp()
9 thì nó chỉ mang tính chất địa phương, nó có thể là hôm nay đối với tôi nhưng có thể là hôm qua, hoặc ngày mai đối với bạn.

Best practices

Convert timezone

Nếu bạn muốn tạo

import datetime

# Dạng datetime
date_time_now = datetime.datetime.now()

# Dạng timestamp
timestamp_now = date_time_now.timestamp()
6 object và lưu thông tin timezone, bạn không nên truyền
import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())

# Dạng 'Asia/Ho_Chi_Minh'

VN_TZ = pytz.timezone('Asia/Ho_Chi_Minh')
date_time_vntz_now = date_time_utc_now.astimezone(VN_TZ)
print(date_time_vntz_now.tzname())
0 trong constructure mà nên dùng hàm
import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())

# Dạng 'Asia/Ho_Chi_Minh'

VN_TZ = pytz.timezone('Asia/Ho_Chi_Minh')
date_time_vntz_now = date_time_utc_now.astimezone(VN_TZ)
print(date_time_vntz_now.tzname())
1 cung cấp bởi
import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())

# Dạng 'Asia/Ho_Chi_Minh'

VN_TZ = pytz.timezone('Asia/Ho_Chi_Minh')
date_time_vntz_now = date_time_utc_now.astimezone(VN_TZ)
print(date_time_vntz_now.tzname())
2:

import datetime
import pytz
from dateutil.parser import parse

# Dạng string time
date_string = '2019-03-21 03:41:16'

# Strptime
format = '%Y-%m-%d %H:%M:%S'
date_time_python = datetime.datetime.strptime(date_string, format)
7

Bạn có thể thấy với

import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())
4 nó sử dụng đúng offset ở thời điểm hiện lại là +8.

Sử dụng UTC trong tính toán nội bộ

Nếu bạn muốn lấy thời gian hiện tại, luôn luôn dùng

import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())

# Dạng 'Asia/Ho_Chi_Minh'

VN_TZ = pytz.timezone('Asia/Ho_Chi_Minh')
date_time_vntz_now = date_time_utc_now.astimezone(VN_TZ)
print(date_time_vntz_now.tzname())
4. Khi người dùng nhập giờ địa phương, lập tức chuyển qua UTC rồi tiếp tục xử lý. Nếu bạn không biết múi giờ của người dùng, hãy hỏi họ, không thể tự ý đoán dựa trên IP hay số điện thoại (đây là ý tưởng thực khi mình làm dự án hiện tại).

Không nên dùng offset-aware datetime

import datetime

# Dạng datetime
date_time_now = datetime.datetime.now()

# Dạng timestamp
timestamp_now = date_time_now.timestamp()
6 object là offset-aware khi nó lưu thông tin về timezone, nếu không thì gọi là offset-navie.

Nó có thể là ý tưởng tốt nếu bạn lưu tzinfo trong

import datetime

# Dạng datetime
date_time_now = datetime.datetime.now()

# Dạng timestamp
timestamp_now = date_time_now.timestamp()
6 object. Nhưng sẽ tốt hơn nếu bạn không làm như vậy. Hãy tận dụng hạn chế trong thiết kế API:

  • Trong tính toán nội bộ sử dụng offset-navie
    import datetime
    
    # Dạng datetime
    date_time_now = datetime.datetime.now()
    
    # Dạng timestamp
    timestamp_now = date_time_now.timestamp()
    
    6 object và quy ước timezone của nó là UTC
  • Khi có giao tiếp với người dùng, chuyển đổi nó qua giờ địa phương

Tại sao bạn nên làm như vậy? Đầu tiên là nhiều thư viện được viết với ngầm định

import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())

# Dạng 'Asia/Ho_Chi_Minh'

VN_TZ = pytz.timezone('Asia/Ho_Chi_Minh')
date_time_vntz_now = date_time_utc_now.astimezone(VN_TZ)
print(date_time_vntz_now.tzname())
8. Thứ hai, sử dụng tzinfo trong khi thư viện chuẩn được thiết kế sai là một ý tưởng tệ hại. Đó cũng là lý do vì sao
import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())

# Dạng 'Asia/Ho_Chi_Minh'

VN_TZ = pytz.timezone('Asia/Ho_Chi_Minh')
date_time_vntz_now = date_time_utc_now.astimezone(VN_TZ)
print(date_time_vntz_now.tzname())
2 cung cấp hàm
import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())

# Dạng 'Asia/Ho_Chi_Minh'

VN_TZ = pytz.timezone('Asia/Ho_Chi_Minh')
date_time_vntz_now = date_time_utc_now.astimezone(VN_TZ)
print(date_time_vntz_now.tzname())
1 để chuyển đổi timezone vì API của thư viện chuẩn không đủ linh hoạt làm việc đó với hơn 500 timezone. Không sử dụng
import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())

# Dạng 'Asia/Ho_Chi_Minh'

VN_TZ = pytz.timezone('Asia/Ho_Chi_Minh')
date_time_vntz_now = date_time_utc_now.astimezone(VN_TZ)
print(date_time_vntz_now.tzname())
0 là cơ hội để bạn trở nên tốt hơn.

Lý do cuối cùng mà bạn không nên dùng offset-aware là bởi vì

import datetime
import pytz

# Dạng native date
date_time_now = datetime.datetime.now()
print(date_time_now.tzname())

# Dạng utc
UTC = pytz.utc
date_time_utc_now = UTC.localize(date_time_now)
print(date_time_utc_now.tzname())

# Dạng 'Asia/Ho_Chi_Minh'

VN_TZ = pytz.timezone('Asia/Ho_Chi_Minh')
date_time_vntz_now = date_time_utc_now.astimezone(VN_TZ)
print(date_time_vntz_now.tzname())
0 object của các thư viện của các ngôn ngữ là khác nhau (implementation defined). Hiện nay chưa có chuẩn nào để truyền tzinfo từ ngôn ngữ này sang ngôn ngữ khác hay HTTP ngoài sử dụng UTC offset như hiện tại.