Getting S3 objects' last modified datetimes with boto
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
S3 stores a last-modified timestamp for each object, and in Python boto3 exposes that timestamp as a timezone-aware datetime. The practical questions are usually which API to call, how to handle pagination, and how to compare the returned timestamp safely.
Use head_object for One Known Key
If you already know the object key, the cleanest choice is head_object.
This avoids listing a whole prefix just to retrieve metadata for one object.
Use list_objects_v2 When You Are Already Listing
If you are enumerating keys anyway, list_objects_v2 includes LastModified in each object summary.
This is convenient for prefix-wide reporting or when you want to find the newest object under a path.
The Value Is a Real datetime
A very useful detail is that LastModified is not returned as a plain string. It is already a Python datetime with time-zone information attached.
Because the value is aware rather than naive, compare it to other aware datetimes such as datetime.now(timezone.utc).
The Resource API Exposes It Too
If your codebase prefers the resource-style API, the same metadata is available there.
Choose the client or resource style that matches the rest of your application. The metadata itself is the same idea either way.
Find the Most Recent Object Under a Prefix
S3 does not sort objects by last-modified time for you. If you need the newest object, fetch the candidates and compute it in Python.
For a small prefix, this is straightforward. For large prefixes, combine the same idea with pagination.
Paginate Large Listings
list_objects_v2 returns at most 1000 keys per response, so large prefixes require a paginator.
If you are searching for the newest object, keep a running maximum while paging instead of storing every result in memory.
One more practical concern is clock interpretation across systems. Even though S3 metadata is returned in a timezone-aware form, your application logic should still normalize timestamps consistently before combining them with database values, logs, or user-facing time displays.
If your goal is change detection rather than display, pair the timestamp with the object key and other metadata such as size or ETag when appropriate. Relying on one field alone can be too simplistic for some workflows.
Common Pitfalls
Treating LastModified like a plain string and comparing it lexicographically is unnecessary and error-prone because boto already gives you a datetime.
Using bucket listing when you already know the exact key adds extra requests and latency.
Ignoring pagination can make your code silently miss objects beyond the first 1000 results.
Summary
- Use
head_objectwhen you know the key and only need one object's metadata. - Use
list_objects_v2when you are listing keys and need metadata for many objects. - '
LastModifiedis returned as a timezone-aware Pythondatetime.' - Paginate large prefixes and compare timestamps as datetimes, not as strings.
Related reading
- Getting started with secure AWS CloudFront streaming with Python
- getting The bucket does not allow ACLs Error
- GKE - How to serve HTTPS via the L7 load balancer?
- GKE autopilot has scaled up my container resources contary to resource requests
- Getting tensorflow is not a supported wheel on this platform
- Getting the class name of an instance
- GKE cluster suddenly not autoscaling nodepool
- GKE does not scale to/from 0 when autoscaling enabled

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.