Week Input Fields
The week input field allows users to select a week and year. It provides a user-friendly week picker and submits data in YYYY-W## format using ISO 8601 week numbering.
Browser Display vs Submitted Format: Browsers display weeks according to user locale, but always submit in consistent ISO 8601 format (YYYY-W##) that your PHP code can rely on.
Basic Usage
Use form_week() to create a week input field:
echo form_week('work_week');
// Output: <input type="week" name="work_week">
Demonstration
Below is the native HTML5 week input rendered by form_week():
Function Signature
function form_week(string $name, ?string $value = null, array $attributes = []): string
Parameters
| Parameter |
Type |
Description |
Default |
$name |
string |
The name attribute for the input (required) |
N/A |
$value |
string|null |
The value in YYYY-W## format |
null |
$attributes |
array |
Additional HTML attributes |
[] |
With a Default Value
echo form_week('timesheet_week', '2025-W52');
// Output: <input type="week" name="timesheet_week" value="2025-W52">
Setting Current Week as Default
$current_week = date('Y') . '-W' . str_pad(date('W'), 2, '0', STR_PAD_LEFT);
echo form_week('reporting_week', $current_week);
Zero-Padding Required: Week numbers must be zero-padded: W01 not W1. Always use str_pad(date('W'), 2, '0', STR_PAD_LEFT) to ensure proper formatting.
With Attributes
$attributes = [
'min' => '2025-W01',
'max' => '2025-W52',
'required' => true
];
echo form_week('schedule_week', '', $attributes);
Output:
<input type="week" name="schedule_week" value="" min="2025-W01" max="2025-W52" required>
Boolean Attributes: Pass true for boolean attributes like required, readonly, or disabled. This generates clean HTML5 syntax: <input required>
Downloadable Demo: Want to see the form_week() function in action? Why not head over to GitHub and check out the complete Weekly Schedules demo module:
https://github.com/trongate/Trongate-v2-Weekly-Schedules-Module
This repository provides a ready-to-use example of building a weekly scheduling system using the Trongate PHP framework (version 2). It includes pagination, form validation, secure admin access, native HTML5 week input handling, and clean separation of concerns.
Common Attributes
| Attribute |
Purpose |
Example |
min |
Earliest selectable week (YYYY-W##) |
['min' => '2025-W01'] |
max |
Latest selectable week (YYYY-W##) |
['max' => '2025-W52'] |
required |
Field must have a value |
['required' => true] |
readonly |
Prevent user editing |
['readonly' => true] |
disabled |
Disable the input |
['disabled' => true] |
Understanding ISO 8601 Week Numbering
Week inputs follow the ISO 8601 international standard for week numbering. Understanding these rules is important:
ISO 8601 Week Rules:
- Weeks start on Monday (not Sunday)
- Week 1 is the first week that contains a Thursday in the new year
- This means January 1st might be in week 52 or 53 of the previous year
- A year can have 52 or 53 weeks
Example of Week 1 Determination
// If January 1, 2025 is a Wednesday:
// - It contains a Thursday (Jan 2) in the same week
// - Therefore: January 1, 2025 is in Week 1 of 2025 (2025-W01)
// If January 1, 2026 is a Thursday:
// - It IS the Thursday of that week
// - Therefore: January 1, 2026 is in Week 1 of 2026 (2026-W01)
// If January 1, 2027 is a Friday:
// - The Thursday of that week is December 31, 2026
// - Therefore: January 1, 2027 is in Week 53 of 2026 (2026-W53)
How to Repopulate Forms After Validation Errors
Controller Example
public function create(): void {
// Fetch posted value (returns empty string if form hasn't been submitted)
$data['work_week'] = post('work_week', true);
$data['schedule_week'] = post('schedule_week', true);
// Pass data to view
$this->view('timesheet_form', $data);
}
View Example
<?php
echo form_open('timesheets/submit');
echo form_label('Work Week');
echo form_week('work_week', $work_week);
echo form_label('Schedule Week');
echo form_week('schedule_week', $schedule_week);
echo form_submit('submit', 'Save');
echo form_close();
?>
Form Repopulation Pattern: Always use post('field_name', true) in the controller to fetch submitted values. The true parameter trims whitespace, ensuring clean data.
Real-World Example: Weekly Timesheet
Controller:
public function timesheet(): void {
$data['headline'] = 'Submit Timesheet';
$data['work_week'] = post('work_week', true);
// Default to current week if not submitted
if ($data['work_week'] === '') {
$data['work_week'] = date('Y') . '-W' . str_pad(date('W'), 2, '0', STR_PAD_LEFT);
}
$data['form_location'] = BASE_URL . 'timesheets/submit';
$this->templates->admin($data);
}
public function submit(): void {
$this->validation->set_rules('work_week', 'work week', 'required|valid_week');
$this->validation->set_rules('hours_worked', 'hours worked', 'required|numeric|greater_than[0]');
if ($this->validation->run() === true) {
$data['work_week'] = post('work_week', true);
$data['hours_worked'] = post('hours_worked', true);
$data['user_id'] = $_SESSION['user_id'];
$this->db->insert($data, 'timesheets');
set_flashdata('Timesheet submitted successfully');
redirect('timesheets/manage');
} else {
$this->timesheet();
}
}
View:
<h1><?= $headline ?></h1>
<?= validation_errors() ?>
<?php
echo form_open($form_location);
echo form_label('Work Week');
$current = date('Y') . '-W' . str_pad(date('W'), 2, '0', STR_PAD_LEFT);
$week_attrs = [
'max' => $current, // Can't submit future timesheets
'required' => true
];
echo form_week('work_week', $work_week, $week_attrs);
echo form_label('Hours Worked');
echo form_number('hours_worked', $hours_worked, ['required' => true, 'step' => 0.5, 'min' => 0]);
echo form_submit('submit', 'Submit Timesheet');
echo form_close();
?>
Working with the Create/Update Pattern
public function create(): void {
$update_id = segment(3, 'int');
if ($update_id > 0 && REQUEST_TYPE === 'GET') {
// Editing existing record - load from database
$record = $this->db->get_where($update_id, 'schedules');
$data['task_name'] = $record->task_name;
$data['schedule_week'] = $record->schedule_week; // Already in YYYY-W## format
} else {
// New record OR validation error - use POST data
$data['task_name'] = post('task_name', true);
$data['schedule_week'] = post('schedule_week', true);
}
$data['form_location'] = BASE_URL . 'schedules/submit/' . $update_id;
$this->view('schedule_form', $data);
}
Type-Casting Segments: Always use segment(3, 'int') when expecting numeric IDs. This prevents type-related bugs and improves code clarity.
Database Storage
Week inputs submit in YYYY-W## format, which can be stored directly in a VARCHAR column:
Table Schema
CREATE TABLE timesheets (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT,
work_week VARCHAR(8), -- Stores YYYY-W##
hours_worked DECIMAL(5, 2),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
Inserting Data
public function submit(): void {
$this->validation->set_rules('work_week', 'work week', 'required|valid_week');
if ($this->validation->run() === true) {
$data['user_id'] = $_SESSION['user_id'];
$data['work_week'] = post('work_week', true); // e.g., "2025-W52"
$data['hours_worked'] = post('hours_worked', true);
$this->db->insert($data, 'timesheets');
redirect('timesheets/manage');
} else {
$this->create();
}
}
Direct Storage: The YYYY-W## format from HTML5 week inputs can be stored directly in a VARCHAR(8) column. No conversion is needed, and the data remains human-readable.
Converting Week to Date Range
To query data for a specific week, you'll often need to convert to a date range:
// Input: 2025-W52
$week = post('work_week', true);
// Parse week
$date = new DateTime();
$date->setISODate(
(int) substr($week, 0, 4), // Year: 2025
(int) substr($week, 6) // Week number: 52
);
// Get Monday of that week
$monday = $date->format('Y-m-d');
// Get Sunday of that week
$date->modify('+6 days');
$sunday = $date->format('Y-m-d');
echo "Week $week runs from $monday to $sunday";
// Output: Week 2025-W52 runs from 2025-12-22 to 2025-12-28
Querying by Week
Query by Stored Week Value
// Simplest approach: query by stored week value
$week = '2025-W52';
$sql = "SELECT * FROM timesheets
WHERE work_week = :week
ORDER BY created_at";
$results = $this->db->query_bind($sql, ['week' => $week], 'array');
Query by Date Range
// Calculate date range for a week
$week = '2025-W52';
list($year, $week_num) = explode('-W', $week);
$date = new DateTime();
$date->setISODate((int) $year, (int) $week_num);
$start_date = $date->format('Y-m-d');
$date->modify('+6 days');
$end_date = $date->format('Y-m-d');
$sql = "SELECT * FROM activities
WHERE activity_date BETWEEN :start AND :end
ORDER BY activity_date";
$results = $this->db->query_bind($sql, [
'start' => $start_date,
'end' => $end_date
], 'array');
Formatting Weeks for Display
When displaying weeks to users, you'll often want to format them in a more readable way:
// Input: 2025-W52
// Extract year and week number
preg_match('/(\d{4})-W(\d{2})/', '2025-W52', $matches);
$year = $matches[1];
$week_num = $matches[2];
echo "Week $week_num of $year"; // Week 52 of 2025
echo "Week $week_num, $year"; // Week 52, 2025
// Get date range for display
$date = new DateTime();
$date->setISODate((int) $year, (int) $week_num);
$start = $date->format('M j');
$date->modify('+6 days');
$end = $date->format('M j, Y');
echo "$start - $end"; // Dec 22 - Dec 28, 2025
// More detailed format
$date->setISODate((int) $year, (int) $week_num);
$monday = $date->format('l, F j');
$date->modify('+6 days');
$sunday = $date->format('l, F j, Y');
echo "$monday through $sunday";
// Monday, December 22 through Sunday, December 28, 2025
Validation
Use the valid_week validation rule to ensure the submitted value is in the correct format:
$this->validation->set_rules('work_week', 'work week', 'required|valid_week');
This validates that the value matches YYYY-W## format and represents a valid week.
Client vs Server Validation: While browsers validate week formats client-side, always use server-side validation with valid_week. Client validation can be bypassed and doesn't protect your database.
See the Validating Date and Time Data chapter for complete validation rule documentation.
Restricting Week Selection
Current Year Only
$current_year = date('Y');
$attributes = [
'min' => $current_year . '-W01',
'max' => $current_year . '-W52',
'required' => true
];
echo form_week('report_week', $report_week, $attributes);
Past 4 Weeks
$current_week = (int) date('W');
$current_year = date('Y');
$max_week = date('Y') . '-W' . str_pad($current_week, 2, '0', STR_PAD_LEFT);
$min_week = date('Y') . '-W' . str_pad(max(1, $current_week - 4), 2, '0', STR_PAD_LEFT);
$attributes = [
'min' => $min_week,
'max' => $max_week,
'required' => true
];
echo form_week('timesheet_week', $timesheet_week, $attributes);
Specific Week Range
$attributes = [
'min' => '2025-W10',
'max' => '2025-W20',
'required' => true
];
echo form_week('project_week', $project_week, $attributes);
Common Use Cases
- Timesheets - Weekly hour tracking and time entry
- Production planning - Weekly manufacturing schedules and capacity planning
- Sales targets - Weekly sales goals, quotas, and performance tracking
- Project management - Sprint planning (typically 1-2 week sprints)
- Staff scheduling - Weekly work rosters and shift planning
- Delivery schedules - Weekly shipping plans and logistics
- Weekly reports - Status reports, KPIs, and performance metrics
- Appointment scheduling - Weekly availability and booking slots
Browser Support and Rendering
Different browsers provide different week picker interfaces:
- Chrome/Edge: Calendar view with week numbers highlighted
- Firefox: Week and year input fields with increment/decrement controls
- Safari: Limited support - may render as text input
- Mobile (iOS/Android): Native week picker where supported
Safari Limitation: Week input support is limited in Safari. It may render as a plain text input. Users can still manually enter values in YYYY-W## format (e.g., "2025-W52"), and validation will work correctly. Consider adding helper text for Safari users.
Providing Helper Text
echo form_label('Work Week');
echo form_week('work_week', $work_week, ['required' => true]);
echo '<small class="help-text">Format: YYYY-W## (e.g., 2025-W52)</small>';
Important Notes
- Value format is always
YYYY-W## with zero-padded week number
- Store as
VARCHAR(8) in database
- No conversion needed between form and database
- Week numbers follow ISO 8601 standard (weeks start Monday)
- Always use
str_pad() for week numbers to ensure zero-padding
- January 1st may be in week 52 or 53 of the previous year
- Safari support is limited - may fallback to text input
- Browser validates format automatically, but server validation is still required
Value Format: The value attribute must be in YYYY-W## format with zero-padded week numbers. Values like 2025-W5 (missing zero) or 2025/W52 (wrong separator) will not work and the field will appear empty.