Here is my solution. My test data is
CaptureID AnimalID StationID cDateTime VisitStart VisitEnd
--------- -------- --------- ------------------- ------------------- -------------------
1 1 1 2013-05-21 08:00:00
2 2 1 2013-05-21 08:02:00
3 1 1 2013-05-21 08:07:00
4 2 1 2013-05-21 08:21:00
5 1 1 2013-05-21 08:28:00
Notes:
I have omitted SpeciesID since AnimalID is the unique identifier, so SpeciesID really belongs in the [Animals] table with the other details about that particular animal.
All VisitStart values are initially NULL. That is important for one of the queries below.
To populate VisitStart, we'll just use the cDateTime for any capture that does not have a previous capture within 20 minutes for the same AnimalID and StationID.
UPDATE Captures SET VisitStart = cDateTime
WHERE NOT EXISTS
(
SELECT * FROM Captures c2
WHERE c2.AnimalID=Captures.AnimalID AND c2.StationID=Captures.StationID
AND c2.cDateTime<Captures.cDateTime
AND c2.cDateTime>=DateAdd("n", -20, Captures.cDateTime)
)
That gives us the start times for the discrete visits:
CaptureID AnimalID StationID cDateTime VisitStart VisitEnd
--------- -------- --------- ------------------- ------------------- -------------------
1 1 1 2013-05-21 08:00:00 2013-05-21 08:00:00
2 2 1 2013-05-21 08:02:00 2013-05-21 08:02:00
3 1 1 2013-05-21 08:07:00
4 2 1 2013-05-21 08:21:00
5 1 1 2013-05-21 08:28:00 2013-05-21 08:28:00
Now we can fill in the rest of the VisitStart values by finding the largest previous VisitStart for that AnimalID/StationID
UPDATE Captures
SET VisitStart = DMax("VisitStart", "Captures", "AnimalID=" & AnimalID & " AND StationID=" & StationID & " AND cDateTime<#" & Format(cDateTime, "yyyy-mm-dd Hh:Nn:Ss") & "#")
WHERE VisitStart IS NULL
That gives us
CaptureID AnimalID StationID cDateTime VisitStart VisitEnd
--------- -------- --------- ------------------- ------------------- -------------------
1 1 1 2013-05-21 08:00:00 2013-05-21 08:00:00
2 2 1 2013-05-21 08:02:00 2013-05-21 08:02:00
3 1 1 2013-05-21 08:07:00 2013-05-21 08:00:00
4 2 1 2013-05-21 08:21:00 2013-05-21 08:02:00
5 1 1 2013-05-21 08:28:00 2013-05-21 08:28:00
A similar query can calculate the VisitEnd values
UPDATE Captures
SET VisitEnd = DMax("cDateTime", "Captures", "AnimalID=" & AnimalID & " AND StationID=" & StationID & " AND VisitStart=#" & Format(VisitStart, "yyyy-mm-dd Hh:Nn:Ss") & "#")
The result is
CaptureID AnimalID StationID cDateTime VisitStart VisitEnd
--------- -------- --------- ------------------- ------------------- -------------------
1 1 1 2013-05-21 08:00:00 2013-05-21 08:00:00 2013-05-21 08:07:00
2 2 1 2013-05-21 08:02:00 2013-05-21 08:02:00 2013-05-21 08:21:00
3 1 1 2013-05-21 08:07:00 2013-05-21 08:00:00 2013-05-21 08:07:00
4 2 1 2013-05-21 08:21:00 2013-05-21 08:02:00 2013-05-21 08:21:00
5 1 1 2013-05-21 08:28:00 2013-05-21 08:28:00 2013-05-21 08:28:00
Calculating the visit duration is simply a matter of using DateDiff()
on VisitStart and VisitEnd. Note that the last visit will have a duration of zero since there was only one capture for it.