DateTime-Lite

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN

        DateTime::Lite::MAX_NANOSECONDS(); # 1_000_000_000
        DateTime::Lite::SECONDS_PER_DAY(); # 86400

        # Error handling
        my $dt2 = DateTime::Lite->new( %bad_args ) ||
            die( DateTime::Lite->error );
        # Chaining: bad calls return a NullObject so the chain continues safely;
        # check the return value of the last call in the chain.
        my $result = $dt->some_method->another_method ||
            die( $dt->error );

VERSION
        v0.6.1

DESCRIPTION
    "DateTime::Lite" is a lightweight, memory-efficient, drop-in replacement
    for DateTime with the following design goals:

    Low dependency footprint
        Runtime dependencies are limited to: DateTime::Lite::TimeZone
        (bundled SQLite timezone data, with automatic fallback to
        DateTime::TimeZone if DBD::SQLite is unavailable),
        DateTime::Locale::FromCLDR (locale data via Locale::Unicode::Data's
        SQLite backend), Locale::Unicode, and core modules.

        The heavy Specio, Params::ValidationCompiler, Try::Tiny, and
        "namespace::autoclean" are eliminated entirely.

    Low memory footprint
        "DateTime" loads a cascade of modules which inflates %INC
        significantly. "DateTime::Lite" avoids this via selective lazy
        loading.

    Accurate timezone data from TZif binaries
        "DateTime::TimeZone" derives its zone data from the IANA Olson
        *source* files ("africa", "northamerica", etc.) via a custom text
        parser ("DateTime::TimeZone::OlsonDB"), then pre-generates one ".pm"
        file per zone at distribution build time. This introduces an extra
        parsing step that is not part of the official IANA toolchain.

        "DateTime::Lite::TimeZone" instead compiles the IANA source files
        with zic(1), which is the official IANA compiler, and reads the
        resulting TZif binary files directly, following RFC 9636
        <https://www.rfc-editor.org/rfc/rfc9636> (TZif versions 1 through
        4). Timestamps are stored as signed 64-bit integers, giving a range
        of roughly "+/-" 292 billion years.

        Crucially, the POSIX footer TZ string embedded in every TZif v2+
        file, such as "EST5EDT,M3.2.0,M11.1.0", is extracted and stored in
        the SQLite database.

        This string encodes the recurring DST rule for all dates beyond the
        last explicit transition. At runtime, "DateTime::Lite::TimeZone"
        evaluates the footer rule via an XS implementation of the IANA
        "tzcode" reference algorithm (see "dtl_posix.h", derived from
        "tzcode2026a/localtime.c", public domain), ensuring correct timezone
        calculations for any date in the future without expanding the full
        transition table.

    XS-accelerated hot paths
        The XS layer covers all CPU-intensive calendar arithmetic
        ("_rd2ymd", "_ymd2rd", "_seconds_as_components", all leap-second
        helpers), plus new functions not in the original: "_rd_to_epoch",
        "_epoch_to_rd", "_normalize_nanoseconds", and "_compare_rd".

    Compatible API
        The public API mirrors DateTime as closely as possible, so existing
        code using "DateTime" should work with "DateTime::Lite" as a drop-in
        replacement.

    Full Unicode CLDR / BCP 47 locale support
        "DateTime" is limited to the set of pre-generated
        "DateTime::Locale::*" modules, one per locale. "DateTime::Lite"
        accepts any valid Unicode CLDR / BCP 47 locale tag, including
        complex forms with Unicode extensions ("-u-"), transform extensions
        ("-t-"), and script subtags.

            my $dt = DateTime::Lite->now( locale => 'en' );    # simple form
            my $dt = DateTime::Lite->now( locale => 'en-GB' ); # simple form
            # And more complex forms too
            my $dt = DateTime::Lite->now( locale => 'he-IL-u-ca-hebrew-tz-jeruslm' );
            my $dt = DateTime::Lite->now( locale => 'ja-Kana-t-it' );
            my $dt = DateTime::Lite->now( locale => 'ar-SA-u-nu-latn' );

        Locale data is resolved dynamically by DateTime::Locale::FromCLDR
        via Locale::Unicode::Data, so tags like
        "he-IL-u-ca-hebrew-tz-jeruslm" or "ja-Kana-t-it" work transparently
        without any additional installed modules.

        Additionally, if the locale tag carries a Unicode timezone extension
        ("-u-tz-"), and no explicit "time_zone" argument is provided to the
        constructor, "DateTime::Lite" will automatically resolve the
        corresponding IANA canonical timezone name from it:

            # time_zone is inferred as 'Asia/Jerusalem' from the -u-tz-jeruslm extension
            my $dt = DateTime::Lite->now( locale => 'he-IL-u-ca-hebrew-tz-jeruslm' );
            say $dt->time_zone;            # Asia/Jerusalem
            say $dt->time_zone_long_name;  # Asia/Jerusalem

        An explicit "time_zone" argument always takes priority over the
        locale extension.

    No die() in normal operation
        Following the Module::Generic / Locale::Unicode error-handling
        philosophy, "DateTime::Lite" never calls "die()" in normal error
        paths.

        Instead it sets a DateTime::Lite::Exception object and returns
        "undef" in scalar context, or an empty list in list context.

        However, if you really want this module to "die" upon error, you can
        pass the "fatal" option with a true value upon object instantiation.

