Or was the clock maintained in software, and based off of something like the 18.2 Hz system timer interrupt?
This is exactly how time was tracked; you can see the implementation of the timer tick handler in the IBM PC Technical Reference, page A-77. It updates a counter, stored in memory as a double word at 0x0040:0x006C, and checks for elapsing days, setting the flag at 0x0040:0x0070 on date changes. These values can be retrieved using interrupt 0x1A service 0x00.
The “real” date and time are tracked by the operating system; in DOS, they could be retrieved using interrupt 0x21 service 0x2A and set using service 0x2B.
System time handling after boot didn’t change with the advent of battery-backed RTCs: the system date and time were still supposed to be updated using the timer IRQ. The BIOS added functions to provide access to the RTC (e.g. interrupt 0x1A service 0x02 to read the clock time), and DOS used those to initialise its own date and time; but after that the RTC wasn’t used in normal operations.
This is still the case nowadays: the RTC is used to initialise the date and time at boot, and after that time is tracked using timers (not the same ones as in the original IBM PC, but still timers).
If the latter, was it common to lose clock accuracy if the timer rate was changed by a running program?
I don’t remember it being common, but it was possible. I don’t think all that many programs changed the timer rate on the IBM PC back then (pre-AT), and those that did could take the new rate into account before chaining to the previous handler. Programs which had to hook the timer were supposed to hook interrupt 0x1C, not the IRQ-driven interrupt 0x08.
There were other tracking bugs though, for example DOSKEY
in DOS 5 could miss date changes (somewhat later than the PC and XT).