I have a Dragino Lora/GPS Shield, which is based on the MT3339 chipset
also used in the Adafruit Ultimate GPS Module. I did a couple of
experiments with this shield in order to answer this very same
questions. My conclusions are in line with the previous answers, namely:
- The rising edge of the PPS signal is aligned with the start of a UTC
second (this I already knew).
- The time stated in an NMEA sentence is valid on the rising edge of
the PPS pulse that immediately preceded that sentence.
Here is what I did:
- I captured both the PPS and the TX signals on a scope, as suggested
in old_timer’s answer

The yellow trace is the PPS signal. It's high for about 100 ms
every second. The cyan trace is TX. This trace shows the serial data is
sent in bursts, with each burst starting shortly after the falling edge
of the PPS signal.
- I timed the serial stream on my computer
The hardware setup was:
amplified antenna → GPS module → Arduino Uno → laptop
The Arduino was used just as a serial/USB gateway (TX of GPS connected
to TX of Arduino, which runs a “do nothing” program). The laptop was
synchronised to within a few milliseconds of UTC via NTP. I used the
following Node.js program for logging timestamped serial data:
const SerialPort = require("serialport");
var port = new SerialPort("/dev/ttyACM0", { baudRate: 9600 });
// Discard the first data chunk.
port.once("data", function() {
// Log subsequent chunks.
port.on("data", function(data) {
console.log(new Date().toISOString().split(/[TZ]/)[1],
JSON.stringify(String(data)));
});
});
The output of the program looks like this (comments added):
20:16:44.810 "\n" <-- end of burst
20:16:45.171 "$GP" <-- start of burst, "GPRMC" sentence
20:16:45.175 "RMC," <--
20:16:45.179 "2016" <-- UTC time: "201645.000",
20:16:45.183 "45.0" <-- meaning 20:16:45.000 UTC
20:16:45.187 "00,A" <--
...
where the first column is the UTC time, with millisecond resolution.
This shows the program (or the serial port driver) is not fast enough to
catch and timestamp individual characters, and there is some buffering
going on. But it is still fast enough four our purposes. It also shows
that the "GPRMC" sentence announcing the time 20:16:45.000 UTC was
transmitted around 20:16:45.18, give or take a few tens of milliseconds.
Note that the same announced time was repeated twice within the same
burst: first in a GPGGA sentence transmitted around 20:16:45.30, then in
a GPGLL sentence transmitted around 20:16:45.74.