Extract photo date taken from EXIF
Turn the date your camera wrote, 2023:06:15 14:30:45, into a normal date and time: 2023-06-15 and 14:30:45, plus the combined 2023-06-15T14:30:45. Impossible days are rejected and no time zone is invented. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Datetime original
- 2023:06:15 14:30:45
- Date
- 2023-06-15
- Time
- 14:30:45
- Iso
- 2023-06-15T14:30:45
- Year
- 2,023
Cameras and phones write when a picture was shot into the EXIF DateTimeOriginal tag using a quirky colon-separated layout: year, month, and day joined with colons, a space, then hours, minutes, and seconds. Pipelines that sort galleries, build timelines, or stamp filenames need that instant as a normal ISO calendar date and clock time, not as raw EXIF text. This capability accepts the DateTimeOriginal string, validates it as a real Gregorian day and a valid wall-clock time, and returns YYYY-MM-DD, HH:MM:SS, and a combined ISO-8601 local datetime without inventing a timezone.
What EXIF DateTimeOriginal looks like and why ISO matters
Every digital camera that embeds Exif metadata can store the capture instant in DateTimeOriginal. The Exif 2.x specification records that value as twenty characters with a rigid shape: four digits for the year, a colon, two digits for the month, another colon, two digits for the day, a single space, then two-digit hour, minute, and second separated by colons. That layout is not ISO-8601 and it is not a Unix timestamp.
Sorting strings lexicographically works only because years come first; joining EXIF values into spreadsheets, SQL date columns, or JavaScript Date constructors fails unless you rewrite the colons in the date part. Photographers also care that DateTimeOriginal is the capture time, not FileModifyDate or the last edit stamp that image editors rewrite. Converting DateTimeOriginal into an ISO date (YYYY-MM-DD), an ISO time (HH:MM:SS), and a combined local ISO string (YYYY-MM-DDTHH:MM:SS) gives you fields that databases, CSV importers, and frontend date pickers already understand.
This tool does not open the image file itself: you pass the tag string you already read from an EXIF library, a dump, or a sidecar. When the tag is absent, empty, or not in the expected pattern, the task fails instead of guessing.
What the date must look like to be accepted
The value must match YYYY:MM:DD HH:MM:SS after trimming; a single space or the letter T between date and time is accepted so dumps that already lean toward ISO still parse if the date still uses EXIF colons. Year must lie between 0001 and 9999. Month must be 01–12.
Day must exist in that month under the Gregorian leap-year rule (February has twenty-nine days only when the year is divisible by four, except centuries not divisible by four hundred). Hour is 00–23; minute and second are 00–59. Example: 2023:06:15 14:30:45 becomes date 2023-06-15, time 14:30:45, and iso 2023-06-15T14:30:45.
Leap-day example: 2024:02:29 00:00:00 succeeds; 2023:02:29 12:00:00 fails.
Where extracting the photo date from EXIF earns its keep
Photo agencies and DAM systems normalize capture dates before import so searches by shoot day stay accurate even when files were copied across machines that rewrote mtimes. Journalism desks and legal evidence workflows need a defensible parse of the camera’s DateTimeOriginal rather than a loose free-text date. Social and e-commerce pipelines that rename uploads with the shoot date call a tiny parse step after bulk EXIF extraction so filenames stay stable.
Content sites that rank for phrases like extract photo date taken from EXIF benefit from a focused landing that answers that intent without the noise of a full EXIF dump tool. Failed validation does not consume balance.
What you can do with it
DAM and gallery import
Convert EXIF DateTimeOriginal from bulk photo ingest into ISO dates for sorting albums, filters, and database columns.
Filename and timeline stamping
Build capture-date filenames and editorial timelines from the camera tag without trusting file modification times.
Evidence and compliance checks
Validate that a claimed shoot timestamp matches a well-formed EXIF DateTimeOriginal before archiving or discovery export.
FAQ
What format is EXIF DateTimeOriginal?
Cameras store it as YYYY:MM:DD HH:MM:SS with colons in the date part. This tool parses that string into ISO date, time, and a combined local ISO datetime.
Does this tool read the image file?
No. Pass the DateTimeOriginal string you already extracted. That keeps the capability pure parse, free in the browser path, and free of binary I/O.
What happens if the tag is missing or malformed?
Empty values, wrong separators, impossible calendar days, and out-of-range times are all rejected.
Is the result timezone-aware?
No. EXIF DateTimeOriginal is a local wall-clock stamp without a zone. The iso field is YYYY-MM-DDTHH:MM:SS without a Z or offset so you do not invent a timezone.
Why use the capture date instead of the file's modified date?
Because the capture date records when the photo was taken, while the modified date changes whenever the file is copied to another machine or edited. Sorting by capture date keeps every shoot in its real order.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/image/exif-date-extract \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"datetime_original":"2023:06:15 14:30:45"}'const res = await fetch("https://api.kit.forhosting.com/image/exif-date-extract", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"datetime_original": "2023:06:15 14:30:45"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/image/exif-date-extract",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"datetime_original": "2023:06:15 14:30:45"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/image/exif-date-extract", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"datetime_original":"2023:06:15 14:30:45"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"datetime_original":"2023:06:15 14:30:45"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/image/exif-date-extract", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"datetime_original": "2023:06:15 14:30:45"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "image.exif_date_extract",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_mb | 15 |
max_megapixels | 12 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
Missing tags and malformed values fail cleanly with invalid_input so automation never treats garbage as a successful parse.
What EXIF DateTimeOriginal looks like and why ISO matters
When the calendar day is impossible—thirty-one February, hour twenty-five, or a non-leap twenty-nine February—the same invalid_input path protects callers from silent corruption. Use the iso field when you need one column; use date and time when your schema splits calendar day from clock time.
Input contract, response shape, and validation rules
POST a JSON body with the required string field datetime_original. Aliases date_time_original, exif_datetime, and taken_at are accepted for convenience when your upstream EXIF reader uses a different key. On success the response echoes a canonical datetime_original with a single space separator, plus date, time, iso, and the integer components year, month, day, hour, minute, and second so clients can format without re-parsing. Missing fields, non-string types, wrong separators such as 2023-06-15 14:30:45 without EXIF colons in the date, and out-of-range components all raise invalid_input and are not billed.
Where extracting the photo date from EXIF earns its keep
Mobile apps that already read EXIF in-process can still call this endpoint when a server-side pipeline must revalidate the same string before writing to Postgres TIMESTAMPTZ or a JSON API.
Technical questions
What does extract photo date from EXIF cost?
The browser tool is free. API requests use prepaid KIT balance at $0.002 per successful call; invalid input is not billed.