KNOWN DIFFERENCES FROM DateTime
    Validation
        "DateTime" uses Specio / Params::ValidationCompiler for constructor
        validation. "DateTime::Lite" performs equivalent checks manually.
        Error messages are similar but not identical.

    No warnings::register abuse
        "DateTime::Lite" uses "warnings::enabled" consistently and does not

README  view on Meta::CPAN


  nanosecond
        my $ns = $dt->nanosecond;

    Returns the fractional-second component in nanoseconds (0-999_999_999).

  day_of_week
        my $dow = $dt->day_of_week;  # 1=Mon .. 7=Sun

    Returns the day of week as a number from 1 (Monday) to 7 (Sunday),
    following the ISO 8601 convention.

  day_of_year
        my $doy = $dt->day_of_year;

    Returns the day of the year (1-366).

  day_abbr
        my $abbr = $dt->day_abbr;  # e.g. "Mon"

    Returns the abbreviated weekday name for the current locale.

  day_name
        my $name = $dt->day_name;  # e.g. "Monday"

    Returns the full weekday name for the current locale.

  month_0
        my $m0 = $dt->month_0;  # 0=Jan .. 11=Dec

    Returns the month as a zero-based number (0-11).

  mon_0
    Alias for "month_0".

  month_abbr
        my $abbr = $dt->month_abbr;  # e.g. "Jan"

    Returns the abbreviated month name for the current locale.

  month_name
        my $name = $dt->month_name;  # e.g. "January"

    Returns the full month name for the current locale.

  week
        my( $wy, $wn ) = $dt->week;

    Returns a two-element list "( $week_year, $week_number )" according to
    ISO 8601 week numbering.

  week_number
        my $wn = $dt->week_number;

    Returns the ISO 8601 week number (1-53).

  week_year
        my $wy = $dt->week_year;

    Returns the year that the ISO 8601 week belongs to. This may differ from
    "year" for days near the start or end of the calendar year.

  quarter
        my $q = $dt->quarter;

    Returns the quarter of the year (1-4).

  epoch
        my $ts = $dt->epoch;

    Returns the Unix timestamp (seconds since 1970-01-01T00:00:00 UTC) as an
    integer.

  hires_epoch
        my $ts = $dt->hires_epoch;

    Returns the Unix timestamp as a floating-point number (IEEE 754 double)
    that includes sub-second precision.

    Precision caveat: a 64-bit double has ~15-16 significant decimal digits.
    A Unix timestamp around 2026 already consumes 10 digits for the integer
    part, leaving only ~6 digits for the fractional part. This means
    precision is effectively limited to the microsecond range (~1 µs);
    nanosecond values smaller than a few hundred nanoseconds will be lost in
    floating-point rounding.

    For full nanosecond precision, combine "epoch" and "nanosecond"
    directly:

        printf "%d.%09d\n", $dt->epoch, $dt->nanosecond;

  jd
        my $jd = $dt->jd;

    Returns the Julian Day Number as a floating-point number.

  mjd
        my $mjd = $dt->mjd;

    Returns the Modified Julian Day (Julian Day minus 2,400,000.5).

  offset
        my $off = $dt->offset;

    Returns the UTC offset in seconds for the current datetime, such as
    32400 for "+09:00".

  time_zone
        my $tz = $dt->time_zone;

    Returns the DateTime::Lite::TimeZone object associated with this
    datetime.

  time_zone_long_name
        my $name = $dt->time_zone_long_name;

    Returns the long name of the time zone, such as "America/New_York".

  time_zone_short_name
        my $abbr = $dt->time_zone_short_name;

