nedarta / yii2-datetime-behavior
Timezone-aware datetime behavior for Yii2
Installs: 9
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 0
Forks: 0
Open Issues: 0
Type:yii2-extension
pkg:composer/nedarta/yii2-datetime-behavior
Requires
- php: >=8.1
- yiisoft/yii2: ^2.0
Requires (Dev)
- phpunit/phpunit: ^12.5
README
Timezone-aware DateTime behavior for Yii2 ActiveRecord models.
This extension provides a clean, future-proof way to automatically convert datetime values between database format and user-facing format, while keeping your database consistent (UTC / UNIX) and your UI localized.
Features
- Automatic timezone conversion (UI ↔ DB)
- Works on
afterFindandbeforeSave - Supports UNIX timestamps and DATETIME columns
- Timezone offset inclusion for robust Formatter integration
- Includes
toTimestamp()helper for UTC-normalized timestamps - Multiple attributes per model
- Ready for multi-timezone users
- Easy to test, no UI or widget coupling
- Compatible with Yii2 Formatter (
asDateTime())
Installation
composer require nedarta/yii2-datetime-behavior
Basic Usage
Model configuration
use nedarta\behaviors\DateTimeBehavior; class Post extends \yii\db\ActiveRecord { public function behaviors(): array { return [ [ 'class' => DateTimeBehavior::class, 'attributes' => ['created_at', 'scheduled_at'], 'inputFormat' => 'Y-m-d H:i', // Optional: // 'dbFormat' => 'unix', // default: 'unix' // 'serverTimeZone' => 'UTC', // default: 'UTC' // 'displayTimeZone' => null, // default: null (falls back to Yii::$app->timeZone) ], ]; } }
What Happens Automatically
| Step | Value | Description |
|---|---|---|
| Database value | 1704031200 |
UTC Unix Timestamp |
After find() |
2023-12-31 16:00 +02:00 |
Local time with offset |
| User edits | 2024-01-01 10:00 |
UI Form input (no offset) |
Before save() |
1704103200 |
Converted back to UTC |
The database always stays in UTC / UNIX format.
The model attribute always contains a user-facing value.
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
attributes |
array |
[] |
Attributes to convert |
dbFormat |
string |
unix |
unix, datetime, date, time, or custom PHP format string (e.g. Y-m-d) |
inputFormat |
string |
Y-m-d H:i |
User / UI format |
serverTimeZone |
string |
UTC |
Database timezone (usually UTC) |
displayTimeZone |
`string | null` | null |
How It Works
DB → UI (afterFind)
- Reads value from database
- Interprets it using
serverTimeZone - Converts to
displayTimeZone - Formats as
inputFormat+P(timezone offset)
UI → DB (beforeSave)
- Parses user input using
inputFormat(tries both with and without offset) - Interprets it in
displayTimeZone(unless offset provided) - Converts to
serverTimeZone - Stores as UNIX timestamp or DATETIME string
Automatic Timezone Fallback
If you don't explicitly set displayTimeZone in the behavior, it will automatically pick up your application's timezone from Yii::$app->formatter->timeZone or Yii::$app->timeZone. This ensures consistency across your application without extra configuration.
// In common/config/main.php 'timeZone' => 'Asia/Tokyo', // In your Model - no displayTimeZone needed! [ 'class' => DateTimeBehavior::class, 'attributes' => ['created_at'], ],
Helper Methods
toTimestamp($attribute)
Returns a UTC-normalized UNIX timestamp for a given attribute, regardless of whether the attribute currently holds a raw database value or a localized UI string.
$timestamp = $model->getBehavior('dt')->toTimestamp('created_at');
Querying
When querying the database (e.g., filtering for "today's events"), you must compare against UTC time. You can use the toDbValue() helper to correctly format your filter values.
Option 1: Static Helper (Simplest)
You don't need a model instance, just the class name:
use nedarta\behaviors\DateTimeBehavior; $now = DateTimeBehavior::now(Event::class); $query->andWhere(['>=', 'datetime', $now]);
Option 2: Direct Model Call
If you have a model instance, you can call the behavior methods directly on it:
$model = new Event(); $query->andWhere(['>=', 'datetime', $model->toDbValue('now')]);
Alternatively, if you are using unix timestamps, you can simply use the PHP time() function:
// Only for dbFormat => 'unix' $query->andWhere(['>=', 'datetime', time()]);
Batch Operations
Since ActiveRecord::updateAll() and insertAll() do not trigger model behaviors, you can use the normalize() method to convert your data array before passing it to the database:
$model = new Post(); $dt = $model->getBehavior('dt'); // Normalize UI-formatted data for batch update $data = $dt->normalize([ 'status' => Post::STATUS_PUBLISHED, 'published_at' => '2024-01-01 12:00', // Will be converted to UTC/Unix ]); Post::updateAll($data, ['author_id' => 1]);
What This Extension Does NOT Do
- Render form inputs or widgets
- Depend on Tempus Dominus or any UI library
- Store business logic
- Guess or auto-detect timezones
This extension operates strictly at the model layer.
Recommended Architecture
[ UI / Widget ]
↓
[ ActiveRecord Attribute ]
↓
[ DateTimeBehavior ]
↓
[ Database (UTC / UNIX) ]
Requirements
- PHP 8.1+
- Yii2
^2.0
Testing
Run the test suite via Composer:
composer test
License
MIT
Roadmap
- PHPUnit test suite
- Support for additional database formats (date, time, custom)
- Support for batch operations (e.g.
updateAll()) - Query helper
toDbValue()for correct filtering - Read-only / write-only modes
- Integration with popular date/time widgets