NAME
    Time::Str - Parse and format date/time strings in multiple standard
    formats

SYNOPSIS
        use Time::Str qw( str2time str2date time2str );

        # Parse to Unix timestamp
        my $time = str2time('2024-12-24T15:30:45Z');
        my $time = str2time('Mon, 24 Dec 2012 15:30:45 +0100', format => 'RFC2822');

        # Parse to components
        my %date = str2date('2024-12-24T15:30:45.500+01:00');
        # (year => 2024, month => 12, day => 24, hour => 15,
        #  minute => 30, second => 45, nanosecond => 500000000,
        #  tz_offset => 60)

        # Format Unix timestamp
        my $str = time2str(1735052445);
        # '2024-12-24T15:30:45Z'

        my $str = time2str(1735052445, format => 'RFC2822', offset => 60);
        # 'Tue, 24 Dec 2024 16:30:45 +0100'

DESCRIPTION
    Time::Str parses date/time strings from various standard formats into
    Unix timestamps or components, and formats Unix timestamps back into
    strings.

    Supported standards include ISO 8601, RFC 3339, RFC 2822, RFC 2616
    (HTTP), ISO 9075 (SQL), ASN.1, and others. A permissive Generic parser
    handles most real-world date/time representations that can be parsed
    without ambiguity.

