Timestamps
Ormed provides automatic timestamp management for created_at and updated_at columns.
Prerequisites
What You’ll Learn
- How timestamp mixins change generated tracked models
- How
createdAt/updatedAtbehave with Carbonized types - How to configure timezone-aware timestamp usage
Step Outcome
By the end of this page, you should be able to:
- Enable timestamps consistently in models + migrations
- Understand automatic timestamp updates on insert/update
- Choose standard vs timezone-aware timestamp mixins
Enabling Timestamps
Add the Timestamps marker mixin to your model:
(table: 'posts')
class TimestampPost extends Model<TimestampPost> with Timestamps {
const TimestampPost({required this.id, required this.title});
(isPrimaryKey: true, autoIncrement: true)
final int id;
final String title;
}
The code generator detects this mixin and:
- Adds virtual
createdAtandupdatedAtfields if not explicitly defined - Applies timestamp implementation to the generated tracked class
- Automatically sets timestamps on insert/update operations
Carbon Integration
Ormed integrates with the Carbonized library to provide a fluent API for date manipulation. The createdAt and updatedAt getters return a CarbonInterface? instance.
final user = await repo.find(1);
if (user != null) {
print(user.createdAt?.diffForHumans()); // "2 hours ago"
print(user.updatedAt?.addDays(1).isFuture); // true
}
Ormed returns immutable Carbon instances from timestamp getters. This means you can safely chain methods like subDay() without accidentally mutating the model's state:
final yesterday = user.createdAt?.subDay(); // Safe! Returns new instance
print(user.createdAt); // Original value unchanged
See the Date and Time Handling guide for more details on mutable vs immutable Carbon behavior.
Flexible Setters
The createdAt and updatedAt setters accept both standard Dart DateTime objects and CarbonInterface instances.
user.updatedAt = DateTime.now();
// or
user.updatedAt = Carbon.now().subDays(1);
Timezone-Aware Timestamps
For timestamps stored in UTC, use TimestampsTZ:
(table: 'articles')
class TimestampArticleTz extends Model<TimestampArticleTz> with TimestampsTZ {
const TimestampArticleTz({required this.id, required this.title});
(isPrimaryKey: true, autoIncrement: true)
final int id;
final String title;
}
This ensures:
- All timestamps are converted to UTC before storage
- Timestamps remain in UTC when retrieved
- Your application handles timezone conversion for display
Prefer UTC storage for multi-region systems; localize only at presentation boundaries.
Migration Setup
Add timestamp columns in your migration:
- Notes
- Code
If you use Timestamps/TimestampsTZ, keep the schema column names aligned with your model configuration.
class AddTimestampsToPosts extends Migration {
const AddTimestampsToPosts();
void up(SchemaBuilder schema) {
schema.table('posts', (table) {
// Non-timezone aware (stored as-is)
table.timestamps();
// OR timezone aware (UTC storage)
// table.timestampsTz();
// OR nullable timestamps
// table.nullableTimestamps();
// table.nullableTimestampsTz();
});
}
void down(SchemaBuilder schema) {
schema.table('posts', (table) {
table.dropColumn('created_at');
table.dropColumn('updated_at');
});
}
}
Custom Column Names
By default, Ormed uses created_at and updated_at. These can be customized via model configuration if needed.
Behavior
On Insert
created_atis set to the current timestampupdated_atis set to the current timestamp
On Update
updated_atis automatically updatedcreated_atremains unchanged
Manual Control
You can manually set timestamps if needed:
// You can manually set timestamps using DateTime or Carbon:
// final post = $TimestampPost(
// id: 0,
// title: 'My Post',
// createdAt: DateTime(2024, 1, 1),
// updatedAt: Carbon.now().subDays(1),
// );
Disabling Automatic Updates
If you still want timestamp columns but need to control updates yourself, disable auto-updates at the model level:
(table: 'audit_logs', timestamps: false)
class AuditLog extends Model<AuditLog> with Timestamps {
const AuditLog({required this.id, required this.message});
(isPrimaryKey: true)
final int id;
final String message;
}
You can also suppress timestamp updates for a scoped block:
await Model.withoutTimestampsOn(<Type>[Post], () async {
await Posts.query().where('id', 42).update({'title': 'No touch'});
});
Without Timestamps
If you don't need automatic timestamps, simply don't include the mixin:
(table: 'logs')
class Log extends Model<Log> {
// No timestamps mixin - manual control
const Log({required this.id, required this.message, this.timestamp});
(isPrimaryKey: true)
final int id;
final String message;
final DateTime? timestamp;
}
Read This Next
Verify Timestamp Behavior
- Insert model and confirm both
created_at+updated_atare set. - Update model and confirm only
updated_atchanges. - Validate timezone behavior (
TimestampsvsTimestampsTZ) in your runtime.