Understanding Date Values
It's important to understand how dates are stored and displayed in React Calendar DateTime Picker. Starting from v2.x, the `onChange` callback provides three parameters for maximum flexibility.
Date Object Format
The library stores dates as `Day` objects internally. The `onChange` callback receives three parameters:
interface Day {
year: number // e.g., 2025
month: number // 1-12 (not 0-11 like JavaScript Date)
day: number // 1-31
hour?: number // Optional: 0-23 (for time selection)
minute?: number // Optional: 0-59 (for time selection)
}
// onChange callback signature (v2.x):
onChange: (
normalizedValue: Day | Range | Multi | null, // Internal Day object
jsDate: Date | RangeDate | Date[] | null, // JavaScript Date (always Gregorian)
formattedString: string | null // Formatted string
) => voidExample: Single Date
When you select a date, the `onChange` callback provides three values:
import { useState } from 'react'
import { DtPicker } from 'react-calendar-datetime-picker'
import type { Day } from 'react-calendar-datetime-picker'
function App() {
const [date, setDate] = useState<Day | null>(null)
const [jsDate, setJsDate] = useState<Date | null>(null)
const [formatted, setFormatted] = useState<string | null>(null)
return (
<DtPicker
onChange={(normalizedValue, jsDate, formattedString) => {
setDate(normalizedValue) // { year: 2025, month: 12, day: 2 }
setJsDate(jsDate) // Date(2025-12-02)
setFormatted(formattedString) // "2025/12/02"
}}
/>
)
}
// After selecting December 2, 2025:
// normalizedValue = { year: 2025, month: 12, day: 2 }
// jsDate = Date(2025-12-02) // Always Gregorian, even for Jalali calendar
// formattedString = "2025/12/02" // Based on dateFormat propImportant: The `onChange` callback now provides three parameters: (1) the internal `Day` object maintaining calendar system integrity, (2) a JavaScript `Date` object always in Gregorian calendar (useful for API calls), and (3) a pre-formatted string ready for display. This gives you maximum flexibility to choose which format to use based on your needs.
Date Range Format
For range selection, the `onChange` callback receives a `Range` object, a `RangeDate` object with JavaScript Dates, and a formatted string:
interface Range {
from: Day // Start date
to: Day | null // End date (null when selecting start)
}
interface RangeDate {
from: Date | null // JavaScript Date (always Gregorian)
to: Date | null // JavaScript Date (always Gregorian)
}
// Example onChange callback:
onChange={(normalizedValue, jsDate, formattedString) => {
// normalizedValue = { from: Day, to: Day }
// jsDate = { from: Date, to: Date }
// formattedString = "from 2025/12/01 to 2025/12/15"
}}
// Example values:
// normalizedValue = {
// from: { year: 2025, month: 12, day: 1 },
// to: { year: 2025, month: 12, day: 15 }
// }
// jsDate = {
// from: Date(2025-12-01),
// to: Date(2025-12-15)
// }
// formattedString = "from 2025/12/01 to 2025/12/15"Multiple Dates Format
For multiple date selection, the `onChange` callback receives an array of `Day` objects, an array of JavaScript Dates, and a formatted string:
type Multi = Day[]
// Example onChange callback:
onChange={(normalizedValue, jsDate, formattedString) => {
// normalizedValue = Day[]
// jsDate = Date[]
// formattedString = dates separated by " + " (e.g., "2025/12/01,2025/12/05,2025/12/10")
// or single date string if only one date is selected
}}
// Example values:
// normalizedValue = [
// { year: 2025, month: 12, day: 1 },
// { year: 2025, month: 12, day: 5 },
// { year: 2025, month: 12, day: 10 }
// ]
// jsDate = [
// Date(2025-12-01),
// Date(2025-12-05),
// Date(2025-12-10)
// ]
// formattedString = "2025/12/01 + 2025/12/05 + 2025/12/10"Custom Display Format
You can customize how dates are displayed using the `dateFormat` prop. The `formattedString` parameter in `onChange` will use this format:
<DtPicker
onChange={(normalizedValue, jsDate, formattedString) => {
console.log(normalizedValue) // { year: 2025, month: 12, day: 2 }
console.log(jsDate) // Date(2025-12-02)
console.log(formattedString) // "02/12/2025" (uses dateFormat)
}}
dateFormat="DD/MM/YYYY" // Custom format
/>
// The formattedString parameter respects:
// - dateFormat prop (e.g., "DD/MM/YYYY", "MM-DD-YYYY", "YYYY-MM-DD HH:mm")
// - locale prop (Persian numerals for 'fa', Latin for others)
// Time format is determined by dateFormat tokens: HH (24-hour) or hh (12-hour)Tip: The `formattedString` parameter is automatically generated based on your `dateFormat` and `locale` props. The time format (12-hour vs 24-hour) is determined by the tokens in `dateFormat` (`HH` for 24-hour, `hh` with `A`/`a` for 12-hour), so you don't need to format dates manually. For more information about data types and their structures, see the Types documentation. Types documentation.
Jalali Calendar Conversion
When using Jalali calendar, the `jsDate` parameter always contains Gregorian dates for API compatibility:
<DtCalendar
calendarSystem="jalali"
onChange={(normalizedValue, jsDate, formattedString) => {
// normalizedValue = { year: 1402, month: 3, day: 11 } // Jalali
// jsDate = Date(2023-06-01) // Gregorian
// formattedString = "1402/03/11" // Jalali format
// Use normalizedValue for internal logic (maintains calendar system)
// Use jsDate for API calls (always Gregorian)
// Use formattedString for display (respects locale and format)
}}
/>Important: The `jsDate` parameter is always in Gregorian calendar, even when using Jalali calendar. This ensures compatibility with standard JavaScript Date APIs and backend systems that expect Gregorian dates. The `normalizedValue` maintains the original calendar system (Jalali or Gregorian) for internal consistency.
Next Steps
- Read the Quick Start guide to learn basic usage
- Learn about data types and their structures
- View interactive examples to see the component in action
