Parse (ParsiDateTime) - parsicore/parsidate GitHub Wiki

Static Function ParsiDateTime::parse

Parses a string containing a Persian date and time into a ParsiDateTime instance, based on a specified format pattern.

Description

This function attempts to interpret the input string s as a Persian date and time according to the structure and specifiers defined by the format string. The process involves:

  1. Structural Matching: Verifies that the input string s precisely matches the literal characters (like spaces, /, -, :, T) present in the format string.
  2. Specifier Extraction: Identifies format specifiers (e.g., %Y, %m, %H, %T) in the format string and extracts the corresponding date and time components from the input string s. The format of these components in s must adhere to the specifier's requirements (e.g., %m expects 2 digits, %T expects "HH:MM:SS").
  3. Validation: After successfully extracting the year, month, day, hour, minute, and second values, it validates these components by internally attempting to create a ParsiDateTime using logic equivalent to ParsiDateTime::new. This ensures the extracted components form both a logically valid Persian date (checking month/day ranges, leap years) and a valid time (checking hour/minute/second ranges).

Supported Format Specifiers for Parsing

The following format specifiers are supported when parsing a date and time string:

  • Date Specifiers:
    • %Y: Parses exactly 4 digits as the Persian year (e.g., "1403").
    • %m: Parses exactly 2 digits as the Persian month (01-12) (e.g., "05").
    • %d: Parses exactly 2 digits as the Persian day (01-31) (e.g., "02").
    • %B: Parses a full Persian month name (case-sensitive, must exactly match standard names like "فروردین", "بهمن").
  • Time Specifiers:
    • %H: Parses exactly 2 digits as the hour (24-hour clock, 00-23) (e.g., "09", "15").
    • %M: Parses exactly 2 digits as the minute (00-59) (e.g., "05", "30").
    • %S: Parses exactly 2 digits as the second (00-59) (e.g., "00", "45").
    • %T: Equivalent to %H:%M:%S. Parses time in the exact format "HH:MM:SS" (e.g., "15:30:05").
  • Literal Specifier:
    • %%: Matches a literal percent sign (%) character in the input string s.

Unsupported Specifiers for Parsing

Specifiers representing calculated values or components not directly used to construct a date/time instance are not supported for parsing. Using any of the following specifiers in the format string will lead to a ParseErrorKind::UnsupportedSpecifier error:

  • %A: Weekday name (e.g., "شنبه").
  • %w: Weekday number (0-6).
  • %j: Ordinal day of the year (001-366).
  • %K: Season name (e.g., "پاییز").
  • (Any other specifiers not listed in the "Supported" section)

Arguments

  • s: The input string slice (&str) containing the date and time representation to be parsed.
  • format: The format string slice (&str) describing the expected structure of s, using literals and supported format specifiers.

Returns

  • Ok(ParsiDateTime): If the input string s successfully matches the format string and the extracted components form a valid Persian date and time, returns the resulting ParsiDateTime instance wrapped in Ok.
  • Err(DateError::ParseError(kind)): If parsing fails, returns an error wrapped in Err. The kind field (ParseErrorKind) provides details:
    • ParseErrorKind::FormatMismatch: The structure of s does not match the format (e.g., wrong separators, missing components, extra trailing characters).
    • ParseErrorKind::InvalidNumber: A numeric component (%Y, %m, %d, %H, %M, %S) could not be parsed as a number or lacked the required number of digits.
    • ParseErrorKind::InvalidMonthName: Input did not contain a recognized Persian month name where %B was expected.
    • ParseErrorKind::UnsupportedSpecifier: The format string contained an unsupported specifier (e.g., %A, %j, %K).
    • ParseErrorKind::InvalidDateValue: Extracted Y/M/D values were syntactically correct but form an invalid date (e.g., "1404/12/30" - 1404 is common; "1403/07/31" - Mehr has 30 days). Checked via internal ParsiDateTime::new.
    • ParseErrorKind::InvalidTimeValue: Extracted H/M/S values were syntactically correct but outside valid ranges (e.g., Hour 24, Minute 60, Second 60). Checked via internal ParsiDateTime::new.

