Skip to main content

Timestamps

Fields named CreatedAt and UpdatedAt are kept up to date for you, whether they come from ant.Base or not. You never have to set them.

What moves them​

type Note struct {
ID int64
CreatedAt time.Time
UpdatedAt time.Time
Text string
}
ActionCreatedAtUpdatedAt
Insert, InsertMany, UpsertSetSet
SaveChanges with a changeMoved
SaveChanges with no changeLeft alone
Bulk UpdateMoved

Times are stored at the database's precision, so the value on your struct matches what's in the table. If you set a time yourself, it's kept on insert, and ant.Set(&U.UpdatedAt, t) wins on update.

A clock for tests​

ant.WithNow lets you set the clock, which keeps tests predictable.

now := time.Date(2026, 1, 1, 12, 0, 0, 0, time.UTC)

clock := ant.WithNow(func() time.Time { return now })

db, err := ant.Open[AppDB](ctx, postgres.Dialect, dsn, clock)

Unix seconds​

ant.UnixTime stores a time as an integer, and it's kept up to date all the same.

type Stamped struct {
ID int64
CreatedAt ant.UnixTime
UpdatedAt ant.UnixTime
}

Opting out​

b.NoTimestamps turns all of this off for one model, and leaves the fields as you set them.

func (Note) Configure(b *ant.ModelBuilder[Note]) {
b.NoTimestamps()
}

To move a parent's UpdatedAt when a child is written, see Touch.