FUNCTIONS
  str2time
        my $time = str2time($string);
        my $time = str2time($string, format => $format);
        my $time = str2time($string, format => $format, precision => $precision);
        my $time = str2time($string, format => 'ASN1UT', pivot_year => 2000);

    Parses a date/time string and returns a Unix timestamp (seconds since
    1970-01-01T00:00:00Z). The timestamp may include fractional seconds.

    The input must include a UTC designator ("Z", "UTC", "GMT") or a numeric
    timezone offset. Strings with only an unresolved timezone abbreviation
    (e.g., "EST", "IST") will croak. See "TIMEZONE ABBREVIATIONS".

   Parameters
    *   $string (required)

        The date/time string to parse.

    *   "format" (optional, default: 'RFC3339')

        The format specification. See "SUPPORTED FORMATS".

    *   "precision" (optional, default: 6 or 9 depending on float size)

        Number of decimal places to preserve for fractional seconds (0-9).
        Fractional digits beyond the specified precision are truncated. See
        "PRECISION HANDLING".

    *   "pivot_year" (optional, default: 1950)

        For formats with two-digit years ("ASN1UT", RFC 850 within
        "RFC2616"), sets the pivot year for century expansion. Two-digit
        years less than "(pivot_year % 100)" map to the next century; others
        map to the current century.

        With the default pivot of 1950: 49 becomes 2049, 50 becomes 1950, 99
        becomes 1999.

   Returns
    A numeric Unix timestamp, possibly with a fractional part. The supported
    range is 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z.

   Errors
    Croaks if:

    *   The string cannot be parsed in the specified format

    *   Date or time components are out of valid ranges

    *   No timezone offset or UTC designator is present

    *   A named parameter is unknown or out of range

   Examples
        # RFC 3339 (default)
        my $t = str2time('2024-12-24T15:30:45Z');
        # 1735052445

        my $t = str2time('2024-12-24T15:30:45.500+01:00');
        # 1735048845.5

        # RFC 2822
        my $t = str2time('Mon, 24 Dec 2012 15:30:45 +0100',
                         format => 'RFC2822');
        # HTTP
        my $t = str2time('Mon, 24 Dec 2012 15:30:45 GMT',
                         format => 'RFC2616');

        # Precision (truncation)
        my $t = str2time('2024-12-24T15:30:45.123456789Z', precision => 3);
        # 1735052445.123

        my $t = str2time('2024-12-24T15:30:45.999999Z', precision => 3);
        # 1735052445.999

  str2date
        my %date = str2date($string);
        my %date = str2date($string, format => $format);
        my %date = str2date($string, format => 'ASN1UT', pivot_year => 2000);

    Parses a date/time string and returns the parsed components. Unlike
    "str2time", this does not require a timezone and preserves all parsed
    information without converting to a timestamp.

   Parameters
    *   $string (required)

        The date/time string to parse.

    *   "format" (optional, default: 'RFC3339')

        The format specification. See "SUPPORTED FORMATS".

    *   "pivot_year" (optional, default: 1950)

        For formats with two-digit years, sets the pivot year for century
        expansion.

   Returns
    In list context, returns key-value pairs. In scalar context, returns a
    hash reference.

    All values are numeric except "tz_utc", "tz_abbrev", and
    "tz_annotation". The following components may be present:

    *   "year" - Four-digit year (1-9999)

    *   "month" - Month (1-12)

    *   "day" - Day of month (1-31)

    *   "hour" - Hour in 24-hour format (0-23)

    *   "minute" - Minute (0-59)

    *   "second" - Second (0-60; 60 allows for leap seconds)

    *   "nanosecond" - Fractional seconds as nanoseconds (0-999999999)

    *   "tz_offset" - Timezone offset in minutes from UTC (e.g., 60 for
        +01:00). Present when a numeric offset or UTC designator was parsed.

    *   "tz_utc" - The UTC designator ("Z", "UTC", "GMT") if one was
        present. When followed by a numeric offset (e.g., "UTC+05:30"),
        "tz_offset" reflects that offset rather than zero.

    *   "tz_abbrev" - The timezone abbreviation as it appeared in the input,
        if present and not a UTC designator. "tz_offset" will not be present
        when "tz_abbrev" is set. See "TIMEZONE ABBREVIATIONS".

    *   "tz_annotation" - Bracketed timezone tag from the input, if present
        (RFC 9557 IXDTF or Java "ZoneId" format, e.g.,
        "[Europe/Stockholm]"). Informational only; does not affect
        "tz_offset".

   Errors
    Croaks if:

    *   The string cannot be parsed in the specified format

    *   Date or time components are out of valid ranges

    *   A named parameter is unknown or out of range

   Examples
        # Full RFC 3339 timestamp
        my %d = str2date('2024-12-24T15:30:45.500+01:00');
        # (year       => 2024,
        #  month      => 12,
        #  day        => 24,
        #  hour       => 15,
        #  minute     => 30,
        #  second     => 45,
        #  nanosecond => 500000000,
        #  tz_offset  => 60)

        # Partial dates
        my %d = str2date('2024-12-24', format => 'W3CDTF');
        # (year => 2024, month => 12, day => 24)

        my %d = str2date('2024', format => 'W3CDTF');
        # (year => 2024)

        # 12-hour clock
        my %d = str2date('December 24, 2024, 3:30 PM', format => 'generic');
        # (..., hour => 15)

        # Two-digit year
        my %d = str2date('Monday, 24-Dec-50 15:30:45 GMT',
                         format => 'RFC2616');
        # (year => 1950, ...)

        # Two-digit year with custom pivot
        my %d = str2date('Monday, 24-Dec-50 15:30:45 GMT',
                         format => 'RFC2616', pivot_year => 1970);
        # (year => 2050, ...)

        # UTC designator
        my %d = str2date('24 Dec 2012 15:30:45 GMT', format => 'RFC2822');
        # (..., tz_utc => 'GMT', tz_offset => 0)

        # UTC designator with offset
        my %d = str2date('December 24, 2024 at 3:30 pm UTC+05:30',
                         format => 'generic');
        # (..., tz_utc => 'UTC', tz_offset => 330)

        # Timezone abbreviation (unresolved)
        my %d = str2date('24 Dec 2012 15:30:45 IST', format => 'RFC2822');
        # (..., tz_abbrev => 'IST')

        # RFC 9557 annotation
        my %d = str2date('2024-12-24T15:30:45.500+01:00[Europe/Stockholm]',
                         format => 'generic');
        # (..., tz_offset => 60, tz_annotation => '[Europe/Stockholm]')

  time2str
        my $str = time2str($time);
        my $str = time2str($time, format => $format);
        my $str = time2str($time, format => $format, offset => $offset);
        my $str = time2str($time, nanosecond => $ns, precision => $prec);

    Formats a Unix timestamp into a date/time string.

   Parameters
    *   $time (required)

        Unix timestamp (seconds since 1970-01-01T00:00:00Z). May be an
        integer or floating-point number. Supported range:
        0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z.

    *   "format" (optional, default: 'RFC3339')

        The output format. See "SUPPORTED FORMATS". Not all formats support
        fractional seconds or timezone offsets.

    *   "offset" (optional, default: 0)

        Timezone offset in minutes from UTC. Positive is east, negative is
        west. Valid range: -1439 to +1439 (-23:59 to +23:59).

    *   "precision" (optional)

        Number of decimal places for fractional seconds (0-9). Fractional
        seconds are rounded to this precision, which may carry into the
        seconds field (e.g., rounding .999 at precision 0 yields the next
        whole second).

        When omitted and the timestamp has fractional seconds, precision is
        auto-detected: 3 if the fractional part is divisible by 0.001, 6 if
        divisible by 0.000001, or 9 otherwise. When specified as 0,
        fractional seconds are omitted after rounding.

        See "PRECISION HANDLING".

    *   "nanosecond" (optional)

        Explicit nanosecond value (0-999999999) for fractional seconds.
        Overrides any fractional part of $time and bypasses rounding. Use
        this for exact control over fractional output or to preserve
        nanosecond precision that floating-point cannot represent. Can be
        combined with "precision" to control zero-padding.

   Returns
    A formatted date/time string.

   Errors
    Croaks if:

    *   $time is outside the supported range

    *   A named parameter is unknown or out of range

   Examples
        # RFC 3339 (default)
        my $str = time2str(1735052445);
        # '2024-12-24T15:30:45Z'

        # Timezone offset
        my $str = time2str(1735052445, offset => 60);
        # '2024-12-24T16:30:45+01:00'

        # Fractional seconds (auto-detected precision)
        my $str = time2str(1735052445.123456);
        # '2024-12-24T15:30:45.123456Z'

        # Explicit precision (rounded)
        my $str = time2str(1735052445.123456, precision => 3);
        # '2024-12-24T15:30:45.123Z'

        # Rounding carries into seconds
        my $str = time2str(1735052445.999999, precision => 3);
        # '2024-12-24T15:30:46.000Z'

        # Zero-padding
        my $str = time2str(1735052445, precision => 3);
        # '2024-12-24T15:30:45.000Z'

        # Nanosecond override (no rounding, auto-detected precision)
        my $str = time2str(1735052445, nanosecond => 500_000_000);
        # '2024-12-24T15:30:45.500Z'

        # Zero-padding with nanosecond
        my $str = time2str(1735052445, nanosecond => 0, precision => 3);
        # '2024-12-24T15:30:45.000Z'

        # RFC 2822
        my $str = time2str(1735052445, format => 'RFC2822', offset => 60);
        # 'Tue, 24 Dec 2024 16:30:45 +0100'

        # HTTP (always GMT)
        my $str = time2str(1735052445, format => 'RFC2616');
        # 'Tue, 24 Dec 2024 15:30:45 GMT'

        # SQL with timezone
        my $str = time2str(1735052445.5, format => 'ISO9075', offset => 60);
        # '2024-12-24 16:30:45.500 +01:00'

        # Common Log Format
        my $str = time2str(1735052445, format => 'CLF', offset => 60);
        # '24/Dec/2024:16:30:45 +0100'

