Sign in to run and submit your work
Reading is open to everyone. Running code and saving drafts need an account so your work is yours and comes back on your next visit.
or
CODE WORKSPACE
Three producers write the same field three ways: ...Z, ...+05:30, and a naive local time with no offset at all. Everything downstream buckets by day, so they have to agree before anything is grouped.
Write normalise_timestamps(rows, assume_zone). Return the normalised records and the rows that could not be trusted.
Function to write
normalise_timestamps(rows: list[dict], assume_zone: str) -> dictA dict with the UTC-normalised `records` and the `rejected` rows with reasons.
How to approach it
Run the starter on the naive row and ask what zone it assumed.
Sample cases
+ 2 held back until you submit
three forms and two failures
UTC, an offset, and a naive timestamp all converge — and the blank and the nonsense are rejected separately.
Input
Argument 1
| id | at |
|---|---|
| a | 2026-09-01T10:00:00Z |
| b | 2026-09-01T10:00:00+05:30 |
| c | 2026-09-01 10:00:00 |
| d | |
| e | nope |
Argument 2
'Asia/Kolkata'Returns
{
'records': [
{
'id': 'a',
'at': '2026-09-01T10:00:00Z'
},
{
'id': 'b',
'at': '2026-09-01T04:30:00Z'
},
{
'id': 'c',
'at': '2026-09-01T04:30:00Z'
}
],
'rejected': [
{
'row': 3,
'value': '',
'reason': 'empty'
},
{
'row': 4,
'value': 'nope',
'reason': 'unparseable'
}
]
}everything already in UTC
A value already in UTC comes back unchanged, in the same Z form it arrived in.
Input
Argument 1
| id | at |
|---|---|
| a | 2026-09-01T10:00:00Z |
Argument 2
'UTC'Returns
{
'records': [
{
'id': 'a',
'at': '2026-09-01T10:00:00Z'
}
],
'rejected': []
}no rows
An empty batch normalises to two empty lists rather than raising on the zone lookup.
Input
Argument 1
[] (empty list)
Argument 2
'UTC'Returns
{
'records': [],
'rejected': []
}Constraints
{'records': [{'id': ..., 'at': ...}], 'rejected': [...]}.datetime.fromisoformat, accepting a trailing Z by treating it as +00:00.assume_zone to it — the producer told you out of band, and guessing UTC would silently shift the day.Z.empty for a blank or missing value, unparseable for one that will not decode, unknown zone when assume_zone does not exist.{'row': <index>, 'value': <the raw value>, 'reason': ...} and do not stop the batch.Worked example
Row b arrives as 2026-09-01T10:00:00+05:30 and row c as the naive 2026-09-01 10:00:00 with Asia/Kolkata assumed.
Both become 2026-09-01T04:30:00Z, which is the point: the offset form said so explicitly and the naive form needed a decision. Row d is blank and row e is nope, and reporting those as two different reasons is what tells somebody whether a column stopped being populated or a producer changed format.
What this tests
That a naive timestamp is missing information rather than being UTC, that the assumption has to be supplied rather than guessed, and that a day boundary in the wrong zone moves rows between days without anything erroring.
normalise_timestamps(rows: list[dict], assume_zone: str) -> dictSubmit for review to find out what your query gets right, what it gets wrong, and how it compares with the best working query for this exercise.
This scenario runs a full workspace — editor, canvas and results side by side. It needs a laptop or desktop to be usable. Open this page on a bigger screen to start building.