README  view on Meta::CPAN


    Returns the date portion as "YYYY-MM-DD" (default separator "-").

  hms( [$sep] )
        my $time = $dt->hms;          # "12:34:56"
        my $time = $dt->hms( '.' );   # "12.34.56"

    Returns the time portion as "HH:MM:SS" (default separator ":">).

  dmy( [$sep] )
        my $dmy = $dt->dmy;           # "09-04-2026"

    Returns the date as "DD-MM-YYYY".

  mdy( [$sep] )
        my $mdy = $dt->mdy;           # "04-09-2026"

    Returns the date as "MM-DD-YYYY".

  rfc3339
        my $str = $dt->rfc3339;       # "2026-04-09T12:34:56+09:00"

    Returns an RFC 3339 string. For a UTC datetime this is the same as
    "iso8601" with a "Z" suffix; for other timezones it appends the numeric
    offset.

ARITHMETIC
  add( %args )
        $dt->add( years => 1, months => 3 );
        $dt->add( hours => 2, minutes => 30 );

    Adds a duration to the datetime in-place (mutates $self). Accepts the
    same keys as "new" in DateTime::Lite::Duration: "years", "months",
    "weeks", "days", "hours", "minutes", "seconds", "nanoseconds".

    Returns $self to allow chaining.

  subtract( %args )
        $dt->subtract( days => 7 );

    Subtracts a duration from the datetime in-place (mutates $self).
    Equivalent to "$dt->add" with all values negated.

  add_duration( $dur )
        my $dur = DateTime::Lite::Duration->new( months => 2 );
        $dt->add_duration( $dur );

    Adds a DateTime::Lite::Duration object to the datetime in-place (mutates
    $self).

    Returns $self to allow chaining.

  subtract_duration( $dur )
        $dt->subtract_duration( $dur );

    Subtracts a DateTime::Lite::Duration object from the datetime in-place
    (mutates $self). Equivalent to "$dt->add_duration( $dur->inverse )".

  subtract_datetime( $dt )
    Returns a DateTime::Lite::Duration representing the difference between
    two "DateTime::Lite" objects (calendar-aware).

  subtract_datetime_absolute( $dt )
    Returns a DateTime::Lite::Duration representing the absolute UTC
    difference in seconds/nanoseconds.

  delta_days( $dt )
        my $dur = $dt1->delta_days( $dt2 );
        printf "%d days apart\n", $dur->days;

    Returns a DateTime::Lite::Duration containing only a "days" component
    representing the number of whole days between $self and $dt.

  delta_md( $dt )
        my $dur = $dt1->delta_md( $dt2 );

    Returns a DateTime::Lite::Duration with "months" and "days" components
    (calendar-aware difference).

  delta_ms( $dt )
        my $dur = $dt1->delta_ms( $dt2 );

    Returns a DateTime::Lite::Duration with "minutes" and "seconds"
    components (absolute clock difference).

SETTERS
  set
        $dt->set( hour => 0, minute => 0, second => 0 );

    Sets one or more datetime components in-place. Accepted keys are any of
    "year", "month", "day", "hour", "minute", "second", "nanosecond".
    Returns $self.

  set_year
        $dt->set_year(2030);

    Sets the year component. Returns $self.

  set_month
        $dt->set_month(12);

    Sets the month (1-12). Returns $self.

  set_day
        $dt->set_month(31);

    Sets the day of the month. Returns $self.

  set_hour
        $dt->set_hour(14);

    Sets the hour (0-23). Returns $self.

  set_minute
        $dt->set_minute(40);

    Sets the minute (0-59). Returns $self.

  set_second
        $dt->set_second(30);

    Sets the second (0-59). Returns $self.

  set_nanosecond
        $dt->set_nanosecond(1000);

    Sets the nanosecond component (0-999_999_999). Returns $self.

  set_locale
        $dt->set_locale( 'zh-TW' );

    Sets the locale. Accepts a CLDR locale string, such as "fr-FR", or a
    DateTime::Locale::FromCLDR object. Returns $self.

  set_formatter
        $dt->set_formatter( $my_formatter );

    Sets the formatter object used by "stringify". Must respond to

README  view on Meta::CPAN

        DateTime::Lite::Duration).

    *   "<=>" and "cmp" - numeric and string comparison, for use with "sort"
        and comparison operators.

    *   "" (stringification) - calls stringify, which delegates to the
        formatter if set, otherwise returns the iso8601 string.

    *   "bool" - always true for finite objects.

    The "fallback" parameter is set, so derived operators ("+=", "-=", etc.)
    work as expected. Do not expect "++" or "--" to be useful.

        my $dt2 = $dt + $duration;  # new datetime
        my $dt3 = $dt - $duration;  # new datetime
        my $dur = $dt - $other_dt;  # Duration

        for my $dt ( sort @datetimes ) { ... }  # uses <=>

  Formatters And Stringification
    You can supply a "formatter" object to control how a datetime is
    stringified. Any constructor accepts a "formatter" argument:

        my $fmt = DateTime::Format::Unicode->new( locale => 'fr-FR' );
        my $dt  = DateTime::Lite->new( year => 2026, formatter => $fmt );

    Or set it afterwards:

        $dt->set_formatter( $fmt );
        my $current_fmt = $dt->formatter;

    Once set, $dt will call "$fmt->format_datetime($dt)" instead of iso8601.
    Pass "undef" to revert to the default.

    A formatter must implement a "format_datetime($dt)" method. The
    DateTime::Format::Unicode module (available separately on CPAN) provides
    a full-featured CLDR formatter with support for date/time intervals and
    additional pattern tokens not covered by format_cldr.