PRECISION HANDLING
    The module handles fractional seconds differently when parsing versus
    formatting.

  Parsing (str2time)
    Fractional seconds beyond the specified precision are truncated, This
    preserves the exact digits provided in the input up to the requested
    precision:

        str2time('2024-12-24T15:30:45.123456Z', precision => 3)
        # Returns: 1735052445.123 (digits beyond 3rd truncated)

        str2time('2024-12-24T15:30:45.999999Z', precision => 3)
        # Returns: 1735052445.999 (NOT .000 of next second)

    Note: "str2date" does not accept a precision parameter. It always
    preserves fractional seconds at full nanosecond resolution in the
    "nanosecond" component.

  Formatting (time2str)
    Fractional seconds are rounded to the specified precision. Rounding
    prevents floating-point artifacts from appearing in formatted output:

        time2str(1735052445.123456, precision => 3)
        # '2024-12-24T15:30:45.123Z'

        time2str(1735052445.999999, precision => 3)
        # '2024-12-24T15:30:46.000Z' (rounds up to next second)

        time2str(1735052445.999999, precision => 0)
        # '2024-12-24T15:30:46Z' (rounds up, fraction omitted)

  Bypassing Rounding
    The "nanosecond" parameter overrides the fractional part of $time and is
    not subject to rounding, giving exact control over the output:

        time2str(1735052445, nanosecond => 999_999_000, precision => 6)
        # '2024-12-24T15:30:45.999999Z' (exact, no rounding)

        time2str(1735052445, nanosecond => 0)
        # '2024-12-24T15:30:45Z' (no fractional part)

FLOATING-POINT PRECISION
    Perl's floating-point type (NV) is typically IEEE 754 double-precision
    (64-bit), providing approximately 15-17 significant decimal digits
    shared between the integer and fractional parts of a number.

  Implications for Timestamps
    Whole seconds are always represented exactly within the supported date
    range (0001-01-01 to 9999-12-31).

    Fractional precision depends on the magnitude of the timestamp:

    *   Millisecond precision ("precision => 3") is exact and stable across
        the entire supported date range.

    *   Microsecond precision ("precision => 6") is reliable for timestamps
        within roughly Â±140 years of the Unix epoch (1830-2110). Beyond this
        range, values may shift by Â±1 microsecond due to floating-point
        spacing.

    *   Nanosecond precision cannot be represented faithfully in a
        floating-point timestamp. Use the "nanosecond" parameter for exact
        sub-microsecond values.

  Default Precision
    When "time2str" formats a timestamp with fractional seconds and neither
    "precision" nor "nanosecond" is specified, it uses a default based on
    Perl's NV (floating-point) type:

    *   6 decimal places when NV is double-precision (64-bit)

    *   9 decimal places when NV has extended precision (e.g., long double)

    This default prevents spurious trailing digits caused by floating-point
    representation. For explicit control, always specify "precision" or
    "nanosecond".

