# ivyforms/1.1/frontend/src/composables/useDateField.ts

The Innovative Form Builder – IvyForms, version 1.1. 299 lines.

- Page: https://pluginprobe.com/plugins/ivyforms/1.1/code/frontend/src/composables/useDateField.ts
- Raw: https://pluginprobe.com/plugins/ivyforms/1.1/raw/frontend/src/composables/useDateField.ts
- Modified: 2026-03-02T13:43:38+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/ivyforms/1.1/code/frontend/src/composables/useDateField.ts#L10-L20`.

```typescript
export function useDateField() {
  function parseDateString(
    dateStr: string,
    format?: string,
  ): { day: string; month: string; year: string } {
    if (!dateStr) {
      return { day: '', month: '', year: '' }
    }

    // Try to parse based on separators
    const separators = ['-', '/', '.']
    let parts: string[] = []

    for (const sep of separators) {
      if (dateStr.includes(sep)) {
        parts = dateStr.split(sep)
        break
      }
    }

    if (parts.length !== 3) {
      return { day: '', month: '', year: '' }
    }

    // Determine format (default to MM/DD/YYYY if not provided)
    const dateFormat = (format || 'MM/DD/YYYY').toUpperCase()

    let day = ''
    let month = ''
    let year = ''

    const formatParts = dateFormat.split(/[/.-]/)
    formatParts.forEach((part, index) => {
      const upperPart = part.toUpperCase()
      if (upperPart === 'DD' || upperPart === 'D') day = parts[index]
      if (upperPart === 'MM' || upperPart === 'M') month = parts[index]
      if (upperPart === 'YYYY' || upperPart === 'YY') year = parts[index]
    })

    return { day, month, year }
  }

  function formatDateString(
    day: string,
    month: string,
    year: string,
    format: string = 'MM/DD/YYYY',
  ): string {
    if (!day || !month || !year) return ''

    const separator = format.includes('/') ? '/' : format.includes('-') ? '-' : '.'

    const formatParts = format.split(/[/.-]/)
    const result = formatParts.map((part) => {
      const upperPart = part.toUpperCase()
      if (upperPart === 'DD' || upperPart === 'D') {
        return upperPart === 'DD' ? day.padStart(2, '0') : day
      }
      if (upperPart === 'MM' || upperPart === 'M') {
        return upperPart === 'MM' ? month.padStart(2, '0') : month
      }
      if (upperPart === 'YYYY') return year
      if (upperPart === 'YY') return year.slice(-2)
      return part
    })

    return result.join(separator)
  }

  function isValidDate(
    day: string | number,
    month: string | number,
    year: string | number,
  ): boolean {
    const d = typeof day === 'string' ? parseInt(day, 10) : day
    const m = typeof month === 'string' ? parseInt(month, 10) : month
    const y = typeof year === 'string' ? parseInt(year, 10) : year

    if (isNaN(d) || isNaN(m) || isNaN(y)) return false
    if (m < 1 || m > 12) return false
    if (d < 1 || d > 31) return false
    if (y < 1000 || y > 9999) return false

    // Check day validity for month
    const daysInMonth = new Date(y, m, 0).getDate()
    return d <= daysInMonth
  }

  function getDaysArray(): Array<{ label: string; value: string }> {
    return Array.from({ length: 31 }, (_, i) => {
      const day = (i + 1).toString().padStart(2, '0')
      return { label: day, value: day }
    })
  }

  function getMonthsArray(): Array<{ label: string; value: string }> {
    return Array.from({ length: 12 }, (_, i) => {
      const month = (i + 1).toString().padStart(2, '0')
      return { label: month, value: month }
    })
  }

  function getYearsArray(
    minYear?: number,
    maxYear?: number,
  ): Array<{ label: string; value: string }> {
    const currentYear = new Date().getFullYear()
    const min = minYear || currentYear - 100
    const max = maxYear || currentYear + 100

    const years: Array<{ label: string; value: string }> = []
    for (let year = min; year <= max; year++) {
      years.push({ label: year.toString(), value: year.toString() })
    }
    return years
  }

  function toISOFormat(dateStr: string, format?: string): string {
    const parsed = parseDateString(dateStr, format)
    if (!parsed.day || !parsed.month || !parsed.year) return ''
    return `${parsed.year}-${parsed.month.padStart(2, '0')}-${parsed.day.padStart(2, '0')}`
  }

  function fromISOFormat(isoDate: string, format: string = 'MM/DD/YYYY'): string {
    if (!isoDate) return ''
    const [year, month, day] = isoDate.split('-')
    return formatDateString(day, month, year, format)
  }

  /**
   * Validate date format based on date format pattern
   * Returns true if date matches the expected format
   */
  function isValidDateFormat(dateStr: string, dateFormat: string): boolean {
    if (!dateStr || typeof dateStr !== 'string') {
      return false
    }

    const trimmed = dateStr.trim()

    if (dateFormat === 'MM/DD/YYYY' || dateFormat === 'M/D/YYYY') {
      return /^(0?[1-9]|1[0-2])\/(0?[1-9]|[12]\d|3[01])\/\d{4}$/.test(trimmed)
    } else if (dateFormat === 'DD/MM/YYYY' || dateFormat === 'D/M/YYYY') {
      return /^(0?[1-9]|[12]\d|3[01])\/(0?[1-9]|1[0-2])\/\d{4}$/.test(trimmed)
    } else if (dateFormat === 'YYYY-MM-DD' || dateFormat === 'YYYY-M-D') {
      return /^\d{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[12]\d|3[01])$/.test(trimmed)
    } else if (dateFormat === 'DD.MM.YYYY' || dateFormat === 'D.M.YYYY') {
      return /^(0?[1-9]|[12]\d|3[01])\.(0?[1-9]|1[0-2])\.\d{4}$/.test(trimmed)
    } else {
      // Default to MM/DD/YYYY
      return /^(0?[1-9]|1[0-2])\/(0?[1-9]|[12]\d|3[01])\/\d{4}$/.test(trimmed)
    }
  }

  /**
   * Parse date string to comparable object
   * Handles multiple date formats and returns standardized object for comparison
   * Returns null if parsing fails
   */
  function parseDateToObject(
    dateStr: string,
    dateFormat: string,
  ): { year: number; month: number; day: number } | null {
    if (!dateStr || typeof dateStr !== 'string') {
      return null
    }

    const trimmed = dateStr.trim()
    let year: number, month: number, day: number

    if (dateFormat === 'MM/DD/YYYY' || dateFormat === 'M/D/YYYY') {
      const match = trimmed.match(/^(0?[1-9]|1[0-2])\/(0?[1-9]|[12]\d|3[01])\/(\d{4})$/)
      if (!match) return null
      month = parseInt(match[1], 10)
      day = parseInt(match[2], 10)
      year = parseInt(match[3], 10)
    } else if (dateFormat === 'DD/MM/YYYY' || dateFormat === 'D/M/YYYY') {
      const match = trimmed.match(/^(0?[1-9]|[12]\d|3[01])\/(0?[1-9]|1[0-2])\/(\d{4})$/)
      if (!match) return null
      day = parseInt(match[1], 10)
      month = parseInt(match[2], 10)
      year = parseInt(match[3], 10)
    } else if (dateFormat === 'YYYY-MM-DD' || dateFormat === 'YYYY-M-D') {
      const match = trimmed.match(/^(\d{4})-(0?[1-9]|1[0-2])-(0?[1-9]|[12]\d|3[01])$/)
      if (!match) return null
      year = parseInt(match[1], 10)
      month = parseInt(match[2], 10)
      day = parseInt(match[3], 10)
    } else if (dateFormat === 'DD.MM.YYYY' || dateFormat === 'D.M.YYYY') {
      const match = trimmed.match(/^(0?[1-9]|[12]\d|3[01])\.(0?[1-9]|1[0-2])\.(\d{4})$/)
      if (!match) return null
      day = parseInt(match[1], 10)
      month = parseInt(match[2], 10)
      year = parseInt(match[3], 10)
    } else {
      // Default to MM/DD/YYYY
      const match = trimmed.match(/^(0?[1-9]|1[0-2])\/(0?[1-9]|[12]\d|3[01])\/(\d{4})$/)
      if (!match) return null
      month = parseInt(match[1], 10)
      day = parseInt(match[2], 10)
      year = parseInt(match[3], 10)
    }

    // Validate ranges
    if (month < 1 || month > 12 || day < 1 || day > 31 || year < 1900 || year > 2100) {
      return null
    }

    return { year, month, day }
  }

  /**
   * Compare two date objects for range validation
   * Returns: negative if a < b, 0 if equal, positive if a > b
   */
  function compareDates(
    a: { year: number; month: number; day: number } | null,
    b: { year: number; month: number; day: number } | null,
  ): number {
    if (!a || !b) return 0

    if (a.year !== b.year) return a.year - b.year
    if (a.month !== b.month) return a.month - b.month
    return a.day - b.day
  }

  /**
   * Validate date is within min/max range
   * Returns: { isInRange: boolean, error?: string }
   */
  function isDateInValidRange(
    dateStr: string,
    dateFormat: string,
    minDateValue?: string | null,
    maxDateValue?: string | null,
  ): { isInRange: boolean; error?: string } {
    // Empty values are allowed (checked by required rule)
    if (!dateStr) {
      return { isInRange: true }
    }

    const currentDate = parseDateToObject(dateStr, dateFormat)
    if (!currentDate) {
      return { isInRange: false, error: 'Invalid date format' }
    }

    const hasMin = minDateValue !== null && minDateValue !== undefined && minDateValue !== ''
    const hasMax = maxDateValue !== null && maxDateValue !== undefined && maxDateValue !== ''

    if (!hasMin && !hasMax) {
      return { isInRange: true }
    }

    // Parse min date
    let minDate: { year: number; month: number; day: number } | null = null
    if (hasMin) {
      minDate = parseDateToObject(minDateValue!, dateFormat)
      if (!minDate) {
        return { isInRange: false, error: `Malformed minimum date value: ${minDateValue}` }
      }
    }

    // Parse max date
    let maxDate: { year: number; month: number; day: number } | null = null
    if (hasMax) {
      maxDate = parseDateToObject(maxDateValue!, dateFormat)
      if (!maxDate) {
        return { isInRange: false, error: `Malformed maximum date value: ${maxDateValue}` }
      }
    }

    // Check range
    if (minDate !== null && compareDates(currentDate, minDate) < 0) {
      return { isInRange: false, error: `Date must be at or after ${minDateValue}` }
    }

    if (maxDate !== null && compareDates(currentDate, maxDate) > 0) {
      return { isInRange: false, error: `Date must be at or before ${maxDateValue}` }
    }

    return { isInRange: true }
  }

  return {
    parseDateString,
    formatDateString,
    isValidDate,
    getDaysArray,
    getMonthsArray,
    getYearsArray,
    toISOFormat,
    fromISOFormat,
    isValidDateFormat,
    parseDateToObject,
    compareDates,
    isDateInValidRange,
  }
}

```
