Timezones improperly handled when retrieving clips
I had some motion on one of my cameras ~30 mins ago but look at the following:
>>> await blink.get_videos_metadata(since=str(datetime.now(timezone.utc) - timedelta(hours=1)), stop=2)
[]
>>> await blink.get_videos_metadata(since=str(datetime.now(timezone.utc) - timedelta(hours=2)), stop=2)
[]
>>> await blink.get_videos_metadata(since=str(datetime.now(timezone.utc) - timedelta(hours=3)), stop=2)
[]
>>> await blink.get_videos_metadata(since=str(datetime.now(timezone.utc) - timedelta(hours=4)), stop=2)
[]
>>> await blink.get_videos_metadata(since=str(datetime.now(timezone.utc) - timedelta(hours=5)), stop=2)
[]
>>> await blink.get_videos_metadata(since=str(datetime.now(timezone.utc) - timedelta(hours=6)), stop=2)
[{'id': 15873035115, 'created_at': '2025-11-22T14:12:13+00:00', ...
I expect timedelta of 1 hour to catch it, but it doesn't until a delta of 6 hours. My timezone is UTC - 5.
I looked at the get_videos_metadata function implementation and noticed this behavior:
>>> datetime.now(timezone.utc)
datetime.datetime(2025, 11, 22, 14, 47, 36, 693905, tzinfo=datetime.timezone.utc)
>>> util.get_time(datetime.now(timezone.utc).timestamp())
'2025-11-22T14:47:46-0500'
Those two dates should be the same but they seem different due to the UTC offset. I believe there's a TZ handling bug.
This seems to give the correct result:
dt = datetime.now(timezone.utc) - timedelta(hours=1) + datetime.now().astimezone().utcoffset()
await blink.get_videos_metadata(since=str(dt), stop=2)
As an aside, the stop parameter is confusing since the code uses for page in range(1, stop). This means stop=2 is needed for the first page.
There 100% is a time zone handling bug that I've never been able to track down. I don't know if it's something I introduced in the library or (my main suspicion) with the way Blink handles timestamp-based API requests.
Noted on the confusing behavior with stop, I agree with you there.
Also I think this is the same issue as #604 so there's some discussion there (I'll keep both open for now)
I think the bug might be in your get_time() util function, which uses a bunch of older Python functions. You can probably use datetime now for everything, and I believe Blink expects UTC times (all the data I've seen has +00:00).
Probably the simplest fix for the stop issue is to use stop + 1 in the for loop.
think the bug might be in your get_time() util function, which uses a bunch of older Python functions. You can probably use datetime now for everything, and I believe Blink expects UTC times (all the data I've seen has +00:00).
It's definitely possible the bug is there- but you can see in the issue referenced earlier that no amount of massaging actually worked with the API. It's been a few years, though, so maybe they fixed that. My initial implementation used UTC only which worked in the Americas, but not Europe (if I remember correctly...might have that reversed), for example. So, unless something has changed on Blinks end, they handle regions differently and it's been difficult to decode.
Feel free to mess around with it- I've been wanting a bullet proof solution here for some time, so would be more than happy if someone else could give it a go!
Probably the simplest fix for the stop issue is to use stop + 1 in the for loop.
Yep agreed with that
My initial implementation used UTC only which worked in the Americas, but not Europe (if I remember correctly...might have that reversed), for example. So, unless something has changed on Blinks end, they handle regions differently and it's been difficult to decode.
Ah, probably the fix will be more complicated then.
I also noticed that the default since=last_refresh also has an issue. So a loop like this misses new clips:
while True:
time.sleep(30)
if blink.refresh():
new_media = await self.blink.get_videos_metadata(since=None, stop=2) # default to last_refresh
...
Did a little more digging, and dumping my findings here.
I modified the API wrapper request_videos() to accept the actual timestamp string (with no conversion) and noticed this:
>>> for i in range(90): print(i, (await request_videos(blink, '2025-11-26T12:18:39+0000', page=0))['media'][i]['created_at'])
...
0 2025-11-26T16:50:22+00:00
1 2025-11-26T15:54:56+00:00
2 2025-11-26T13:44:24+00:00
3 2025-11-26T12:23:01+00:00
4 2025-11-25T23:47:47+00:00
5 2025-11-26T16:50:59+00:00
...
Here 2025-11-26T12:18:39+0000 is the timestamp of a recent clip and I'm trying to get the subsequent ones only. Notice that it doesn't sort the media by created_at but it's sorted by updated_at:
>>> for i in range(90): print(i, (await request_videos(blink, '2025-11-26T12:18:39+0000', page=0))['media'][i]['updated_at'])
...
0 2025-11-26T18:20:44+00:00
1 2025-11-26T18:20:43+00:00
2 2025-11-26T18:20:43+00:00
3 2025-11-26T18:20:42+00:00
4 2025-11-26T18:20:42+00:00
5 2025-11-26T16:54:51+00:00
...
Didn't look at the other pages to confirm, but I'm guessing all the returned medias are after the date I requested.
So it seems that the since argument refers to the updated_at field, not the created_at field. No idea what "updated" refers to though.
Anyway, looks like this is already known in check_new_videos(), but I recall some bugs there.