CLDR PATTERNS
    The CLDR (Unicode Common Locale Data Repository) pattern language is
    more powerful and more complex than strftime. Unlike strftime, patterns
    are plain letters with no prefix, so any literal text must be quoted.

  Quoting and escaping
    Surround literal ASCII letters with single quotes ("'"). To include a
    literal single quote, write two consecutive single quotes (''). Spaces
    and non-letter characters are always passed through unchanged.

        my $p1 = q{'Today is ' EEEE};           # "Today is Thursday"
        my $p2 = q{'It is now' h 'o''clock' a}; # "It is now 9 o'clock AM"

  Pattern length and padding
    Most patterns pad with leading zeroes when the specifier is longer than
    one character. For example, "h" gives 9 but "hh" gives 09. The exception
    is that five of a letter usually means the narrow form, such as "EEEEE"
    gives "T" for Thursday, not a five-character wide value.

  Format vs. stand-alone forms
    Many tokens have a *format* form (used inside a larger string) and a
    *stand-alone* form (used alone, such as in a calendar header). They are
    distinguished by case: "M" is format, "L" is stand-alone for months;
    "E"/"e" is format, "c" is stand-alone for weekdays.

  Token reference
        Era
          G{1,3}   abbreviated era (BC, AD)
          GGGG     wide era (Before Christ, Anno Domini)
          GGGGG    narrow era

        Year
          y        year, zero-padded as needed
          yy       two-digit year (special case)
          Y{1,}    week-of-year calendar year (from week_year)
          u{1,}    same as y, but yy is not special

        Quarter
          Q{1,2}   quarter as number (1-4)
          QQQ      abbreviated format quarter
          QQQQ     wide format quarter
          q{1,2}   quarter as number (stand-alone)
          qqq      abbreviated stand-alone quarter
          qqqq     wide stand-alone quarter

        Month
          M{1,2}   numerical month (format)
          MMM      abbreviated format month name
          MMMM     wide format month name
          MMMMM    narrow format month name
          L{1,2}   numerical month (stand-alone)
          LLL      abbreviated stand-alone month name
          LLLL     wide stand-alone month name
          LLLLL    narrow stand-alone month name

        Week
          w{1,2}   week of year (from week_number)
          W        week of month (from week_of_month)

        Day
          d{1,2}   day of month
          D{1,3}   day of year
          F        day of week in month (from weekday_of_month)
          g{1,}    modified Julian day (from mjd)

        Weekday
          E{1,3}   abbreviated format weekday
          EEEE     wide format weekday
          EEEEE    narrow format weekday
          e{1,2}   locale-based numeric weekday (1 = first day of week for locale)
          eee      abbreviated format weekday (same as E{1,3})
          eeee     wide format weekday
          eeeee    narrow format weekday
          c        numeric weekday, Monday = 1 (stand-alone)
          ccc      abbreviated stand-alone weekday
          cccc     wide stand-alone weekday
          ccccc    narrow stand-alone weekday

        Period
          a        AM or PM (localized)

        Hour
          h{1,2}   hour 1-12
          H{1,2}   hour 0-23
          K{1,2}   hour 0-11
          k{1,2}   hour 1-24
          j{1,2}   locale-preferred hour (12h or 24h)

        Minute / Second
          m{1,2}   minute
          s{1,2}   second
          S{1,}    fractional seconds (without decimal point)
          A{1,}    millisecond of day

        Time zone

