English Version
Developer Guide: Handling Dates and Timezones
This document outlines the standard conventions for handlingdate and datetime attributes in our Laravel application with a MongoDB database. Adhering to these conventions is crucial for data integrity, consistency, and scalability.
Core Philosophy: Store as UTC, Work with Local Time
Our system is built on a single, industry-standard principle:- Storage Layer: All date and time information is stored in the database as a native BSON
Dateobject, which is always in UTC. This provides an unambiguous, universal source of truth. - Application Layer: All interaction with date objects within the application (in controllers, views, etc.) is done using
Carbonobjects that are automatically converted to our application’s default timezone (defined inconfig/app.timezone, e.g.,Asia/Jakarta).
The Core Components
MongoUtcDateCast&MongoUtcDateTimeCast: These are “smart” custom casts.
- On
set(Saving): They take a local time string, convert it to a UTC timestamp, and ensure it’s saved as a native BSONDate.MongoUtcDateCastalso appliesstartOfDay(). - On
get(Retrieving): They take the UTC BSONDatefrom the database and automatically convert it into aCarbonobject in the application’s local timezone. This makes the entire UTC conversion process invisible to the rest of the application.
FannableAttributesTrait: This is a powerful helper for creating derivative, read-only helper fields. Its primary roles are:
- To automatically create a companion
<fieldname>Tzfield (e.g.,ExpDateTz) containing the timezone string (Asia/Jakartaby default). - To generate additional formatted string versions of a date for easy display or API responses (e.g.,
ExpDateStr).
How to Use It (The Conventions)
Step 1: Model Setup
To make any model’s date fields “smart”, follow these steps:- Use the Trait: Add
use FannableAttributes;to your model. - Configure Casts: In the
$castsarray, map yourdateanddatetimefields to the appropriate custom cast. - (Optional) Configure Fan-Out: In the
$fanOutAttributesarray, define any additional string formats you need. TheTzfield will be created automatically for any field in this array. - (Optional) API Timezone Override: Add
'tz'to your model’s$fillablearray to allow API calls to specify a timezone.
Document.php
Step 2: Saving Data
- From Web Forms (Default Timezone): Your controller code is simple. The system handles the rest.
- From an API (Timezone Override): If an incoming request includes a
tzfield, the system will use it to interpret the date string.
Step 3: Displaying Data
Because our “smart” casts automatically convert the date to the local timezone on retrieval, your view/Blade code is incredibly simple. You do not need to call->setTimezone() in your views.
Querying Data (Considerations)
This is the most critical part to remember to avoid bugs. The Golden Rule: Always build your query boundaries using local timeCarbon objects. The database driver will automatically convert them to UTC for the query.
- Querying a
datetimeRange: Find documents updated between 3 PM and 4 PM local time.
- Querying a
date-only Field: Find documents whereExpDateis October 31st, 2025 (local time).
Caveats and Best Practices
- Database Viewer: Be aware that tools like Studio 3T, in their default JSON view, may display BSON Dates as strings. This can be misleading. Use the “Tree View” or “Table View” to see the correct
ISODatetype. - The
TzField: The automatically generated<fieldname>Tzfield is for context and display logic. Do not attempt to query against it for date ranges. Always query against the primary, indexed BSONDatefield (e.g.,ExpDate). - Consistency: Use these casts and traits for all date and datetime fields across the application to ensure predictable, bug-free behavior.
Summary of Resulting Data
A correctly saved document in MongoDB will look like this, providing the best of all worlds:Versi Bahasa Indonesia
Panduan Developer: Menangani Tanggal dan Zona Waktu
Dokumen ini menjelaskan konvensi standar untuk menangani atributdate (tanggal) dan datetime (tanggal-waktu) pada aplikasi Laravel kita dengan database MongoDB. Mengikuti konvensi ini sangat penting untuk integritas, konsistensi, dan skalabilitas data.
Filosofi Inti: Simpan sebagai UTC, Gunakan Waktu Lokal
Sistem kita dibangun di atas satu prinsip standar industri:- Layer Penyimpanan (Database): Semua informasi tanggal dan waktu disimpan di database sebagai objek BSON
Datebawaan MongoDB, yang selalu dalam format UTC. Ini memberikan sumber kebenaran tunggal yang universal dan tidak ambigu. - Layer Aplikasi: Semua interaksi dengan objek tanggal di dalam aplikasi (di controller, view, dll.) dilakukan menggunakan objek
Carbonyang secara otomatis dikonversi ke zona waktu default aplikasi kita (didefinisikan diconfig/app.timezone, contoh:Asia/Jakarta).
Komponen Inti
MongoUtcDateCast&MongoUtcDateTimeCast: Ini adalah custom cast “pintar”.
- Saat
set(Menyimpan): Mengambil string waktu lokal, mengubahnya menjadi timestamp UTC, dan memastikan data disimpan sebagai objek BSONDate.MongoUtcDateCastjuga menerapkanstartOfDay(). - Saat
get(Mengambil): Mengambil objek BSONDateUTC dari database dan secara otomatis mengubahnya menjadi objekCarbondalam zona waktu lokal aplikasi. Ini membuat seluruh proses konversi UTC tidak terlihat oleh bagian aplikasi lainnya.
FannableAttributesTrait: Ini adalah helper yang kuat untuk membuat field turunan (hanya-baca) secara otomatis. Peran utamanya adalah:
- Secara otomatis membuat field pendamping
<fieldname>Tz(contoh:ExpDateTz) yang berisi string zona waktu (Asia/Jakartasecara default). - Membuat versi string tambahan dari tanggal untuk kemudahan tampilan atau respons API (contoh:
ExpDateStr).
Cara Penggunaan (Konvensi)
Langkah 1: Pengaturan Model
Untuk membuat field tanggal pada model menjadi “pintar”, ikuti langkah-langkah ini:- Gunakan Trait: Tambahkan
use FannableAttributes;ke model Anda. - Konfigurasi Casts: Di dalam array
$casts, petakan fielddatedandatetimeAnda ke cast kustom yang sesuai. - (Opsional) Konfigurasi Fan-Out: Di dalam array
$fanOutAttributes, definisikan format string tambahan yang Anda butuhkan. FieldTzakan dibuat secara otomatis untuk setiap field yang ada di dalam array ini. - (Opsional) Override Zona Waktu API: Tambahkan
'tz'ke array$fillablepada model Anda untuk mengizinkan panggilan API menentukan zona waktu.
Document.php
Langkah 2: Menyimpan Data
- Dari Form Web (Zona Waktu Default): Kode controller Anda tetap sederhana. Sistem akan menangani sisanya.
- Dari API (Override Zona Waktu): Jika permintaan yang masuk menyertakan field
tz, sistem akan menggunakannya untuk menginterpretasikan string tanggal.
Langkah 3: Menampilkan Data
Karena cast “pintar” kita secara otomatis mengonversi tanggal ke zona waktu lokal saat pengambilan data, kode view/Blade Anda menjadi sangat sederhana. Anda tidak perlu memanggil->setTimezone() di dalam view.
Melakukan Query (Pertimbangan)
Ini adalah bagian paling penting untuk diingat agar terhindar dari bug. Aturan Emas: Selalu bangun batasan query Anda menggunakan objekCarbon waktu lokal. Driver database akan secara otomatis mengubahnya ke UTC untuk query.
- Query Rentang
datetime: Cari dokumen yang diperbarui antara jam 3 sore dan 4 sore waktu lokal.
- Query
date-only (hanya tanggal): Cari dokumen di manaExpDateadalah 31 Oktober 2025 (waktu lokal).
Peringatan dan Praktik Terbaik (Caveats)
- Tampilan Database (Viewer): Hati-hati, tools seperti Studio 3T pada tampilan JSON defaultnya mungkin menampilkan BSON
Datesebagai string. Ini bisa menyesatkan. Gunakan “Tree View” atau “Table View” untuk melihat tipeISODateyang benar. - Field
Tz: Field<fieldname>Tzyang dibuat otomatis adalah untuk konteks dan logika tampilan. Jangan mencoba melakukan query rentang tanggal pada field ini. Selalu lakukan query pada field BSONDateutama yang terindeks (contoh:ExpDate). - Konsistensi: Gunakan cast dan trait ini untuk semua field tanggal dan datetime di seluruh aplikasi untuk memastikan perilaku yang dapat diprediksi dan bebas bug.