SUPPORTED FORMATS
    The following format specifiers are recognized (case-insensitive). The
    default format is "RFC3339".

  ANSIC (alias: ctime)
    ANSI C asctime() / ctime() format.

      DDD MMM (_D|DD) HH:MM:SS YYYY

    Where "_D" is a space-padded single-digit day.

    Parsing:

      Mon Dec  1 03:04:05 2024
      Tue Dec 24 15:30:45 2024

    Formatting:

      time2str(1735052445, format => 'ANSIC')
      # 'Tue Dec 24 15:30:45 2024'

    Limitations: Always UTC. Fractional seconds and timezone offsets are not
    supported; the "offset" parameter is ignored.

  ASN1GT
    ASN.1 GeneralizedTime as defined in ITU-T X.680.

      YYYYMMDDhh[mm[ss]][(.|,)fraction][Z|Â±hh[mm]]

    Parsing:

    Hours are required; minutes and seconds are optional. The fractional
    part may use a period or comma and applies to the least significant time
    component present. The timezone designator is optional.

      2024122415                   # hour only, no timezone
      2024122415Z                  # hour only, UTC
      2024122415,5Z                # decimal hour (30 minutes)
      201212241530Z                # hour and minute
      201212241530,5Z              # decimal minute (30 seconds)
      20121224153045               # full time, no timezone
      20121224153045Z              # full time, UTC
      20121224153045.500Z          # with fractional seconds
      20121224153045,123456789Z    # nanoseconds, comma separator
      20121224153045+0100          # with numeric offset

    Timezone offset format: "Â±HHMM" or "Â±HH"

    Formatting:

      time2str(1735052445, format => 'ASN1GT')
      # '20241224153045Z'

      time2str(1735052445, format => 'ASN1GT', precision => 3)
      # '20241224153045.500Z'

      time2str(1735052445, format => 'ASN1GT', offset => 60)
      # '20241224163045+0100'

    Limitations: Formatting always outputs hours, minutes, and seconds.
    Decimal hours and decimal minutes are not produced.

  ASN1UT
    ASN.1 UTCTime as defined in ITU-T X.680.

      YYMMDDhhmm[ss](Z|Â±hhmm)

    Parsing:

    Two-digit year; seconds are optional. A timezone designator is required.

      9412211010Z           # without seconds
      241224153045Z         # with seconds
      241224153045+0100     # with numeric offset

    Timezone offset format: "Â±HHMM"

    Formatting:

      time2str(1735052445, format => 'ASN1UT')
      # '241224153045Z'

      time2str(1735052445, format => 'ASN1UT', offset => 60)
      # '241224163045+0100'

    Limitations: Fractional seconds are not supported.

  CLF
    Common Log Format.

      DD/MMM/YYYY:HH:MM:SS[.fraction] Â±HHMM

    Parsing:

      24/Dec/2024:15:30:45 +0100
      24/Dec/2024:15:30:45.500 +0100
      24/Dec/2024:15:30:45.123456789 -0500

    Timezone offset format: "Â±HHMM"

    Formatting:

      time2str(1735052445, format => 'CLF')
      # '24/Dec/2024:15:30:45 +0000'

      time2str(1735052445, format => 'CLF', offset => 60)
      # '24/Dec/2024:16:30:45 +0100'

      time2str(1735052445.5, format => 'CLF', precision => 3, offset => 60)
      # '24/Dec/2024:16:30:45.500 +0100'

  Generic
    A permissive parser that accepts a wide variety of real-world date/time
    representations, restricted to those that can be parsed
    deterministically. Parsing only; cannot be used with "time2str".

    See "GENERIC FORMAT PARSING" for the full grammar, rules, and examples.

  Git
    Default date format used by Git.

      DDD MMM D HH:MM:SS YYYY Â±HHMM

    Parsing:

      Mon Dec 1 03:04:05 2024 +0100
      Mon Dec 24 15:30:45 2012 +0100

    Timezone offset format: "Â±HHMM"

    Formatting:

      time2str(1735052445, format => 'Git')
      # 'Tue Dec 24 15:30:45 2024 +0000'

      time2str(1735052445, format => 'Git', offset => 60)
      # 'Tue Dec 24 16:30:45 2024 +0100'

    Limitations: Fractional seconds are not supported.

  ISO8601
    Calendar date and time as defined in ISO 8601. Accepts both extended
    (with separators) and basic (compact) forms. Minutes, seconds,
    fractional seconds, and timezone are all optional when a time is
    present. The fractional part applies to the least significant time
    component present, allowing decimal hours and decimal minutes.

    Extended format:

      YYYY-MM-DD
      YYYY-MM-DDThh[:mm[:ss]][(.|,)fraction][Z|Â±hh[:mm]]

    Basic format:

      YYYYMMDD
      YYYYMMDDThh[mm[ss]][(.|,)fraction][Z|Â±hh[mm]]

    Parsing:

      2024-12-24                   # date only (extended)
      20241224                     # date only (basic)
      2024-12-24T15Z               # hour only
      2024-12-24T15,5Z             # decimal hour (15:30)
      2024-12-24T15:30Z            # hour and minute
      2024-12-24T15:30.5Z          # decimal minute (15:30:30)
      2024-12-24T15:30:45Z         # full time
      2024-12-24T15:30:45.500Z     # fractional seconds
      2024-12-24T15:30:45,500Z     # comma separator
      20241224T153045Z             # basic
      20241224T1530,5Z             # basic, decimal minute
      20241224T153045+0100         # basic with offset
      2024-12-24T15:30:45+01:00    # extended with offset

    Formatting:

    Produces extended format, identical to RFC3339.

      time2str(1735052445, format => 'ISO8601')
      # '2024-12-24T15:30:45Z'

      time2str(1735052445, format => 'ISO8601', offset => 60)
      # '2024-12-24T16:30:45+01:00'

      time2str(1735052445.5, format => 'ISO8601', precision => 3)
      # '2024-12-24T15:30:45.500Z'

    Limitations: Formatting always produces extended format with full time
    (hours, minutes, seconds). Date-only, basic format, decimal hours, and
    decimal minutes are not produced.

  ISO9075 (alias: SQL)
    ISO 9075 Database Language SQL timestamp format.

      YYYY-MM-DD
      YYYY-MM-DD HH:MM:SS[.fraction]
      YYYY-MM-DD HH:MM:SS[.fraction] Â±HH:MM

    Parsing:

      2024-12-24
      2024-12-24 15:30:45
      2024-12-24 15:30:45.500
      2024-12-24 15:30:45.123456789
      2024-12-24 15:30:45 +01:00
      2024-12-24 15:30:45.500 +01:00

    Timezone offset format: "Â±HH:MM"

    Formatting:

      time2str(1735052445, format => 'ISO9075')
      # '2024-12-24 15:30:45 +00:00'

      time2str(1735052445, format => 'ISO9075', offset => 60)
      # '2024-12-24 16:30:45 +01:00'

      time2str(1735052445.5, format => 'ISO9075', precision => 3, offset => 60)
      # '2024-12-24 16:30:45.500 +01:00'

    Limitations: Formatting always includes a timezone offset. Date-only
    parsing is supported but date-only output is not.

  RFC2616 (aliases: RFC7231, HTTP)
    HTTP-date as defined in RFC 2616 / RFC 7231. Parses three sub-formats:

      DDD, DD MMM YYYY HH:MM:SS GMT    # IMF-fixdate (preferred)
      DDDD, DD-MMM-YY HH:MM:SS GMT     # RFC 850 (obsolete)
      DDD MMM _D HH:MM:SS YYYY         # ANSI C asctime

    Parsing:

      Mon, 24 Dec 2012 15:30:45 GMT    # IMF-fixdate
      Monday, 24-Dec-12 15:30:45 GMT   # RFC 850
      Mon Dec 24 15:30:45 2012         # asctime

    Formatting:

    Always produces IMF-fixdate in GMT:

      time2str(1735052445, format => 'RFC2616')
      # 'Tue, 24 Dec 2024 15:30:45 GMT'

    Limitations: Always GMT. The "offset" parameter is ignored.

    Fractional seconds are not supported.

  RFC2822 (aliases: RFC5322, IMF, EMAIL)
    Internet Message Format date as defined in RFC 2822 / RFC 5322.

      [DDD,] D MMM YYYY HH:MM[:SS] (Â±HHMM|UT|UTC|GMT|abbrev)

    Parsing:

    Day name and seconds are optional. Accepts numeric offsets, UTC
    designators ("UT", "UTC", "GMT"), and timezone abbreviations.
    Abbreviations are returned in "tz_abbrev" without resolution.

      Mon, 24 Dec 2012 15:30:45 +0100
      Mon, 24 Dec 2012 15:30 +0100
      24 Dec 2012 15:30:45 +0100
      24 Dec 2012 15:30:45 GMT
      24 Dec 2012 15:30:45 CET

    Timezone offset format: "Â±HHMM"

    See "TIMEZONE ABBREVIATIONS".

    Formatting:

    Always produces a numeric offset:

      time2str(1735052445, format => 'RFC2822')
      # 'Tue, 24 Dec 2024 15:30:45 +0000'

      time2str(1735052445, format => 'RFC2822', offset => 60)
      # 'Tue, 24 Dec 2024 16:30:45 +0100'

    Limitations: Fractional seconds are not supported.

  RFC3339
    Internet timestamp as defined in RFC 3339, a profile of ISO 8601.

      YYYY-MM-DD(T|t| )HH:MM:SS[.fraction](Z|z|Â±HH:MM)

    Parsing:

    The date/time separator may be "T", "t", or a space. The UTC designator
    may be "Z" or "z".

      2024-12-24T15:30:45Z
      2024-12-24t15:30:45z
      2024-12-24 15:30:45Z
      2024-12-24T15:30:45.500Z
      2024-12-24T15:30:45.123456789Z
      2024-12-24T15:30:45+01:00
      2024-12-24T15:30:45-05:00

    Timezone offset format: "Â±HH:MM"

    Formatting:

    Always produces uppercase "T" and "Z" (or "Â±HH:MM"):

      time2str(1735052445, format => 'RFC3339')
      # '2024-12-24T15:30:45Z'
  
      time2str(1735052445, format => 'RFC3339', offset => 60)
      # '2024-12-24T16:30:45+01:00'
  
      time2str(1735052445.5, format => 'RFC3339', precision => 3)
      # '2024-12-24T15:30:45.500Z'

  RFC4287 (alias: ATOM)
    Atom feed timestamp as defined in RFC 4287. Stricter than RFC 3339:
    requires uppercase "T" and "Z", no space separator, no lowercase
    designators.

      YYYY-MM-DDTHH:MM:SS[.fraction](Z|Â±HH:MM)

    Parsing:

      2024-12-24T15:30:45Z
      2024-12-24T15:30:45.500Z
      2024-12-24T15:30:45.123456789Z
      2024-12-24T15:30:45+01:00

    Timezone offset format: "Â±HH:MM"

    Formatting: Identical to RFC3339.

  RFC5280 (alias: x509)
    X.509 certificate validity times as defined in RFC 5280. Certificates
    encode validity as ASN.1 UTCTime (two-digit year) for dates before 2050
    and GeneralizedTime (four-digit year) for dates from 2050 onward. Both
    forms require UTC and do not permit fractional seconds or timezone
    offsets.

      YYMMDDhhmmssZ           # UTCTime
      YYYYMMDDhhmmssZ         # GeneralizedTime

    Parsing:

    Accepts both forms. Two-digit years are expanded using "pivot_year"
    (default 1950), which matches the RFC 5280 convention: years 00-49 map
    to 2000-2049, years 50-99 map to 1950-1999.

      121224153045Z            # UTCTime, year 12 -> 2012
      491231235959Z            # UTCTime, year 49 -> 2049
      500101000000Z            # UTCTime, year 50 -> 1950
      20500101000000Z          # GeneralizedTime
      99991231235959Z          # GeneralizedTime

    Formatting:

    Automatically selects the form based on the timestamp: UTCTime for dates
    before 2050-01-01T00:00:00Z, GeneralizedTime for dates from 2050 onward.

      time2str(1356359445, format => 'RFC5280')
      # '121224143045Z'        - before 2050, UTCTime

      time2str(2524608000, format => 'RFC5280')
      # '20500101000000Z'      - from 2050, GeneralizedTime

    Limitations: Always UTC. The "offset" parameter is ignored. Fractional
    seconds are not supported.

  RFC5545 (alias: iCal)
    iCalendar date and date-time as defined in RFC 5545.

      YYYYMMDD
      YYYYMMDDThhmmss[Z]

    Parsing:

    Date-only and date-time forms are accepted. Without "Z", parses as local
    time with no "tz_offset".

      20241224                     # date only
      20241224T153045              # local time
      20241224T153045Z             # UTC

    Formatting:

      time2str(1735052445, format => 'RFC5545')
      # '20241224T153045Z'

    Limitations: Always UTC. The "offset" parameter is ignored. Fractional
    seconds are not supported.

  Ruby
    Date format popularized by Ruby on Rails and Twitter.

      DDD MMM DD HH:MM:SS Â±HHMM YYYY

    Parsing:

      Mon Dec 01 03:04:05 +0100 2024
      Mon Dec 24 15:30:45 +0100 2012

    Timezone offset format: "Â±HHMM"

    Formatting:

      time2str(1735052445, format => 'Ruby')
      # 'Tue Dec 24 15:30:45 +0000 2024'

      time2str(1735052445, format => 'Ruby', offset => 60)
      # 'Tue Dec 24 16:30:45 +0100 2024'

    Limitations: Fractional seconds are not supported.

  Unix
    The date(1) command output format as defined by POSIX.

      DDD MMM (_D|DD) HH:MM:SS (Â±HHMM|UTC|GMT|abbrev) YYYY
      DDD MMM (_D|DD) HH:MM:SS YYYY (Â±HHMM|UTC|GMT|abbrev)

    Where "_D" is a space-padded single-digit day.

    Parsing:

    Accepts the timezone before or after the year. Accepts numeric offsets,
    UTC designators ("UTC", "GMT"), and timezone abbreviations.
    Abbreviations are returned in "tz_abbrev" without resolution.

      Mon Dec  1 03:04:05 2024 UTC
      Mon Dec 24 15:30:45 2012 UTC
      Mon Dec  1 03:04:05 UTC 2024
      Mon Dec 24 15:30:45 UTC 2012

    Timezone offset format: "Â±HHMM"

    See "TIMEZONE ABBREVIATIONS".

    Formatting:

    Always produces the zone-before-year. Uses "UTC" for zero offset and a
    numeric offset otherwise.

      time2str(1735052445, format => 'Unix')
      # 'Tue Dec 24 15:30:45 UTC 2024'

      time2str(1735052445, format => 'Unix', offset => 60)
      # 'Tue Dec 24 16:30:45 +0100 2024'

    Limitations: Fractional seconds are not supported.

  W3CDTF (alias: W3C)
    W3C Date and Time Format, a profile of ISO 8601.

      YYYY
      YYYY-MM
      YYYY-MM-DD
      YYYY-MM-DDTHH:MM:SS[.fraction](Z|Â±HH:MM)

    Parsing:

    Supports partial dates. A timezone designator is required when a time
    component is present.

      2024                             # year only
      2024-12                          # year and month
      2024-12-24                       # date only
      2024-12-24T15:30:45Z             # full datetime
      2024-12-24T15:30:45.500Z
      2024-12-24T15:30:45.123456789Z
      2024-12-24T15:30:45+01:00

    Timezone offset format: "Â±HH:MM"

    Formatting: Identical to RFC3339.

