Go APIs for hardware RTC access on Linux and native wake scheduling on Windows and macOS. Each backend exposes its actual capabilities; the library never uses system time as a substitute for a hardware clock read.
Derived from cleroux/rtc, under the MIT license.
Requires Go 1.25 or newer. The only module dependency is golang.org/x/sys.
go get github.com/lib-x/rtc@v0.1.0clock, err := rtc.OpenDefault()
if err != nil { return err }
defer clock.Close()
wakeAt, err := clock.WakeAfter(8 * time.Hour)
if err != nil { return err }
fmt.Println("Wake requested for", wakeAt)Import github.com/lib-x/rtc. This code sets an alarm; it does not shut down or
suspend the machine. On Windows, the timer is cancelled when the handle closes
or the process exits. Keep both alive until the intended wake time. Linux and
macOS events persist after Close. Consult PlatformCapabilities() before
choosing how to manage process lifetime or a power state.
| Capability | Linux | Windows | macOS |
|---|---|---|---|
Hardware clock read (Time) |
RTC device | ErrUnsupported |
ErrUnsupported |
| Wake mechanism | RTC wake alarm ioctl | Native wake-enabled waitable timer | System pmset event |
| Sleep/hibernate resume request | Driver/firmware dependent | Policy/hardware dependent | Model/policy dependent |
| Power-on request after shutdown | Driver/firmware dependent | Unsupported | Model/firmware dependent |
| Alarm readback | Hardware | This instance's target and native signal state | OS schedule |
| Alarm survives close/process exit | Yes | No | Yes |
| Scope | One hardware alarm shared with other software | One unnamed timer per instance | Events with the selected owner name |
| Open argument | Device path | Empty string | Stable application owner name |
| Default | /dev/rtc0 |
Unnamed timer | lib-x.rtc |
Supported() reports whether a native backend exists for the current OS. Linux
(including Go's Android/Linux build target), Windows and macOS have backends.
Other OSes compile with stubs returning ErrUnsupported.
PlatformCapabilities() describes the backend contract, not successful hardware
probing. PowerOnRequest means the OS/driver can accept a power-on request; it
never guarantees that the current machine can boot from full shutdown (S5).
SystemReadback is false on Windows because its reported target is process-local,
not firmware readback. Successful OS scheduling is not proof of actual wake.
| Method | Purpose |
|---|---|
OpenDefault() |
Open the platform default |
Open(identifier) |
Select a Linux device or macOS owner; Windows requires empty |
Time() |
Read hardware time in UTC; Linux only |
WakeAfter(duration) |
Schedule relative wake, rounded up to a second |
SetWakeAlarm(time) |
Schedule at an absolute UTC second; truncate subseconds |
WakeAlarm() |
Read alarm state within the backend's documented scope |
CancelWakeAlarm() |
Cancel within that scope; safe to repeat |
Close() |
Release the instance; safe to repeat |
Methods on one instance are safe for concurrent use. ErrClosed identifies use
after close. Wrapped system errors support errors.Is. ErrAlarmMismatch
identifies readback failures on Linux/macOS. Writes may already have changed
state when a later check fails; inspect WakeAlarm before retrying.
The OS must maintain the RTC in UTC. Time reads hardware time and WakeAfter
uses that reading; neither modifies the system clock. SetWakeAlarm and
CancelWakeAlarm verify hardware readback. Device permissions, date limits and
wake support depend on the driver. Containers need access to /dev/rtc0.
Only one alarm exists per device: coordinate ownership with other applications.
Compared with cleroux/rtc v1.0.0, this backend fixes RTC_WKALM_RD being confused
with RTC_ALM_READ, retains a valid date during cancellation, normalizes UTC,
verifies writes, and serializes operations against idempotent close. Descriptor
creation uses CLOEXEC. This focused API does not include upstream ticker/timer APIs.
Uses CreateWaitableTimerW and absolute SetWaitableTimer with resume enabled.
WakeAfter uses the system clock. The native timer can resume a suspended
system if wake timers and firmware policy allow it. It cannot boot a fully
shut-down system. If Windows reports resume as unsupported, the library returns
ErrUnsupported instead of advertising a successful wake timer.
WakeAlarm reports only this instance's target and native signal status. It does
not enumerate global timers or read the hardware RTC. Keep the process running
and handle open during sleep/hibernation. Close and process exit cancel the timer.
Uses /usr/bin/pmset schedule wakeorpoweron, with bounded execution and separate
arguments, without a shell. Root permissions are required for modifications.
Use a stable unique owner, e.g. rtc.Open("com.example.backup"), to recover and
cancel your event after restart. Multiple processes using the same owner must
coordinate. Only that owner's exact event is cancelled; global cancelall and
system repeating schedules are never used. Conflicting or unrecognized owner
records produce errors instead of broad cancellation.
WakeAfter uses the system clock. pmset uses local wall time, so the backend
converts UTC to the system timezone and verifies the resulting OS schedule.
Ambiguous local timestamps and dates beyond 2068 are rejected. A later system
timezone change can affect how schedules are displayed or interpreted; read back
before relying on them. Actual power-on support depends on model, firmware, power
connection and system policy. The library never claims direct hardware RTC reads.
go test -race ./... uses fake devices, fake native timers or fake command runners.
Tests never write real wake events, change power settings or shut down a machine.
CI runs tests and vet on Linux, Windows and macOS, and checks Linux arm64 builds.
Real sleep/hibernate/S5 wake testing is a separate hardware validation step.