DenverCoder1/github-readme-streak-stats · error · InvalidArgumentException
400
400
Error message
Invalid timezone.
What it means
getCurrentDate() resolves the current date (Y-m-d) in a caller-supplied timezone. The timezone string is passed straight to PHP's DateTimeZone constructor; when it is not a recognized timezone identifier, the constructor throws and the library re-throws it as an InvalidArgumentException with HTTP-style code 400. This lets callers distinguish bad user input (e.g. an invalid tz query parameter) from internal failures.
Solutions
- Validate the timezone against DateTimeZone::listIdentifiers() (or @timezone_identification_list) before calling getCurrentDate().
- Use full IANA identifiers like 'America/New_York' instead of abbreviations or Windows timezone names.
- Convert Windows timezone names with intl's timezone translation if the input originates from a Windows/ .NET system.
- If the parameter is optional, pass an empty string to fall back to date_default_timezone_get() rather than a placeholder value.
Example fix
// before
$date = getCurrentDate($_GET['tz'] ?? 'America/New York');
// after
$tz = $_GET['tz'] ?? '';
if ($tz !== '' && !in_array($tz, DateTimeZone::listIdentifiers(), true)) {
$tz = '';
}
$date = getCurrentDate($tz); Defensive patterns
Strategy: validation
Validate before calling
function isValidTimezone(string $tz): bool {
return $tz === '' || in_array($tz, DateTimeZone::listIdentifiers(), true);
}
if (!isValidTimezone($timezone)) {
throw new InvalidArgumentException('Unsupported timezone: ' . $timezone);
} Type guard
function isKnownTimezone(mixed $tz): bool {
return is_string($tz) && in_array($tz, DateTimeZone::listIdentifiers(), true);
} Try / catch
try {
$date = getCurrentDate($timezone);
} catch (InvalidArgumentException $e) {
if ($e->getCode() === 400) {
http_response_code(400);
echo json_encode(['error' => 'Invalid timezone supplied']);
} else {
throw $e;
}
} Prevention
- Only pass IANA identifiers (DateTimeZone::listIdentifiers()) — never abbreviations or Windows names.
- Validate user-supplied timezone parameters at the request boundary before any date math.
- Prefer passing '' to use the server default instead of guessing a timezone string.
- Normalize input (trim, exact case) since identifiers are case- and whitespace-sensitive.
When it happens
Trigger: Calling getCurrentDate() (directly or via stats endpoints that accept a timezone parameter) with a string that is not a valid IANA timezone identifier or UTC offset, e.g. 'America/New York', 'EST' where abbreviation support is unavailable, an empty-but-whitespace string that bypasses the '' fallback, or a typo like 'Europe/Londonn'.
Common situations: Passing user-supplied timezone query parameters straight through without validation; legacy timezone abbreviations ('PST', 'CET') that DateTimeZone rejects as identifiers; config files carrying hand-edited timezone values; locale migration where an old app stored Windows timezone names ('Pacific Standard Time') instead of IANA names ('America/Los_Angeles').
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
AI-assisted analysis of DenverCoder1/github-readme-streak-stats@70dd50f921 (2026-09-15).
Data as JSON: /api/errors/c5da8a61f0a7ef19.
Report an issue: GitHub.
Appendix: source
Thrown at src/stats.php:296
}
}
}
return $contributions;
}
/**
* Get the current date for a requested timezone.
*
* @param string $timezone Timezone identifier, or empty for the server default
* @param DateTimeImmutable|null $now Current time override for tests
* @return string Current date in Y-m-d format
*/
function getCurrentDate(string $timezone = "", ?DateTimeImmutable $now = null): string
{
try {
$dateTimezone = new DateTimeZone($timezone ?: date_default_timezone_get());
} catch (Exception) {
throw new InvalidArgumentException("Invalid timezone.", 400);
}
$now = $now ?: new DateTimeImmutable("now");
return $now->setTimezone($dateTimezone)->format("Y-m-d");
}
/**
* Normalize names of days of the week (eg. ["Sunday", " mon", "TUE"] -> ["Sun", "Mon", "Tue"])
*
* @param array<string> $days List of days of the week
* @return array<string> List of normalized days of the week
*/
function normalizeDays(array $days): array
{
return array_filter(
array_map(function ($dayOfWeek) {
// trim whitespace, capitalize first letter only, return first 3 characters
$dayOfWeek = substr(ucfirst(strtolower(trim($dayOfWeek))), 0, 3);View on GitHub (pinned to 70dd50f921)