GENERIC FORMAT PARSING
    The "generic" format parser accepts a wide variety of real-world
    date/time representations, restricted to those that can be parsed
    deterministically. A date is always required. Time and timezone are
    optional, but a timezone may only appear when a time is present.

  Date
    A date is always required. Three categories are accepted.

   Numeric Dates (Y-M-D only)
    When all three components are numeric, they must appear in
    year-month-day order to avoid the ambiguity between American (M/D/Y) and
    European (D/M/Y) conventions. The separator must be a hyphen, slash, or
    period, consistent within the date.

      2024-12-24
      2024/12/24
      2024.12.24

    These are rejected:

      12-24-2024  # M-D-Y not accepted
      24-12-2024  # D-M-Y not accepted
      2024-12/24  # mixed separators

   Dates with Textual Months
    When the month is given as a name or Roman numeral it is unambiguous, so
    the day and year may appear in any order relative to the month. Month
    names may be abbreviated ("Jan", "Feb", ...) or written in full
    ("January", "February", ...).

    Roman numerals ("I" through "XII") are accepted only in day-month-year
    order.

    Month names and Roman numerals are all case-insensitive.

    Separator-based (hyphen, slash, or period, consistent within the date):

      2024-Dec-24       # Y-M-D
      24-Dec-2024       # D-M-Y
      Dec-24-2024       # M-D-Y
      2024/December/24
      24.XII.2024       # Roman numeral, D-M-Y only

    Space-separated:

      24 December 2024
      December 24, 2024
      24. XII. 2024

    In space-separated dates, an ordinal suffix ("st", "nd", "rd", "th") or
    a trailing period may follow the day. A trailing period or comma may
    follow the month:

      24th December 2024
      24. December 2024
      December 24th, 2024
      24. XII. 2024
      24 XII. 2024
      24. XII 2024

   Compact Dates (No Separators)
    Accepted only when the month is textual. Roman numerals are accepted in
    day-month-year order:

      24DEC2024
      24Dec2024
      2024DEC24
      2024Dec24
      24XII2024

   Day Names
    An optional day name prefix (e.g., "Monday," or "Mon,") is accepted
    before the date but not validated against the actual date. Day names are
    case-insensitive.

      Monday, 24 December 2024
      Mon, 24 Dec 2024

   Year
    A four-digit year is always required. Two-digit years are not accepted.

  Time of Day
    Optional. When present, it must be separated from the date by "T", a
    comma and space, the word "at" surrounded by spaces, or a plain space.

      2024-12-24T15:30:45
      2024-12-24 15:30:45
      December 24, 2024, 15:30
      Monday, 24th December 2024 at 3:30 pm

    Either "HH:MM" or "HH" with an AM/PM indicator is required as a minimum.

   24-Hour Time
    Hours and minutes separated by a colon. Hours may be one or two digits;
    minutes are always two digits. Seconds are optional (two digits,
    colon-separated). An optional fractional part may follow the seconds,
    separated by a period or comma, up to nine digits.

      15:30
      9:05
      15:30:45
      15:30:45.500
      15:30:45,500
      15:30:45.123456789

   12-Hour Time
    An AM/PM indicator is required. Hours must be 1-12. Minutes, seconds,
    and fractional seconds follow the same rules as 24-hour time but are
    optional. The indicator may appear with or without a separating space.

    Accepted forms: "AM", "am", "PM", "pm", "A.M.", "a.m.", "P.M.", "p.m."

      3 PM
      3PM
      3:30 PM
      3:30:45 pm
      3:30:45.500 P.M.
      12 p.m.

    Midnight is "12:00 AM", noon is "12:00 PM".

  Timezone
    Optional; may only appear when a time is present.

   UTC Designators
    "Z", "UTC", and "GMT" set "tz_utc" to the matched designator and
    "tz_offset" to 0, unless followed by a numeric offset (e.g.,
    "UTC+05:30"), in which case "tz_offset" reflects that offset.

   Numeric Offsets
      Â±1
      Â±01
      Â±0100
      Â±01:00
      Â±05:30

   Combined UTC and Offset
    "UTC" or "GMT" followed immediately by a numeric offset. "tz_utc" is set
    to the designator; "tz_offset" reflects the numeric part:

      UTC+1
      UTC+01:00
      GMT+5:30

   Timezone Abbreviations
    Abbreviations matching "[A-Z][A-Za-z][A-Z]{1,4}" are accepted. UTC
    designators are handled as above; all others (e.g., "EST", "CET", "IST")
    are returned in "tz_abbrev" without resolution.

    See "TIMEZONE ABBREVIATIONS".

   Timezone Annotations
    RFC 9557 (IXDTF) bracketed tags and Java "ZoneId" annotations are
    captured in "tz_annotation". Parenthesized comments are accepted but
    discarded.

      +01:00[Europe/Stockholm]
      +01:00[u-ca=hebrew]
      +0100[Europe/Stockholm]
      +0100 (CET)
      +0100 (Central European Time)

  Validation
    *   Dates must be valid for the Gregorian calendar, including leap years

    *   Hours: 0-23 (24-hour) or 1-12 (12-hour with AM/PM)

    *   Minutes: 0-59

    *   Seconds: 0-60 (60 allows for leap seconds)

  Examples
      # ISO 8601
      2024-12-24
      2024-12-24T15:30
      2024-12-24T15:30+01
      2024-12-24T15:30:45,500+01

      # RFC 3339
      2024-12-24T15:30:45+01:00
      2024-12-24T15:30:45.500+01:00

      # RFC 9557
      2024-12-24T15:30:45.500+01:00[Europe/Stockholm]

      # RFC 2822
      Mon, 24 Dec 2024 15:30:45 +0100
      24 Dec 2024 15:30 +0100

      # RFC 2616 (HTTP)
      Mon, 24 Dec 2024 15:30:45 GMT

      # RFC 9051 (IMAP)
      24-Dec-2024 15:30:45 +0100

      # ISO 9075 (SQL)
      2024-12-24 15:30:45
      2024-12-24 15:30:45.500 +01:00

      # ECMAScript Date.prototype.toString
      Mon Dec 24 2024 15:30:45 GMT+0100 (Central European Time)

      # Long-form textual
      Monday, 24 December 2024, 15:30 GMT+1
      Monday, 24th December 2024 at 3:30 pm UTC+1
      December 24th, 2024 at 3:30 PM

      # Short-form variations
      Dec/24/2024 03:30:45 PM
      24. XII. 2024 12PM UTC+1
      24DEC2024 12:30:45.500
      24.Dec.2024 15:30:45

