The 26-year-old joined former captain Martin Crowe on 17 test centuries when he hit a full toss from Dean Elgar to the fence for his 10th boundary.
Williamson had moved to 148 at stumps with Mitchell Santner on 13, the home side holding a seven run lead over South Africa’s first innings of 314.
Williamson also surpassed 5,000 test runs, the fastest New Zealander to do so in his 110th innings. Just five other of his countrymen have reached the mark.
The skipper shared in a 190-run partnership with opener Jeet Raval, who passed 50 for the fifth time and proved the perfect foil to the New Zealand skipper during a knock of 88.
The lefthander was dropped on 83 by South Africa captain Faf du Plessis and then got bogged down as he battled against the second new ball.
He failed to score a run for 25 deliveries before hitting Kagiso Rabada for a boundary but he fell shortly after when wicketkeeper Quinton de Kock took a brilliant, diving catch with one hand from an inside edge off Morne Morkel.
Tom Latham was the first wicket to fall when the opener became Morkel’s 250th test scalp during the first session which was delayed for 90 minutes due to overnight rain.
Rabada slowed New Zealand’s momentum in the final hour of play when he trapped Neil Broom in front for 12 and then had Henry Nicholls caught by De Kock on his next delivery. Santner, however, thwarted the hat-trick ball.
South Africa lead the series 1-0 having won the second game in Wellington by eight wickets. The rain-hit first test in Dunedin ended in a draw.
(Reporting by Greg Stutchbury; Editing by Ian Ransom)