Examples (Rust)

use parsidate::{ParsiDateTime, ParsiDate, DateError, ParseErrorKind}; // Assuming these types exist

// --- Success Cases ---

let s1 = "1403/05/02 15:30:45";
let fmt1 = "%Y/%m/%d %H:%M:%S";
let expected1 = ParsiDateTime::new(1403, 5, 2, 15, 30, 45).unwrap();
assert_eq!(ParsiDateTime::parse(s1, fmt1), Ok(expected1));

// Using %T for the time part
let s2 = "1403-05-02T09:05:00";
let fmt2 = "%Y-%m-%dT%T"; // ISO-like format
let expected2 = ParsiDateTime::new(1403, 5, 2, 9, 5, 0).unwrap();
assert_eq!(ParsiDateTime::parse(s2, fmt2), Ok(expected2));

// Using Persian month name %B
let s3 = "22 بهمن 1399 - 23:59:59"; // Assuming "بهمن" is recognized
let fmt3 = "%d %B %Y - %T";
let expected3 = ParsiDateTime::new(1399, 11, 22, 23, 59, 59).unwrap();
assert_eq!(ParsiDateTime::parse(s3, fmt3), Ok(expected3));


// --- Error Cases ---

// InvalidTimeValue: Hour 24 is out of range (00-23)
assert_eq!(
    ParsiDateTime::parse("1403/05/02 24:00:00", fmt1),
    Err(DateError::ParseError(ParseErrorKind::InvalidTimeValue))
);

// InvalidDateValue: Day 30 of Esfand in a non-leap year (1404)
assert_eq!(
    ParsiDateTime::parse("1404/12/30 10:00:00", fmt1),
    Err(DateError::ParseError(ParseErrorKind::InvalidDateValue))
);

// InvalidNumber: Minute '3' has only 1 digit, but %M (via %T or directly) expects 2 ('03')
assert_eq!(
    ParsiDateTime::parse("1403/05/02 15:3:45", fmt1),
    Err(DateError::ParseError(ParseErrorKind::InvalidNumber)) // Or possibly FormatMismatch
);

// FormatMismatch: Input uses '-' for time separator, but format (%T or %H:%M:%S) expects ':'
assert_eq!(
    ParsiDateTime::parse("1403/05/02 15-30-45", fmt1),
    Err(DateError::ParseError(ParseErrorKind::FormatMismatch))
);

// FormatMismatch: Input string is missing the time part required by the format
assert_eq!(
    ParsiDateTime::parse("1403/05/02", fmt1),
    Err(DateError::ParseError(ParseErrorKind::FormatMismatch))
);

// FormatMismatch: Input string has extra characters not accounted for in the format
assert_eq!(
    ParsiDateTime::parse("1403/05/02 15:30:45 extra", fmt1),
    Err(DateError::ParseError(ParseErrorKind::FormatMismatch))
);

// InvalidMonthName: Using a non-Persian or misspelled month name where %B expects a valid one
assert_eq!(
    ParsiDateTime::parse("22 Бахман 1399 - 23:59:59", fmt3), // Using Cyrillic 'B' for demo
    Err(DateError::ParseError(ParseErrorKind::InvalidMonthName))
);

// UnsupportedSpecifier: Format string uses %A (weekday) which is not supported for parsing
assert_eq!(
    ParsiDateTime::parse("Tuesday 1403 10:00:00", "%A %Y %T"), // Hypothetical input
    Err(DateError::ParseError(ParseErrorKind::UnsupportedSpecifier))
);

// UnsupportedSpecifier: Format string uses %K (season)
assert_eq!(
    ParsiDateTime::parse("Spring 1403 10:00:00", "%K %Y %T"), // Hypothetical input
    Err(DateError::ParseError(ParseErrorKind::UnsupportedSpecifier))
);