TIMEZONE ABBREVIATIONS
    The "Generic", "RFC2822", and "Unix" parsers accept timezone
    abbreviations.

    *   UTC designators ("UTC", "GMT", "UT", "Z")

        Unambiguous. Set "tz_utc" to the matched designator and "tz_offset"
        to 0, unless followed by a numeric offset.

    *   All other abbreviations

        Returned as-is in "tz_abbrev". "tz_offset" will not be present. This
        module intentionally does not resolve abbreviations like "EST",
        "CET", or "IST" to numeric offsets, as many are ambiguous (e.g.,
        "IST" could mean India Standard Time UTC+5:30, Israel Standard Time
        UTC+2, or Irish Standard Time UTC+1).

    "str2time" requires a resolved offset and will croak if only an
    unresolved abbreviation is present. Use "str2date" to retrieve the
    components including "tz_abbrev", then resolve externally:

        my %d = str2date('24 Dec 2012 15:30:45 IST', format => 'RFC2822');
        # (..., tz_abbrev => 'IST')

EXPORTS
    Nothing is exported by default. Functions can be imported individually
    or by category:

      use Time::Str qw(time2str str2time);  # individual functions
      use Time::Str qw(:all);               # all functions

SEE ALSO
    Time::Moment, DateTime, Time::Piece

STANDARDS
    *   ISO 8601:2019 - Data elements and interchange formats

    *   RFC 3339 - Date and Time on the Internet: Timestamps

    *   RFC 2822 / RFC 5322 - Internet Message Format

    *   RFC 2616 / RFC 7231 - HTTP/1.1

    *   RFC 4287 - The Atom Syndication Format

    *   RFC 5280 - Internet X.509 Public Key Infrastructure (PKIX)

    *   RFC 5545 - Internet Calendaring and Scheduling (iCalendar)

    *   RFC 9051 - Internet Message Access Protocol (IMAP)

    *   RFC 9557 - Date and Time on the Internet: Timestamps with Additional
        Information

    *   ISO 9075 - SQL Database Language

    *   ITU-T X.680 (ISO/IEC 8824-1) - ASN.1

    *   W3C Date and Time Formats

AUTHOR
    Christian Hansen

COPYRIGHT AND LICENSE
    Copyright (C) 2026 by Christian Hansen

    This library is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself.

