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

v0.1.0 2026-02-04 13:43 UTC

This package is auto-updated.

Last update: 2026-02-08 07:32:29 UTC


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 afterFind and beforeSave
  • 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)

  1. Reads value from database
  2. Interprets it using serverTimeZone
  3. Converts to displayTimeZone
  4. Formats as inputFormat + P (timezone offset)

UI → DB (beforeSave)

  1. Parses user input using inputFormat (tries both with and without offset)
  2. Interprets it in displayTimeZone (unless offset provided)
  3. Converts to serverTimeZone
  4. 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