README  view on Meta::CPAN

    supported by DateTime::Format::Unicode:

    *   "b" / "B" - period and flexible period of day ("noon", "at
        night"...)

    *   "O" / "OOOO" - localized GMT format ("GMT-8", "GMT-08:00")

    *   "r" - related Gregorian year

    *   "x"/"X" - ISO 8601 timezone offsets with optional "Z"

  CLDR Available Formats
    The CLDR data includes locale-specific pre-defined format skeletons. A
    skeleton is a pattern key that maps to a locale-appropriate rendering
    pattern. For example, the skeleton "MMMd" maps to "MMM d" in "en-US"
    (giving "Apr 9") and to "d MMM" in "fr-FR" (giving "9 avr.").

    Retrieve the locale-specific pattern via the locale object and pass it
    to "format_cldr":

        say $dt->format_cldr( $dt->locale->available_format('MMMd') );
        say $dt->format_cldr( $dt->locale->available_format('yQQQ') );
        say $dt->format_cldr( $dt->locale->available_format('hm') );

    See "available_formats" in DateTime::Locale::FromCLDR for the full list
    of skeletons for any given locale.

  DateTime::Format::Unicode
    For more advanced formatting, including features not covered by
    "format_cldr()", use DateTime::Format::Unicode (available separately on
    CPAN). It provides:

    *   Support for the additional tokens listed above ("b", "B", "O", "r",
        "x", "X")

    *   Formatting of datetime intervals, such as "Apr 9 - 12, 2026"

    *   Full CLDR number system support (Arabic-Indic numerals, etc.)

    *   Any CLDR locale, including complex tags such as
        "es-419-u-ca-gregory"

        use DateTime::Format::Unicode;

        my $fmt = DateTime::Format::Unicode->new(
            locale  => 'ja-JP',
            pattern => 'GGGGy年M月d日(EEEE)',
        ) || die( DateTime::Format::Unicode->error );

        say $fmt->format_datetime( $dt );

        # Interval formatting:
        my $fmt2 = DateTime::Format::Unicode->new(
            locale  => 'en',
            pattern => 'GyMMMd',
        );
        say $fmt2->format_interval( $dt1, $dt2 );  # e.g. "Apr 9 - 12, 2026"

HOW DATETIME MATH WORKS
    Date math in "DateTime::Lite" follows the same model as DateTime. The
    key distinction is between *calendar units* (months, days) and *clock
    units* (minutes, seconds, nanoseconds). Understanding this distinction
    is essential for correct results.

  Duration buckets
    A DateTime::Lite::Duration stores its components in five independent
    *buckets*: months, days, minutes, seconds, nanoseconds. Each bucket is
    kept as a signed integer. The buckets are not normalised against each
    other: a duration of "{ months => 1, days => 31 }" is distinct from "{
    months => 2, days => 0 }" because the number of days in a month varies.

  Calendar vs. clock units
    *Calendar units* (months, days) are relative: their real duration
    depends on the datetime to which they are applied. *Clock units*
    (minutes, seconds, nanoseconds) are absolute.

    When add applies a duration, calendar units are applied first, then
    clock units:

        $dt->add( months => 1, hours => 2 );
        # Step 1: advance by 1 month  (calendar)
        # Step 2: advance by 2 hours  (clock)

  End-of-month handling
    Adding months to a date whose day is beyond the end of the target month
    requires a policy decision. DateTime::Lite::Duration supports three
    "end_of_month" modes:

    *   "wrap" (default) - wrap into the next month. January 31 + 1 month =
        March 3 (or 2 in leap years).

    *   "limit" - clamp to the last day of the target month. January 31 + 1
        month = February 28 (or 29 in leap years).

    *   "preserve" - like "limit", but remember that the original day was at
        the end of month, so a further addition of one month will also land
        on the last day.

  Subtraction
    "$dt1->subtract_datetime( $dt2 )" returns a duration representing the
    difference. The calendar part is computed in months and days (from the
    local dates), and the clock part in seconds and nanoseconds (from the
    UTC representations). This is the most commonly useful result.

    "$dt1->subtract_datetime_absolute( $dt2 )" returns a duration in pure
    clock units (seconds and nanoseconds), based on the UTC epoch
    difference. This is useful when you need an exact elapsed time
    independent of DST changes.

  Leap seconds
    "DateTime::Lite" handles leap seconds when the time zone is not
    floating. Adding a duration in clock units across a leap second boundary
    will correctly account for the extra second.

SEE ALSO
    DateTime, DateTime::Lite::Duration, DateTime::Lite::Exception,
    DateTime::Lite::Infinite, DateTime::Locale::FromCLDR,
    Locale::Unicode::Data, DateTime::Format::Unicode

CREDITS
    Credits to the original author of DateTime, Dave Rolsky and all the
    contributors for their great work on which this module DateTime::Lite is
    derived.

AUTHOR
    Jacques Deguest <jack@deguest.jp>

COPYRIGHT & LICENSE
    Copyright(c) 2026 DEGUEST Pte. Ltd.

    All rights reserved

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



( run in 1.209 second using v1.01-cache-2.11-cpan-39bf76dae61 )