# `sqlgen::Timestamp` The `sqlgen::Timestamp` class provides a type-safe way to handle SQL timestamp fields in C++. It supports both regular timestamps and timestamps with time zones, with format validation at runtime. The class is essentially a wrapper around `std::tm` that adds format validation and SQL integration. ## Usage ### Basic Definition Define a timestamp field in your struct with a specific format: ```cpp struct Person { sqlgen::PrimaryKey id; std::string first_name; std::string last_name; sqlgen::Timestamp<"%Y-%m-%d %H:%M:%S"> birthdate; // Regular timestamp sqlgen::Timestamp<"%Y-%m-%d %H:%M:%S%z"> created_at; // Timestamp with timezone }; ``` This generates the following SQL schema: ```sql CREATE TABLE IF NOT EXISTS "Person"( "id" INTEGER NOT NULL, "first_name" TEXT NOT NULL, "last_name" TEXT NOT NULL, "birthdate" TIMESTAMP NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL, PRIMARY KEY ("id") ); ``` ### Construction and Assignment Create and assign timestamp values: ```cpp // Direct string assignment Person person{ .id = 1, .first_name = "Homer", .last_name = "Simpson", .birthdate = "1989-12-17 12:00:00", .created_at = "2024-03-20 15:30:00+0000" }; // Create from std::tm std::tm birth_tm = std::tm{}; birth_tm.tm_year = 89; // Years since 1900 birth_tm.tm_mon = 11; // 0-11 for months birth_tm.tm_mday = 17; // Day of month birth_tm.tm_hour = 12; birth_tm.tm_min = 0; birth_tm.tm_sec = 0; sqlgen::Timestamp<"%Y-%m-%d %H:%M:%S"> birthdate(birth_tm); // Safe construction with error handling auto result = sqlgen::Timestamp<"%Y-%m-%d %H:%M:%S">::from_string("1989-12-17 12:00:00"); if (result) { auto birthdate = result.value(); // Use birthdate... } else { // Handle error... } ``` ### Accessing Values Access the timestamp value in different formats: ```cpp const auto person = Person{ .birthdate = "1989-12-17 12:00:00" }; // Get as formatted string const std::string& str_value2 = person.birthdate.str(); // Returns "1989-12-17 12:00:00" // Get as std::tm for time operations const std::tm& tm_value = person.birthdate.tm(); // Direct access to underlying std::tm ``` ### Time Zone Support The class supports both regular timestamps and timestamps with time zones: ```cpp // Regular timestamp (without timezone) sqlgen::Timestamp<"%Y-%m-%d %H:%M:%S"> local_time; // Timestamp with timezone sqlgen::Timestamp<"%Y-%m-%d %H:%M:%S%z"> utc_time; // Examples local_time = "2024-03-20 15:30:00"; // Local time utc_time = "2024-03-20 15:30:00+0000"; // UTC time with offset ``` ## Format Specification The timestamp format is specified using a template parameter that follows the strftime format specifiers. This format is significant because: 1. It defines the expected string format when reading timestamps from the database 2. It determines how timestamps are formatted when writing to the database 3. It enforces consistency between your C++ code and database storage For example, with this definition: ```cpp struct Person { sqlgen::Timestamp<"%Y-%m-%d %H:%M:%S"> birthdate; }; ``` - When reading from the database, the timestamp must be in the format "YYYY-MM-DD HH:MM:SS" - When writing to the database, the timestamp will be formatted as "YYYY-MM-DD HH:MM:SS" - Any attempt to assign a string in a different format will throw a runtime error The most importand supported format specifiers are: - `%Y`: Year with century (e.g., 2024) - `%m`: Month (01-12) - `%d`: Day of month (01-31) - `%H`: Hour in 24h format (00-23) - `%M`: Minute (00-59) - `%S`: Second (00-59) - `%z`: Timezone offset (e.g., +0000, -0500) Please refer to https://en.cppreference.com/w/cpp/chrono/c/strftime for a comprehensive list of supported format specifiers. Common format patterns: - `"%Y-%m-%d %H:%M:%S"` for regular timestamps - `"%Y-%m-%d %H:%M:%S%z"` for timestamps with timezone ### Database Integration The format parameter ensures type safety and consistency in database operations: ```cpp // Reading from database const auto people = sqlgen::read>(conn).value(); // All timestamps in 'people' will be in the format "%Y-%m-%d %H:%M:%S" // Writing to database const auto person = Person{ .birthdate = "1989-12-17 12:00:00" // Must match the format }; sqlgen::write(conn, person); // Will be stored in the database in this format // Querying with timestamps const auto query = sqlgen::read> | where("birthdate"_c == "1989-12-17 12:00:00"); // Must match the format ``` This format validation helps prevent: - Data corruption from inconsistent timestamp formats - SQL injection by validating the format before database operations - Runtime errors from malformed timestamp strings ## Notes - The template parameter `_format` specifies the expected timestamp format - Format validation occurs at runtime when values are assigned - The class is a wrapper around `std::tm` that adds: - Format validation - String conversion - SQL integration - Type safety - The class supports: - Direct string assignment with format validation - Construction from `std::tm` - Safe construction with error handling via `from_string` - Multiple access methods for the underlying value - Direct access to the underlying `std::tm` via `tm()` - Reflection for SQL operations - Move and copy semantics - Timezone support varies by database: - PostgreSQL supports both regular timestamps and timestamps with timezone - SQLite treats all timestamps as UTC - The class uses the underlying `rfl::Timestamp` implementation for core functionality - All string operations are validated against the specified format - Invalid format strings will throw a runtime error - The class provides both compile-time and runtime safety