OpenCV VideoCapture and imwrite missing timezone support for timestamps
0 reputation · 24 Jul 2022, 17:45 UTC
0 reputation · 24 Jul 2022, 17:45 UTC
The goal is to obtain frame timestamps that reflect absolute civil time with a specific regional time‑zone offset when capturing video or writing images.
Currently, OpenCV’s VideoCapture::get(CAP_PROP_POS_MSEC) returns only elapsed milliseconds since stream start and provides no wall‑clock or timezone information, while imwrite discards any existing EXIF DateTimeOriginal field and does not embed a timezone offset, leaving the timestamp ambiguous.
Given the absence of an API to attach or interpret a time‑zone to these timestamps, what strategies can be used to associate a known zone with frame data without modifying the library?
VideoCapture?DateTimeOriginal when using imwrite?34275 reputation · 24 Jul 2022, 23:21 UTC
OpenCV does not store or expose timezone information; you must supply the offset yourself and attach it to the frame data externally.
OpenCV’s VideoCapture::get(CAP_PROP_POS_MSEC) returns raw milliseconds elapsed since the stream started, derived from the system clock without any conversion to civil time. imwrite writes images using the C library’s time/localtime functions, which produce a DateTimeOriginal string without a timezone offset, and the library does not provide an API to embed one.
CAP_PROP_POS_MSEC is a monotonic offset from stream start, not a wall‑clock timestamp.imwrite saves JPEG/PNG, any EXIF DateTime field is generated from localtime and lacks a +HH:MM offset.std::chrono::zoned_time or datetime object.VideoCapture timestampsdatetime.now().astimezone().utcoffset() in Python).pos_msec = cap.get(cv2.CAP_PROP_POS_MSEC).datetime (utc = datetime.utcfromtimestamp(pos_msec/1000.0)) and then add the previously captured offset to obtain the civil time in the desired zone.DateTimeOriginal when using imwritecv2.imwrite, use an external tool to rewrite the EXIF block with a timezone‑aware string. Example with exiftool (command line):
exiftool -DateTimeOriginal="2025:09:26 14:32:10+02:00" image.jpg
Pillow to read the saved image, modify the EXIF dict, and write it back:
from PIL import Image, ExifTags
import piexif
img = Image.open('image.jpg')
exif_dict = piexif.load(img.info.get('exif', b''))
# Create a timezone‑aware string, e.g. '2025:09:26 14:32:10+02:00'
exif_dict['Exif'][piexif.ExifIFD.DateTimeOriginal] = b'2025:09:26 14:32:10+02:00'
exif_bytes = piexif.dump(exif_dict)
img.save('image.jpg', exif=exif_bytes)
cv2.putText before saving.If you need the timezone inside the video container, write the raw frames with cv2.VideoWriter and then use ffmpeg to add a user‑data tag or metadata entry:
ffmpeg -i raw.mp4 -metadata:s:v:0 timezone="+02:00" -c copy output.mp4
This does not alter frame timing; it only adds interpretive context.
To confirm whether the above approach fits your workflow, please specify: Which programming language binding (Python, C++, Java, etc.) are you using for OpenCV? The answer influences whether you can use datetime with zoneinfo directly or need to rely on std::chrono and external libraries.
Use comments to ask for clarification. Post a solution as an answer.
34,275 reputation · 24 Jul 2022, 18:40 UTC
One clarification on the conversion steps above: CAP_PROP_POS_MSEC counts elapsed time since the stream or file opened, so passing it straight to utcfromtimestamp() yields a 1970-based value. Anchor it first: log the host UTC clock when the capture opens, compute anchor + timedelta(milliseconds=pos_msec), and convert per frame with zoneinfo (Python 3.9+). Anchoring in UTC rather than a fixed local offset also keeps long recordings correct across DST transitions.
Also worth knowing: POS_MSEC reliability varies by backend. Live V4L2 or some FFmpeg sources can return 0 or estimated values, so for live cameras grabbing time.time() per read() is often more trustworthy than the property.
For the EXIF side, the offset belongs in OffsetTimeOriginal (EXIF 2.31) alongside DateTimeOriginal; inject both post-write with ExifTool, e.g. exiftool -DateTimeOriginal='...' -OffsetTimeOriginal='+05:30' frame.jpg, then verify with exiftool -DateTimeOriginal -OffsetTimeOriginal, since many viewers still ignore the offset tag.