DateTime-1.51/0000755000175000017500000000000013457144251013002 5ustar autarchautarchDateTime-1.51/Makefile.PL0000644000175000017500000000744713457144251014770 0ustar autarchautarch# This Makefile.PL for DateTime was generated by # Dist::Zilla::Plugin::DROLSKY::MakeMaker 1.01 # and Dist::Zilla::Plugin::MakeMaker::Awesome 0.42. # Don't edit it but the dist.ini and plugins used to construct it. use strict; use warnings; use 5.008004; use ExtUtils::MakeMaker; check_conflicts(); my %WriteMakefileArgs = ( "ABSTRACT" => "A date and time object for Perl", "AUTHOR" => "Dave Rolsky ", "CONFIGURE_REQUIRES" => { "Dist::CheckConflicts" => "0.02", "ExtUtils::MakeMaker" => 0 }, "DISTNAME" => "DateTime", "LICENSE" => "artistic_2", "MIN_PERL_VERSION" => "5.008004", "NAME" => "DateTime", "PREREQ_PM" => { "Carp" => 0, "DateTime::Locale" => "1.06", "DateTime::TimeZone" => "2.02", "Dist::CheckConflicts" => "0.02", "POSIX" => 0, "Params::ValidationCompiler" => "0.26", "Scalar::Util" => 0, "Specio" => "0.18", "Specio::Declare" => 0, "Specio::Exporter" => 0, "Specio::Library::Builtins" => 0, "Specio::Library::Numeric" => 0, "Specio::Library::String" => 0, "Try::Tiny" => 0, "XSLoader" => 0, "base" => 0, "integer" => 0, "namespace::autoclean" => "0.19", "overload" => 0, "parent" => 0, "strict" => 0, "warnings" => 0, "warnings::register" => 0 }, "TEST_REQUIRES" => { "CPAN::Meta::Check" => "0.011", "CPAN::Meta::Requirements" => 0, "ExtUtils::MakeMaker" => 0, "File::Spec" => 0, "Storable" => 0, "Test::Fatal" => 0, "Test::More" => "0.96", "Test::Warnings" => "0.005", "utf8" => 0 }, "VERSION" => "1.51", "test" => { "TESTS" => "t/*.t" } ); my $gcc_warnings = $ENV{AUTHOR_TESTING} && $] >= 5.008008 ? q{ -Wall -Werror} : q{}; $WriteMakefileArgs{DEFINE} = ( $WriteMakefileArgs{DEFINE} || q{} ) . $gcc_warnings; my %FallbackPrereqs = ( "CPAN::Meta::Check" => "0.011", "CPAN::Meta::Requirements" => 0, "Carp" => 0, "DateTime::Locale" => "1.06", "DateTime::TimeZone" => "2.02", "Dist::CheckConflicts" => "0.02", "ExtUtils::MakeMaker" => 0, "File::Spec" => 0, "POSIX" => 0, "Params::ValidationCompiler" => "0.26", "Scalar::Util" => 0, "Specio" => "0.18", "Specio::Declare" => 0, "Specio::Exporter" => 0, "Specio::Library::Builtins" => 0, "Specio::Library::Numeric" => 0, "Specio::Library::String" => 0, "Storable" => 0, "Test::Fatal" => 0, "Test::More" => "0.96", "Test::Warnings" => "0.005", "Try::Tiny" => 0, "XSLoader" => 0, "base" => 0, "integer" => 0, "namespace::autoclean" => "0.19", "overload" => 0, "parent" => 0, "strict" => 0, "utf8" => 0, "warnings" => 0, "warnings::register" => 0 ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); sub check_conflicts { if ( eval { require './lib/DateTime/Conflicts.pm'; 1; } ) { if ( eval { DateTime::Conflicts->check_conflicts; 1 } ) { return; } else { my $err = $@; $err =~ s/^/ /mg; warn "***\n$err***\n"; } } else { print <<'EOF'; *** Your toolchain doesn't support configure_requires, so Dist::CheckConflicts hasn't been installed yet. You should check for conflicting modules manually by examining the list of conflicts in DateTime::Conflicts once the installation finishes. *** EOF } return if $ENV{AUTOMATED_TESTING} || $ENV{NONINTERACTIVE_TESTING}; # More or less copied from Module::Build return if $ENV{PERL_MM_USE_DEFAULT}; return unless -t STDIN && ( -t STDOUT || !( -f STDOUT || -c STDOUT ) ); sleep 4; } DateTime-1.51/CREDITS0000644000175000017500000000223313457144251014022 0ustar autarchautarchThe core implementations for the DateTime.pm and DateTime::Duration modules originally came from Date::ICal and Date::ICal::Duration, both of which were written by Rich Bowen with help from the Reefknot team. Nowadays much of this code has been rewritten to the point that it is fundamentally original work. Parts of the API come from Time::Piece, by Matt Sergeant , who had help from Jarkko Hietaniemi . That API was originally created by Larry Wall. None of the code is shared. The DateTime::Locale functionality is based in part on the Date::Language modules that come with Graham Barr's TimeDate module suite. The strftime method in this module also borrows heavily from Graham's implementation. The week number and week year algorithms were taken from Steffen Beyer's Date::Calc module, but rewritten in Perl from scratch. The code for handling nanoseconds and the code for leap seconds were both largely written by Flavio Soibelmann Glock, who also has contributed various other features and fixes. Many others have helped out with code, ideas, and bug reports. See the Changes file for details. DateTime-1.51/META.yml0000644000175000017500000006712713457144251014270 0ustar autarchautarch--- abstract: 'A date and time object for Perl' author: - 'Dave Rolsky ' build_requires: CPAN::Meta::Check: '0.011' CPAN::Meta::Requirements: '0' ExtUtils::MakeMaker: '0' File::Spec: '0' Storable: '0' Test::Fatal: '0' Test::More: '0.96' Test::Warnings: '0.005' utf8: '0' configure_requires: Dist::CheckConflicts: '0.02' ExtUtils::MakeMaker: '0' dynamic_config: 0 generated_by: 'Dist::Zilla version 6.012, CPAN::Meta::Converter version 2.150010' license: artistic_2 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: DateTime provides: DateTime: file: lib/DateTime.pm version: '1.51' DateTime::Duration: file: lib/DateTime/Duration.pm version: '1.51' DateTime::Helpers: file: lib/DateTime/Helpers.pm version: '1.51' DateTime::Infinite: file: lib/DateTime/Infinite.pm version: '1.51' DateTime::Infinite::Future: file: lib/DateTime/Infinite.pm version: '1.51' DateTime::Infinite::Past: file: lib/DateTime/Infinite.pm version: '1.51' DateTime::LeapSecond: file: lib/DateTime/LeapSecond.pm version: '1.51' DateTime::PP: file: lib/DateTime/PP.pm version: '1.51' DateTime::PPExtra: file: lib/DateTime/PPExtra.pm version: '1.51' DateTime::Types: file: lib/DateTime/Types.pm version: '1.51' requires: Carp: '0' DateTime::Locale: '1.06' DateTime::TimeZone: '2.02' Dist::CheckConflicts: '0.02' POSIX: '0' Params::ValidationCompiler: '0.26' Scalar::Util: '0' Specio: '0.18' Specio::Declare: '0' Specio::Exporter: '0' Specio::Library::Builtins: '0' Specio::Library::Numeric: '0' Specio::Library::String: '0' Try::Tiny: '0' XSLoader: '0' base: '0' integer: '0' namespace::autoclean: '0.19' overload: '0' parent: '0' perl: '5.008004' strict: '0' warnings: '0' warnings::register: '0' resources: MailingList: datetime@perl.org bugtracker: https://github.com/houseabsolute/DateTime.pm/issues homepage: http://metacpan.org/release/DateTime repository: git://github.com/houseabsolute/DateTime.pm.git version: '1.51' x_Dist_Zilla: perl: version: '5.026002' plugins: - class: Dist::Zilla::Plugin::PruneCruft name: PruneCruft version: '6.012' - class: Dist::Zilla::Plugin::Git::GatherDir config: Dist::Zilla::Plugin::GatherDir: exclude_filename: - CODE_OF_CONDUCT.md - CONTRIBUTING.md - LICENSE - Makefile.PL - README.md - cpanfile - leap_seconds.h - ppport.h exclude_match: [] follow_symlinks: 0 include_dotfiles: 0 prefix: '' prune_directory: [] root: . Dist::Zilla::Plugin::Git::GatherDir: include_untracked: 0 name: '@DROLSKY/Git::GatherDir' version: '2.046' - class: Dist::Zilla::Plugin::ManifestSkip name: '@DROLSKY/ManifestSkip' version: '6.012' - class: Dist::Zilla::Plugin::License name: '@DROLSKY/License' version: '6.012' - class: Dist::Zilla::Plugin::ExecDir name: '@DROLSKY/ExecDir' version: '6.012' - class: Dist::Zilla::Plugin::ShareDir name: '@DROLSKY/ShareDir' version: '6.012' - class: Dist::Zilla::Plugin::Manifest name: '@DROLSKY/Manifest' version: '6.012' - class: Dist::Zilla::Plugin::CheckVersionIncrement name: '@DROLSKY/CheckVersionIncrement' version: '0.121750' - class: Dist::Zilla::Plugin::TestRelease name: '@DROLSKY/TestRelease' version: '6.012' - class: Dist::Zilla::Plugin::ConfirmRelease name: '@DROLSKY/ConfirmRelease' version: '6.012' - class: Dist::Zilla::Plugin::UploadToCPAN name: '@DROLSKY/UploadToCPAN' version: '6.012' - class: Dist::Zilla::Plugin::VersionFromMainModule config: Dist::Zilla::Role::ModuleMetadata: Module::Metadata: '1.000033' version: '0.006' name: '@DROLSKY/VersionFromMainModule' version: '0.04' - class: Dist::Zilla::Plugin::Authority name: '@DROLSKY/Authority' version: '1.009' - class: Dist::Zilla::Plugin::AutoPrereqs name: '@DROLSKY/AutoPrereqs' version: '6.012' - class: Dist::Zilla::Plugin::CopyFilesFromBuild name: '@DROLSKY/CopyFilesFromBuild' version: '0.170880' - class: Dist::Zilla::Plugin::GitHub::Meta name: '@DROLSKY/GitHub::Meta' version: '0.47' - class: Dist::Zilla::Plugin::GitHub::Update config: Dist::Zilla::Plugin::GitHub::Update: metacpan: 1 name: '@DROLSKY/GitHub::Update' version: '0.47' - class: Dist::Zilla::Plugin::MetaResources name: '@DROLSKY/MetaResources' version: '6.012' - class: Dist::Zilla::Plugin::MetaProvides::Package config: Dist::Zilla::Plugin::MetaProvides::Package: finder_objects: - class: Dist::Zilla::Plugin::FinderCode name: '@DROLSKY/MetaProvides::Package/AUTOVIV/:InstallModulesPM' version: '6.012' include_underscores: 0 Dist::Zilla::Role::MetaProvider::Provider: $Dist::Zilla::Role::MetaProvider::Provider::VERSION: '2.002004' inherit_missing: '1' inherit_version: '1' meta_noindex: '1' Dist::Zilla::Role::ModuleMetadata: Module::Metadata: '1.000033' version: '0.006' name: '@DROLSKY/MetaProvides::Package' version: '2.004003' - class: Dist::Zilla::Plugin::Meta::Contributors name: '@DROLSKY/Meta::Contributors' version: '0.003' - class: Dist::Zilla::Plugin::MetaConfig name: '@DROLSKY/MetaConfig' version: '6.012' - class: Dist::Zilla::Plugin::MetaJSON name: '@DROLSKY/MetaJSON' version: '6.012' - class: Dist::Zilla::Plugin::MetaYAML name: '@DROLSKY/MetaYAML' version: '6.012' - class: Dist::Zilla::Plugin::NextRelease name: '@DROLSKY/NextRelease' version: '6.012' - class: Dist::Zilla::Plugin::Prereqs config: Dist::Zilla::Plugin::Prereqs: phase: test type: requires name: '@DROLSKY/Test::More with subtest' version: '6.012' - class: Dist::Zilla::Plugin::Prereqs config: Dist::Zilla::Plugin::Prereqs: phase: develop type: requires name: '@DROLSKY/Modules for use with tidyall' version: '6.012' - class: Dist::Zilla::Plugin::Prereqs config: Dist::Zilla::Plugin::Prereqs: phase: develop type: requires name: '@DROLSKY/Test::Version which fixes https://github.com/plicease/Test-Version/issues/7' version: '6.012' - class: Dist::Zilla::Plugin::PromptIfStale config: Dist::Zilla::Plugin::PromptIfStale: check_all_plugins: 0 check_all_prereqs: 0 modules: - Dist::Zilla::PluginBundle::DROLSKY phase: build run_under_travis: 0 skip: [] name: '@DROLSKY/Dist::Zilla::PluginBundle::DROLSKY' version: '0.055' - class: Dist::Zilla::Plugin::PromptIfStale config: Dist::Zilla::Plugin::PromptIfStale: check_all_plugins: 1 check_all_prereqs: 1 modules: [] phase: release run_under_travis: 0 skip: - Dist::Zilla::Plugin::DROLSKY::Contributors - Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch - Dist::Zilla::Plugin::DROLSKY::License - Dist::Zilla::Plugin::DROLSKY::TidyAll - Dist::Zilla::Plugin::DROLSKY::WeaverConfig - Pod::Weaver::PluginBundle::DROLSKY name: '@DROLSKY/PromptIfStale' version: '0.055' - class: Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable name: '@DROLSKY/Test::Pod::Coverage::Configurable' version: '0.07' - class: Dist::Zilla::Plugin::Test::PodSpelling config: Dist::Zilla::Plugin::Test::PodSpelling: directories: - bin - lib spell_cmd: '' stopwords: - AEST - Anno - BCE - CLDR - CPAN - DATETIME - DROLSKY - "DROLSKY's" - DateTime - DateTimes - Datetime - Datetimes - Domini - EEEE - EEEEE - Flávio - Formatters - GGGG - GGGGG - Glock - Hant - IEEE - IEEE - LLL - LLLL - LLLLL - Liang - "Liang's" - MMM - MMMM - MMMMM - Measham - "Measham's" - POSIX - PayPal - PayPal - QQQ - QQQQ - Rata - Rata - Rolsky - "Rolsky's" - SU - Soibelmann - Storable - TW - TZ - Tsai - UTC - VVVV - YAPCs - ZZZZ - ZZZZZ - afterwards - bian - ccc - cccc - ccccc - conformant - datetime - "datetime's" - datetimes - decrement - dian - drolsky - durations - eee - eeee - eeeee - fallback - formatter - hh - iCal - ji - mutiplication - na - namespace - ni - nitty - "other's" - proleptic - qqq - qqqq - sexagesimal - subclasses - uu - vvvv - wiki - yy - yyyy - yyyyy - zh - zzzz wordlist: Pod::Wordlist name: '@DROLSKY/Test::PodSpelling' version: '2.007005' - class: Dist::Zilla::Plugin::PodSyntaxTests name: '@DROLSKY/PodSyntaxTests' version: '6.012' - class: Dist::Zilla::Plugin::DROLSKY::RunExtraTests config: Dist::Zilla::Role::TestRunner: default_jobs: 24 name: '@DROLSKY/DROLSKY::RunExtraTests' version: '1.01' - class: Dist::Zilla::Plugin::MojibakeTests name: '@DROLSKY/MojibakeTests' version: '0.8' - class: Dist::Zilla::Plugin::Test::CleanNamespaces config: Dist::Zilla::Plugin::Test::CleanNamespaces: filename: xt/author/clean-namespaces.t skips: - DateTime::Conflicts name: '@DROLSKY/Test::CleanNamespaces' version: '0.006' - class: Dist::Zilla::Plugin::Test::CPAN::Changes config: Dist::Zilla::Plugin::Test::CPAN::Changes: changelog: Changes name: '@DROLSKY/Test::CPAN::Changes' version: '0.012' - class: Dist::Zilla::Plugin::Test::CPAN::Meta::JSON name: '@DROLSKY/Test::CPAN::Meta::JSON' version: '0.004' - class: Dist::Zilla::Plugin::Test::EOL config: Dist::Zilla::Plugin::Test::EOL: filename: xt/author/eol.t finder: - ':ExecFiles' - ':InstallModules' - ':TestFiles' trailing_whitespace: 1 name: '@DROLSKY/Test::EOL' version: '0.19' - class: Dist::Zilla::Plugin::Test::NoTabs config: Dist::Zilla::Plugin::Test::NoTabs: filename: xt/author/no-tabs.t finder: - ':InstallModules' - ':ExecFiles' - ':TestFiles' name: '@DROLSKY/Test::NoTabs' version: '0.15' - class: Dist::Zilla::Plugin::Test::Portability config: Dist::Zilla::Plugin::Test::Portability: options: '' name: '@DROLSKY/Test::Portability' version: '2.001000' - class: Dist::Zilla::Plugin::Test::TidyAll name: '@DROLSKY/Test::TidyAll' version: '0.04' - class: Dist::Zilla::Plugin::Test::ReportPrereqs name: '@DROLSKY/Test::ReportPrereqs' version: '0.027' - class: Dist::Zilla::Plugin::Test::Version name: '@DROLSKY/Test::Version' version: '1.09' - class: Dist::Zilla::Plugin::DROLSKY::Contributors name: '@DROLSKY/DROLSKY::Contributors' version: '1.01' - class: Dist::Zilla::Plugin::Git::Contributors config: Dist::Zilla::Plugin::Git::Contributors: git_version: 2.20.1 include_authors: 0 include_releaser: 1 order_by: name paths: [] name: '@DROLSKY/Git::Contributors' version: '0.035' - class: Dist::Zilla::Plugin::SurgicalPodWeaver config: Dist::Zilla::Plugin::PodWeaver: config_plugins: - '@DROLSKY' finder: - ':InstallModules' - ':ExecFiles' plugins: - class: Pod::Weaver::Plugin::EnsurePod5 name: '@CorePrep/EnsurePod5' version: '4.015' - class: Pod::Weaver::Plugin::H1Nester name: '@CorePrep/H1Nester' version: '4.015' - class: Pod::Weaver::Plugin::SingleEncoding name: '@DROLSKY/SingleEncoding' version: '4.015' - class: Pod::Weaver::Plugin::Transformer name: '@DROLSKY/List' version: '4.015' - class: Pod::Weaver::Plugin::Transformer name: '@DROLSKY/Verbatim' version: '4.015' - class: Pod::Weaver::Section::Region name: '@DROLSKY/header' version: '4.015' - class: Pod::Weaver::Section::Name name: '@DROLSKY/Name' version: '4.015' - class: Pod::Weaver::Section::Version name: '@DROLSKY/Version' version: '4.015' - class: Pod::Weaver::Section::Region name: '@DROLSKY/prelude' version: '4.015' - class: Pod::Weaver::Section::Generic name: SYNOPSIS version: '4.015' - class: Pod::Weaver::Section::Generic name: DESCRIPTION version: '4.015' - class: Pod::Weaver::Section::Generic name: OVERVIEW version: '4.015' - class: Pod::Weaver::Section::Collect name: ATTRIBUTES version: '4.015' - class: Pod::Weaver::Section::Collect name: METHODS version: '4.015' - class: Pod::Weaver::Section::Collect name: FUNCTIONS version: '4.015' - class: Pod::Weaver::Section::Collect name: TYPES version: '4.015' - class: Pod::Weaver::Section::Leftovers name: '@DROLSKY/Leftovers' version: '4.015' - class: Pod::Weaver::Section::Region name: '@DROLSKY/postlude' version: '4.015' - class: Pod::Weaver::Section::GenerateSection name: '@DROLSKY/generate SUPPORT' version: '1.06' - class: Pod::Weaver::Section::AllowOverride name: '@DROLSKY/allow override SUPPORT' version: '0.05' - class: Pod::Weaver::Section::GenerateSection name: '@DROLSKY/generate SOURCE' version: '1.06' - class: Pod::Weaver::Section::GenerateSection name: '@DROLSKY/generate DONATIONS' version: '1.06' - class: Pod::Weaver::Section::Authors name: '@DROLSKY/Authors' version: '4.015' - class: Pod::Weaver::Section::Contributors name: '@DROLSKY/Contributors' version: '0.009' - class: Pod::Weaver::Section::Legal name: '@DROLSKY/Legal' version: '4.015' - class: Pod::Weaver::Section::Region name: '@DROLSKY/footer' version: '4.015' name: '@DROLSKY/SurgicalPodWeaver' version: '0.0023' - class: Dist::Zilla::Plugin::DROLSKY::WeaverConfig name: '@DROLSKY/DROLSKY::WeaverConfig' version: '1.01' - class: Dist::Zilla::Plugin::ReadmeAnyFromPod config: Dist::Zilla::Role::FileWatcher: version: '0.006' name: '@DROLSKY/README.md in build' version: '0.163250' - class: Dist::Zilla::Plugin::GenerateFile::FromShareDir config: Dist::Zilla::Plugin::GenerateFile::FromShareDir: destination_filename: CONTRIBUTING.md dist: Dist-Zilla-PluginBundle-DROLSKY encoding: UTF-8 has_xs: '1' location: build source_filename: CONTRIBUTING.md Dist::Zilla::Role::RepoFileInjector: allow_overwrite: 1 repo_root: . version: '0.009' name: '@DROLSKY/Generate CONTRIBUTING.md' version: '0.014' - class: Dist::Zilla::Plugin::GenerateFile::FromShareDir config: Dist::Zilla::Plugin::GenerateFile::FromShareDir: destination_filename: CODE_OF_CONDUCT.md dist: Dist-Zilla-PluginBundle-DROLSKY encoding: UTF-8 has_xs: '1' location: build source_filename: CODE_OF_CONDUCT.md Dist::Zilla::Role::RepoFileInjector: allow_overwrite: 1 repo_root: . version: '0.009' name: '@DROLSKY/Generate CODE_OF_CONDUCT.md' version: '0.014' - class: Dist::Zilla::Plugin::InstallGuide config: Dist::Zilla::Role::ModuleMetadata: Module::Metadata: '1.000033' version: '0.006' name: '@DROLSKY/InstallGuide' version: '1.200013' - class: Dist::Zilla::Plugin::CPANFile name: '@DROLSKY/CPANFile' version: '6.012' - class: Dist::Zilla::Plugin::PPPort name: '@DROLSKY/PPPort' version: '0.008' - class: Dist::Zilla::Plugin::DROLSKY::License name: '@DROLSKY/DROLSKY::License' version: '1.01' - class: Dist::Zilla::Plugin::CheckStrictVersion name: '@DROLSKY/CheckStrictVersion' version: '0.001' - class: Dist::Zilla::Plugin::CheckSelfDependency config: Dist::Zilla::Plugin::CheckSelfDependency: finder: - ':InstallModules' Dist::Zilla::Role::ModuleMetadata: Module::Metadata: '1.000033' version: '0.006' name: '@DROLSKY/CheckSelfDependency' version: '0.011' - class: Dist::Zilla::Plugin::CheckPrereqsIndexed name: '@DROLSKY/CheckPrereqsIndexed' version: '0.020' - class: Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch config: Dist::Zilla::Role::Git::Repo: git_version: 2.20.1 repo_root: . name: '@DROLSKY/DROLSKY::Git::CheckFor::CorrectBranch' version: '1.01' - class: Dist::Zilla::Plugin::EnsureChangesHasContent name: '@DROLSKY/EnsureChangesHasContent' version: '0.02' - class: Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts config: Dist::Zilla::Role::Git::Repo: git_version: 2.20.1 repo_root: . name: '@DROLSKY/Git::CheckFor::MergeConflicts' version: '0.014' - class: Dist::Zilla::Plugin::DROLSKY::TidyAll name: '@DROLSKY/DROLSKY::TidyAll' version: '1.01' - class: Dist::Zilla::Plugin::Git::Check config: Dist::Zilla::Plugin::Git::Check: untracked_files: die Dist::Zilla::Role::Git::DirtyFiles: allow_dirty: - CODE_OF_CONDUCT.md - CONTRIBUTING.md - Changes - LICENSE - Makefile.PL - README.md - cpanfile - leap_seconds.h - ppport.h - tidyall.ini allow_dirty_match: [] changelog: Changes Dist::Zilla::Role::Git::Repo: git_version: 2.20.1 repo_root: . name: '@DROLSKY/Git::Check' version: '2.046' - class: Dist::Zilla::Plugin::Git::Commit config: Dist::Zilla::Plugin::Git::Commit: add_files_in: [] commit_msg: v%V%n%n%c Dist::Zilla::Role::Git::DirtyFiles: allow_dirty: - CODE_OF_CONDUCT.md - CONTRIBUTING.md - Changes - LICENSE - Makefile.PL - README.md - cpanfile - leap_seconds.h - ppport.h - tidyall.ini allow_dirty_match: [] changelog: Changes Dist::Zilla::Role::Git::Repo: git_version: 2.20.1 repo_root: . Dist::Zilla::Role::Git::StringFormatter: time_zone: local name: '@DROLSKY/Commit generated files' version: '2.046' - class: Dist::Zilla::Plugin::Git::Tag config: Dist::Zilla::Plugin::Git::Tag: branch: ~ changelog: Changes signed: 0 tag: v1.51 tag_format: v%V tag_message: v%V Dist::Zilla::Role::Git::Repo: git_version: 2.20.1 repo_root: . Dist::Zilla::Role::Git::StringFormatter: time_zone: local name: '@DROLSKY/Git::Tag' version: '2.046' - class: Dist::Zilla::Plugin::Git::Push config: Dist::Zilla::Plugin::Git::Push: push_to: - origin remotes_must_exist: 1 Dist::Zilla::Role::Git::Repo: git_version: 2.20.1 repo_root: . name: '@DROLSKY/Git::Push' version: '2.046' - class: Dist::Zilla::Plugin::BumpVersionAfterRelease config: Dist::Zilla::Plugin::BumpVersionAfterRelease: finders: - ':ExecFiles' - ':InstallModules' global: 0 munge_makefile_pl: 1 name: '@DROLSKY/BumpVersionAfterRelease' version: '0.018' - class: Dist::Zilla::Plugin::Git::Commit config: Dist::Zilla::Plugin::Git::Commit: add_files_in: [] commit_msg: 'Bump version after release' Dist::Zilla::Role::Git::DirtyFiles: allow_dirty: - Changes - dist.ini allow_dirty_match: - (?^:.+) changelog: Changes Dist::Zilla::Role::Git::Repo: git_version: 2.20.1 repo_root: . Dist::Zilla::Role::Git::StringFormatter: time_zone: local name: '@DROLSKY/Commit version bump' version: '2.046' - class: Dist::Zilla::Plugin::Git::Push config: Dist::Zilla::Plugin::Git::Push: push_to: - origin remotes_must_exist: 1 Dist::Zilla::Role::Git::Repo: git_version: 2.20.1 repo_root: . name: '@DROLSKY/Push version bump' version: '2.046' - class: Dist::Zilla::Plugin::DROLSKY::MakeMaker config: Dist::Zilla::Plugin::MakeMaker: make_path: make version: '6.012' Dist::Zilla::Plugin::MakeMaker::Awesome: version: '0.42' Dist::Zilla::Role::TestRunner: default_jobs: 24 version: '6.012' name: '@DROLSKY/DROLSKY::MakeMaker' version: '1.01' - class: Dist::Zilla::Plugin::lib config: Dist::Zilla::Plugin::lib: lib: - . name: lib version: '0.001002' - class: inc::LeapSecondsHeader name: =inc::LeapSecondsHeader version: ~ - class: Dist::Zilla::Plugin::CopyFilesFromBuild name: CopyFilesFromBuild version: '0.170880' - class: Dist::Zilla::Plugin::MetaResources name: MetaResources version: '6.012' - class: Dist::Zilla::Plugin::Prereqs config: Dist::Zilla::Plugin::Prereqs: phase: develop type: requires name: DevelopRequires version: '6.012' - class: Dist::Zilla::Plugin::PurePerlTests name: PurePerlTests version: '0.06' - class: Dist::Zilla::Plugin::Conflicts name: Conflicts version: '0.19' - class: Dist::Zilla::Plugin::Test::CheckBreaks config: Dist::Zilla::Plugin::Test::CheckBreaks: conflicts_module: - DateTime::Conflicts no_forced_deps: 0 Dist::Zilla::Role::ModuleMetadata: Module::Metadata: '1.000033' version: '0.006' name: Test::CheckBreaks version: '0.019' - class: Dist::Zilla::Plugin::FinderCode name: ':InstallModules' version: '6.012' - class: Dist::Zilla::Plugin::FinderCode name: ':IncModules' version: '6.012' - class: Dist::Zilla::Plugin::FinderCode name: ':TestFiles' version: '6.012' - class: Dist::Zilla::Plugin::FinderCode name: ':ExtraTestFiles' version: '6.012' - class: Dist::Zilla::Plugin::FinderCode name: ':ExecFiles' version: '6.012' - class: Dist::Zilla::Plugin::FinderCode name: ':PerlExecFiles' version: '6.012' - class: Dist::Zilla::Plugin::FinderCode name: ':ShareFiles' version: '6.012' - class: Dist::Zilla::Plugin::FinderCode name: ':MainModule' version: '6.012' - class: Dist::Zilla::Plugin::FinderCode name: ':AllFiles' version: '6.012' - class: Dist::Zilla::Plugin::FinderCode name: ':NoFiles' version: '6.012' - class: Dist::Zilla::Plugin::FinderCode name: '@DROLSKY/MetaProvides::Package/AUTOVIV/:InstallModulesPM' version: '6.012' zilla: class: Dist::Zilla::Dist::Builder config: is_trial: '0' version: '6.012' x_authority: cpan:DROLSKY x_breaks: DateTime::Format::Mail: '<= 0.402' x_contributors: - 'Ben Bennett ' - 'Christian Hansen ' - 'Daisuke Maki ' - 'Dan Book ' - 'Dan Stewart ' - 'David E. Wheeler ' - 'David Precious ' - 'Doug Bell ' - 'Flávio Soibelmann Glock ' - 'Gianni Ceccarelli ' - 'Gregory Oschwald ' - 'Hauke D ' - 'Iain Truskett ' - 'Jason McIntosh ' - 'Joshua Hoblitt ' - 'Karen Etheridge ' - 'Michael Conrad ' - 'Michael R. Davis ' - 'Mohammad S Anwar ' - 'M Somerville ' - 'Nick Tonkin <1nickt@users.noreply.github.com>' - 'Olaf Alders ' - 'Ovid ' - 'Paul Howarth ' - 'Philippe Bruhat (BooK) ' - 'Ricardo Signes ' - 'Richard Bowen ' - 'Ron Hill ' - 'Sam Kington ' - 'viviparous ' x_generated_by_perl: v5.26.2 x_serialization_backend: 'YAML::Tiny version 1.73' DateTime-1.51/Changes0000644000175000017500000016437013457144251014310 0ustar autarchautarch1.51 2019-04-21 - Fix CLDR formatting of 'S' pattern with more than 9 digits of precision. While we only store nanoseconds in the DateTime object we should still be able to handle an arbitrary number of digits properly. Fixed by Slaven Rezić. GH #89. 1.50 2018-08-01 - The %F strftime pattern incorrectly zero-padded numbers less than four digits. According to POSIX::strftime, this should output the year as-is without padding. Reported by Andy Lester. GH #83. 1.49 2018-05-20 - Updated the ppport.h with the latest version of Devel::PPPort. This fixes a compilation warning when compiling with 5.27.11. Reported by Jim Keenan. Fixed GH #81. 1.48 2018-03-26 - The last release would die if Sub::Util was not available, but this should just be an optional requirement. Fixed by Paul Howarth. Fixes GH #77. PR #78. 1.47 2018-03-25 - DateTime::Duration->multiply now only allows integer multipliers. Implemented by Dan Stewart. PR #73. - Added is_last_day_of_quarter() and is_last_day_of_year() methods. Implemented by Dan Stewart. PR #72. - When an exception was thrown while adding a duration the object could be left in a broken state, with the duration partially applied. Subsequent addition or subtraction would produce the wrong results. Reported by Pawel Pabian. GH #74. 1.46 2018-02-11 - Fixed the formatting for the CLDR "S" symbol. It could in some cases round _up_ to 1 instead of truncating a value. For example, the "SSS" symbol would format 999,999,999 nanoseconds as "1.000". Fixed by Gianni Ceccarelli. PR #71. 1.45 2017-12-26 - Added month_length(), quarter_length() and year_length() methods. Implemented by Dan Stewart. PR #70. 1.44 2017-08-20 - Added a stringify() method. This does exactly the same thing as stringification overloading does. GH #58. - Added an is_last_day_of_month() method to indicate whether or not an object falls on the last day of its month. GH #60. 1.43 2017-05-29 - Added a small optimization for boolification overloading. Rather than relying on a fallback to stringification, we now return true directly, which is a little faster in cases like "if ($might_be_dt) { ... }". - The datetime() method now accepts a single argument to use as the separate between the date and time portion. This defaults to "T". 1.42 2016-12-25 - The DateTime::Duration->add and ->subtract methods now accept DateTime::Duration objects. This used to work by accident, but this is now done intentionally (with docs and tests). Reported by Petr Pisar. GitHub #50. 1.41 2016-11-16 - The DateTime->add and ->subtract methods now accept DateTime::Duration objects. This used to work by accident, but this is now done intentionally (with docs and tests). Based on PR #45 from Sam Kington. 1.40 2016-11-12 - Switched from RT to the GitHub issue tracker. 1.39 2016-09-17 - Bump minimum required Perl to 5.8.4 from 5.8.1. Looking at CPAN Testers, this distro hasn't actually passed with earlier Perl versions since 1.35. I'm not explicitly testing with anything earlier than 5.8.8 1.38 2016-09-16 - This release includes changes from past trial releases to switch from Params::Validate and Params::ValidationCompiler. Relevant release notes from those trial releases are repeated here for clarity. - Replaced Params::Validate with Params::ValidationCompiler and Specio. In my benchmarks this makes constructing a new DateTime object about 14% faster. However, it slows down module load time by about 100 milliseconds (1/10 of a second) on my desktop system with a primed cache (so really measuring compile time, not disk load time). - When you pass a locale to $dt->set you will now get a warning suggesting you should use $dt->set_locale instead. The previous trial releases didn't allow locale to be passed at all, which broke a lot of modules. I've sent PRs, but for now the parameter should be allowed (but discouraged). Reported by Slaven Rezić. RT #115420. - Removed the long-deprecated DateTime->DefaultLanguage method. Use DefaultLocale instead. - Removed the long-deprecated "language" constructor parameter. Use "locale" instead. 1.37 2016-08-14 (TRIAL RELEASE) - Require the latest Params::ValidationCompiler (0.11). 1.36 2016-08-06 - Require namespace::autoclean 0.19. 1.35 2016-08-05 - Use namespace::autoclean in all packages which import anything. Without cleaning the namespace, DateTime ends up with "methods" like try and catch (from Try::Tiny), which can lead to very confusing bugs. Reported by Mischa Schwieger. RT #115983. 1.34 2016-07-06 - Added the leap second coming on December 31, 2016. 1.33 2016-06-29 - Fixed the $dt->set docs to say that you cannot pass a locale (even though you can but you'll get a warning) and added more docs for $dt->set_locale. - Require DateTime::Locale 1.05. - Require DateTime::TimeZone 2.00. 1.32 2016-06-28 - This release *does not* include any of the changes in the 1.29-1.30 TRIAL releases. - When you pass a locale to $dt->set you will now get a warning suggesting you should use $dt->set_locale instead. If you have DateTime::Format::Mail installed you should upgrade to 0.0403 or later, since that module will trigger this warning. - Added support for $dt->truncate( to => 'quarter' ). Implemented by Michael Conrad. GitHub #17. 1.31 2016-06-18 (TRIAL RELEASE) - When you pass a locale to $dt->set you will now get a warning suggesting you should use $dt->set_locale instead. The previous trial releases didn't allow locale to be passed at all, which broke a lot of modules. I've sent PRs, but for now the parameter should be allowed (but discouraged). Reported by Slaven Rezić. RT #115420. 1.30 2016-06-18 (TRIAL RELEASE) - Require the latest version of Params::ValidationCompiler (0.06). Tests failed with 0.01. 1.29 2016-06-17 (TRIAL RELEASE) - Replaced Params::Validate with Params::ValidationCompiler and Specio. In my benchmarks this makes constructing a new DateTime object about 14% faster. However, it slows down module load time by about 100 milliseconds (1/10 of a second) on my desktop system with a primed cache (so really measuring compile time, not disk load time). 1.28 2016-05-21 - Fixed handling of some floating point epochs. Because DateTime treated the epoch like a string instead of a number, certain epochs with a non-integer value ended up treated like integers (Perl is weird). Patch by Christian Hansen. GitHub #15. This also addresses the problem that GitHub #6 brought up. Addresses RT #96452, reported by Slaven Rezić. 1.27 2016-05-13 - Added an environment variable PERL_DATETIME_DEFAULT_TZ to globally set the default time zone. Using this is very dangerous! Be careful!. Patch by Ovid. GitHub #14. 1.26 2016-03-21 - Switched from Module::Build to ExtUtils::MakeMaker. Implementation by Karen Etheridge. GitHub #13. 1.25 2016-03-06 - DateTime->from_object would die if given a DateTime::Infinite object. Now it returns another DateTime::Infinite object. Reported by Greg Oschwald. RT #112712. 1.24 2016-02-29 - The last release partially broke $dt->time. If you passed a value to use as unit separator, this was ignored. Reported by Sergiy Zuban. RT #112585. 1.23 2016-02-28 - Make all DateTime::Infinite objects return the system's representation of positive or negative infinity for any method which returns a number of string representation (year(), month(), ymd(), iso8601(), etc.). Previously some of these methods could return "Nan", "-Inf--Inf--Inf", and other confusing outputs. Reported by Greg Oschwald. RT #110341. 1.22 2016-02-21 (TRIAL RELEASE) - Fixed several issues with the handling of non-integer values passed to from_epoch(). This method was simply broken for negative values, which would end up being incremented by a full second, so for example -0.5 became 0.5. The method did not accept all valid float values. Specifically, it did not accept values in scientific notation. Finally, this method now rounds all non-integer values to the nearest millisecond. This matches the precision we can expect from Perl itself (53 bits) in most cases. Patch by Christian Hansen. GitHub #11. 1.21 2015-09-30 - Make all tests pass with both the current DateTime::Locale and the upcoming new version (currently still in trial releases). 1.20 2015-07-01 - The 1.18 release added the June 30, 2015 leap second to the XS code, but I forgot to update the corresponding pure Perl implementation in DateTime::LeapSecond. 1.19 2015-05-31 - If you compared a DateTime object to an undef value, you might have received a warning pointing to code inside DateTime.pm, instead of in your own code. Fixed by Jason McIntosh. GH #7. - The 30future-tz.t could fail if run at certain very specific times. This should now be much less likely, unless a time zone being tested implements a DST change at noon (which would even more insane than DST already is by a huge factor). Reported by Karen Etheridge and diagnosed by Slaven Rezić. RT #102925. 1.18 2015-01-05 - There will be a new leap second on June 30, 2015. 1.17 2015-01-04 - No code changes from the 1.16 release. 1.16 2015-01-04 (TRIAL RELEASE) - Test fix for systems where IVs are 4 bytes long. 1.15 2015-01-03 (TRIAL RELEASE) - Trying this again ... Experimental fix for adding very large numbers of days. Previously, trying to add more than around 2^28 days could cause errors if the result ended up in a leap year. This is being released as a trial release because I'm not sure how this change will behave on a 32-bit Perl. Reported by KMX. RT #97046. 1.14 2015-01-03 - Accidentally released 1.13 as a non-TRIAL release. Releasing 1.13 minus the integer change so there's a known-safe stable release on CPAN for people to install. 1.13 2015-01-03 * This release was deleted from CPAN. - Experimental fix for adding very large numbers of days. Previously, trying to add more than around 2^28 days could cause errors if the result ended up in a leap year. This is being released as a trial release because I'm not sure how this change will behave on a 32-bit Perl. Reported by KMX. RT #97046. - Various small doc chances to address RT #96958, #98733, and #101262. 1.12 2014-08-31 - The last release had the wrong repo info in the metadata. 1.11 2014-08-31 - The latest historical changes in DateTime::TimeZone 1.74 caused some tests to fail. Reported by Slaven Rezić. RT #98483. - This release of DateTime.pm now requires the DateTime::TimeZone 1.74. 1.10 2014-05-05 - Some tests added in 1.09 would fail on a Perl without a 64-bit gmtime(). Reported by Jerome Eteve. RT #95345. 1.09 2014-05-03 - A call to ->truncate( to => 'week' ) could fail but leave the object changed. RT #93347. - The value of ->jd() is now calculated based on ->mjd() instead of the other way around. This reduces floating point errors a bit when calculating MJD, and should have a neglible impact on the accuracy of JD. Reported by Anye Li. RT #92972. See the ticket for a more detailed description of what this fixes. - Attempting to construct a DateTime object with a year >= 5000 and a time zone other than floating or DST now issues a warning. This warning may go away once DateTime::TimeZone is made much faster. Inspired by a bug report from Lloyd Fournier. RT #92655. 1.08 2014-03-11 - DateTime now calls DateTime->_core_time() instead of calling Perl's time() built-in directly. This makes it much easier to override the value of time() that DateTime sees. This may make it easier to write tests for code that uses DateTime . 1.07 2014-02-06 - Added a hack to get this module working on Android. RT #92671. 1.06 2013-12-31 - DateTime's attempt to generate infinity by calculating 9**9**9 actually got a number on some platforms, like powerpcspe. Reported by Gregor Hermann. RT #91696. 1.05 2013-12-22 - Added a new CLDR ZZZZZ specifier, which is like ZZZ but inserts a colon. Patch by Ricardo Signes. - Added a new option for the truncate() method to truncate to the "local_week". This truncates to the locale's notion of the first day of the week, rather than always truncating to Monday. Patch by Christian Hansen. 1.04 2013-12-07 - Calling set_locale() or set_formatter() on an object with an ambiguous local time could change the underlying UTC time for that object. Reported by Marta Cuaresma Saturio. RT #90583. 1.03 2013-04-17 - The set_time_zone() method was not returning the object when called with a name that matched the current zone. Reported by Noel Maddy. RT #84699. 1.02 2013-04-15 - When a constructor method like new() or today() was called on an object, you'd get an error message like 'Can't locate object method "_normalize_nanoseconds" via package "2013-04-15T00:00:00"'. This has been fixed to provide a sane error message. Patch by Doug Bell. - When set_time_zone() is called with a name that matches the current time zone, DateTime now short circuits and avoids a lot of work. Patch by Mark Stosberg. 1.01 2013-04-01 - Fixed test failures on older Perls. 1.00 2013-03-31 - Bumped the version to 1.00. This is mostly because my prior use of both X.YY and X.YYYY versions causes trouble for some packaging systems. Plus after 10 years it's probably ready to be called 1.00. Requested by Adam. RT #82800. - The %j specifier for strftime was not zero-padding 1 and 2 digit numbers. Fixed by Christian Hansen. RT #84310. - The truncate method was sloppy about validating its "to" parameter, so you could pass things like "years" or "month whatever anything goes". The method would accept the parameter but then not actually truncate the object. RT #84229. - Previously, if a call to $dt->set_time_zone() failed it would still change the time zone of the object, leaving it in a broken state. Reported by Bill Moseley. RT #83940. - DateTime::Infinite objects should no longer die when methods that require a locale are called. Instead, these methods return undef for names and Inf/-Inf for numbers. This affects methods such as day_name() as well as CLDR and strftime formats. When a locale-specific format is used (like the "full" datetime format) it uses the en_US format. Reported by Paul Boldra. RT #67550. 0.78 2012-11-16 - Reverted the change to round nanoseconds up or down in various situtations. Now we always round down. This avoids the case where rounding up would require us to then increment the second value (which could then require us to increment the minute, which could then require us to increment the hour, which could then ...). In other words, we don't want to round 2011-12-31T23:59:59.999999 up to 2012-01-01T00:00:00, because that would be insane. This applies to the return values for ->microsecond, ->millisecond, and the %N specifier for strftime. Patch by Martin Hasch. RT #79845. 0.77 2012-09-25 - POD changes that should make the documentation look better, especially on the web. 0.76 2012-07-01 - The DateTime->subtract method ignored the end_of_month parameter. Patch by Chris Reinhardt. RT #77844. 0.75 2012-06-11 - The epoch for years 1-999 was broken because Time::Local is "clever". A pox on all clever APIs, I say! Reported by Christian Hansen. RT #77719. - Shut up compilation warning from 5.17.x. Reported by Tom Wyant. RT #77490. 0.74 2012-03-22 - Small packaging fix for metacpan's benefit. No need to upgrade. 0.73 2012-03-17 - Change tests to work with Zefram's entirely rebuilt DateTime::TimeZone distribution, which will replace the current implementation. Patch by Zefram. RT #75757. 0.72 2012-01-05 - Remove Test::DependentModules from the dep list. This is used by some author-only tests. Reported by Zefram. 0.71 2012-01-05 - There will be a new leap second on June 30, 2012. 0.70 2011-05-09 - Really fix %N, finally. This was breaking the DateTime::Event::Recurrence test suite. Patch by Dagfinn Ilmari Mannsåker. 0.69 2011-05-03 - When a DateTime object had nanoseconds == 0, the %N strftime specifier always returned "0" regardless of the precision requested. Reported by John Siracusa. RT #67928. 0.68 2011-04-25 - The tests for %N in the last release relied on the vagaries of floating point math on a 64-bit system. Now the from_epoch() method just uses string operations to separate the epoch into an integer value and a mantissa. This avoids floating point insanity. Reported by zefram. RT #67736. 0.67 2011-04-24 - The %N strftime specifier simply truncated nanoseconds, rather than rounding them. Reported by Michael R. Davis. RT #66744. - The %U strftime specifier was off by one in years where January 1st was a Sunday. Patch by Christian Hansen. RT #67631. - The %W strftime specifier was off by one in years where January 1st was a Sunday or Monday. Patch by Christian Hansen. RT #67631. - Some small optimizations from Christian Hansen. The biggest impact is for calculating week_of_month, week_number, and week_year. - This distro now requires Perl 5.8.1+ (it implicitly did this anyway now that Params::Validate is 5.8.1+). 0.66 2010-11-26 - A bunch of documentation cleanup. No code changes. 0.65 2010-10-25 - Actually put the right $VERSION in every package. No other changes. 0.64 2010-10-25 * All the constructors besides new() ended up calling new(), which meant that these constructors went through the parameter validation code twice. Avoiding this should make everything that constructs a new object (besides new() itself) a little faster. ** This change breaks DateTime::Fiscal::Retail454, but no other modules, to the best of my knowledge. ** - The t/39no-so.t test failed for some people. I can't reproduce it, but this release will hopefully fix the problem. Patch by Tokuhiro Matsuno. RT #62061. - Added a section on the DateTime Project ecosystem to the docs. Addresses RT #60930. - Fixed wiki links in the docs now that the wiki has moved to a new wiki platform. - Restored some of the dzil-ification. The repo now has a very minimal Build.PL file which is just enough to build the XS code and run the tests. This fixes the total lack of prereqs in the META.* files. Reported by Bjørn-Olav. RT #62427. 0.63 2010-09-24 - Actually bump the version in the module files. Oops. Reported by bricas. 0.62 2010-09-23 - Don't try to test with DateTime::Format::Strptime unless we have a relatively recent version. Should fix some test failures. 0.61 2010-07-16 - Switching to dzil in 0.56 broke the --pp flag for the Build.PL. Reported by Jonathan Noack. RT #59421. 0.60 2010-07-03 - By default, Dist::Zilla generates a Build.PL that requires Module::Build 0.3601+, but this distro really doesn't need any particular version. 0.59 2010-06-29 - More packaging fixes. This release makes sure that POD only shows up in the right files. In 0.56 through 0.58, some POD in the wrong place confused the search.cpan.org POD display code, and the main module's documentation wasn't viewable. 0.58 2010-06-28 - Versions 0.56 and 0.57 did not build XS properly when installing. 0.57 2010-06-26 - Make DateTime::LeapSecond have the same $VERSION as every other .pm file. 0.56 2010-06-26 - The set_formatter() method did not return the DateTime object, and did not actually validate the value provided for the formatter. Based on a patch by Andrew Whatson. RT #58506. - Improved docs on floating time zone. Based on suggestions by Michael Svoboda. RT #56389. - Added mention of end-of-month algorithms to docs on DateTime math. Based on a patch by Michael R. Davis. RT #58533. - License is now Artistic 2.0. 0.55 2010-03-16 - Get all tests passing on 5.6.2. Thanks to Zefram for help spotting the problems. - Moved code to my hg repo at http://hg.urth.org/hg/DateTime.pm. 0.54 2010-03-14 - Bumped the DateTime::TimeZone prereq to 1.09 to force people to use a modern version. Previously the minimum version was 0.59, and there have been a lot of bug fixes since then. - String overloading now extends to string comparison, so a DateTime object can be compared to any string. In other words if ( $dt eq $string ) { ... } will simply stringify $dt and then do a normal string-is-equals check. Previously, this would blow up unless both operands were a DateTime object. Note that future versions of Test::More (0.95_01+) will no longer stringify arguments to is(), which means that older versions of DateTime may cause new test failures when you upgrade Test::More. It is highly recommended that you upgrade DateTime before upgrading to Test::More 0.95_01+. Patch by Michael Schwern. RT #55453. - Allow passing end_of_month setting to $duration->inverse(). Requested by John Siracusa. RT #53985. 0.53 2009-12-06 - Added Test::Exception to build_requires. 0.52 2009-12-05 - Numeric to ->new() are now all validated to make sure they are integers. Previously, things like "month => 11.2" would have been allowed. Based on a bug report from Max Kanat-Alexandar. RT #45767. - Added a warning to the docs suggesting that you cache the locale time zone if you need to make many DateTime objects in the local zone. Looking up the local zone can be fairly expensive. RT #46753. 0.51 2009-11-01 - Switched to Module::Build. To force a non-XS build, start the build process with "perl Build.PL --pp". - POD-related tests are only run for the maintainer now. - Fixed handling of negative years in CLDR formatting for "y" and "u" patterns. Note that the LDML spec says nothing about how this should work, so I took my best guess. 0.50 2009-05-11 - Tests were failing on Win32 because they attempted to use a negative epoch. Fixed so that these tests are skipped. Fixes RT #45966. 0.49 2009-05-04 - A bug in the test code for handling overloaded objects in from_epoch resulted in a test failure on Perl 5.8.x. This release contains no changes besides a test code fix. 0.48 2009-05-04 - Some of the accessors (the "main" ones like year(), month(), day(), etc) now warn if they are passed a value. Patch from Shawn Moore. Fixes RT #6979. - DateTime::Duration expected DateTime to be loaded and used some constants from it, but did not explicitly "use DateTime". Reported by Jeff Kubina. RT #44740. - The CLDR formatting for "c" and "cc" was incorrectly using the local day of the week. This meant that it gave the wrong result for locales where Monday is not considered the first day of the week. Reported by Maros Kollar. RT #45007. - DateTime->from_epoch did not allow an object which overloaded numification as the epoch value. Patch by Michael Schwern. RT #45653. - Fixed how datetime subtraction is handled for some cases around DST changes. This had been improved back in 0.30, but there were still bugs. RT #45235. 0.47 2009-03-01 - The handling of CLDR format 'j' and 'jj' was backwards, using 24 hour time for locales that wanted 12 hour, and vice versa. Reported by Maros Kollar. - The CLDR formatting was missing support for lower-case "q" patterns. Reported by Maros Kollar. 0.46 2009-02-28 - Added a duration_class method for the benefit of DateTime.pm subclasses. Patch by Shawn Moore. 0.4501 2008-11-25 - The epoch() method got broken in the recent shuffling between Time::Local and Time::y2038. Unfortunately, the tests to catch this also got lost in the shuffle. Reported by Avianna Chao. 0.45 2008-11-11 - Reverted the changes to use Time::y2038, on the recommendation of Michael Schwern (the author of said module), because it is not yet stable. This may come back in a future release. 0.4401 2008-11-03 - In order to handle epochs > 2**32 properly on a 32-bit machine, we also need to import gmtime from Time::y2038. This changes fixes a whole bunch of test failures seen with 0.44. 0.44 2008-11-01 - XS-capable DateTime.pm now uses Time::y2038 instead of Time::Local. This lets it handle epochs up to 142 million years before and after the Unix epoch. - Fixed a compiler warning with Perl 5.10.0. - Fixed docs for year_with_era, which had AD and BC backwards. Reported by Vynce Montgomery. RT #39923. - The format_cldr() method did not format the "yy" format properly when the year ended in "0X". Reported by Wilson Santos. RT #40555. 0.4305 2008-10-03 - The pure Perl version of this module did not know about the end of 2008 leap second. Reported by James T Monty. 0.4304 2008-07-13 - Fix test failures when tests are run with DateTime::Locale 0.41. Reported by David Cantrell via CPAN Testers. 0.4303 2008-07-12 - There is a new leap second coming at the end of 2008. 0.4302 2008-05-20 [ BUG FIXES ] - The 41cldr_format.t test blew up on Perl 5.6.x, because of a bug in the test code. 0.4301 2008-05-18 [ BUG FIXES ] - In the 0.43 release, I forgot to change the DateTime::Locale dependency to require DT::Locale 0.40. 0.43 2008-05-18 [ *** BACKWARDS INCOMPATIBILITIES *** ] * Dropped support for Perl 5.005. [ ENHANCEMENTS ] - Added support for formatting the CLDR date pattern language, which is much more powerful than strftime. This, combined with the latest DateTime::Locale, makes the localized output much more correct. [ BUG FIXES ] - The hour_1() method was returning the real hour + 1, rather than just representing midnight as 24 instead of 0. This bug fix will probably break someone's code. 0.42 2008-02-29 [ BUG FIXES ] - The 17set_return.t tests failed on leap days, like today. Reported by Duncan Ferguson. RT #33695. 0.41 2007-09-10 [ BUG FIXES ] - The 13strftime.t test was failing when DateTime::Locale 0.35 was installed. The test has been adjusted and we now list DT::Locale 0.35 as the minimum version. Reported by David Cantrell. 0.40 2007-08-30 [ BUG FIXES ] - A custom formatter would be lost after a call to set() or truncate(). Reported by Kjell-Magne Øierud. RT #28728. - The truncate() method docs said it accepted "second" as a parameter, but it didn't actually do the right thing with it. Now it always truncates nanoseconds to 0 for any parameter it is passed. 0.39 2007-07-17 [ BUG FIXES ] - Yet more changes to how infinity is handled and tested. This passes for me on 32-bit Win XP and 64-bit Linux, which is promising. Patch by Yitzchak Scott-Thoennes. RT #22392. 0.38 2007-06-30 [ BUG FIXES ] - Require Test::Pod::Coverage 1.08 in pod-coverage.t, since we use all_modules, which was only exported as of version 1.08. Reported by MATSUNO Tokuhiro. Fixes RT #26594. - Fixed a bad link to the old FAQ location in the docs. Reported by Ric Signes. Fixes RT #26846. [ ENHANCEMENTS ] - DateTime.pm now explicitly overloads string comparison. This was done so that comparing a DateTime.pm object to a string returns false, rather than throwing an exception. Reported by Chris Dolan. Addresses RT #26085. 0.37 2007-03-30 [ BUG FIXES ] - Require DateTime::Locale 0.34, which fixes a problem that manifested when thawing a DateTime.pm object. See http://www.mail-archive.com/datetime@perl.org/msg05633.html for some discussion of this. - Added pod coverage tests, and added some POD for undocumented methods as a result. [ ENHANCEMENTS ] - This distro is now GPG-signed, per RT #24776. 0.36 2007-01-18 [ BUG FIXES ] - For infinity, use 100 ** 1000 instead of 100 ** 100 ** 100. This may fix the problems with infinity on some platforms (or may not). Suggested by Bjorn Tackmann. See RT #17390, #19626, and #22392. - Require DateTime::TimeZone 0.59, which includes a similar fix. 0.35 2006-10-22 [ ENHANCEMENTS ] - Added several new methods for getting locale-based data, era_abbr(), era_name(), quarter_abbr(), and quarter_name(). The era() method returns the same data as era_abbr(), but is deprecated. 0.34 2006-08-11 [ BUG FIXES ] - DateTime's code to fall back to the pure Perl implementation was broken in most cases, making it fairly useless. Reported by Adam Kennedy and Brendan Gibson. - Under Perl 5.6.2 (and presumably 5.6.x), some of the tests mysteriously failed. I tracked this down to a weird interaction between DateTime's string overloading and Test::Builder->cmp_ok(). See RT 19626. 0.33 2006-08-09 (the "Asia/Kaohsiung" release) [ ENHANCEMENTS ] - Attempting to do an overloaded operation (add, subtract, compare) with an inappropriate argument (like $dt + 1) gives a more useful error message. [ BUG FIXES ] - The fixes in 0.30 for subtract_datetime() crossing a DST change had a bug. When subtracting two dates, both occurring on a DST change date, but where the dates did not cross the change, the answer was off by an hour. Reported by Chris Prather. See RT 20697. - Borrowed a tweak from version.pm's Makefile.PL to make compiler detection work with MSVC. 0.32 2006-07-24 [ BUG FIXES ] - Change how C compiler detection is done in the Makefile.PL so it does not rely on having make on the system. The new way should work on (most?) Unix and Win32 systems. Suggested by David Golden. See RT 18969. 0.31 2006-05-21 [ ENHANCEMENTS ] - Switched some uses of die() to Carp::croak(), where appropriate. This should make error messages more useful in many cases. Based on a suggestion by Max Maischein. See RT tickets 11692 & 18728. [ BUG FIXES ] - Removed all uses of UNIVERSAL::isa and UNIVERSAL::can as functions. - Tweaked 20infinite.t test to give more useful output for some failures, though it probably doesn't fix them. See RT 17390. 0.30 2005-12-22 [ ENHANCEMENTS ] - Expanded and rewrote the docs on date math to try to explain exactly how DateTime.pm works, and in particular cover the problems DST introduces to various types of date math. The docs now also include some specific recommendations on getting sane results from datetime math. - Added calendar_duration() and clock_duration() methods to DateTime::Duration - Explicitly override the stringification method for DateTime::Infinite objects. They now stringify as whatever the IEEE infinity and negative infinity numbers stringify to on your platform. On Linux this is "inf" and "-inf". CPAN RT #16632. [ BUG FIXES ] - delta_md() and delta_days() did not always return correct values when crossing a DST change. - The pure Perl version of the code had a dependency ordering problem where DateTime::LeapSecond depended on other pure Perl code that wasn't yet available. I'm not sure how this ever worked. - Remove mentions of leap second on 1971-12-31 from the docs, because there was no leap second that day. Reported by Mike Schilli. - If you added a second to a datetime that was on a leap second (like 2005-12-31T23:59:60) it got "stuck" and kept returning the same datetime. Reported by Mike Schilli. - Changes to the tests in 20infinite.t may fix failures seen on some platforms and with new versions of Test::More (0.62 was known to cause failures) [ *** BACKWARDS INCOMPATIBILITIES *** ] - The subtract_datetime() method switched back to using the local portion of the date _and_ time, but it now accounts for days with DST changes specially. This produces results that fix the bugs that were fixed by previous subtraction changes in 0.28 and 0.29, but without introducing even more bugs. The overall result should be sane, but please see the docs for details. 0.2901 2005-07-04 - A leap second for the end of 2005 was announced. 0.29 2005-06-03 [ *** BACKWARDS INCOMPATIBILITIES *** ] - When adding/subtracting a duration with months or days that crossed a DST change, the result was based on the local time, not the UTC time. For consistent results, it is necessary to use the UTC time (but local date) for all date math. Reported by J. Alexander Docauer. 0.28 2005-02-27 [ ENHANCEMENTS ] - The era names for the era() method are now retrieved from the DateTime.pm object's associated locale. The old era() method, which was hard-coded to use BCE and CE, is renamed secular_era(). The christian_era() method remains the same. [ BUG FIXES ] - Fixed an embarassing bug in the subtract_datetime() method. It was subtracting local times, not UTC, which caused bugs when doing subtraction across a DST change. This method is used to implement subtraction overloading, so that was affected as well. Reported by Mike Schilli. - The docs for the %U and %W strftime specifiers implied that these should be zero-padded, but the code was not doing so. Reported by J Docauer. 0.27 2005-01-31 [ ENHANCEMENTS ] - Added local_rd_values() method for the benefit of other modules like DateTime::Event::Recurrence. 0.26 2005-01-27 [ BUG FIXES ] - The docs claimed that the delta_ms(), delta_md(), delta_days() methods always returned a positive duration, but this was not true for delta_md() or delta_days(). 0.25 2005-01-10 (the "new year, new bugs" release) [ BUG FIXES ] - Calling set_time_zone() for a datetime very close to a time zone change died for many of the Olson time zones. - The docs for the from_object constructor said that by default, new objects were in the UTC time zone, but in reality the default was the floating time zone. The docs were changed to match the code. Ticket 9278 on rt.cpan.org. 0.24 2004-12-10 (the "have I mentioned I hate leap seconds" release) [ BUG FIXES ] - Fixed even more bugs related to leap seconds and time zones. Reported by Eugene van der Pijll. [ KNOWN BUGS ] - Offsets with a seconds portion (like "+00:00:30") act strangely near leap seconds. Reported by Eugene van der Pijll. This will be fixed in a future release. 0.23 2004-12-09 (the "oh how I hate leap seconds" release) [ ENHANCEMENTS ] - Added a number of convenience "set" methods: set_year, set_month, set_day, set_hour, set_minute, set_second, set_nanosecond, and set_locale. Suggested by Michael Schwern. - Added christian_era and year_with_christian_era methods. - Clarified that from_epoch(), today(), and now() all return objects in the UTC time zone. Suggested by Sagar Shah and others. - Added formatter parameter to constructor, which allows per-object stringification. Based on a patch from Daisuke Maki. [ BUG FIXES ] - Trying to serialize DateTime::Infinite objects with Storable blew up. Patch by Daisuke Maki. - Require Test::More 0.34+, since I use a function introduced in that version in the tests. Suggested by Jean Forget. - Fix a bug in strftime() which could cause weirdness with pathological specifiers like "%%{day_name}%n". Reported by Jean Forget. - Fixed a number of bugs related to leap seconds and time zones. Reported by Eugene van der Pijll. 0.22 2004-07-23 [ *** BACKWARDS INCOMPATIBILITIES *** ] - The leap second table we were using mistakenly included a leap second on December 31, 1971. This will break all versions of the DateTime::Format::Epoch::TAI64 module up to and including version 0.06. Most users of DateTime.pm will not be affected. Patch by Joshua Hoblitt. 0.2101 2004-06-10 [ BUG FIXES ] - There was a bug in the date math code that occurred if you tried to add enough days, minutes or seconds to generate a datetime 10 years in the future (or so). If the the DateTime object had a a time zone with recurring DST changes, then the date math operation would cause a fatal error "Invalid local time for date in time zone ...". Reported by Dave Faraldo. 0.21 2004-03-28 (The "Another YAPC::Taipei release party release" release) [ *** BACKWARDS INCOMPATIBILITIES *** ] - When given mixed positive & negative arguments, DateTime::Duration no longer forces all arguments to be negative. - For mixed durations, the is_positive, is_zero, and is_negative methods all return false. - Brought back stringification overloading. As of version 1.06, Devel::StackTrace will ignore this overloading when displaying a trace. [ ENHANCEMENTS ] - Add a new in_units() method to DateTime::Duration. Patch by Andrew Pimlott. - Rely on DateTime::TimeZone and DateTime::Locale having their own Storable hooks, as opposed to handling them in DateTime.pm's own Storable hooks. This should fix RT ticket #5542, reported by Dan Rowles (I hope). - More docs on how date math is done. See the new section "The Results of Date Math". [ BUG FIXES ] - DateTime::Duration's is_positive, is_zero, and is_negative methods could incorrectly return true if a duration contained mixed positive and negative units. - Better normalization of nanoseconds in DateTime::Duration. Patch by Andrew Pimlott. 0.20 2004-02-12 [ IMPROVEMENTS ] - Tweaked the "How Date Math is Done" section in DateTime.pm to provide some more explicit examples. [ BUG FIXES ] - If seconds are not negative, DateTime::Duration will try to keep nanoseconds >= 0 when normalizing them to seconds, as long as this doesn't make seconds become negative. Suggested by Andrew Pimlott. - In the datetime subtraction code, there was an off-by-one error in the code to determine if one of the datetimes occurred in a minute containing a leap second. This led to the result of the subtraction being off by one second. Patch by Andrew Pimlott. - A duration's nanoseconds weren't normalized after multiplication. Patch by Andrew Pimlott. 0.1901 2004-01-07 (the "people care about ancient history?" release) [ BUG FIXES ] - The day of week was totally busted for dates before 0000-12-25. Reported by Flavio Glock. 0.19 2003-12-01 (the "never look before a leap second" release) [ IMPROVEMENTS ] - DateTime::Duration now provides a compare() class method. - DateTime::Duration now overloads comparison to throw an exception, because comparison requires a base DateTime object. Note that previous versions of DateTime::Duration _did not_ overload comparison, so if you were comparing them, you were just comparing the value of the object references. Thanks to Rick Measham, Jon Swartz, and Max Maischein for contributing to the discussion on datetime@perl.org about how to implement this feature. - Added DateTime::Duration->multiply to complement multiplication overloading. - Added a leap_seconds method. - Added a section to the docs about floating datetimes. - DateTime::LeapSecond no longer contains code copied from DateTime.pm, instead it just uses DateTime.pm directly. Patch by Joshua Hoblitt. [ BACKWARDS INCOMPATIBILITIES ] - DateTime::LeapSecond's leap_seconds() function now returns the number of leap seconds that have occurred, as opposed to the difference between TAI and UTC for a given Rata Die day, which is what it was returning previously. This means that the values it returns are 9 second less than the previous version. This does not affect DateTime.pm because it never looke at the actual value, just the difference between two leap second values, which remains the same. 0.18 2003-10-26 (the "delta, delta, delta, can I help ya, help ya, help ya?" release) [ IMPROVEMENTS ] - Added several new methods for calculating the difference between two datetime objects. These are delta_md(), delta_days(), and delta_ms(). Each of these methods returns the difference as a duration containing just certain units. [ BUG FIXES ] - Require Pod::Man 1.14+, so that head3/head4 markup doesn't cause installation to die. [ BACKWARDS INCOMPATIBILITIES ] - The local_rd_as_seconds method is deprecated, as it doesn't really serve much purpose. 0.1705 2003-10-07 [ BUG FIXES ] - Subtracting one datetime from another was still broken, and my fix in 0.1704 broke many other subtractions. Reported by Pierre Denis again. Many thanks to Pierre for paying attention. - Subtracting datetimes where the subtraction crossed a leap second was also broken. 0.1704 2003-10-07 [ IMPROVEMENTS ] - Documented the behavior of strftime() when given an invalid format. [ BUG FIXES ] - The DateTime::Duration synopsis showed a sign() method that doesn't exist, so I removed it from the synopsis. Reported by Flavio Glock. - Subtracting one datetime from another was seriously broken. The values for days & weeks were wrong in many cases. Reported by Pierre Denis. 0.1703 2003-09-22 [ BUG FIXES ] - truncate( to => 'week' ) caused a fatal error when the beginning of the week was in the previous month. Reported by R. Mathews (rt.cpan.org #3843). 0.1702 2003-09-18 [ IMPROVEMENTS ] - Added truncate( to => 'week' ). Suggested by Flavio Glock. 0.1701 2003-09-15 [ BUG FIXES ] - If from_epoch was given a fractional epoch with a floating point value with more than 9 digits after the decimal point, the object ended up containing a floating point number of nanoseconds. We now truncate this number to an integer. Fixed by Joshua Hoblitt. - The %V strftime specifier was documented, but not implemented. Reported by Joshua Hoblitt. - Test #56 in 03components.t would die with "Invalid offset: -124" when run with DateTime::TimeZone 0.2502+. Next time, I'll read my own docs ;) 0.17 2003-08-29 (the "math is hard" release) [ BACKWARDS INCOMPATIBILITIES ] - The default end_of_month mode for negative durations is now "preserve". This makes more sense, as the previous default meant that the following code: print DateTime->new( year => 2003, month => 5, day => 31 ) ->subtract( months => 1 )->ymd; printed "2003-05-01" as opposed to "2003-04-30". Thanks to Thomas Klausner for starting a discussion on this problem. - The subtract_datetime method now returns different results, as does subtraction overloading when both sides of the subtraction are DateTime objects. The subtract_datetime_absolute method returns results similar to what was previously returned from subtract_datetime. Thanks to Matthew McGillis for bringing this up, and Joshua Hoblitt and Eugene van der Pijll for contributing to the ensuing discussion. [ IMPROVEMENTS ] - DateTime.pm compare() method is now documented to work with any other calendar class that provides a utc_rd_values() method. - Added the subtract_datetime_absolute method. See the docs for details. - Documented the inverse() method in DateTime::Duration. 0.1601 2003-08-07 [ BUG FIXES ] - On platforms like Win32, where we can't find a finite() or isfinite() function/macro, the DateTime::LeapSecond code wasn't being loaded, so many tests failed. Reported by Ron Hill. 0.16 2003-08-06 [ IMPROVEMENTS ] - The XS code now implements leap second-related calculations. However, this is only used on platforms where we can find a usable finite() or isfinite() function/macro, so it isn't used on Win32. - This distro has now borged the DateTime::LeapSecond module. It is only loaded when the XS leap second code cannot be used. - Other miscellaneous performance improvements. 0.1503 2003-07-31 [ BUG FIXES ] - Adding a duration with delta months to an infinite DateTime was quite broken. Reported by Eugene van der Pijll. 0.1502 2003-07-31 [ BUG FIXES ] - XSLoader wasn't the problem on Solaris, so it's back. - Now loading the XS version of DateTime.pm is wrapped in an eval block. If it fails with an error about the object version not matching, the pure Perl version is loaded instead. This should fix Solaris. Thanks to Joshua Hoblitt for identifying this bug. 0.1501 2003-07-30 [ BUG FIXES ] - Fixed the from_object() method to set the returned object's time zone to the floating time zone if the source object did not have a time zone, as specified in the docs. Previously, the returned object's time zone was UTC. Patch by Eugene van der Pjill. - For this release, at least, the module always uses Dynaloader. This is in order to see if this fixes a problem on Solaris where the install library version of the DateTime .so file is loaded instead of the newly compiled version in the blib directory. 0.15 2003-07-29 [ IMPROVEMENTS ] - The utc_rd_values() method now returns nanoseconds in addition to Rata Die days and seconds. Based on a patch by Joshua Hoblitt. - The from_object() method expects objects to return the same values from their utc_rd_values() methods. Based on a patch by Joshua Hoblitt. [ BUG FIXES ] - Fixed a bug in the pure Perl version of _normalize_tai_seconds that caused very weird results from datetime math. This version may be used on platforms where the XS code compiles, so it can affect quite a number of systems. Reported by Dan Sully. 0.1402 2003-07-24 [ BUG FIXES ] - Fix DefaultLocale method, which didn't work at all. Reported by Serge Leger. 0.1401 2003-07-24 [ BUG FIXES ] - Fix a test failure in 13strftime.t under Perl 5.6.1 (and probably 5.6.0). 0.14 2003-07-23 [ BACKWARDS INCOMPATIBILITIES ] - The DateTime::Language modules are no longer being developed or distributed as part of the DateTime.pm distribution. Because of this, all "language" parameters should now be replaced by "locale" parameter. The "language" parameter is deprecated and will be removed in a future release. Also note that locales should be specified via ISO codes, not names like "English". The old DateTime::Language names will continue to work indefinitely, but they load DateTime::Locale objects instead. Locale-specific data will be returned in utf8 when necessary. - Similarly, the "language" and "DefaultLanguage" methods are now deprecated in favor of "locale" and "DefaultLocale". [ IMPROVEMENTS ] - DateTime::Duration now returns the object from mutator methods, in order to make method chaining possible. Suggested by Ben Bennett. - If the value for second given to new() is 60 or 61, then it must be a valid leap second. - DateTime now uses DateTime::Locale for localization, which allows for real language and territory based localization. The locale code is generated from the ICU project's data, and is much more complete than the DateTime::Language modules. However, we are losing (hopefully only temporarily) support for the various African languages contributed by Daniel Yacob. Support for those languages should return in a future release of DateTime::Locale. - Support for the '%c', '%x', and '%X' strftime format specifiers, which output localized date and time strings. - Added the time_zone_long_name method, primarily for the benefit of DateTime::Locale. - Added a note to the DateTime::Infinite docs warning that it may not work well on Win32. [ BUG FIXES ] - DateTime::Duration was not consistent in how it handled mixed positive and negative constructor parameters. Reported by Ben Bennett. 0.13 2003-05-05 [ IMPROVEMENTS ] - DateTime now does more validation of parameters given to constructors and to the set() method, so bogus values like a month of 13 are a fatal error. - Added a new constructor, from_day_of_year(). - Added a number of new "get" methods, including era, year_with_era, hour_1, hour_12, hour_12_0, weekday_of_month, and week_of_month. Based in part on a patch from Rick Measham. - Now any object method can be called in strftime format by using "%{method}" as a format specifier. Patch from Rick Measham - Added an is_zero method to DateTime::Duration, for objects of zero length. - DateTime->from_epoch will now accept a floating point epoch and turn the post-decimal portion into nanoseconds. This was done in order to interface more accurately with Time::HiRes. - Added a DateTime->hires_epoch method that returns a floating point value for epoch, also for compatibility with Time::HiRes. - DateTime.pm now implements Storable hooks to reduce the size of serialized DateTime objects. In particular, the contained time zone object is not serialized along with the DateTime object. - It is now possible to create arbitrary DateTime::Language subclasses in any namespace. [ BUG FIXES ] - "Fixed" 20infinite.t failures on Windows with 2 icky hacks. The first simply doesn't compile the XS code that deals with infinite numbers on Win32, so the pure Perl version is used instead. However, the rest of the XS code is still compiled on Win32. The other hack is to simply skip a failing test in 20infinite.t on Win32. Hopefully, this will eventually be fixed but given that this is not core functionality for most users, I'd rather get this release out the door now. - Fix epoch() method to work properly with dates greater than 50 years ago. Apparently, if Time::Local is given a year less than 100, it tries to guess the century, and it doesn't do this by simply adding 1900. Numbers less than 53 (for the year 2003) are treated as being in the current century. Ugh. - Fixed compilation on HPUX. Patch from Dan Sully. - The last_day_of_month() method did not accept a nanosecond parameter. - A DT::Duration object created with just nanoseconds was always positive, regardless of the value given for nanoseconds. - Fixed a serious bug when subtracting one datetime from another that could cause the result to be off by up to a second, and negative when it should be positive. This was caused by the introduction of nanoseconds in 0.10. - A zero length duration reported itself as positive when it should be neither positive nor negative. - In Perl 5.6.1/Red Hat Linux 7.2, multiplying a variable with value zero by -1 gives negative-zero, which breaks tests. perl -e ' $x=0; $x*=-1; print $x ' -0 Patch by Flavio Glock. - Comparing a DateTime::Infinite object to a regular datetime could cause a fatal error. Reported by John Peacock. - Fixed a failure in the 04epoch.t tests on Win32. Negative epoch values don't work on Win32. [ BACKWARDS INCOMPATIBILITIES ] - The "Portugese" language module has been renamed to "Portuguese". I'm so embarassed! Reported by Richard Evans. - DateTime::Infinite objects no longer die if "set" methods are called. Instead, these methods are now no-op methods that simply return the original object. This makes these objects more usable when mixed with regular datetime objects. - Removed the fractional_second constructor parameter. It was incorrectly documented anyway. The fractional_second _accessor_ is still there. - DateTime::Duration objects of zero length no longer return true for is_positive. 0.12 2003-05-05 [ BUG FIXES ] - Make sure tests always run with warnings on. - Fix line that had "$] >= 5.6.0" to be "$] >= 5.006". This caused warnings and was just wrong. Reported by John Siracusa. - Quiet warnings from pure Perl implementation. - Quiet warnings from language modules with Unicode when used with Perl 5.00503. 0.11 2003-05-03 [ IMPROVEMENTS ] - Moved a little bit of the leap second code to XS, so DateTime.pm may be a tiny bit faster. - Added name() method to DateTime::Language. Suggested by Rick Measham. - Use XSLoader with Perl 5.6.0+, which according to ancient perl5-porters discussions saves some memory. - Added infinite DateTime objects. See the DateTime::Infinite docs for details. [ BUG FIXES ] - The %I and %l strftime formats were formatting hours as 0-11, not 1-12 as documented. Patch by Simon Newton. - A DateTime::Duration object created only with weeks as a parameter always was positive. Fixed by Flavio Glock. [ BACKWARDS INCOMPATIBILTIES ] - Because of changes in DateTime::TimeZone 0.13, which this version now requires, when a local time is ambiguous, the latest UTC time is used, rather than the earliest, as was done previously. - The Brazilian language module has been renamed as Portugese. - Removed DateTime::Duration->compare (which I forgot to document anyway ;) and comparison overloading for DT::Duration. There's no meaningful way to compare 60 days to 2 months. 0.10 2003-04-19 (the "I'm sure the new regime will be spiffy" release) [IMPROVEMENTS] - Added Tigre language module. Contributed by Daniel Yacob. - DateTime::Duration objects now overload multiplication. Implemented by Flavio Glock. - Added support for nanoseconds in DateTime.pm and DateTime::Duration. Implemented by Flavio Glock. - Added complete support for leap seconds (through use of DateTime::LeapSecond). Mostly implemented by Flavio Glock. [ BACKWARDS INCOMPATIBILTIES ] - Because of the addition of leap seconds to the mix, we are now forced to handle seconds separately from minutes when doing date math. This means that several aspects of the DateTime::Duration API have changed. Specifically: -- There is now an additional delta_minutes() method. -- The hash returned by the deltas() method now includes a "minutes" key. -- The seconds delta may be greater than 59. -- The seconds() method may return a number greater than 59. 0.09 2003-04-05 (the "liberation through violence" release) [IMPROVEMENTS] - As requested by numerous people, there is now a pure Perl implementation of DateTime.pm included with this distribution. If you don't have a C compiler it will be used instead of the XS implementation. - Document how floating time zones are handling in comparisons, and add the compare_ignore_floating method. Based on a patch from Eugene van der Pijll. - Allow from_epoch(), now(), and today() to accept a time_zone parameter. Based on suggestions from Tim Bunce and Joshua Hoblitt. - Allow extraction of AM/PM string list from DateTime::Language classes. - Added quarter() and day_of_quarter() methods. Based on a patch from Tim Allwine. [BUG FIXES] - If a datetime had the floating timezone and then set_time_zone was used to set it to something else, the internal UTC time of the object was not changed, meaning that its offset could be calculated incorrectly. Patch by Eugene van der Pijll. - If datetime math was done with hours, minutes, or seconds, the return value of ->epoch would be wrong after this. Based on report and patch from Iain Truskett. 0.08 2003-03-21 (the "anti-war" release) [IMPROVEMENTS] - All set/modify methods now return the datetime object, in order to make method chaining possible. Patch by Iain Truskett. - The _greg2rd and _rd2greg methods have been renamed _ymd2rd and _rd2ymd, so as to make them look more normal when used in subclasses. - Added a truncate() method. Suggested by Flavio Glock. - Added Swedish language module. Contributed by Christian Hansen. - Added language modules for Afar, Amharic, Gedeo, Oromo, Sidama, Somali, and Tigrinya (Eritrean and Ethiopian), all courtesy of Daniel Yacob. - Various doc improvements, including a section on invalid local times. [BUG FIXES] - The week() method was wrong for many dates. Reported by Christian Hansen. - The last_day_of_month() method had the DateTime class hard-coded in it. Reported by Eugene van der Pijll. - Fixed a bug when comparing a datetime object to infinity (or negative infinity). Fixed by Flavio Glock. - Date math has been fixed so that it affects the _local_ times. This means that sometimes 1 day is not equal to 24 hours when the addition/subtraction crosses over a Daylight Saving Time change. See the "How Date Math is Done" section of the docs for more details. [BACKWARDS INCOMPATIBILITIES] - Objects constructed via the new() method now have a "floating" time zone by default, instead of using the "local" time zone. This is just simpler to deal with, and for code where time zones are unimportant, this is the most appropriate default. 0.07 2003-02-26 [IMPROVEMENTS] - Added a small hack to the compare() method so that this module can be used with Set::Infinite. - Changed compare so that it can be used to compare two objects from different calendars that conform to the DateTime::Calendar interface. - Added explanation of exactly what calendar this module represents ("proleptic Gregorian calendar") to docs. - Added a Spanish language DateTime::Language subclass. Implemented by Flavio S. Glock. - Added support for specifying a language by ISO code ("en" or "pt-br") as well as the subclass name. Based on a patch from Eric Cholet. - Revamped the externally visible DateTime::Language API. - Objects created via the from_object() method are set to the time zone of the object from which they were created, if it has one, or UTC otherwise. [BUG FIXES] - The from_object() method was broken because it retrieved a UTC datetime from the object passed in, and then created a new DateTime object using that UTC time as a _local_ time. [BACKWARDS INCOMPATIBILITIES] - Removed stringification overloading. Having this in place made it impossible to create a strack trace in much of the time zone code. - Renamed the DateTime::Language->subclasses method as languages. - It is no longer possible to directly instantiate a DateTime::Language subclass, instead use: my $en = DateTime::Language->new( language => 'English' ); - The from_object() method no longer accepts a "time_zone" parameter. 0.06 2003-02-16 - The docs said that there was no year 0 in the Gregorian calendar, but that was wrong. The year() method can now return 0. The year_0() method has been removed. - Added jd() and mjd() methods. - Re-implemented some of the core code in XS for speed. 0.05 2003-02-13 - Fix handling and reporting of epoch times. Epoch times are, by definition, UTC times, so any time created from an epoch should always have its time zone set to "UTC". This can be changed after the object is created. Similarly, value returned by the epoch() method needs to be based on the object's UTC time, not it's local time. Bug reported by Kellan Elliott-McCrea. - Change year_0 so that -1 BCE is 0, not 1 CE. This corresponds to astronomical years. - Change ymd, dmy, mdy, and iso8601 to use Gregorian years (..., -2, -1, 1, 2, ... ) as opposed to astronomical years. Also make sure all negative years are formatted as 4 digits. 0.04 2003-02-10 - Explicitly set time zone for objects created during tests. 0.03 2003-02-09 - Giving a language parameter to a constructor method didn't load the language class. - Test that all language classes are at least loadable. - Added Brazilian (not quite a language ;) and Danish, again stolen from Graham Barr's TimeDate suite. - Added is_dst method. Requested by Matt Sergeant. 0.02 2003-02-09 - Fixed a bug in calculating day of year in leap years (it was +1 off starting in February). Reported by Matt Sergeant. - Subtracting one datetime from another was broken in most cases. Improved the tests for this quite a bit. Reported by Eric Cholet. - Made the version number a non-dev-release so it's visible when CPAN.pm tries to install it as a prereq for something else. 0.01_00 2003-02-04 - The first alpha release. This module draws on Date::ICal for much of its internals, so it has more history than a normal alpha release. DateTime-1.51/CONTRIBUTING.md0000644000175000017500000000774113457144251015244 0ustar autarchautarch# CONTRIBUTING Thank you for considering contributing to this distribution. This file contains instructions that will help you work with the source code. Please note that if you have any questions or difficulties, you can reach the maintainer(s) through the bug queue described later in this document (preferred), or by emailing the releaser directly. You are not required to follow any of the steps in this document to submit a patch or bug report; these are just recommendations, intended to help you (and help us help you faster). The distribution is managed with [Dist::Zilla](https://metacpan.org/release/Dist-Zilla). However, you can still compile and test the code with the `MakeFile.PL` in the repository: perl Makefile.PL make make test You may need to satisfy some dependencies. The easiest way to satisfy dependencies is to install the last release. This is available at https://metacpan.org/release/DateTime You can use [`cpanminus`](https://metacpan.org/pod/App::cpanminus) to do this without downloading the tarball first: $ cpanm --reinstall --installdeps --with-recommends DateTime [`Dist::Zilla`](https://metacpan.org/pod/Dist::Zilla) is a very powerful authoring tool, but requires a number of author-specific plugins. If you would like to use it for contributing, install it from CPAN, then the following command to install the needed distros: $ dzil authordeps --missing | cpanm There may also be additional requirements not needed by the dzil build which are needed for tests or other development: $ dzil listdeps --author --missing | cpanm Or, you can use the 'dzil stale' command to install all requirements at once: $ cpanm Dist::Zilla::App::Command::stale $ dzil stale --all | cpanm You can also do this via cpanm directly: $ cpanm --reinstall --installdeps --with-develop --with-recommends DateTime Once installed, here are some dzil commands you might try: $ dzil build $ dzil test $ dzil test --release $ dzil xtest $ dzil listdeps --json $ dzil build --notgz You can learn more about Dist::Zilla at http://dzil.org/. The code for this distribution is [hosted on GitHub](https://github.com/houseabsolute/DateTime.pm). You can submit code changes by forking the repository, pushing your code changes to your clone, and then submitting a pull request. See the GitHub documentation for [detailed instructions on pull requests](https://help.github.com/articles/creating-a-pull-request) If you have found a bug, but do not have an accompanying patch to fix it, you can submit an issue report [via the web](https://github.com/houseabsolute/DateTime.pm/issues). There is a mailing list available for users of this distribution, datetime@perl.org ## Continuous Integration All pull requests for this distribution will be automatically tested on Linux by [Travis](https://travis-ci.org/houseabsolute/DateTime.pm) and on Windows by [AppVeyor](https://ci.appveyor.com/project/autarch/DateTime.pm). All CI results will be visible in the pull request on GitHub. Follow the appropriate links for details when tests fail. ## TidyAll This distribution uses [Code::TidyAll](https://metacpan.org/release/Code-TidyAll) to enforce a uniform coding style. This is tested as part of the author testing suite. You can install and run tidyall by running the following commands: $ cpanm Code::TidyAll $ tidyall -a Please run this before committing your changes and address any issues it brings up. ## Contributor Names If you send a patch or pull request, your name and email address will be included in the documentation as a contributor (using the attribution on the commit or patch), unless you specifically request for it not to be. If you wish to be listed under a different name or address, you should submit a pull request to the `.mailmap` file to contain the correct mapping. ## Generated By This file was generated via Dist::Zilla::Plugin::GenerateFile::FromShareDir 0.014 from a template file originating in Dist-Zilla-PluginBundle-DROLSKY-1.01. DateTime-1.51/LICENSE0000644000175000017500000002152713457144251014016 0ustar autarchautarchThis software is Copyright (c) 2003 - 2019 by Dave Rolsky. This is free software, licensed under: The Artistic License 2.0 (GPL Compatible) The Artistic License 2.0 Copyright (c) 2000-2006, The Perl Foundation. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble This license establishes the terms under which a given free software Package may be copied, modified, distributed, and/or redistributed. The intent is that the Copyright Holder maintains some artistic control over the development of that Package while still keeping the Package available as open source and free software. You are always permitted to make arrangements wholly outside of this license directly with the Copyright Holder of a given Package. If the terms of this license do not permit the full use that you propose to make of the Package, you should contact the Copyright Holder and seek a different licensing arrangement. Definitions "Copyright Holder" means the individual(s) or organization(s) named in the copyright notice for the entire Package. "Contributor" means any party that has contributed code or other material to the Package, in accordance with the Copyright Holder's procedures. "You" and "your" means any person who would like to copy, distribute, or modify the Package. "Package" means the collection of files distributed by the Copyright Holder, and derivatives of that collection and/or of those files. A given Package may consist of either the Standard Version, or a Modified Version. "Distribute" means providing a copy of the Package or making it accessible to anyone else, or in the case of a company or organization, to others outside of your company or organization. "Distributor Fee" means any fee that you charge for Distributing this Package or providing support for this Package to another party. It does not mean licensing fees. "Standard Version" refers to the Package if it has not been modified, or has been modified only in ways explicitly requested by the Copyright Holder. "Modified Version" means the Package, if it has been changed, and such changes were not explicitly requested by the Copyright Holder. "Original License" means this Artistic License as Distributed with the Standard Version of the Package, in its current version or as it may be modified by The Perl Foundation in the future. "Source" form means the source code, documentation source, and configuration files for the Package. "Compiled" form means the compiled bytecode, object code, binary, or any other form resulting from mechanical transformation or translation of the Source form. Permission for Use and Modification Without Distribution (1) You are permitted to use the Standard Version and create and use Modified Versions for any purpose without restriction, provided that you do not Distribute the Modified Version. Permissions for Redistribution of the Standard Version (2) You may Distribute verbatim copies of the Source form of the Standard Version of this Package in any medium without restriction, either gratis or for a Distributor Fee, provided that you duplicate all of the original copyright notices and associated disclaimers. At your discretion, such verbatim copies may or may not include a Compiled form of the Package. (3) You may apply any bug fixes, portability changes, and other modifications made available from the Copyright Holder. The resulting Package will still be considered the Standard Version, and as such will be subject to the Original License. Distribution of Modified Versions of the Package as Source (4) You may Distribute your Modified Version as Source (either gratis or for a Distributor Fee, and with or without a Compiled form of the Modified Version) provided that you clearly document how it differs from the Standard Version, including, but not limited to, documenting any non-standard features, executables, or modules, and provided that you do at least ONE of the following: (a) make the Modified Version available to the Copyright Holder of the Standard Version, under the Original License, so that the Copyright Holder may include your modifications in the Standard Version. (b) ensure that installation of your Modified Version does not prevent the user installing or running the Standard Version. In addition, the Modified Version must bear a name that is different from the name of the Standard Version. (c) allow anyone who receives a copy of the Modified Version to make the Source form of the Modified Version available to others under (i) the Original License or (ii) a license that permits the licensee to freely copy, modify and redistribute the Modified Version using the same licensing terms that apply to the copy that the licensee received, and requires that the Source form of the Modified Version, and of any works derived from it, be made freely available in that license fees are prohibited but Distributor Fees are allowed. Distribution of Compiled Forms of the Standard Version or Modified Versions without the Source (5) You may Distribute Compiled forms of the Standard Version without the Source, provided that you include complete instructions on how to get the Source of the Standard Version. Such instructions must be valid at the time of your distribution. If these instructions, at any time while you are carrying out such distribution, become invalid, you must provide new instructions on demand or cease further distribution. If you provide valid instructions or cease distribution within thirty days after you become aware that the instructions are invalid, then you do not forfeit any of your rights under this license. (6) You may Distribute a Modified Version in Compiled form without the Source, provided that you comply with Section 4 with respect to the Source of the Modified Version. Aggregating or Linking the Package (7) You may aggregate the Package (either the Standard Version or Modified Version) with other packages and Distribute the resulting aggregation provided that you do not charge a licensing fee for the Package. Distributor Fees are permitted, and licensing fees for other components in the aggregation are permitted. The terms of this license apply to the use and Distribution of the Standard or Modified Versions as included in the aggregation. (8) You are permitted to link Modified and Standard Versions with other works, to embed the Package in a larger work of your own, or to build stand-alone binary or bytecode versions of applications that include the Package, and Distribute the result without restriction, provided the result does not expose a direct interface to the Package. Items That are Not Considered Part of a Modified Version (9) Works (including, but not limited to, modules and scripts) that merely extend or make use of the Package, do not, by themselves, cause the Package to be a Modified Version. In addition, such works are not considered parts of the Package itself, and are not subject to the terms of this license. General Provisions (10) Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. (11) If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. (12) This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. (13) This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. (14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. DateTime-1.51/README.md0000644000175000017500000020467713457144251014301 0ustar autarchautarch# NAME DateTime - A date and time object for Perl # VERSION version 1.51 # SYNOPSIS use DateTime; $dt = DateTime->new( year => 1964, month => 10, day => 16, hour => 16, minute => 12, second => 47, nanosecond => 500000000, time_zone => 'Asia/Taipei', ); $dt = DateTime->from_epoch( epoch => $epoch ); $dt = DateTime->now; # same as ( epoch => time() ) $year = $dt->year; $month = $dt->month; # 1-12 $day = $dt->day; # 1-31 $dow = $dt->day_of_week; # 1-7 (Monday is 1) $hour = $dt->hour; # 0-23 $minute = $dt->minute; # 0-59 $second = $dt->second; # 0-61 (leap seconds!) $doy = $dt->day_of_year; # 1-366 (leap years) $doq = $dt->day_of_quarter; # 1.. $qtr = $dt->quarter; # 1-4 # all of the start-at-1 methods above have corresponding start-at-0 # methods, such as $dt->day_of_month_0, $dt->month_0 and so on $ymd = $dt->ymd; # 2002-12-06 $ymd = $dt->ymd('/'); # 2002/12/06 $mdy = $dt->mdy; # 12-06-2002 $mdy = $dt->mdy('/'); # 12/06/2002 $dmy = $dt->dmy; # 06-12-2002 $dmy = $dt->dmy('/'); # 06/12/2002 $hms = $dt->hms; # 14:02:29 $hms = $dt->hms('!'); # 14!02!29 $is_leap = $dt->is_leap_year; # these are localizable, see Locales section $month_name = $dt->month_name; # January, February, ... $month_abbr = $dt->month_abbr; # Jan, Feb, ... $day_name = $dt->day_name; # Monday, Tuesday, ... $day_abbr = $dt->day_abbr; # Mon, Tue, ... # May not work for all possible datetime, see the docs on this # method for more details. $epoch_time = $dt->epoch; $dt2 = $dt + $duration_object; $dt3 = $dt - $duration_object; $duration_object = $dt - $dt2; $dt->set( year => 1882 ); $dt->set_time_zone( 'America/Chicago' ); $dt->set_formatter( $formatter ); # DESCRIPTION DateTime is a class for the representation of date/time combinations, and is part of the Perl DateTime project. For details on this project please see [http://datetime.perl.org/](http://datetime.perl.org/). The DateTime site has a FAQ which may help answer many "how do I do X?" questions. The FAQ is at [http://datetime.perl.org/wiki/datetime/page/FAQ](http://datetime.perl.org/wiki/datetime/page/FAQ). It represents the Gregorian calendar, extended backwards in time before its creation (in 1582). This is sometimes known as the "proleptic Gregorian calendar". In this calendar, the first day of the calendar (the epoch), is the first day of year 1, which corresponds to the date which was (incorrectly) believed to be the birth of Jesus Christ. The calendar represented does have a year 0, and in that way differs from how dates are often written using "BCE/CE" or "BC/AD". For infinite datetimes, please see the [DateTime::Infinite](https://metacpan.org/pod/DateTime::Infinite) module. # USAGE ## 0-based Versus 1-based Numbers The DateTime.pm module follows a simple logic for determining whether or not a given number is 0-based or 1-based. Month, day of month, day of week, and day of year are 1-based. Any method that is 1-based also has an equivalent 0-based method ending in "\_0". So for example, this class provides both `day_of_week()` and `day_of_week_0()` methods. The `day_of_week_0()` method still treats Monday as the first day of the week. All _time_-related numbers such as hour, minute, and second are 0-based. Years are neither, as they can be both positive or negative, unlike any other datetime component. There _is_ a year 0. There is no `quarter_0()` method. ## Error Handling Some errors may cause this module to die with an error string. This can only happen when calling constructor methods, methods that change the object, such as `set()`, or methods that take parameters. Methods that retrieve information about the object, such as `year()` or `epoch()`, will never die. ## Locales All the object methods which return names or abbreviations return data based on a locale. This is done by setting the locale when constructing a DateTime object. If this is not set, then "en-US" is used. ## Floating DateTimes The default time zone for new DateTime objects, except where stated otherwise, is the "floating" time zone. This concept comes from the iCal standard. A floating datetime is one which is not anchored to any particular time zone. In addition, floating datetimes do not include leap seconds, since we cannot apply them without knowing the datetime's time zone. The results of date math and comparison between a floating datetime and one with a real time zone are not really valid, because one includes leap seconds and the other does not. Similarly, the results of datetime math between two floating datetimes and two datetimes with time zones are not really comparable. If you are planning to use any objects with a real time zone, it is strongly recommended that you **do not** mix these with floating datetimes. ## Math If you are going to be doing date math, please read the section ["How DateTime Math Works"](#how-datetime-math-works). ## Determining the Local Time Zone Can Be Slow If `$ENV{TZ}` is not set, it may involve reading a number of files in `/etc` or elsewhere. If you know that the local time zone won't change while your code is running, and you need to make many objects for the local time zone, it is strongly recommended that you retrieve the local time zone once and cache it: our $App::LocalTZ = DateTime::TimeZone->new( name => 'local' ); ... # then everywhere else my $dt = DateTime->new( ..., time_zone => $App::LocalTZ ); DateTime itself does not do this internally because local time zones can change, and there's no good way to determine if it's changed without doing all the work to look it up. Do not try to use named time zones (like "America/Chicago") with dates very far in the future (thousands of years). The current implementation of `DateTime::TimeZone` will use a huge amount of memory calculating all the DST changes from now until the future date. Use UTC or the floating time zone and you will be safe. ## Globally Setting a Default Time Zone **Warning: This is very dangerous. Do this at your own risk!** By default, `DateTime` uses either the floating time zone or UTC for newly created objects, depending on the constructor. You can force `DateTime` to use a different time zone by setting the `PERL_DATETIME_DEFAULT_TZ` environment variable. As noted above, this is very dangerous, as it affects all code that creates a `DateTime` object, including modules from CPAN. If those modules expect the normal default, then setting this can cause confusing breakage or subtly broken data. Before setting this variable, you are strongly encouraged to audit your CPAN dependencies to see how they use `DateTime`. Try running the test suite for each dependency with this environment variable set before using this in production. ## Upper and Lower Bounds Internally, dates are represented the number of days before or after 0001-01-01. This is stored as an integer, meaning that the upper and lower bounds are based on your Perl's integer size (`$Config{ivsize}`). The limit on 32-bit systems is around 2^29 days, which gets you to year (+/-)1,469,903. On a 64-bit system you get 2^62 days, (+/-)12,626,367,463,883,278 (12.626 quadrillion). # METHODS DateTime provide many methods. The documentation breaks them down into groups based on what they do (constructor, accessors, modifiers, etc.). ## Constructors All constructors can die when invalid parameters are given. ### Warnings Currently, constructors will warn if you try to create a far future DateTime (year >= 5000) with any time zone besides floating or UTC. This can be very slow if the time zone has future DST transitions that need to be calculated. If the date is sufficiently far in the future this can be _really_ slow (minutes). All warnings from DateTime use the `DateTime` category and can be suppressed with: no warnings 'DateTime'; This warning may be removed in the future if [DateTime::TimeZone](https://metacpan.org/pod/DateTime::TimeZone) is made much faster. ### DateTime->new( ... ) This class method accepts parameters for each date and time component: "year", "month", "day", "hour", "minute", "second", "nanosecond". It also accepts "locale", "time\_zone", and "formatter" parameters. my $dt = DateTime->new( year => 1966, month => 10, day => 25, hour => 7, minute => 15, second => 47, nanosecond => 500000000, time_zone => 'America/Chicago', ); DateTime validates the "month", "day", "hour", "minute", and "second", and "nanosecond" parameters. The valid values for these parameters are: - month An integer from 1-12. - day An integer from 1-31, and it must be within the valid range of days for the specified month. - hour An integer from 0-23. - minute An integer from 0-59. - second An integer from 0-61 (to allow for leap seconds). Values of 60 or 61 are only allowed when they match actual leap seconds. - nanosecond An integer >= 0. If this number is greater than 1 billion, it will be normalized into the second value for the DateTime object. Invalid parameter types (like an array reference) will cause the constructor to die. The value for seconds may be from 0 to 61, to account for leap seconds. If you give a value greater than 59, DateTime does check to see that it really matches a valid leap second. All of the parameters are optional except for "year". The "month" and "day" parameters both default to 1, while the "hour", "minute", "second", and "nanosecond" parameters all default to 0. The "locale" parameter should be a string containing a locale code, like "en-US" or "zh-Hant-TW", or an object returned by `DateTime::Locale->load`. See the [DateTime::Locale](https://metacpan.org/pod/DateTime::Locale) documentation for details. The "time\_zone" parameter can be either a string or a `DateTime::TimeZone` object. A string will simply be passed to the `DateTime::TimeZone->new` method as its "name" parameter. This string may be an Olson DB time zone name ("America/Chicago"), an offset string ("+0630"), or the words "floating" or "local". See the `DateTime::TimeZone` documentation for more details. The default time zone is "floating". The "formatter" can be either a scalar or an object, but the class specified by the scalar or the object must implement a `format_datetime()` method. #### Parsing Dates **This module does not parse dates!** That means there is no constructor to which you can pass things like "March 3, 1970 12:34". Instead, take a look at the various `DateTime::Format::*` modules on CPAN. These parse all sorts of different date formats, and you're bound to find something that can handle your particular needs. #### Ambiguous Local Times Because of Daylight Saving Time, it is possible to specify a local time that is ambiguous. For example, in the US in 2003, the transition from to saving to standard time occurred on October 26, at 02:00:00 local time. The local clock changed from 01:59:59 (saving time) to 01:00:00 (standard time). This means that the hour from 01:00:00 through 01:59:59 actually occurs twice, though the UTC time continues to move forward. If you specify an ambiguous time, then the latest UTC time is always used, in effect always choosing standard time. In this case, you can simply subtract an hour to the object in order to move to saving time, for example: # This object represent 01:30:00 standard time my $dt = DateTime->new( year => 2003, month => 10, day => 26, hour => 1, minute => 30, second => 0, time_zone => 'America/Chicago', ); print $dt->hms; # prints 01:30:00 # Now the object represent 01:30:00 saving time $dt->subtract( hours => 1 ); print $dt->hms; # still prints 01:30:00 Alternately, you could create the object with the UTC time zone, and then call the `set_time_zone()` method to change the time zone. This is a good way to ensure that the time is not ambiguous. #### Invalid Local Times Another problem introduced by Daylight Saving Time is that certain local times just do not exist. For example, in the US in 2003, the transition from standard to saving time occurred on April 6, at the change to 2:00:00 local time. The local clock changes from 01:59:59 (standard time) to 03:00:00 (saving time). This means that there is no 02:00:00 through 02:59:59 on April 6! Attempting to create an invalid time currently causes a fatal error. This may change in future version of this module. ### DateTime->from\_epoch( epoch => $epoch, ... ) This class method can be used to construct a new DateTime object from an epoch time instead of components. Just as with the `new()` method, it accepts "time\_zone", "locale", and "formatter" parameters. If the epoch value is a floating-point value, it will be rounded to nearest microsecond. By default, the returned object will be in the UTC time zone. ### DateTime->now( ... ) This class method is equivalent to calling `from_epoch()` with the value returned from Perl's `time()` function. Just as with the `new()` method, it accepts "time\_zone" and "locale" parameters. By default, the returned object will be in the UTC time zone. ### DateTime->today( ... ) This class method is equivalent to: DateTime->now(@_)->truncate( to => 'day' ); ### DateTime->from\_object( object => $object, ... ) This class method can be used to construct a new DateTime object from any object that implements the `utc_rd_values()` method. All `DateTime::Calendar` modules must implement this method in order to provide cross-calendar compatibility. This method accepts a "locale" and "formatter" parameter If the object passed to this method has a `time_zone()` method, that is used to set the time zone of the newly created `DateTime.pm` object. Otherwise, the returned object will be in the floating time zone. ### DateTime->last\_day\_of\_month( ... ) This constructor takes the same arguments as can be given to the `new()` method, except for "day". Additionally, both "year" and "month" are required. ### DateTime->from\_day\_of\_year( ... ) This constructor takes the same arguments as can be given to the `new()` method, except that it does not accept a "month" or "day" argument. Instead, it requires both "year" and "day\_of\_year". The day of year must be between 1 and 366, and 366 is only allowed for leap years. ### $dt->clone() This object method returns a new object that is replica of the object upon which the method is called. ## "Get" Methods This class has many methods for retrieving information about an object. ### $dt->year() Returns the year. ### $dt->ce\_year() Returns the year according to the BCE/CE numbering system. The year before year 1 in this system is year -1, aka "1 BCE". ### $dt->era\_name() Returns the long name of the current era, something like "Before Christ". See the [Locales](#locales) section for more details. ### $dt->era\_abbr() Returns the abbreviated name of the current era, something like "BC". See the [Locales](#locales) section for more details. ### $dt->christian\_era() Returns a string, either "BC" or "AD", according to the year. ### $dt->secular\_era() Returns a string, either "BCE" or "CE", according to the year. ### $dt->year\_with\_era() Returns a string containing the year immediately followed by its era abbreviation. The year is the absolute value of `ce_year()`, so that year 1 is "1AD" and year 0 is "1BC". ### $dt->year\_with\_christian\_era() Like `year_with_era()`, but uses the christian\_era() method to get the era name. ### $dt->year\_with\_secular\_era() Like `year_with_era()`, but uses the secular\_era() method to get the era name. ### $dt->month() Returns the month of the year, from 1..12. Also available as `$dt->mon()`. ### $dt->month\_name() Returns the name of the current month. See the [Locales](#locales) section for more details. ### $dt->month\_abbr() Returns the abbreviated name of the current month. See the [Locales](#locales) section for more details. ### $dt->day() Returns the day of the month, from 1..31. Also available as `$dt->mday()` and `$dt->day_of_month()`. ### $dt->day\_of\_week() Returns the day of the week as a number, from 1..7, with 1 being Monday and 7 being Sunday. Also available as `$dt->wday()` and `$dt->dow()`. ### $dt->local\_day\_of\_week() Returns the day of the week as a number, from 1..7. The day corresponding to 1 will vary based on the locale. ### $dt->day\_name() Returns the name of the current day of the week. See the [Locales](#locales) section for more details. ### $dt->day\_abbr() Returns the abbreviated name of the current day of the week. See the [Locales](#locales) section for more details. ### $dt->day\_of\_year() Returns the day of the year. Also available as `$dt->doy()`. ### $dt->quarter() Returns the quarter of the year, from 1..4. ### $dt->quarter\_name() Returns the name of the current quarter. See the [Locales](#locales) section for more details. ### $dt->quarter\_abbr() Returns the abbreviated name of the current quarter. See the [Locales](#locales) section for more details. ### $dt->day\_of\_quarter() Returns the day of the quarter. Also available as `$dt->doq()`. ### $dt->weekday\_of\_month() Returns a number from 1..5 indicating which week day of the month this is. For example, June 9, 2003 is the second Monday of the month, and so this method returns 2 for that day. ### $dt->ymd( $optional\_separator ), $dt->mdy(...), $dt->dmy(...) Each method returns the year, month, and day, in the order indicated by the method name. Years are zero-padded to four digits. Months and days are 0-padded to two digits. By default, the values are separated by a dash (-), but this can be overridden by passing a value to the method. The `$dt->ymd()` method is also available as `$dt->date()`. ### $dt->hour() Returns the hour of the day, from 0..23. ### $dt->hour\_1() Returns the hour of the day, from 1..24. ### $dt->hour\_12() Returns the hour of the day, from 1..12. ### $dt->hour\_12\_0() Returns the hour of the day, from 0..11. ### $dt->am\_or\_pm() Returns the appropriate localized abbreviation, depending on the current hour. ### $dt->minute() Returns the minute of the hour, from 0..59. Also available as `$dt->min()`. ### $dt->second() Returns the second, from 0..61. The values 60 and 61 are used for leap seconds. Also available as `$dt->sec()`. ### $dt->fractional\_second() Returns the second, as a real number from 0.0 until 61.999999999 The values 60 and 61 are used for leap seconds. ### $dt->millisecond() Returns the fractional part of the second as milliseconds (1E-3 seconds). Half a second is 500 milliseconds. This value will always be rounded down to the nearest integer. ### $dt->microsecond() Returns the fractional part of the second as microseconds (1E-6 seconds). Half a second is 500\_000 microseconds. This value will always be rounded down to the nearest integer. ### $dt->nanosecond() Returns the fractional part of the second as nanoseconds (1E-9 seconds). Half a second is 500\_000\_000 nanoseconds. ### $dt->hms( $optional\_separator ) Returns the hour, minute, and second, all zero-padded to two digits. If no separator is specified, a colon (:) is used by default. Also available as `$dt->time()`. ### $dt->datetime( $optional\_separator ) This method is equivalent to: $dt->ymd('-') . 'T' . $dt->hms(':') The `$optional_separator` parameter allows you to override the separator between the date and time, for e.g. `$dt->datetime(q{ })`. This method is also available as `$dt->iso8601()`, but it's not really a very good ISO8601 format, as it lacks a time zone. If called as `$dt->iso8601()` you cannot change the separator, as ISO8601 specifies that "T" must be used to separate them. ### $dt->stringify() This method returns a stringified version of the object. It is how stringification overloading is implemented. If the object has a formatter, then its `format_datetime()` method is used to produce a string. Otherwise, this method calls `$dt->iso8601()` to produce a string. See ["Formatters And Stringification"](#formatters-and-stringification) for details. ### $dt->is\_leap\_year() This method returns a true or false value indicating whether or not the datetime object is in a leap year. ### $dt->is\_last\_day\_of\_month() This method returns a true or false value indicating whether or not the datetime object is the last day of the month. ### $dt->is\_last\_day\_of\_quarter() This method returns a true or false value indicating whether or not the datetime object is the last day of the quarter. ### $dt->is\_last\_day\_of\_year() This method returns a true or false value indicating whether or not the datetime object is the last day of the year. ### $dt->month\_length() This method returns the number of days in the current month. ### $dt->quarter\_length() This method returns the number of days in the current quarter. ### $dt->year\_length() This method returns the number of days in the current year. ### $dt->week() ($week_year, $week_number) = $dt->week; Returns information about the calendar week which contains this datetime object. The values returned by this method are also available separately through the week\_year and week\_number methods. The first week of the year is defined by ISO as the one which contains the fourth day of January, which is equivalent to saying that it's the first week to overlap the new year by at least four days. Typically the week year will be the same as the year that the object is in, but dates at the very beginning of a calendar year often end up in the last week of the prior year, and similarly, the final few days of the year may be placed in the first week of the next year. ### $dt->week\_year() Returns the year of the week. See `$dt->week()` for details. ### $dt->week\_number() Returns the week of the year, from 1..53. See `$dt->week()` for details. ### $dt->week\_of\_month() The week of the month, from 0..5. The first week of the month is the first week that contains a Thursday. This is based on the ICU definition of week of month, and correlates to the ISO8601 week of year definition. A day in the week _before_ the week with the first Thursday will be week 0. ### $dt->jd(), $dt->mjd() These return the Julian Day and Modified Julian Day, respectively. The value returned is a floating point number. The fractional portion of the number represents the time portion of the datetime. ### $dt->time\_zone() This returns the `DateTime::TimeZone` object for the datetime object. ### $dt->offset() This returns the offset from UTC, in seconds, of the datetime object according to the time zone. ### $dt->is\_dst() Returns a boolean indicating whether or not the datetime object is currently in Daylight Saving Time or not. ### $dt->time\_zone\_long\_name() This is a shortcut for `$dt->time_zone->name`. It's provided so that one can use "%{time\_zone\_long\_name}" as a strftime format specifier. ### $dt->time\_zone\_short\_name() This method returns the time zone abbreviation for the current time zone, such as "PST" or "GMT". These names are **not** definitive, and should not be used in any application intended for general use by users around the world. ### $dt->strftime( $format, ... ) This method implements functionality similar to the `strftime()` method in C. However, if given multiple format strings, then it will return multiple scalars, one for each format string. See the ["strftime Patterns"](#strftime-patterns) section for a list of all possible strftime patterns. If you give a pattern that doesn't exist, then it is simply treated as text. Note that any deviation from the POSIX standard is probably a bug. DateTime should match the output of `POSIX::strftime` for any given pattern. ### $dt->format\_cldr( $format, ... ) This method implements formatting based on the CLDR date patterns. If given multiple format strings, then it will return multiple scalars, one for each format string. See the ["CLDR Patterns"](#cldr-patterns) section for a list of all possible CLDR patterns. If you give a pattern that doesn't exist, then it is simply treated as text. ### $dt->epoch() Return the UTC epoch value for the datetime object. Datetimes before the start of the epoch will be returned as a negative number. The return value from this method is always an integer. Since the epoch does not account for leap seconds, the epoch time for 1972-12-31T23:59:60 (UTC) is exactly the same as that for 1973-01-01T00:00:00. ### $dt->hires\_epoch() Returns the epoch as a floating point number. The floating point portion of the value represents the nanosecond value of the object. This method is provided for compatibility with the `Time::HiRes` module. Note that this method suffers from the imprecision of floating point numbers, and the result may end up rounded to an arbitrary degree depending on your platform. my $dt = DateTime->new( year => 2012, nanosecond => 4 ); say $dt->hires_epoch(); On my system, this simply prints `1325376000` because adding `0.000000004` to `1325376000` returns `1325376000`. ### $dt->is\_finite(), $dt->is\_infinite() These methods allow you to distinguish normal datetime objects from infinite ones. Infinite datetime objects are documented in [DateTime::Infinite](https://metacpan.org/pod/DateTime::Infinite). ### $dt->utc\_rd\_values() Returns the current UTC Rata Die days, seconds, and nanoseconds as a three element list. This exists primarily to allow other calendar modules to create objects based on the values provided by this object. ### $dt->local\_rd\_values() Returns the current local Rata Die days, seconds, and nanoseconds as a three element list. This exists for the benefit of other modules which might want to use this information for date math, such as `DateTime::Event::Recurrence`. ### $dt->leap\_seconds() Returns the number of leap seconds that have happened up to the datetime represented by the object. For floating datetimes, this always returns 0. ### $dt->utc\_rd\_as\_seconds() Returns the current UTC Rata Die days and seconds purely as seconds. This number ignores any fractional seconds stored in the object, as well as leap seconds. ### $dt->locale() Returns the current locale object. ### $dt->formatter() Returns current formatter object or class. See ["Formatters And Stringification"](#formatters-and-stringification) for details. ## "Set" Methods The remaining methods provided by `DateTime.pm`, except where otherwise specified, return the object itself, thus making method chaining possible. For example: my $dt = DateTime->now->set_time_zone( 'Australia/Sydney' ); my $first = DateTime ->last_day_of_month( year => 2003, month => 3 ) ->add( days => 1 ) ->subtract( seconds => 1 ); ### $dt->set( .. ) This method can be used to change the local components of a date time. This method accepts any parameter allowed by the `new()` method except for "locale" or "time\_zone". Use `set_locale()` and `set_time_zone()` for those instead. This method performs parameter validation just like the `new()` method. **Do not use this method to do date math. Use the `add()` and `subtract()` methods instead.** ### $dt->set\_year(), $dt->set\_month(), etc. DateTime has a `set_*` method for every item that can be passed to the constructor: - $dt->set\_year() - $dt->set\_month() - $dt->set\_day() - $dt->set\_hour() - $dt->set\_minute() - $dt->set\_second() - $dt->set\_nanosecond() These are shortcuts to calling `set()` with a single key. They all take a single parameter. ### $dt->truncate( to => ... ) This method allows you to reset some of the local time components in the object to their "zero" values. The "to" parameter is used to specify which values to truncate, and it may be one of "year", "quarter", "month", "week", "local\_week", "day", "hour", "minute", or "second". For example, if "month" is specified, then the local day becomes 1, and the hour, minute, and second all become 0. If "week" is given, then the datetime is set to the Monday of the week in which it occurs, and the time components are all set to 0. If you truncate to "local\_week", then the first day of the week is locale-dependent. For example, in the `en-US` locale, the first day of the week is Sunday. ### $dt->set\_locale( $locale ) Sets the object's locale. You can provide either a locale code like "en-US" or an object returned by `DateTime::Locale->load`. ### $dt->set\_time\_zone( $tz ) This method accepts either a time zone object or a string that can be passed as the "name" parameter to `DateTime::TimeZone->new()`. If the new time zone's offset is different from the old time zone, then the _local_ time is adjusted accordingly. For example: my $dt = DateTime->new( year => 2000, month => 5, day => 10, hour => 15, minute => 15, time_zone => 'America/Los_Angeles', ); print $dt->hour; # prints 15 $dt->set_time_zone( 'America/Chicago' ); print $dt->hour; # prints 17 If the old time zone was a floating time zone, then no adjustments to the local time are made, except to account for leap seconds. If the new time zone is floating, then the _UTC_ time is adjusted in order to leave the local time untouched. Fans of Tsai Ming-Liang's films will be happy to know that this does work: my $dt = DateTime->now( time_zone => 'Asia/Taipei' ); $dt->set_time_zone( 'Europe/Paris' ); Yes, now we can know "ni3 na4 bian1 ji2dian3?" ### $dt->set\_formatter( $formatter ) Set the formatter for the object. See ["Formatters And Stringification"](#formatters-and-stringification) for details. You can set this to `undef` to revert to the default formatter. ## Math Methods Like the set methods, math related methods always return the object itself, to allow for chaining: $dt->add( days => 1 )->subtract( seconds => 1 ); ### $dt->duration\_class() This returns `DateTime::Duration`, but exists so that a subclass of `DateTime.pm` can provide a different value. ### $dt->add\_duration( $duration\_object ) This method adds a `DateTime::Duration` to the current datetime. See the [DateTime::Duration](https://metacpan.org/pod/DateTime::Duration) docs for more details. ### $dt->add( parameters for DateTime::Duration ) This method is syntactic sugar around the `add_duration()` method. It simply creates a new `DateTime::Duration` object using the parameters given, and then calls the `add_duration()` method. ### $dt->add( $duration\_object ) A synonym of `$dt->add_duration( $duration_object )`. ### $dt->subtract\_duration( $duration\_object ) When given a `DateTime::Duration` object, this method simply calls `invert()` on that object and passes that new duration to the `add_duration` method. ### $dt->subtract( DateTime::Duration->new parameters ) Like `add()`, this is syntactic sugar for the `subtract_duration()` method. ### $dt->subtract( $duration\_object ) A synonym of `$dt->subtract_duration( $duration_object )`. ### $dt->subtract\_datetime( $datetime ) This method returns a new `DateTime::Duration` object representing the difference between the two dates. The duration is **relative** to the object from which `$datetime` is subtracted. For example: 2003-03-15 00:00:00.00000000 - 2003-02-15 00:00:00.00000000 ------------------------------- = 1 month Note that this duration is not an absolute measure of the amount of time between the two datetimes, because the length of a month varies, as well as due to the presence of leap seconds. The returned duration may have deltas for months, days, minutes, seconds, and nanoseconds. ### $dt->delta\_md( $datetime ) ### $dt->delta\_days( $datetime ) Each of these methods returns a new `DateTime::Duration` object representing some portion of the difference between two datetimes. The `delta_md()` method returns a duration which contains only the month and day portions of the duration is represented. The `delta_days()` method returns a duration which contains only days. The `delta_md` and `delta_days` methods truncate the duration so that any fractional portion of a day is ignored. Both of these methods operate on the date portion of a datetime only, and so effectively ignore the time zone. Unlike the subtraction methods, **these methods always return a positive (or zero) duration**. ### $dt->delta\_ms( $datetime ) Returns a duration which contains only minutes and seconds. Any day and month differences to minutes are converted to minutes and seconds. This method also **always return a positive (or zero) duration**. ### $dt->subtract\_datetime\_absolute( $datetime ) This method returns a new `DateTime::Duration` object representing the difference between the two dates in seconds and nanoseconds. This is the only way to accurately measure the absolute amount of time between two datetimes, since units larger than a second do not represent a fixed number of seconds. Note that because of leap seconds, this may not return the same result as doing this math based on the value returned by `$dt->epoch()`. ## Class Methods ### DateTime->DefaultLocale( $locale ) This can be used to specify the default locale to be used when creating DateTime objects. If unset, then "en-US" is used. ### DateTime->compare( $dt1, $dt2 ), DateTime->compare\_ignore\_floating( $dt1, $dt2 ) $cmp = DateTime->compare( $dt1, $dt2 ); $cmp = DateTime->compare_ignore_floating( $dt1, $dt2 ); Compare two DateTime objects. The semantics are compatible with Perl's `sort()` function; it returns -1 if $dt1 < $dt2, 0 if $dt1 == $dt2, 1 if $dt1 \> $dt2. If one of the two DateTime objects has a floating time zone, it will first be converted to the time zone of the other object. This is what you want most of the time, but it can lead to inconsistent results when you compare a number of DateTime objects, some of which are floating, and some of which are in other time zones. If you want to have consistent results (because you want to sort a number of objects, for example), you can use the `compare_ignore_floating()` method: @dates = sort { DateTime->compare_ignore_floating($a, $b) } @dates; In this case, objects with a floating time zone will be sorted as if they were UTC times. Since DateTime objects overload comparison operators, this: @dates = sort @dates; is equivalent to this: @dates = sort { DateTime->compare($a, $b) } @dates; DateTime objects can be compared to any other calendar class that implements the `utc_rd_values()` method. ## Testing Code That Uses DateTime If you are trying to test code that calls uses DateTime, you may want to be able to explicitly set the value returned by Perl's `time()` builtin. This builtin is called by `DateTime->now()` and `DateTime->today()`. You can override `CORE::GLOBAL::time()`, but this will only work if you do this **before** loading DateTime. If doing this is inconvenient, you can also override `DateTime::_core_time()`: no warnings 'redefine'; local *DateTime::_core_time = sub { return 42 }; DateTime is guaranteed to call this subroutine to get the current `time()` value. You can also override the `_core_time()` sub in a subclass of DateTime and use that. ## How DateTime Math Works It's important to have some understanding of how datetime math is implemented in order to effectively use this module and `DateTime::Duration`. ### Making Things Simple If you want to simplify your life and not have to think too hard about the nitty-gritty of datetime math, I have several recommendations: - use the floating time zone If you do not care about time zones or leap seconds, use the "floating" timezone: my $dt = DateTime->now( time_zone => 'floating' ); Math done on two objects in the floating time zone produces very predictable results. Note that in most cases you will want to start by creating an object in a specific zone and _then_ convert it to the floating time zone. When an object goes from a real zone to the floating zone, the time for the object remains the same. This means that passing the floating zone to a constructor may not do what you want. my $dt = DateTime->now( time_zone => 'floating' ); is equivalent to my $dt = DateTime->now( time_zone => 'UTC' )->set_time_zone('floating'); This might not be what you wanted. Instead, you may prefer to do this: my $dt = DateTime->now( time_zone => 'local' )->set_time_zone('floating'); - use UTC for all calculations If you do care about time zones (particularly DST) or leap seconds, try to use non-UTC time zones for presentation and user input only. Convert to UTC immediately and convert back to the local time zone for presentation: my $dt = DateTime->new( %user_input, time_zone => $user_tz ); $dt->set_time_zone('UTC'); # do various operations - store it, retrieve it, add, subtract, etc. $dt->set_time_zone($user_tz); print $dt->datetime; - math on non-UTC time zones If you need to do date math on objects with non-UTC time zones, please read the caveats below carefully. The results `DateTime.pm` produces are predictable and correct, and mostly intuitive, but datetime math gets very ugly when time zones are involved, and there are a few strange corner cases involving subtraction of two datetimes across a DST change. If you can always use the floating or UTC time zones, you can skip ahead to ["Leap Seconds and Date Math"](#leap-seconds-and-date-math) - date vs datetime math If you only care about the date (calendar) portion of a datetime, you should use either `delta_md()` or `delta_days()`, not `subtract_datetime()`. This will give predictable, unsurprising results, free from DST-related complications. - subtract\_datetime() and add\_duration() You must convert your datetime objects to the UTC time zone before doing date math if you want to make sure that the following formulas are always true: $dt2 - $dt1 = $dur $dt1 + $dur = $dt2 $dt2 - $dur = $dt1 Note that using `delta_days` ensures that this formula always works, regardless of the timezone of the objects involved, as does using `subtract_datetime_absolute()`. Other methods of subtraction are not always reversible. - never do math on two objects where only one is in the floating time zone The date math code accounts for leap seconds whenever the `DateTime` object is not in the floating time zone. If you try to do math where one object is in the floating zone and the other isn't, the results will be confusing and wrong. ### Adding a Duration to a Datetime The parts of a duration can be broken down into five parts. These are months, days, minutes, seconds, and nanoseconds. Adding one month to a date is different than adding 4 weeks or 28, 29, 30, or 31 days. Similarly, due to DST and leap seconds, adding a day can be different than adding 86,400 seconds, and adding a minute is not exactly the same as 60 seconds. We cannot convert between these units, except for seconds and nanoseconds, because there is no fixed conversion between the two units, because of things like leap seconds, DST changes, etc. `DateTime.pm` always adds (or subtracts) days, then months, minutes, and then seconds and nanoseconds. If there are any boundary overflows, these are normalized at each step. For the days and months the local (not UTC) values are used. For minutes and seconds, the local values are used. This generally just works. This means that adding one month and one day to February 28, 2003 will produce the date April 1, 2003, not March 29, 2003. my $dt = DateTime->new( year => 2003, month => 2, day => 28 ); $dt->add( months => 1, days => 1 ); # 2003-04-01 - the result On the other hand, if we add months first, and then separately add days, we end up with March 29, 2003: $dt->add( months => 1 )->add( days => 1 ); # 2003-03-29 We see similar strangeness when math crosses a DST boundary: my $dt = DateTime->new( year => 2003, month => 4, day => 5, hour => 1, minute => 58, time_zone => "America/Chicago", ); $dt->add( days => 1, minutes => 3 ); # 2003-04-06 02:01:00 $dt->add( minutes => 3 )->add( days => 1 ); # 2003-04-06 03:01:00 Note that if you converted the datetime object to UTC first you would get predictable results. If you want to know how many seconds a duration object represents, you have to add it to a datetime to find out, so you could do: my $now = DateTime->now( time_zone => 'UTC' ); my $later = $now->clone->add_duration($duration); my $seconds_dur = $later->subtract_datetime_absolute($now); This returns a duration which only contains seconds and nanoseconds. If we were add the duration to a different datetime object we might get a different number of seconds. [DateTime::Duration](https://metacpan.org/pod/DateTime::Duration) supports three different end-of-month algorithms for adding months. This comes into play when an addition results in a day past the end of the month (for example, adding one month to January 30). # 2010-08-31 + 1 month = 2010-10-01 $dt->add( months => 1, end_of_month => 'wrap' ); # 2010-01-30 + 1 month = 2010-02-28 $dt->add( months => 1, end_of_month => 'limit' ); # 2010-04-30 + 1 month = 2010-05-31 $dt->add( months => 1, end_of_month => 'preserve' ); By default, it uses "wrap" for positive durations and "preserve" for negative durations. See [DateTime::Duration](https://metacpan.org/pod/DateTime::Duration) for a detailed explanation of these algorithms. If you need to do lots of work with durations, take a look at Rick Measham's `DateTime::Format::Duration` module, which lets you present information from durations in many useful ways. There are other subtract/delta methods in DateTime.pm to generate different types of durations. These methods are `subtract_datetime()`, `subtract_datetime_absolute()`, `delta_md()`, `delta_days()`, and `delta_ms()`. ### Datetime Subtraction Date subtraction is done solely based on the two object's local datetimes, with one exception to handle DST changes. Also, if the two datetime objects are in different time zones, one of them is converted to the other's time zone first before subtraction. This is best explained through examples: The first of these probably makes the most sense: my $dt1 = DateTime->new( year => 2003, month => 5, day => 6, time_zone => 'America/Chicago', ); # not DST my $dt2 = DateTime->new( year => 2003, month => 11, day => 6, time_zone => 'America/Chicago', ); # is DST my $dur = $dt2->subtract_datetime($dt1); # 6 months Nice and simple. This one is a little trickier, but still fairly logical: my $dt1 = DateTime->new( year => 2003, month => 4, day => 5, hour => 1, minute => 58, time_zone => "America/Chicago", ); # is DST my $dt2 = DateTime->new( year => 2003, month => 4, day => 7, hour => 2, minute => 1, time_zone => "America/Chicago", ); # not DST my $dur = $dt2->subtract_datetime($dt1); # 2 days and 3 minutes Which contradicts the result this one gives, even though they both make sense: my $dt1 = DateTime->new( year => 2003, month => 4, day => 5, hour => 1, minute => 58, time_zone => "America/Chicago", ); # is DST my $dt2 = DateTime->new( year => 2003, month => 4, day => 6, hour => 3, minute => 1, time_zone => "America/Chicago", ); # not DST my $dur = $dt2->subtract_datetime($dt1); # 1 day and 3 minutes This last example illustrates the "DST" exception mentioned earlier. The exception accounts for the fact 2003-04-06 only lasts 23 hours. And finally: my $dt2 = DateTime->new( year => 2003, month => 10, day => 26, hour => 1, time_zone => 'America/Chicago', ); my $dt1 = $dt2->clone->subtract( hours => 1 ); my $dur = $dt2->subtract_datetime($dt1); # 60 minutes This seems obvious until you realize that subtracting 60 minutes from `$dt2` in the above example still leaves the clock time at "01:00:00". This time we are accounting for a 25 hour day. ### Reversibility Date math operations are not always reversible. This is because of the way that addition operations are ordered. As was discussed earlier, adding 1 day and 3 minutes in one call to `add()` is not the same as first adding 3 minutes and 1 day in two separate calls. If we take a duration returned from `subtract_datetime()` and then try to add or subtract that duration from one of the datetimes we just used, we sometimes get interesting results: my $dt1 = DateTime->new( year => 2003, month => 4, day => 5, hour => 1, minute => 58, time_zone => "America/Chicago", ); my $dt2 = DateTime->new( year => 2003, month => 4, day => 6, hour => 3, minute => 1, time_zone => "America/Chicago", ); my $dur = $dt2->subtract_datetime($dt1); # 1 day and 3 minutes $dt1->add_duration($dur); # gives us $dt2 $dt2->subtract_duration($dur); # gives us 2003-04-05 02:58:00 - 1 hour later than $dt1 The `subtract_duration()` operation gives us a (perhaps) unexpected answer because it first subtracts one day to get 2003-04-05T03:01:00 and then subtracts 3 minutes to get the final result. If we explicitly reverse the order we can get the original value of `$dt1`. This can be facilitated by `DateTime::Duration`'s `calendar_duration()` and `clock_duration()` methods: $dt2->subtract_duration( $dur->clock_duration ) ->subtract_duration( $dur->calendar_duration ); ### Leap Seconds and Date Math The presence of leap seconds can cause even more anomalies in date math. For example, the following is a legal datetime: my $dt = DateTime->new( year => 1972, month => 12, day => 31, hour => 23, minute => 59, second => 60, time_zone => 'UTC' ); If we do the following: $dt->add( months => 1 ); Then the datetime is now "1973-02-01 00:00:00", because there is no 23:59:60 on 1973-01-31. Leap seconds also force us to distinguish between minutes and seconds during date math. Given the following datetime: my $dt = DateTime->new( year => 1972, month => 12, day => 31, hour => 23, minute => 59, second => 30, time_zone => 'UTC' ); we will get different results when adding 1 minute than we get if we add 60 seconds. This is because in this case, the last minute of the day, beginning at 23:59:00, actually contains 61 seconds. Here are the results we get: # 1972-12-31 23:59:30 - our starting datetime $dt->clone->add( minutes => 1 ); # 1973-01-01 00:00:30 - one minute later $dt->clone->add( seconds => 60 ); # 1973-01-01 00:00:29 - 60 seconds later $dt->clone->add( seconds => 61 ); # 1973-01-01 00:00:30 - 61 seconds later ### Local vs. UTC and 24 hours vs. 1 day When math crosses a daylight saving boundary, a single day may have more or less than 24 hours. For example, if you do this: my $dt = DateTime->new( year => 2003, month => 4, day => 5, hour => 2, time_zone => 'America/Chicago', ); $dt->add( days => 1 ); then you will produce an _invalid_ local time, and therefore an exception will be thrown. However, this works: my $dt = DateTime->new( year => 2003, month => 4, day => 5, hour => 2, time_zone => 'America/Chicago', ); $dt->add( hours => 24 ); and produces a datetime with the local time of "03:00". If all this makes your head hurt, there is a simple alternative. Just convert your datetime object to the "UTC" time zone before doing date math on it, and switch it back to the local time zone afterwards. This avoids the possibility of having date math throw an exception, and makes sure that 1 day equals 24 hours. Of course, this may not always be desirable, so caveat user! ## Overloading This module explicitly overloads the addition (+), subtraction (-), string and numeric comparison operators. This means that the following all do sensible things: my $new_dt = $dt + $duration_obj; my $new_dt = $dt - $duration_obj; my $duration_obj = $dt - $new_dt; foreach my $dt ( sort @dts ) { ... } Additionally, the fallback parameter is set to true, so other derivable operators (+=, -=, etc.) will work properly. Do not expect increment (++) or decrement (--) to do anything useful. The string comparison operators, `eq` or `ne`, will use the string value to compare with non-DateTime objects. DateTime objects do not have a numeric value, using `==` or `<=>` to compare a DateTime object with a non-DateTime object will result in an exception. To safely sort mixed DateTime and non-DateTime objects, use `sort { $a cmp $b } @dates`. The module also overloads stringification using the object's formatter, defaulting to `iso8601()` method. See ["Formatters And Stringification"](#formatters-and-stringification) for details. ## Formatters And Stringification You can optionally specify a "formatter", which is usually a DateTime::Format::\* object/class, to control the stringification of the DateTime object. Any of the constructor methods can accept a formatter argument: my $formatter = DateTime::Format::Strptime->new(...); my $dt = DateTime->new(year => 2004, formatter => $formatter); Or, you can set it afterwards: $dt->set_formatter($formatter); $formatter = $dt->formatter(); Once you set the formatter, the overloaded stringification method will use the formatter. If unspecified, the `iso8601()` method is used. A formatter can be handy when you know that in your application you want to stringify your DateTime objects into a special format all the time, for example to a different language. If you provide a formatter class name or object, it must implement a `format_datetime` method. This method will be called with just the DateTime object as its argument. ## CLDR Patterns The CLDR pattern language is both more powerful and more complex than strftime. Unlike strftime patterns, you often have to explicitly escape text that you do not want formatted, as the patterns are simply letters without any prefix. For example, "yyyy-MM-dd" is a valid CLDR pattern. If you want to include any lower or upper case ASCII characters as-is, you can surround them with single quotes ('). If you want to include a single quote, you must escape it as two single quotes (''). 'Today is ' EEEE 'It is now' h 'o''clock' a Spaces and any non-letter text will always be passed through as-is. Many CLDR patterns which produce numbers will pad the number with leading zeroes depending on the length of the format specifier. For example, "h" represents the current hour from 1-12. If you specify "hh" then the 1-9 will have a leading zero prepended. However, CLDR often uses five of a letter to represent the narrow form of a pattern. This inconsistency is necessary for backwards compatibility. CLDR often distinguishes between the "format" and "stand-alone" forms of a pattern. The format pattern is used when the thing in question is being placed into a larger string. The stand-alone form is used when displaying that item by itself, for example in a calendar. It also often provides three sizes for each item, wide (the full name), abbreviated, and narrow. The narrow form is often just a single character, for example "T" for "Tuesday", and may not be unique. CLDR provides a fairly complex system for localizing time zones that we ignore entirely. The time zone patterns just use the information provided by `DateTime::TimeZone`, and _do not follow the CLDR spec_. The output of a CLDR pattern is always localized, when applicable. CLDR provides the following patterns: - G{1,3} The abbreviated era (BC, AD). - GGGG The wide era (Before Christ, Anno Domini). - GGGGG The narrow era, if it exists (and it mostly doesn't). - y and y{3,} The year, zero-prefixed as needed. Negative years will start with a "-", and this will be included in the length calculation. In other, words the "yyyyy" pattern will format year -1234 as "-1234", not "-01234". - yy This is a special case. It always produces a two-digit year, so "1976" becomes "76". Negative years will start with a "-", making them one character longer. - Y{1,} The year in "week of the year" calendars, from `$dt->week_year()`. - u{1,} Same as "y" except that "uu" is not a special case. - Q{1,2} The quarter as a number (1..4). - QQQ The abbreviated format form for the quarter. - QQQQ The wide format form for the quarter. - q{1,2} The quarter as a number (1..4). - qqq The abbreviated stand-alone form for the quarter. - qqqq The wide stand-alone form for the quarter. - M{1,2\] The numerical month. - MMM The abbreviated format form for the month. - MMMM The wide format form for the month. - MMMMM The narrow format form for the month. - L{1,2\] The numerical month. - LLL The abbreviated stand-alone form for the month. - LLLL The wide stand-alone form for the month. - LLLLL The narrow stand-alone form for the month. - w{1,2} The week of the year, from `$dt->week_number()`. - W The week of the month, from `$dt->week_of_month()`. - d{1,2} The numeric day of the month. - D{1,3} The numeric day of the year. - F The day of the week in the month, from `$dt->weekday_of_month()`. - g{1,} The modified Julian day, from `$dt->mjd()`. - E{1,3} and eee The abbreviated format form for the day of the week. - EEEE and eeee The wide format form for the day of the week. - EEEEE and eeeee The narrow format form for the day of the week. - e{1,2} The _local_ numeric day of the week, from 1 to 7. This number depends on what day is considered the first day of the week, which varies by locale. For example, in the US, Sunday is the first day of the week, so this returns 2 for Monday. - c The numeric day of the week from 1 to 7, treating Monday as the first of the week, regardless of locale. - ccc The abbreviated stand-alone form for the day of the week. - cccc The wide stand-alone form for the day of the week. - ccccc The narrow format form for the day of the week. - a The localized form of AM or PM for the time. - h{1,2} The hour from 1-12. - H{1,2} The hour from 0-23. - K{1,2} The hour from 0-11. - k{1,2} The hour from 1-24. - j{1,2} The hour, in 12 or 24 hour form, based on the preferred form for the locale. In other words, this is equivalent to either "h{1,2}" or "H{1,2}". - m{1,2} The minute. - s{1,2} The second. - S{1,} The fractional portion of the seconds, rounded based on the length of the specifier. This returned _without_ a leading decimal point, but may have leading or trailing zeroes. - A{1,} The millisecond of the day, based on the current time. In other words, if it is 12:00:00.00, this returns 43200000. - z{1,3} The time zone short name. - zzzz The time zone long name. - Z{1,3} The time zone offset. - ZZZZ The time zone short name and the offset as one string, so something like "CDT-0500". - ZZZZZ The time zone offset as a sexagesimal number, so something like "-05:00". (This is useful for W3C format.) - v{1,3} The time zone short name. - vvvv The time zone long name. - V{1,3} The time zone short name. - VVVV The time zone long name. ### CLDR "Available Formats" The CLDR data includes pre-defined formats for various patterns such as "month and day" or "time of day". Using these formats lets you render information about a datetime in the most natural way for users from a given locale. These formats are indexed by a key that is itself a CLDR pattern. When you look these up, you get back a different CLDR pattern suitable for the locale. Let's look at some example We'll use `2008-02-05T18:30:30` as our example datetime value, and see how this is rendered for the `en-US` and `fr-FR` locales. - `MMMd` The abbreviated month and day as number. For `en-US`, we get the pattern `MMM d`, which renders as `Feb 5`. For `fr-FR`, we get the pattern `d MMM`, which renders as `5 févr.`. - `yQQQ` The year and abbreviated quarter of year. For `en-US`, we get the pattern `QQQ y`, which renders as `Q1 2008`. For `fr-FR`, we get the same pattern, `QQQ y`, which renders as `T1 2008`. - `hm` The 12-hour time of day without seconds. For `en-US`, we get the pattern `h:mm a`, which renders as `6:30 PM`. For `fr-FR`, we get the exact same pattern and rendering. The available formats for each locale are documented in the POD for that locale. To get back the format, you use the `$locale->format_for` method. For example: say $dt->format_cldr( $dt->locale->format_for('MMMd') ); ## strftime Patterns The following patterns are allowed in the format string given to the `$dt->strftime()` method: - %a The abbreviated weekday name. - %A The full weekday name. - %b The abbreviated month name. - %B The full month name. - %c The default datetime format for the object's locale. - %C The century number (year/100) as a 2-digit integer. - %d The day of the month as a decimal number (range 01 to 31). - %D Equivalent to %m/%d/%y. This is not a good standard format if you want folks from both the United States and the rest of the world to understand the date! - %e Like %d, the day of the month as a decimal number, but a leading zero is replaced by a space. - %F Equivalent to %Y-%m-%d (the ISO 8601 date format) - %G The ISO 8601 year with century as a decimal number. The 4-digit year corresponding to the ISO week number (see %V). This has the same format and value as %Y, except that if the ISO week number belongs to the previous or next year, that year is used instead. (TZ) - %g Like %G, but without century, i.e., with a 2-digit year (00-99). - %h Equivalent to %b. - %H The hour as a decimal number using a 24-hour clock (range 00 to 23). - %I The hour as a decimal number using a 12-hour clock (range 01 to 12). - %j The day of the year as a decimal number (range 001 to 366). - %k The hour (24-hour clock) as a decimal number (range 0 to 23); single digits are preceded by a blank. (See also %H.) - %l The hour (12-hour clock) as a decimal number (range 1 to 12); single digits are preceded by a blank. (See also %I.) - %m The month as a decimal number (range 01 to 12). - %M The minute as a decimal number (range 00 to 59). - %n A newline character. - %N The fractional seconds digits. Default is 9 digits (nanoseconds). %3N milliseconds (3 digits) %6N microseconds (6 digits) %9N nanoseconds (9 digits) This value will always be rounded down to the nearest integer. - %p Either \`AM' or \`PM' according to the given time value, or the corresponding strings for the current locale. Noon is treated as \`pm' and midnight as \`am'. - %P Like %p but in lowercase: \`am' or \`pm' or a corresponding string for the current locale. - %r The time in a.m. or p.m. notation. In the POSIX locale this is equivalent to \`%I:%M:%S %p'. - %R The time in 24-hour notation (%H:%M). (SU) For a version including the seconds, see %T below. - %s The number of seconds since the epoch. - %S The second as a decimal number (range 00 to 61). - %t A tab character. - %T The time in 24-hour notation (%H:%M:%S). - %u The day of the week as a decimal, range 1 to 7, Monday being 1. See also %w. - %U The week number of the current year as a decimal number, range 00 to 53, starting with the first Sunday as the first day of week 01. See also %V and %W. - %V The ISO 8601:1988 week number of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the current year, and with Monday as the first day of the week. See also %U and %W. - %w The day of the week as a decimal, range 0 to 6, Sunday being 0. See also %u. - %W The week number of the current year as a decimal number, range 00 to 53, starting with the first Monday as the first day of week 01. - %x The default date format for the object's locale. - %X The default time format for the object's locale. - %y The year as a decimal number without a century (range 00 to 99). - %Y The year as a decimal number including the century. - %z The time-zone as hour offset from UTC. Required to emit RFC822-conformant dates (using "%a, %d %b %Y %H:%M:%S %z"). - %Z The short name for the time zone, typically an abbreviation like "EST" or "AEST". - %% A literal \`%' character. - %{method} Any method name may be specified using the format `%{method}` name where "method" is a valid `DateTime.pm` object method. ## DateTime.pm and Storable DateTime implements Storable hooks in order to reduce the size of a serialized DateTime object. # THE DATETIME PROJECT ECOSYSTEM This module is part of a larger ecosystem of modules in the DateTime family. ## [DateTime::Set](https://metacpan.org/pod/DateTime::Set) The [DateTime::Set](https://metacpan.org/pod/DateTime::Set) module represents sets (including recurrences) of datetimes. Many modules return sets or recurrences. ## Format Modules The various format modules exist to parse and format datetimes. For example, [DateTime::Format::HTTP](https://metacpan.org/pod/DateTime::Format::HTTP) parses dates according to the RFC 1123 format: my $datetime = DateTime::Format::HTTP->parse_datetime('Thu Feb 3 17:03:55 GMT 1994'); print DateTime::Format::HTTP->format_datetime($datetime); Most format modules are suitable for use as a `formatter` with a DateTime object. All format modules start with `DateTime::Format::`. ## Calendar Modules There are a number of modules on CPAN that implement non-Gregorian calendars, such as the Chinese, Mayan, and Julian calendars. All calendar modules start with `DateTime::Calendar::`. ## Event Modules There are a number of modules that calculate the dates for events, such as Easter, Sunrise, etc. All event modules start with `DateTime::Event::`. ## Others There are many other modules that work with DateTime, including modules in the `DateTimeX` namespace, as well as others. See the [datetime wiki](http://datetime.perl.org) and [search.cpan.org](http://search.cpan.org/search?query=datetime&mode=dist) for more details. # KNOWN BUGS The tests in `20infinite.t` seem to fail on some machines, particularly on Win32. This appears to be related to Perl's internal handling of IEEE infinity and NaN, and seems to be highly platform/compiler/phase of moon dependent. If you don't plan to use infinite datetimes you can probably ignore this. This will be fixed (perhaps) in future versions. # SEE ALSO [A Date with Perl](http://www.houseabsolute.com/presentations/a-date-with-perl/) - a talk I've given at a few YAPCs. [datetime@perl.org mailing list](http://lists.perl.org/list/datetime.html) [http://datetime.perl.org/](http://datetime.perl.org/) # SUPPORT Bugs may be submitted at [https://github.com/houseabsolute/DateTime.pm/issues](https://github.com/houseabsolute/DateTime.pm/issues). There is a mailing list available for users of this distribution, [mailto:datetime@perl.org](mailto:datetime@perl.org). I am also usually active on IRC as 'autarch' on `irc://irc.perl.org`. # SOURCE The source code repository for DateTime can be found at [https://github.com/houseabsolute/DateTime.pm](https://github.com/houseabsolute/DateTime.pm). # DONATIONS If you'd like to thank me for the work I've done on this module, please consider making a "donation" to me via PayPal. I spend a lot of free time creating free software, and would appreciate any support you'd care to offer. Please note that **I am not suggesting that you must do this** in order for me to continue working on this particular software. I will continue to do so, inasmuch as I have in the past, for as long as it interests me. Similarly, a donation made in this way will probably not make me work on this software much more, unless I get so many donations that I can consider working on free software full time (let's all have a chuckle at that together). To donate, log into PayPal and send money to autarch@urth.org, or use the button at [http://www.urth.org/~autarch/fs-donation.html](http://www.urth.org/~autarch/fs-donation.html). # AUTHOR Dave Rolsky # CONTRIBUTORS - Ben Bennett - Christian Hansen - Daisuke Maki - Dan Book - Dan Stewart - David E. Wheeler - David Precious - Doug Bell - Flávio Soibelmann Glock - Gianni Ceccarelli - Gregory Oschwald - Hauke D - Iain Truskett <deceased> - Jason McIntosh - Joshua Hoblitt - Karen Etheridge - Michael Conrad - Michael R. Davis - Mohammad S Anwar - M Somerville - Nick Tonkin <1nickt@users.noreply.github.com> - Olaf Alders - Ovid <curtis\_ovid\_poe@yahoo.com> - Paul Howarth - Philippe Bruhat (BooK) - Ricardo Signes - Richard Bowen - Ron Hill - Sam Kington - viviparous <viviparous@prc> # COPYRIGHT AND LICENSE This software is Copyright (c) 2003 - 2019 by Dave Rolsky. This is free software, licensed under: The Artistic License 2.0 (GPL Compatible) The full text of the license can be found in the `LICENSE` file included with this distribution. DateTime-1.51/TODO0000644000175000017500000000120413457144251013467 0ustar autarchautarchTODO list for Perl module DateTime - what's the relation between UT1 and MJD/JD ? see: http://hpiers.obspm.fr/eop-pc/earthor/utc/leapsecond.html * strftime method - more tests for other languages * sub-second resolution - more tests: add/subtract/compare * Other - document RD days/seconds(/nanosecs?) in a separate document that will be the reference for DateTime.pm internals, as well as being useful for other calendar implementors. - thorough tests for subtraction & addition overloading NOTE TO FUTURE DEVELOPERS: Attempting to implement add_duration in XS actually seemed to slow date math operations down. Sad but true. DateTime-1.51/DateTime.xs0000644000175000017500000001546513457144251015065 0ustar autarchautarch#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #define NEED_sv_2pv_flags #include "ppport.h" #include /* This file is generated by tools/leap_seconds_header.pl */ #include "leap_seconds.h" /* This is a temporary hack until a better solution can be found to get the finite() function on Win32 */ #ifndef WIN32 # include # ifndef isfinite # ifdef finite # define finite isfinite # endif # endif #endif #define DAYS_PER_400_YEARS 146097 #define DAYS_PER_4_YEARS 1461 #define MARCH_1 306 #define SECONDS_PER_DAY 86400 const int PREVIOUS_MONTH_DOY[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; const int PREVIOUS_MONTH_DOLY[12] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; IV _real_is_leap_year(IV y) { /* See http://www.perlmonks.org/?node_id=274247 for where this silliness comes from */ return (y % 4) ? 0 : (y % 100) ? 1 : (y % 400) ? 0 : 1; } MODULE = DateTime PACKAGE = DateTime PROTOTYPES: ENABLE void _rd2ymd(self, d, extra = 0) IV d; IV extra; PREINIT: IV y, m; IV c; IV quarter; IV yadj = 0; IV dow, doy, doq; IV rd_days; PPCODE: rd_days = d; d += MARCH_1; if (d <= 0) { yadj = -1 * (((-1 * d) / DAYS_PER_400_YEARS) + 1); d -= yadj * DAYS_PER_400_YEARS; } /* c is century */ c = ((d * 4) - 1) / DAYS_PER_400_YEARS; d -= c * DAYS_PER_400_YEARS / 4; y = ((d * 4) - 1) / DAYS_PER_4_YEARS; d -= y * DAYS_PER_4_YEARS / 4; m = ((d * 12) + 1093) / 367; d -= ((m * 367) - 1094) / 12; y += (c * 100) + (yadj * 400); if (m > 12) { ++y; m -= 12; } EXTEND(SP, extra ? 7 : 3); mPUSHi(y); mPUSHi(m); mPUSHi(d); if (extra) { quarter = ( ( 1.0 / 3.1 ) * m ) + 1; dow = rd_days % 7; if ( dow <= 0 ) { dow += 7; } mPUSHi(dow); if (_real_is_leap_year(y)) { doy = PREVIOUS_MONTH_DOLY[m - 1] + d; doq = doy - PREVIOUS_MONTH_DOLY[ (3 * quarter) - 3 ]; } else { doy = PREVIOUS_MONTH_DOY[m - 1] + d; doq = doy - PREVIOUS_MONTH_DOY[ (3 * quarter ) - 3 ]; } mPUSHi(doy); mPUSHi(quarter); mPUSHi(doq); } void _ymd2rd(self, y, m, d) IV y; IV m; IV d; PREINIT: IV adj; PPCODE: if (m <= 2) { adj = (14 - m) / 12; y -= adj; m += 12 * adj; } else if (m > 14) { adj = (m - 3) / 12; y += adj; m -= 12 * adj; } if (y < 0) { adj = (399 - y) / 400; d -= DAYS_PER_400_YEARS * adj; y += 400 * adj; } d += (m * 367 - 1094) / 12 + y % 100 * DAYS_PER_4_YEARS / 4 + (y / 100 * 36524 + y / 400) - MARCH_1; EXTEND(SP, 1); mPUSHi(d); void _seconds_as_components(self, secs, utc_secs = 0, secs_modifier = 0) IV secs; IV utc_secs; IV secs_modifier; PREINIT: IV h, m, s; PPCODE: secs -= secs_modifier; h = secs / 3600; secs -= h * 3600; m = secs / 60; s = secs - (m * 60); if (utc_secs >= SECONDS_PER_DAY) { if (utc_secs >= SECONDS_PER_DAY + 1) { /* If we just use %d and the IV, we get a warning that IV is not an int. */ croak("Invalid UTC RD seconds value: %s", SvPV_nolen(newSViv(utc_secs))); } s += (utc_secs - SECONDS_PER_DAY) + 60; m = 59; h--; if (h < 0) { h = 23; } } EXTEND(SP, 3); mPUSHi(h); mPUSHi(m); mPUSHi(s); #ifdef isfinite void _normalize_tai_seconds(self, days, secs) SV* days; SV* secs; PPCODE: if (isfinite(SvNV(days)) && isfinite(SvNV(secs))) { IV d = SvIV(days); IV s = SvIV(secs); IV adj; if (s < 0) { adj = (s - (SECONDS_PER_DAY - 1)) / SECONDS_PER_DAY; } else { adj = s / SECONDS_PER_DAY; } d += adj; s -= adj * SECONDS_PER_DAY; sv_setiv(days, (IV) d); sv_setiv(secs, (IV) s); } void _normalize_leap_seconds(self, days, secs) SV* days; SV* secs; PPCODE: if (isfinite(SvNV(days)) && isfinite(SvNV(secs))) { IV d = SvIV(days); IV s = SvIV(secs); IV day_length; while (s < 0) { SET_DAY_LENGTH(d - 1, day_length); s += day_length; d--; } SET_DAY_LENGTH(d, day_length); while (s > day_length - 1) { s -= day_length; d++; SET_DAY_LENGTH(d, day_length); } sv_setiv(days, (IV) d); sv_setiv(secs, (IV) s); } #endif /* ifdef isfinite */ void _time_as_seconds(self, h, m, s) IV h; IV m; IV s; PPCODE: EXTEND(SP, 1); mPUSHi(h * 3600 + m * 60 + s); void _is_leap_year(self, y) IV y; PPCODE: EXTEND(SP, 1); mPUSHi(_real_is_leap_year(y)); void _day_length(self, utc_rd) IV utc_rd; PPCODE: IV day_length; SET_DAY_LENGTH(utc_rd, day_length); EXTEND(SP, 1); mPUSHi(day_length); void _day_has_leap_second(self, utc_rd) IV utc_rd; PPCODE: IV day_length; SET_DAY_LENGTH(utc_rd, day_length); EXTEND(SP, 1); mPUSHi(day_length > 86400 ? 1 : 0); void _accumulated_leap_seconds(self, utc_rd) IV utc_rd; PPCODE: IV leap_seconds; SET_LEAP_SECONDS(utc_rd, leap_seconds); EXTEND(SP, 1); mPUSHi(leap_seconds); DateTime-1.51/perltidyrc0000644000175000017500000000045513457144251015112 0ustar autarchautarch-l=78 -i=4 -ci=4 -se -b -bar -boc -vt=0 -vtc=0 -cti=0 -pt=1 -bt=1 -sbt=1 -bbt=1 -nolq -npro -nsfs --blank-lines-before-packages=0 --opening-hash-brace-right --no-outdent-long-comments --iterations=2 -wbb="% + - * / x != == >= <= =~ !~ < > | & >= < = **= += *= &= <<= &&= -= /= |= >>= ||= .= %= ^= x=" DateTime-1.51/META.json0000644000175000017500000012563313457144251014435 0ustar autarchautarch{ "abstract" : "A date and time object for Perl", "author" : [ "Dave Rolsky " ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 6.012, CPAN::Meta::Converter version 2.150010", "license" : [ "artistic_2" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "DateTime", "prereqs" : { "configure" : { "requires" : { "Dist::CheckConflicts" : "0.02", "ExtUtils::MakeMaker" : "0" }, "suggests" : { "JSON::PP" : "2.27300" } }, "develop" : { "requires" : { "Code::TidyAll" : "0.56", "Code::TidyAll::Plugin::SortLines::Naturally" : "0.000003", "Code::TidyAll::Plugin::Test::Vars" : "0.02", "Cwd" : "0", "Devel::PPPort" : "3.23", "Module::Implementation" : "0", "Parallel::ForkManager" : "1.19", "Perl::Critic" : "1.126", "Perl::Tidy" : "20160302", "Pod::Coverage::TrustPod" : "0", "Pod::Wordlist" : "0", "Storable" : "0", "Test::CPAN::Changes" : "0.19", "Test::CPAN::Meta::JSON" : "0.16", "Test::CleanNamespaces" : "0.15", "Test::Code::TidyAll" : "0.50", "Test::DependentModules" : "0", "Test::EOL" : "0", "Test::Fatal" : "0", "Test::Mojibake" : "0", "Test::More" : "0.96", "Test::NoTabs" : "0", "Test::Pod" : "1.41", "Test::Pod::Coverage" : "1.08", "Test::Portability::Files" : "0", "Test::Spelling" : "0.12", "Test::Vars" : "0.009", "Test::Version" : "2.05", "Test::Warnings" : "0.005", "autodie" : "0", "utf8" : "0" } }, "runtime" : { "requires" : { "Carp" : "0", "DateTime::Locale" : "1.06", "DateTime::TimeZone" : "2.02", "Dist::CheckConflicts" : "0.02", "POSIX" : "0", "Params::ValidationCompiler" : "0.26", "Scalar::Util" : "0", "Specio" : "0.18", "Specio::Declare" : "0", "Specio::Exporter" : "0", "Specio::Library::Builtins" : "0", "Specio::Library::Numeric" : "0", "Specio::Library::String" : "0", "Try::Tiny" : "0", "XSLoader" : "0", "base" : "0", "integer" : "0", "namespace::autoclean" : "0.19", "overload" : "0", "parent" : "0", "perl" : "5.008004", "strict" : "0", "warnings" : "0", "warnings::register" : "0" } }, "test" : { "recommends" : { "CPAN::Meta" : "2.120900" }, "requires" : { "CPAN::Meta::Check" : "0.011", "CPAN::Meta::Requirements" : "0", "ExtUtils::MakeMaker" : "0", "File::Spec" : "0", "Storable" : "0", "Test::Fatal" : "0", "Test::More" : "0.96", "Test::Warnings" : "0.005", "utf8" : "0" } } }, "provides" : { "DateTime" : { "file" : "lib/DateTime.pm", "version" : "1.51" }, "DateTime::Duration" : { "file" : "lib/DateTime/Duration.pm", "version" : "1.51" }, "DateTime::Helpers" : { "file" : "lib/DateTime/Helpers.pm", "version" : "1.51" }, "DateTime::Infinite" : { "file" : "lib/DateTime/Infinite.pm", "version" : "1.51" }, "DateTime::Infinite::Future" : { "file" : "lib/DateTime/Infinite.pm", "version" : "1.51" }, "DateTime::Infinite::Past" : { "file" : "lib/DateTime/Infinite.pm", "version" : "1.51" }, "DateTime::LeapSecond" : { "file" : "lib/DateTime/LeapSecond.pm", "version" : "1.51" }, "DateTime::PP" : { "file" : "lib/DateTime/PP.pm", "version" : "1.51" }, "DateTime::PPExtra" : { "file" : "lib/DateTime/PPExtra.pm", "version" : "1.51" }, "DateTime::Types" : { "file" : "lib/DateTime/Types.pm", "version" : "1.51" } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/houseabsolute/DateTime.pm/issues" }, "homepage" : "http://metacpan.org/release/DateTime", "repository" : { "type" : "git", "url" : "git://github.com/houseabsolute/DateTime.pm.git", "web" : "https://github.com/houseabsolute/DateTime.pm" }, "x_MailingList" : "datetime@perl.org" }, "version" : "1.51", "x_Dist_Zilla" : { "perl" : { "version" : "5.026002" }, "plugins" : [ { "class" : "Dist::Zilla::Plugin::PruneCruft", "name" : "PruneCruft", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::Git::GatherDir", "config" : { "Dist::Zilla::Plugin::GatherDir" : { "exclude_filename" : [ "CODE_OF_CONDUCT.md", "CONTRIBUTING.md", "LICENSE", "Makefile.PL", "README.md", "cpanfile", "leap_seconds.h", "ppport.h" ], "exclude_match" : [], "follow_symlinks" : 0, "include_dotfiles" : 0, "prefix" : "", "prune_directory" : [], "root" : "." }, "Dist::Zilla::Plugin::Git::GatherDir" : { "include_untracked" : 0 } }, "name" : "@DROLSKY/Git::GatherDir", "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::ManifestSkip", "name" : "@DROLSKY/ManifestSkip", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::License", "name" : "@DROLSKY/License", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::ExecDir", "name" : "@DROLSKY/ExecDir", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::ShareDir", "name" : "@DROLSKY/ShareDir", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::Manifest", "name" : "@DROLSKY/Manifest", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::CheckVersionIncrement", "name" : "@DROLSKY/CheckVersionIncrement", "version" : "0.121750" }, { "class" : "Dist::Zilla::Plugin::TestRelease", "name" : "@DROLSKY/TestRelease", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::ConfirmRelease", "name" : "@DROLSKY/ConfirmRelease", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::UploadToCPAN", "name" : "@DROLSKY/UploadToCPAN", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::VersionFromMainModule", "config" : { "Dist::Zilla::Role::ModuleMetadata" : { "Module::Metadata" : "1.000033", "version" : "0.006" } }, "name" : "@DROLSKY/VersionFromMainModule", "version" : "0.04" }, { "class" : "Dist::Zilla::Plugin::Authority", "name" : "@DROLSKY/Authority", "version" : "1.009" }, { "class" : "Dist::Zilla::Plugin::AutoPrereqs", "name" : "@DROLSKY/AutoPrereqs", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::CopyFilesFromBuild", "name" : "@DROLSKY/CopyFilesFromBuild", "version" : "0.170880" }, { "class" : "Dist::Zilla::Plugin::GitHub::Meta", "name" : "@DROLSKY/GitHub::Meta", "version" : "0.47" }, { "class" : "Dist::Zilla::Plugin::GitHub::Update", "config" : { "Dist::Zilla::Plugin::GitHub::Update" : { "metacpan" : 1 } }, "name" : "@DROLSKY/GitHub::Update", "version" : "0.47" }, { "class" : "Dist::Zilla::Plugin::MetaResources", "name" : "@DROLSKY/MetaResources", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::MetaProvides::Package", "config" : { "Dist::Zilla::Plugin::MetaProvides::Package" : { "finder_objects" : [ { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : "@DROLSKY/MetaProvides::Package/AUTOVIV/:InstallModulesPM", "version" : "6.012" } ], "include_underscores" : 0 }, "Dist::Zilla::Role::MetaProvider::Provider" : { "$Dist::Zilla::Role::MetaProvider::Provider::VERSION" : "2.002004", "inherit_missing" : 1, "inherit_version" : 1, "meta_noindex" : 1 }, "Dist::Zilla::Role::ModuleMetadata" : { "Module::Metadata" : "1.000033", "version" : "0.006" } }, "name" : "@DROLSKY/MetaProvides::Package", "version" : "2.004003" }, { "class" : "Dist::Zilla::Plugin::Meta::Contributors", "name" : "@DROLSKY/Meta::Contributors", "version" : "0.003" }, { "class" : "Dist::Zilla::Plugin::MetaConfig", "name" : "@DROLSKY/MetaConfig", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::MetaJSON", "name" : "@DROLSKY/MetaJSON", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::MetaYAML", "name" : "@DROLSKY/MetaYAML", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::NextRelease", "name" : "@DROLSKY/NextRelease", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::Prereqs", "config" : { "Dist::Zilla::Plugin::Prereqs" : { "phase" : "test", "type" : "requires" } }, "name" : "@DROLSKY/Test::More with subtest", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::Prereqs", "config" : { "Dist::Zilla::Plugin::Prereqs" : { "phase" : "develop", "type" : "requires" } }, "name" : "@DROLSKY/Modules for use with tidyall", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::Prereqs", "config" : { "Dist::Zilla::Plugin::Prereqs" : { "phase" : "develop", "type" : "requires" } }, "name" : "@DROLSKY/Test::Version which fixes https://github.com/plicease/Test-Version/issues/7", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::PromptIfStale", "config" : { "Dist::Zilla::Plugin::PromptIfStale" : { "check_all_plugins" : 0, "check_all_prereqs" : 0, "modules" : [ "Dist::Zilla::PluginBundle::DROLSKY" ], "phase" : "build", "run_under_travis" : 0, "skip" : [] } }, "name" : "@DROLSKY/Dist::Zilla::PluginBundle::DROLSKY", "version" : "0.055" }, { "class" : "Dist::Zilla::Plugin::PromptIfStale", "config" : { "Dist::Zilla::Plugin::PromptIfStale" : { "check_all_plugins" : 1, "check_all_prereqs" : 1, "modules" : [], "phase" : "release", "run_under_travis" : 0, "skip" : [ "Dist::Zilla::Plugin::DROLSKY::Contributors", "Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch", "Dist::Zilla::Plugin::DROLSKY::License", "Dist::Zilla::Plugin::DROLSKY::TidyAll", "Dist::Zilla::Plugin::DROLSKY::WeaverConfig", "Pod::Weaver::PluginBundle::DROLSKY" ] } }, "name" : "@DROLSKY/PromptIfStale", "version" : "0.055" }, { "class" : "Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable", "name" : "@DROLSKY/Test::Pod::Coverage::Configurable", "version" : "0.07" }, { "class" : "Dist::Zilla::Plugin::Test::PodSpelling", "config" : { "Dist::Zilla::Plugin::Test::PodSpelling" : { "directories" : [ "bin", "lib" ], "spell_cmd" : "", "stopwords" : [ "AEST", "Anno", "BCE", "CLDR", "CPAN", "DATETIME", "DROLSKY", "DROLSKY's", "DateTime", "DateTimes", "Datetime", "Datetimes", "Domini", "EEEE", "EEEEE", "Fl\u00e1vio", "Formatters", "GGGG", "GGGGG", "Glock", "Hant", "IEEE", "IEEE", "LLL", "LLLL", "LLLLL", "Liang", "Liang's", "MMM", "MMMM", "MMMMM", "Measham", "Measham's", "POSIX", "PayPal", "PayPal", "QQQ", "QQQQ", "Rata", "Rata", "Rolsky", "Rolsky's", "SU", "Soibelmann", "Storable", "TW", "TZ", "Tsai", "UTC", "VVVV", "YAPCs", "ZZZZ", "ZZZZZ", "afterwards", "bian", "ccc", "cccc", "ccccc", "conformant", "datetime", "datetime's", "datetimes", "decrement", "dian", "drolsky", "durations", "eee", "eeee", "eeeee", "fallback", "formatter", "hh", "iCal", "ji", "mutiplication", "na", "namespace", "ni", "nitty", "other's", "proleptic", "qqq", "qqqq", "sexagesimal", "subclasses", "uu", "vvvv", "wiki", "yy", "yyyy", "yyyyy", "zh", "zzzz" ], "wordlist" : "Pod::Wordlist" } }, "name" : "@DROLSKY/Test::PodSpelling", "version" : "2.007005" }, { "class" : "Dist::Zilla::Plugin::PodSyntaxTests", "name" : "@DROLSKY/PodSyntaxTests", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::DROLSKY::RunExtraTests", "config" : { "Dist::Zilla::Role::TestRunner" : { "default_jobs" : 24 } }, "name" : "@DROLSKY/DROLSKY::RunExtraTests", "version" : "1.01" }, { "class" : "Dist::Zilla::Plugin::MojibakeTests", "name" : "@DROLSKY/MojibakeTests", "version" : "0.8" }, { "class" : "Dist::Zilla::Plugin::Test::CleanNamespaces", "config" : { "Dist::Zilla::Plugin::Test::CleanNamespaces" : { "filename" : "xt/author/clean-namespaces.t", "skips" : [ "DateTime::Conflicts" ] } }, "name" : "@DROLSKY/Test::CleanNamespaces", "version" : "0.006" }, { "class" : "Dist::Zilla::Plugin::Test::CPAN::Changes", "config" : { "Dist::Zilla::Plugin::Test::CPAN::Changes" : { "changelog" : "Changes" } }, "name" : "@DROLSKY/Test::CPAN::Changes", "version" : "0.012" }, { "class" : "Dist::Zilla::Plugin::Test::CPAN::Meta::JSON", "name" : "@DROLSKY/Test::CPAN::Meta::JSON", "version" : "0.004" }, { "class" : "Dist::Zilla::Plugin::Test::EOL", "config" : { "Dist::Zilla::Plugin::Test::EOL" : { "filename" : "xt/author/eol.t", "finder" : [ ":ExecFiles", ":InstallModules", ":TestFiles" ], "trailing_whitespace" : 1 } }, "name" : "@DROLSKY/Test::EOL", "version" : "0.19" }, { "class" : "Dist::Zilla::Plugin::Test::NoTabs", "config" : { "Dist::Zilla::Plugin::Test::NoTabs" : { "filename" : "xt/author/no-tabs.t", "finder" : [ ":InstallModules", ":ExecFiles", ":TestFiles" ] } }, "name" : "@DROLSKY/Test::NoTabs", "version" : "0.15" }, { "class" : "Dist::Zilla::Plugin::Test::Portability", "config" : { "Dist::Zilla::Plugin::Test::Portability" : { "options" : "" } }, "name" : "@DROLSKY/Test::Portability", "version" : "2.001000" }, { "class" : "Dist::Zilla::Plugin::Test::TidyAll", "name" : "@DROLSKY/Test::TidyAll", "version" : "0.04" }, { "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs", "name" : "@DROLSKY/Test::ReportPrereqs", "version" : "0.027" }, { "class" : "Dist::Zilla::Plugin::Test::Version", "name" : "@DROLSKY/Test::Version", "version" : "1.09" }, { "class" : "Dist::Zilla::Plugin::DROLSKY::Contributors", "name" : "@DROLSKY/DROLSKY::Contributors", "version" : "1.01" }, { "class" : "Dist::Zilla::Plugin::Git::Contributors", "config" : { "Dist::Zilla::Plugin::Git::Contributors" : { "git_version" : "2.20.1", "include_authors" : 0, "include_releaser" : 1, "order_by" : "name", "paths" : [] } }, "name" : "@DROLSKY/Git::Contributors", "version" : "0.035" }, { "class" : "Dist::Zilla::Plugin::SurgicalPodWeaver", "config" : { "Dist::Zilla::Plugin::PodWeaver" : { "config_plugins" : [ "@DROLSKY" ], "finder" : [ ":InstallModules", ":ExecFiles" ], "plugins" : [ { "class" : "Pod::Weaver::Plugin::EnsurePod5", "name" : "@CorePrep/EnsurePod5", "version" : "4.015" }, { "class" : "Pod::Weaver::Plugin::H1Nester", "name" : "@CorePrep/H1Nester", "version" : "4.015" }, { "class" : "Pod::Weaver::Plugin::SingleEncoding", "name" : "@DROLSKY/SingleEncoding", "version" : "4.015" }, { "class" : "Pod::Weaver::Plugin::Transformer", "name" : "@DROLSKY/List", "version" : "4.015" }, { "class" : "Pod::Weaver::Plugin::Transformer", "name" : "@DROLSKY/Verbatim", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Region", "name" : "@DROLSKY/header", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Name", "name" : "@DROLSKY/Name", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Version", "name" : "@DROLSKY/Version", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Region", "name" : "@DROLSKY/prelude", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Generic", "name" : "SYNOPSIS", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Generic", "name" : "DESCRIPTION", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Generic", "name" : "OVERVIEW", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "ATTRIBUTES", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "METHODS", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "FUNCTIONS", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "TYPES", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Leftovers", "name" : "@DROLSKY/Leftovers", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Region", "name" : "@DROLSKY/postlude", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::GenerateSection", "name" : "@DROLSKY/generate SUPPORT", "version" : "1.06" }, { "class" : "Pod::Weaver::Section::AllowOverride", "name" : "@DROLSKY/allow override SUPPORT", "version" : "0.05" }, { "class" : "Pod::Weaver::Section::GenerateSection", "name" : "@DROLSKY/generate SOURCE", "version" : "1.06" }, { "class" : "Pod::Weaver::Section::GenerateSection", "name" : "@DROLSKY/generate DONATIONS", "version" : "1.06" }, { "class" : "Pod::Weaver::Section::Authors", "name" : "@DROLSKY/Authors", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Contributors", "name" : "@DROLSKY/Contributors", "version" : "0.009" }, { "class" : "Pod::Weaver::Section::Legal", "name" : "@DROLSKY/Legal", "version" : "4.015" }, { "class" : "Pod::Weaver::Section::Region", "name" : "@DROLSKY/footer", "version" : "4.015" } ] } }, "name" : "@DROLSKY/SurgicalPodWeaver", "version" : "0.0023" }, { "class" : "Dist::Zilla::Plugin::DROLSKY::WeaverConfig", "name" : "@DROLSKY/DROLSKY::WeaverConfig", "version" : "1.01" }, { "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod", "config" : { "Dist::Zilla::Role::FileWatcher" : { "version" : "0.006" } }, "name" : "@DROLSKY/README.md in build", "version" : "0.163250" }, { "class" : "Dist::Zilla::Plugin::GenerateFile::FromShareDir", "config" : { "Dist::Zilla::Plugin::GenerateFile::FromShareDir" : { "destination_filename" : "CONTRIBUTING.md", "dist" : "Dist-Zilla-PluginBundle-DROLSKY", "encoding" : "UTF-8", "has_xs" : 1, "location" : "build", "source_filename" : "CONTRIBUTING.md" }, "Dist::Zilla::Role::RepoFileInjector" : { "allow_overwrite" : 1, "repo_root" : ".", "version" : "0.009" } }, "name" : "@DROLSKY/Generate CONTRIBUTING.md", "version" : "0.014" }, { "class" : "Dist::Zilla::Plugin::GenerateFile::FromShareDir", "config" : { "Dist::Zilla::Plugin::GenerateFile::FromShareDir" : { "destination_filename" : "CODE_OF_CONDUCT.md", "dist" : "Dist-Zilla-PluginBundle-DROLSKY", "encoding" : "UTF-8", "has_xs" : 1, "location" : "build", "source_filename" : "CODE_OF_CONDUCT.md" }, "Dist::Zilla::Role::RepoFileInjector" : { "allow_overwrite" : 1, "repo_root" : ".", "version" : "0.009" } }, "name" : "@DROLSKY/Generate CODE_OF_CONDUCT.md", "version" : "0.014" }, { "class" : "Dist::Zilla::Plugin::InstallGuide", "config" : { "Dist::Zilla::Role::ModuleMetadata" : { "Module::Metadata" : "1.000033", "version" : "0.006" } }, "name" : "@DROLSKY/InstallGuide", "version" : "1.200013" }, { "class" : "Dist::Zilla::Plugin::CPANFile", "name" : "@DROLSKY/CPANFile", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::PPPort", "name" : "@DROLSKY/PPPort", "version" : "0.008" }, { "class" : "Dist::Zilla::Plugin::DROLSKY::License", "name" : "@DROLSKY/DROLSKY::License", "version" : "1.01" }, { "class" : "Dist::Zilla::Plugin::CheckStrictVersion", "name" : "@DROLSKY/CheckStrictVersion", "version" : "0.001" }, { "class" : "Dist::Zilla::Plugin::CheckSelfDependency", "config" : { "Dist::Zilla::Plugin::CheckSelfDependency" : { "finder" : [ ":InstallModules" ] }, "Dist::Zilla::Role::ModuleMetadata" : { "Module::Metadata" : "1.000033", "version" : "0.006" } }, "name" : "@DROLSKY/CheckSelfDependency", "version" : "0.011" }, { "class" : "Dist::Zilla::Plugin::CheckPrereqsIndexed", "name" : "@DROLSKY/CheckPrereqsIndexed", "version" : "0.020" }, { "class" : "Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch", "config" : { "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.20.1", "repo_root" : "." } }, "name" : "@DROLSKY/DROLSKY::Git::CheckFor::CorrectBranch", "version" : "1.01" }, { "class" : "Dist::Zilla::Plugin::EnsureChangesHasContent", "name" : "@DROLSKY/EnsureChangesHasContent", "version" : "0.02" }, { "class" : "Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts", "config" : { "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.20.1", "repo_root" : "." } }, "name" : "@DROLSKY/Git::CheckFor::MergeConflicts", "version" : "0.014" }, { "class" : "Dist::Zilla::Plugin::DROLSKY::TidyAll", "name" : "@DROLSKY/DROLSKY::TidyAll", "version" : "1.01" }, { "class" : "Dist::Zilla::Plugin::Git::Check", "config" : { "Dist::Zilla::Plugin::Git::Check" : { "untracked_files" : "die" }, "Dist::Zilla::Role::Git::DirtyFiles" : { "allow_dirty" : [ "CODE_OF_CONDUCT.md", "CONTRIBUTING.md", "Changes", "LICENSE", "Makefile.PL", "README.md", "cpanfile", "leap_seconds.h", "ppport.h", "tidyall.ini" ], "allow_dirty_match" : [], "changelog" : "Changes" }, "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.20.1", "repo_root" : "." } }, "name" : "@DROLSKY/Git::Check", "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::Git::Commit", "config" : { "Dist::Zilla::Plugin::Git::Commit" : { "add_files_in" : [], "commit_msg" : "v%V%n%n%c" }, "Dist::Zilla::Role::Git::DirtyFiles" : { "allow_dirty" : [ "CODE_OF_CONDUCT.md", "CONTRIBUTING.md", "Changes", "LICENSE", "Makefile.PL", "README.md", "cpanfile", "leap_seconds.h", "ppport.h", "tidyall.ini" ], "allow_dirty_match" : [], "changelog" : "Changes" }, "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.20.1", "repo_root" : "." }, "Dist::Zilla::Role::Git::StringFormatter" : { "time_zone" : "local" } }, "name" : "@DROLSKY/Commit generated files", "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::Git::Tag", "config" : { "Dist::Zilla::Plugin::Git::Tag" : { "branch" : null, "changelog" : "Changes", "signed" : 0, "tag" : "v1.51", "tag_format" : "v%V", "tag_message" : "v%V" }, "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.20.1", "repo_root" : "." }, "Dist::Zilla::Role::Git::StringFormatter" : { "time_zone" : "local" } }, "name" : "@DROLSKY/Git::Tag", "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::Git::Push", "config" : { "Dist::Zilla::Plugin::Git::Push" : { "push_to" : [ "origin" ], "remotes_must_exist" : 1 }, "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.20.1", "repo_root" : "." } }, "name" : "@DROLSKY/Git::Push", "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease", "config" : { "Dist::Zilla::Plugin::BumpVersionAfterRelease" : { "finders" : [ ":ExecFiles", ":InstallModules" ], "global" : 0, "munge_makefile_pl" : 1 } }, "name" : "@DROLSKY/BumpVersionAfterRelease", "version" : "0.018" }, { "class" : "Dist::Zilla::Plugin::Git::Commit", "config" : { "Dist::Zilla::Plugin::Git::Commit" : { "add_files_in" : [], "commit_msg" : "Bump version after release" }, "Dist::Zilla::Role::Git::DirtyFiles" : { "allow_dirty" : [ "Changes", "dist.ini" ], "allow_dirty_match" : [ "(?^:.+)" ], "changelog" : "Changes" }, "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.20.1", "repo_root" : "." }, "Dist::Zilla::Role::Git::StringFormatter" : { "time_zone" : "local" } }, "name" : "@DROLSKY/Commit version bump", "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::Git::Push", "config" : { "Dist::Zilla::Plugin::Git::Push" : { "push_to" : [ "origin" ], "remotes_must_exist" : 1 }, "Dist::Zilla::Role::Git::Repo" : { "git_version" : "2.20.1", "repo_root" : "." } }, "name" : "@DROLSKY/Push version bump", "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::DROLSKY::MakeMaker", "config" : { "Dist::Zilla::Plugin::MakeMaker" : { "make_path" : "make", "version" : "6.012" }, "Dist::Zilla::Plugin::MakeMaker::Awesome" : { "version" : "0.42" }, "Dist::Zilla::Role::TestRunner" : { "default_jobs" : 24, "version" : "6.012" } }, "name" : "@DROLSKY/DROLSKY::MakeMaker", "version" : "1.01" }, { "class" : "Dist::Zilla::Plugin::lib", "config" : { "Dist::Zilla::Plugin::lib" : { "lib" : [ "." ] } }, "name" : "lib", "version" : "0.001002" }, { "class" : "inc::LeapSecondsHeader", "name" : "=inc::LeapSecondsHeader", "version" : null }, { "class" : "Dist::Zilla::Plugin::CopyFilesFromBuild", "name" : "CopyFilesFromBuild", "version" : "0.170880" }, { "class" : "Dist::Zilla::Plugin::MetaResources", "name" : "MetaResources", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::Prereqs", "config" : { "Dist::Zilla::Plugin::Prereqs" : { "phase" : "develop", "type" : "requires" } }, "name" : "DevelopRequires", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::PurePerlTests", "name" : "PurePerlTests", "version" : "0.06" }, { "class" : "Dist::Zilla::Plugin::Conflicts", "name" : "Conflicts", "version" : "0.19" }, { "class" : "Dist::Zilla::Plugin::Test::CheckBreaks", "config" : { "Dist::Zilla::Plugin::Test::CheckBreaks" : { "conflicts_module" : [ "DateTime::Conflicts" ], "no_forced_deps" : 0 }, "Dist::Zilla::Role::ModuleMetadata" : { "Module::Metadata" : "1.000033", "version" : "0.006" } }, "name" : "Test::CheckBreaks", "version" : "0.019" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":InstallModules", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":IncModules", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":TestFiles", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ExtraTestFiles", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ExecFiles", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":PerlExecFiles", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ShareFiles", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":MainModule", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":AllFiles", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":NoFiles", "version" : "6.012" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : "@DROLSKY/MetaProvides::Package/AUTOVIV/:InstallModulesPM", "version" : "6.012" } ], "zilla" : { "class" : "Dist::Zilla::Dist::Builder", "config" : { "is_trial" : 0 }, "version" : "6.012" } }, "x_authority" : "cpan:DROLSKY", "x_breaks" : { "DateTime::Format::Mail" : "<= 0.402" }, "x_contributors" : [ "Ben Bennett ", "Christian Hansen ", "Daisuke Maki ", "Dan Book ", "Dan Stewart ", "David E. Wheeler ", "David Precious ", "Doug Bell ", "Fl\u00e1vio Soibelmann Glock ", "Gianni Ceccarelli ", "Gregory Oschwald ", "Hauke D ", "Iain Truskett ", "Jason McIntosh ", "Joshua Hoblitt ", "Karen Etheridge ", "Michael Conrad ", "Michael R. Davis ", "Mohammad S Anwar ", "M Somerville ", "Nick Tonkin <1nickt@users.noreply.github.com>", "Olaf Alders ", "Ovid ", "Paul Howarth ", "Philippe Bruhat (BooK) ", "Ricardo Signes ", "Richard Bowen ", "Ron Hill ", "Sam Kington ", "viviparous " ], "x_generated_by_perl" : "v5.26.2", "x_serialization_backend" : "Cpanel::JSON::XS version 4.02" } DateTime-1.51/CODE_OF_CONDUCT.md0000644000175000017500000000625413457144251015610 0ustar autarchautarch# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at autarch@urth.org. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org DateTime-1.51/inc/0000755000175000017500000000000013457144251013553 5ustar autarchautarchDateTime-1.51/inc/LeapSecondsHeader.pm0000644000175000017500000001132313457144251017422 0ustar autarchautarchpackage inc::LeapSecondsHeader; use strict; use warnings; use autodie; my $VERSION = 0.04; use Dist::Zilla::File::InMemory; use Moose; has _leap_second_data => ( is => 'ro', isa => 'HashRef', lazy => 1, builder => '_build_leap_second_data', ); with 'Dist::Zilla::Role::FileGatherer'; sub gather_files { my $self = shift; $self->add_file( Dist::Zilla::File::InMemory->new( name => 'leap_seconds.h', encoding => 'bytes', content => $self->_header, ), ); } my $x = 1; my %months = map { $_ => $x++ } qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ); sub _build_leap_second_data { my $self = shift; open my $fh, '<', 'leaptab.txt'; my @leap_seconds; my @rd; my %rd_length; my $value = -1; while (<$fh>) { my ( $year, $mon, $day, $leap_seconds ) = split /\s+/; $mon =~ s/\W//; $leap_seconds =~ s/^([+-])//; my $mult = $1 eq '+' ? 1 : -1; my $utc_epoch = _ymd2rd( $year, $months{$mon}, $day ); $value += $leap_seconds * $mult; push @leap_seconds, $value; push @rd, $utc_epoch; $rd_length{ $utc_epoch - 1 } = $leap_seconds; } close $fh; push @leap_seconds, ++$value; return { leap_seconds => \@leap_seconds, rd => \@rd, rd_length => \%rd_length, }; } sub _header { my $self = shift; my ( $leap_seconds, $rd, $rd_length ) = @{ $self->_leap_second_data }{qw( leap_seconds rd rd_length )}; my $set_leap_seconds = <<"EOF"; #define SET_LEAP_SECONDS(utc_rd, ls) \\ { \\ { \\ if (utc_rd < $rd->[0]) { \\ ls = $leap_seconds->[0]; \\ EOF for ( my $x = 1; $x < @{$rd}; $x++ ) { my $condition = $x == @{$rd} ? "utc_rd < $rd->[$x]" : "utc_rd >= $rd->[$x - 1] && utc_rd < $rd->[$x]"; $set_leap_seconds .= <<"EOF" } else if ($condition) { \\ ls = $leap_seconds->[$x]; \\ EOF } $set_leap_seconds .= <<"EOF"; } else { \\ ls = $leap_seconds->[-1]; \\ } \\ } \\ } EOF my $set_extra_seconds = <<"EOF"; #define SET_EXTRA_SECONDS(utc_rd, es) \\ { \\ { \\ es = 0; \\ switch (utc_rd) { \\ EOF my $set_day_length = <<"EOF"; #define SET_DAY_LENGTH(utc_rd, dl) \\ { \\ { \\ dl = 86400; \\ switch (utc_rd) { \\ EOF foreach my $utc_rd ( sort keys %{$rd_length} ) { $set_extra_seconds .= <<"EOF"; case $utc_rd: es = $rd_length->{$utc_rd}; break; \\ EOF $set_day_length .= <<"EOF"; case $utc_rd: dl = 86400 + $rd_length->{$utc_rd}; break; \\ EOF } $set_extra_seconds .= <<"EOF"; } \\ } \\ } EOF $set_day_length .= <<"EOF"; } \\ } \\ } EOF my $generator = ref $self; my $header = <<"EOF"; /* This file is auto-generated by the leap second code generator ($VERSION). This code generator comes with the DateTime.pm module distribution in the tools/ directory Generated $generator. Do not edit this file directly. */ EOF return join q{}, ( $header, $set_leap_seconds, $set_extra_seconds, $set_day_length, ); } # from lib/DateTimePP.pm sub _ymd2rd { use integer; my ( $y, $m, $d ) = @_; my $adj; # make month in range 3..14 (treat Jan & Feb as months 13..14 of # prev year) if ( $m <= 2 ) { $y -= ( $adj = ( 14 - $m ) / 12 ); $m += 12 * $adj; } elsif ( $m > 14 ) { $y += ( $adj = ( $m - 3 ) / 12 ); $m -= 12 * $adj; } # make year positive (oh, for a use integer 'sane_div'!) if ( $y < 0 ) { $d -= 146097 * ( $adj = ( 399 - $y ) / 400 ); $y += 400 * $adj; } # add: day of month, days of previous 0-11 month period that began # w/March, days of previous 0-399 year period that began w/March # of a 400-multiple year), days of any 400-year periods before # that, and 306 days to adjust from Mar 1, year 0-relative to Jan # 1, year 1-relative (whew) $d += ( $m * 367 - 1094 ) / 12 + $y % 100 * 1461 / 4 + ( $y / 100 * 36524 + $y / 400 ) - 306; } 1; DateTime-1.51/lib/0000755000175000017500000000000013457144251013550 5ustar autarchautarchDateTime-1.51/lib/DateTime/0000755000175000017500000000000013457144251015244 5ustar autarchautarchDateTime-1.51/lib/DateTime/Conflicts.pm0000644000175000017500000000161313457144251017527 0ustar autarchautarchpackage # hide from PAUSE DateTime::Conflicts; use strict; use warnings; # this module was generated with Dist::Zilla::Plugin::Conflicts 0.19 use Dist::CheckConflicts -dist => 'DateTime', -conflicts => { 'DateTime::Format::Mail' => '0.402', }, -also => [ qw( Carp DateTime::Locale DateTime::TimeZone Dist::CheckConflicts POSIX Params::ValidationCompiler Scalar::Util Specio Specio::Declare Specio::Exporter Specio::Library::Builtins Specio::Library::Numeric Specio::Library::String Try::Tiny XSLoader base integer namespace::autoclean overload parent strict warnings warnings::register ) ], ; 1; # ABSTRACT: Provide information on conflicts for DateTime # Dist::Zilla: -PodWeaver DateTime-1.51/lib/DateTime/Helpers.pm0000644000175000017500000000061413457144251017205 0ustar autarchautarchpackage DateTime::Helpers; use strict; use warnings; our $VERSION = '1.51'; use Scalar::Util (); sub can { my $object = shift; my $method = shift; return unless Scalar::Util::blessed($object); return $object->can($method); } sub isa { my $object = shift; my $method = shift; return unless Scalar::Util::blessed($object); return $object->isa($method); } 1; DateTime-1.51/lib/DateTime/PPExtra.pm0000644000175000017500000000330413457144251017125 0ustar autarchautarchpackage DateTime::PPExtra; use strict; use warnings; our $VERSION = '1.51'; use DateTime::LeapSecond; ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines) sub _normalize_tai_seconds { return if grep { $_ == DateTime::INFINITY() || $_ == DateTime::NEG_INFINITY() } @_[ 1, 2 ]; # This must be after checking for infinity, because it breaks in # presence of use integer ! use integer; my $adj; if ( $_[2] < 0 ) { $adj = ( $_[2] - 86399 ) / 86400; } else { $adj = $_[2] / 86400; } $_[1] += $adj; $_[2] -= $adj * 86400; } sub _normalize_leap_seconds { # args: 0 => days, 1 => seconds my $delta_days; use integer; # rough adjust - can adjust many days if ( $_[2] < 0 ) { $delta_days = ( $_[2] - 86399 ) / 86400; } else { $delta_days = $_[2] / 86400; } my $new_day = $_[1] + $delta_days; my $delta_seconds = ( 86400 * $delta_days ) + DateTime::LeapSecond::leap_seconds($new_day) - DateTime::LeapSecond::leap_seconds( $_[1] ); $_[2] -= $delta_seconds; $_[1] = $new_day; # fine adjust - up to 1 day my $day_length = DateTime::LeapSecond::day_length($new_day); if ( $_[2] >= $day_length ) { $_[2] -= $day_length; $_[1]++; } elsif ( $_[2] < 0 ) { $day_length = DateTime::LeapSecond::day_length( $new_day - 1 ); $_[2] += $day_length; $_[1]--; } } my @subs = qw( _normalize_tai_seconds _normalize_leap_seconds ); for my $sub (@subs) { ## no critic (TestingAndDebugging::ProhibitNoStrict) no strict 'refs'; *{ 'DateTime::' . $sub } = __PACKAGE__->can($sub); } 1; DateTime-1.51/lib/DateTime/Infinite.pm0000644000175000017500000001367013457144251017356 0ustar autarchautarch## no critic (Modules::ProhibitMultiplePackages) package DateTime::Infinite; use strict; use warnings; use namespace::autoclean; our $VERSION = '1.51'; use DateTime; use DateTime::TimeZone; use base qw(DateTime); foreach my $m (qw( set set_time_zone truncate )) { ## no critic (TestingAndDebugging::ProhibitNoStrict) no strict 'refs'; *{"DateTime::Infinite::$m"} = sub { return $_[0] }; } sub is_finite {0} sub is_infinite {1} ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines) sub _rd2ymd { return $_[2] ? ( $_[1] ) x 7 : ( $_[1] ) x 3; } sub _seconds_as_components { return ( $_[1] ) x 3; } sub ymd { return $_[0]->iso8601; } sub mdy { return $_[0]->iso8601; } sub dmy { return $_[0]->iso8601; } sub hms { return $_[0]->iso8601; } sub hour_12 { return $_[0]->_infinity_string; } sub hour_12_0 { return $_[0]->_infinity_string; } sub datetime { return $_[0]->_infinity_string; } sub stringify { return $_[0]->_infinity_string; } sub _infinity_string { return $_[0]->{utc_rd_days} == DateTime::INFINITY ? DateTime::INFINITY . q{} : DateTime::NEG_INFINITY . q{}; } sub _week_values { [ $_[0]->{utc_rd_days}, $_[0]->{utc_rd_days} ] } sub STORABLE_freeze {return} sub STORABLE_thaw {return} package DateTime::Infinite::Future; use strict; use warnings; use base qw(DateTime::Infinite); { my $Pos = bless { utc_rd_days => DateTime::INFINITY, utc_rd_secs => DateTime::INFINITY, local_rd_days => DateTime::INFINITY, local_rd_secs => DateTime::INFINITY, rd_nanosecs => DateTime::INFINITY, tz => DateTime::TimeZone->new( name => 'floating' ), locale => FakeLocale->instance(), }, __PACKAGE__; $Pos->_calc_utc_rd; $Pos->_calc_local_rd; sub new {$Pos} } package DateTime::Infinite::Past; use strict; use warnings; use base qw(DateTime::Infinite); { my $Neg = bless { utc_rd_days => DateTime::NEG_INFINITY, utc_rd_secs => DateTime::NEG_INFINITY, local_rd_days => DateTime::NEG_INFINITY, local_rd_secs => DateTime::NEG_INFINITY, rd_nanosecs => DateTime::NEG_INFINITY, tz => DateTime::TimeZone->new( name => 'floating' ), locale => FakeLocale->instance(), }, __PACKAGE__; $Neg->_calc_utc_rd; $Neg->_calc_local_rd; sub new {$Neg} } package # hide from PAUSE FakeLocale; use strict; use warnings; use DateTime::Locale; my $Instance; sub instance { return $Instance ||= bless { locale => DateTime::Locale->load('en_US') }, __PACKAGE__; } sub id { return 'infinite'; } sub language_id { return 'infinite'; } sub name { 'Fake locale for Infinite DateTime objects'; } sub language { 'Fake locale for Infinite DateTime objects'; } my @methods = qw( script_id territory_id variant_id script territory variant native_name native_language native_script native_territory native_variant ); for my $meth (@methods) { ## no critic (TestingAndDebugging::ProhibitNoStrict) no strict 'refs'; *{$meth} = sub {undef}; } # Totally arbitrary sub first_day_of_week { return 1; } sub prefers_24_hour_time { return 0; } our $AUTOLOAD; ## no critic (ClassHierarchies::ProhibitAutoloading) sub AUTOLOAD { my $self = shift; my ($meth) = $AUTOLOAD =~ /::(\w+)$/; if ( $meth =~ /format/ && $meth !~ /^(?:day|month|quarter)/ ) { return $self->{locale}->$meth(@_); } return []; } 1; # ABSTRACT: Infinite past and future DateTime objects __END__ =pod =encoding UTF-8 =head1 NAME DateTime::Infinite - Infinite past and future DateTime objects =head1 VERSION version 1.51 =head1 SYNOPSIS my $future = DateTime::Infinite::Future->new(); my $past = DateTime::Infinite::Past->new(); =head1 DESCRIPTION This module provides two L subclasses, C and C. The objects are in the "floating" timezone, and this cannot be changed. =head1 METHODS The only constructor for these two classes is the C method, as shown in the L. This method takes no parameters. All "get" methods in this module simply return infinity, positive or negative. If the method is expected to return a string, it returns the string representation of positive or negative infinity used by your system. For example, on my system calling C returns a number which when printed appears either "Inf" or "-Inf". This also applies to methods that are compound stringifications, which return the same strings even for things like C or C The object is not mutable, so the C, C, and C methods are all do-nothing methods that simply return the object they are called with. Obviously, the C method returns false and the C method returns true. =head1 SEE ALSO datetime@perl.org mailing list http://datetime.perl.org/ =head1 BUGS There seem to be lots of problems when dealing with infinite numbers on Win32. This may be a problem with this code, Perl, or Win32's IEEE math implementation. Either way, the module may not be well-behaved on Win32 operating systems. Bugs may be submitted at L. There is a mailing list available for users of this distribution, L. I am also usually active on IRC as 'autarch' on C. =head1 SOURCE The source code repository for DateTime can be found at L. =head1 AUTHOR Dave Rolsky =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2003 - 2019 by Dave Rolsky. This is free software, licensed under: The Artistic License 2.0 (GPL Compatible) The full text of the license can be found in the F file included with this distribution. =cut DateTime-1.51/lib/DateTime/LeapSecond.pm0000644000175000017500000001134013457144251017616 0ustar autarchautarchpackage DateTime::LeapSecond; use strict; use warnings; use namespace::autoclean; our $VERSION = '1.51'; our ( @RD, @LEAP_SECONDS, %RD_LENGTH ); use DateTime; # Generates a Perl binary decision tree sub _make_utx { my ( $beg, $end, $tab, $op ) = @_; my $step = int( ( $end - $beg ) / 2 ); my $tmp; if ( $step <= 0 ) { $tmp = "${tab}return $LEAP_SECONDS[$beg + 1];\n"; return $tmp; } $tmp = "${tab}if (\$val < " . $RD[ $beg + $step ] . ") {\n"; $tmp .= _make_utx( $beg, $beg + $step, $tab . q{ }, $op ); $tmp .= "${tab}}\n"; $tmp .= "${tab}else {\n"; $tmp .= _make_utx( $beg + $step, $end, $tab . q{ }, $op ); $tmp .= "${tab}}\n"; return $tmp; } # Process BEGIN data and write binary tree decision table sub _init { my $value = -1; while (@_) { my ( $year, $mon, $mday, $leap_seconds ) = ( shift, shift, shift, shift ); # print "$year,$mon,$mday\n"; ## no critic (Subroutines::ProtectPrivateSubs) my $utc_epoch = DateTime->_ymd2rd( $year, ( $mon =~ /Jan/i ? 1 : 7 ), $mday ); $value++; push @LEAP_SECONDS, $value; push @RD, $utc_epoch; $RD_LENGTH{ $utc_epoch - 1 } = $leap_seconds; # warn "$year,$mon,$mday = $utc_epoch +$value"; } push @LEAP_SECONDS, ++$value; my $tmp; # write binary tree decision table $tmp = "sub leap_seconds {\n"; $tmp .= " my \$val = shift;\n"; $tmp .= _make_utx( -1, 1 + $#RD, q{ }, '+' ); $tmp .= "}; 1\n"; # NOTE: uncomment the line below to see the code: #warn $tmp; ## no critic (BuiltinFunctions::ProhibitStringyEval) eval $tmp or die $@; } sub extra_seconds { exists $RD_LENGTH{ $_[0] } ? $RD_LENGTH{ $_[0] } : 0; } sub day_length { exists $RD_LENGTH{ $_[0] } ? 86400 + $RD_LENGTH{ $_[0] } : 86400; } sub _initialize { # There are no leap seconds before 1972, because that's the # year this system was implemented. # # year month day number-of-leapseconds # _init( qw( 1972 Jul. 1 +1 1973 Jan. 1 +1 1974 Jan. 1 +1 1975 Jan. 1 +1 1976 Jan. 1 +1 1977 Jan. 1 +1 1978 Jan. 1 +1 1979 Jan. 1 +1 1980 Jan. 1 +1 1981 Jul. 1 +1 1982 Jul. 1 +1 1983 Jul. 1 +1 1985 Jul. 1 +1 1988 Jan. 1 +1 1990 Jan. 1 +1 1991 Jan. 1 +1 1992 Jul. 1 +1 1993 Jul. 1 +1 1994 Jul. 1 +1 1996 Jan. 1 +1 1997 Jul. 1 +1 1999 Jan. 1 +1 2006 Jan. 1 +1 2009 Jan. 1 +1 2012 Jul. 1 +1 2015 Jul. 1 +1 2017 Jan. 1 +1 ) ); } __PACKAGE__->_initialize(); 1; # ABSTRACT: leap seconds table and utilities __END__ =pod =encoding UTF-8 =head1 NAME DateTime::LeapSecond - leap seconds table and utilities =head1 VERSION version 1.51 =head1 SYNOPSIS use DateTime; use DateTime::LeapSecond; print "Leap seconds between years 1990 and 2000 are "; print DateTime::Leapsecond::leap_seconds( $utc_rd_2000 ) - DateTime::Leapsecond::leap_seconds( $utc_rd_1990 ); =head1 DESCRIPTION This module is used to calculate leap seconds for a given Rata Die day. It is used when DateTime.pm cannot compile the XS version of this code. This library is known to be accurate for dates until Jun 2017. There are no leap seconds before 1972, because that's the year this system was implemented. =over 4 =item * leap_seconds( $rd ) Returns the number of accumulated leap seconds for a given day. =item * extra_seconds( $rd ) Returns the number of leap seconds for a given day, in the range -2 .. 2. =item * day_length( $rd ) Returns the number of seconds for a given day, in the range 86398 .. 86402. =back =head1 SEE ALSO L http://datetime.perl.org =head1 SUPPORT Bugs may be submitted at L. There is a mailing list available for users of this distribution, L. I am also usually active on IRC as 'autarch' on C. =head1 SOURCE The source code repository for DateTime can be found at L. =head1 AUTHOR Dave Rolsky =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2003 - 2019 by Dave Rolsky. This is free software, licensed under: The Artistic License 2.0 (GPL Compatible) The full text of the license can be found in the F file included with this distribution. =cut DateTime-1.51/lib/DateTime/PP.pm0000644000175000017500000001265413457144251016131 0ustar autarchautarchpackage DateTime::PP; use strict; use warnings; our $VERSION = '1.51'; ## no critic (Variables::ProhibitPackageVars) $DateTime::IsPurePerl = 1; ## use critic my @MonthLengths = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ); my @LeapYearMonthLengths = @MonthLengths; $LeapYearMonthLengths[1]++; my @EndOfLastMonthDayOfYear; { my $x = 0; foreach my $length (@MonthLengths) { push @EndOfLastMonthDayOfYear, $x; $x += $length; } } my @EndOfLastMonthDayOfLeapYear = @EndOfLastMonthDayOfYear; $EndOfLastMonthDayOfLeapYear[$_]++ for 2 .. 11; ## no critic (Subroutines::ProhibitUnusedPrivateSubroutines) sub _time_as_seconds { shift; my ( $hour, $min, $sec ) = @_; $hour ||= 0; $min ||= 0; $sec ||= 0; my $secs = $hour * 3600 + $min * 60 + $sec; return $secs; } sub _rd2ymd { my $class = shift; use integer; my $d = shift; my $rd = $d; my $yadj = 0; my ( $c, $y, $m ); # add 306 days to make relative to Mar 1, 0 if ( ( $d += 306 ) <= 0 ) { # avoid ambiguity in C division of negatives $yadj = -( -$d / 146097 + 1 ); $d -= $yadj * 146097; } $c = ( $d * 4 - 1 ) / 146097; # calc # of centuries $d is after 29 Feb of yr 0 $d -= $c * 146097 / 4; # (4 centuries = 146097 days) $y = ( $d * 4 - 1 ) / 1461; # calc number of years into the century, $d -= $y * 1461 / 4; # again March-based (4 yrs =~ 146[01] days) $m = ( $d * 12 + 1093 ) / 367; # get the month (3..14 represent March through $d -= ( $m * 367 - 1094 ) / 12; # February of following year) $y += $c * 100 + $yadj * 400; # get the real year, which is off by # one if month is January or February if ( $m > 12 ) { ++$y; $m -= 12; } if ( $_[0] ) { my $dow; if ( $rd < -6 ) { $dow = ( $rd + 6 ) % 7; $dow += $dow ? 8 : 1; } else { $dow = ( ( $rd + 6 ) % 7 ) + 1; } my $doy = $class->_end_of_last_month_day_of_year( $y, $m ); $doy += $d; my $quarter; { no integer; $quarter = int( ( 1 / 3.1 ) * $m ) + 1; } my $qm = ( 3 * $quarter ) - 2; my $doq = ( $doy - $class->_end_of_last_month_day_of_year( $y, $qm ) ); return ( $y, $m, $d, $dow, $doy, $quarter, $doq ); } return ( $y, $m, $d ); } sub _ymd2rd { shift; # ignore class use integer; my ( $y, $m, $d ) = @_; my $adj; # make month in range 3..14 (treat Jan & Feb as months 13..14 of # prev year) if ( $m <= 2 ) { $y -= ( $adj = ( 14 - $m ) / 12 ); $m += 12 * $adj; } elsif ( $m > 14 ) { $y += ( $adj = ( $m - 3 ) / 12 ); $m -= 12 * $adj; } # make year positive (oh, for a use integer 'sane_div'!) if ( $y < 0 ) { $d -= 146097 * ( $adj = ( 399 - $y ) / 400 ); $y += 400 * $adj; } # add: day of month, days of previous 0-11 month period that began # w/March, days of previous 0-399 year period that began w/March # of a 400-multiple year), days of any 400-year periods before # that, and finally subtract 306 days to adjust from Mar 1, year # 0-relative to Jan 1, year 1-relative (whew) $d += ( $m * 367 - 1094 ) / 12 + $y % 100 * 1461 / 4 + ( $y / 100 * 36524 + $y / 400 ) - 306; } sub _seconds_as_components { shift; my $secs = shift; my $utc_secs = shift; my $modifier = shift || 0; use integer; $secs -= $modifier; my $hour = $secs / 3600; $secs -= $hour * 3600; my $minute = $secs / 60; my $second = $secs - ( $minute * 60 ); if ( $utc_secs && $utc_secs >= 86400 ) { # there is no such thing as +3 or more leap seconds! die "Invalid UTC RD seconds value: $utc_secs" if $utc_secs > 86401; $second += $utc_secs - 86400 + 60; $minute = 59; $hour--; $hour = 23 if $hour < 0; } return ( $hour, $minute, $second ); } sub _end_of_last_month_day_of_year { my $class = shift; my ( $y, $m ) = @_; $m--; return ( $class->_is_leap_year($y) ? $EndOfLastMonthDayOfLeapYear[$m] : $EndOfLastMonthDayOfYear[$m] ); } sub _is_leap_year { shift; my $year = shift; # According to Bjorn Tackmann, this line prevents an infinite loop # when running the tests under Qemu. I cannot reproduce this on # Ubuntu or with Strawberry Perl on Win2K. return 0 if $year == DateTime::INFINITY() || $year == DateTime::NEG_INFINITY(); return 0 if $year % 4; return 1 if $year % 100; return 0 if $year % 400; return 1; } sub _day_length { DateTime::LeapSecond::day_length( $_[1] ) } sub _accumulated_leap_seconds { DateTime::LeapSecond::leap_seconds( $_[1] ) } my @subs = qw( _time_as_seconds _rd2ymd _ymd2rd _seconds_as_components _end_of_last_month_day_of_year _is_leap_year _day_length _accumulated_leap_seconds ); for my $sub (@subs) { ## no critic (TestingAndDebugging::ProhibitNoStrict) no strict 'refs'; *{ 'DateTime::' . $sub } = __PACKAGE__->can($sub); } # This is down here so that _ymd2rd is available when it loads, # because it will load DateTime::LeapSecond, which needs # DateTime->_ymd2rd to be available when it is loading require DateTime::PPExtra; 1; DateTime-1.51/lib/DateTime/Types.pm0000644000175000017500000000724413457144251016715 0ustar autarchautarchpackage DateTime::Types; use strict; use warnings; use namespace::autoclean; our $VERSION = '1.51'; use parent 'Specio::Exporter'; use Specio 0.18; use Specio::Declare; use Specio::Library::Builtins -reexport; use Specio::Library::Numeric -reexport; use Specio::Library::String; any_can_type( 'ConvertibleObject', methods => ['utc_rd_values'], ); declare( 'DayOfMonth', parent => t('Int'), inline => sub { $_[0]->parent->inline_check( $_[1] ) . " && $_[1] >= 1 && $_[1] <= 31"; }, ); declare( 'DayOfYear', parent => t('Int'), inline => sub { $_[0]->parent->inline_check( $_[1] ) . " && $_[1] >= 1 && $_[1] <= 366"; }, ); object_isa_type( 'Duration', class => 'DateTime::Duration', ); enum( 'EndOfMonthMode', values => [qw( wrap limit preserve )], ); any_can_type( 'Formatter', methods => ['format_datetime'], ); my $locale_object = declare( 'LocaleObject', parent => t('Object'), inline => sub { # Can't use $_[1] directly because 5.8 gives very weird errors my $var = $_[1]; <<"EOF"; ( $var->isa('DateTime::Locale::FromData') || $var->isa('DateTime::Locale::Base') ) EOF }, ); union( 'Locale', of => [ t('NonEmptySimpleStr'), $locale_object ], ); my $time_zone_object = object_can_type( 'TZObject', methods => [ qw( is_floating is_utc name offset_for_datetime short_name_for_datetime ) ], ); declare( 'TimeZone', of => [ t('NonEmptySimpleStr'), $time_zone_object ], ); declare( 'Hour', parent => t('PositiveOrZeroInt'), inline => sub { $_[0]->parent->inline_check( $_[1] ) . " && $_[1] >= 0 && $_[1] <= 23"; }, ); declare( 'Minute', parent => t('PositiveOrZeroInt'), inline => sub { $_[0]->parent->inline_check( $_[1] ) . " && $_[1] >= 0 && $_[1] <= 59"; }, ); declare( 'Month', parent => t('PositiveInt'), inline => sub { $_[0]->parent->inline_check( $_[1] ) . " && $_[1] >= 1 && $_[1] <= 12"; }, ); declare( 'Nanosecond', parent => t('PositiveOrZeroInt'), ); declare( 'Second', parent => t('PositiveOrZeroInt'), inline => sub { $_[0]->parent->inline_check( $_[1] ) . " && $_[1] >= 0 && $_[1] <= 61"; }, ); enum( 'TruncationLevel', values => [ qw( year quarter month day hour minute second nanosecond week local_week ) ], ); declare( 'Year', parent => t('Int'), ); 1; # ABSTRACT: Types used for parameter checking in DateTime __END__ =pod =encoding UTF-8 =head1 NAME DateTime::Types - Types used for parameter checking in DateTime =head1 VERSION version 1.51 =head1 DESCRIPTION This module has no user-facing parts. =for Pod::Coverage .* =head1 SUPPORT Bugs may be submitted at L. There is a mailing list available for users of this distribution, L. I am also usually active on IRC as 'autarch' on C. =head1 SOURCE The source code repository for DateTime can be found at L. =head1 AUTHOR Dave Rolsky =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2003 - 2019 by Dave Rolsky. This is free software, licensed under: The Artistic License 2.0 (GPL Compatible) The full text of the license can be found in the F file included with this distribution. =cut DateTime-1.51/lib/DateTime/Duration.pm0000644000175000017500000004500713457144251017375 0ustar autarchautarchpackage DateTime::Duration; use strict; use warnings; use namespace::autoclean; our $VERSION = '1.51'; use Carp (); use DateTime; use DateTime::Helpers; use DateTime::Types; use Params::ValidationCompiler 0.26 qw( validation_for ); use Scalar::Util qw( blessed ); use overload ( fallback => 1, '+' => '_add_overload', '-' => '_subtract_overload', '*' => '_multiply_overload', '<=>' => '_compare_overload', 'cmp' => '_compare_overload', ); sub MAX_NANOSECONDS () {1_000_000_000} # 1E9 = almost 32 bits my @all_units = qw( months days minutes seconds nanoseconds ); { my %units = map { $_ => { # XXX - what we really want is to accept an integer, Inf, -Inf, # and NaN, but I can't figure out how to accept NaN since it never # compares to anything. type => t('Defined'), default => 0, } } qw( years months weeks days hours minutes seconds nanoseconds ); my $check = validation_for( name => '_check_new_params', name_is_optional => 1, params => { %units, end_of_month => { type => t('EndOfMonthMode'), optional => 1, }, }, ); sub new { my $class = shift; my %p = $check->(@_); my $self = bless {}, $class; $self->{months} = ( $p{years} * 12 ) + $p{months}; $self->{days} = ( $p{weeks} * 7 ) + $p{days}; $self->{minutes} = ( $p{hours} * 60 ) + $p{minutes}; $self->{seconds} = $p{seconds}; if ( $p{nanoseconds} ) { $self->{nanoseconds} = $p{nanoseconds}; $self->_normalize_nanoseconds; } else { # shortcut - if they don't need nanoseconds $self->{nanoseconds} = 0; } $self->{end_of_month} = ( defined $p{end_of_month} ? $p{end_of_month} : $self->{months} < 0 ? 'preserve' : 'wrap' ); return $self; } } # make the signs of seconds, nanos the same; 0 < abs(nanos) < MAX_NANOS # NB this requires nanoseconds != 0 (callers check this already) sub _normalize_nanoseconds { my $self = shift; return if ( $self->{nanoseconds} == DateTime::INFINITY() || $self->{nanoseconds} == DateTime::NEG_INFINITY() || $self->{nanoseconds} eq DateTime::NAN() ); my $seconds = $self->{seconds} + $self->{nanoseconds} / MAX_NANOSECONDS; $self->{seconds} = int($seconds); $self->{nanoseconds} = $self->{nanoseconds} % MAX_NANOSECONDS; $self->{nanoseconds} -= MAX_NANOSECONDS if $seconds < 0; } sub clone { bless { %{ $_[0] } }, ref $_[0] } sub years { abs( $_[0]->in_units('years') ) } sub months { abs( $_[0]->in_units( 'months', 'years' ) ) } sub weeks { abs( $_[0]->in_units('weeks') ) } sub days { abs( $_[0]->in_units( 'days', 'weeks' ) ) } sub hours { abs( $_[0]->in_units('hours') ) } sub minutes { abs( $_[0]->in_units( 'minutes', 'hours' ) ) } sub seconds { abs( $_[0]->in_units('seconds') ) } sub nanoseconds { abs( $_[0]->in_units( 'nanoseconds', 'seconds' ) ) } sub is_positive { $_[0]->_has_positive && !$_[0]->_has_negative } sub is_negative { !$_[0]->_has_positive && $_[0]->_has_negative } sub _has_positive { ( grep { $_ > 0 } @{ $_[0] }{@all_units} ) ? 1 : 0; } sub _has_negative { ( grep { $_ < 0 } @{ $_[0] }{@all_units} ) ? 1 : 0; } sub is_zero { return 0 if grep { $_ != 0 } @{ $_[0] }{@all_units}; return 1; } sub delta_months { $_[0]->{months} } sub delta_days { $_[0]->{days} } sub delta_minutes { $_[0]->{minutes} } sub delta_seconds { $_[0]->{seconds} } sub delta_nanoseconds { $_[0]->{nanoseconds} } sub deltas { map { $_ => $_[0]->{$_} } @all_units; } sub in_units { my $self = shift; my @units = @_; my %units = map { $_ => 1 } @units; my %ret; my ( $months, $days, $minutes, $seconds ) = @{$self}{qw( months days minutes seconds )}; if ( $units{years} ) { $ret{years} = int( $months / 12 ); $months -= $ret{years} * 12; } if ( $units{months} ) { $ret{months} = $months; } if ( $units{weeks} ) { $ret{weeks} = int( $days / 7 ); $days -= $ret{weeks} * 7; } if ( $units{days} ) { $ret{days} = $days; } if ( $units{hours} ) { $ret{hours} = int( $minutes / 60 ); $minutes -= $ret{hours} * 60; } if ( $units{minutes} ) { $ret{minutes} = $minutes; } if ( $units{seconds} ) { $ret{seconds} = $seconds; $seconds = 0; } if ( $units{nanoseconds} ) { $ret{nanoseconds} = $seconds * MAX_NANOSECONDS + $self->{nanoseconds}; } wantarray ? @ret{@units} : $ret{ $units[0] }; } sub is_wrap_mode { $_[0]->{end_of_month} eq 'wrap' ? 1 : 0 } sub is_limit_mode { $_[0]->{end_of_month} eq 'limit' ? 1 : 0 } sub is_preserve_mode { $_[0]->{end_of_month} eq 'preserve' ? 1 : 0 } sub end_of_month_mode { $_[0]->{end_of_month} } sub calendar_duration { my $self = shift; return ( ref $self ) ->new( map { $_ => $self->{$_} } qw( months days end_of_month ) ); } sub clock_duration { my $self = shift; return ( ref $self ) ->new( map { $_ => $self->{$_} } qw( minutes seconds nanoseconds end_of_month ) ); } sub inverse { my $self = shift; my %p = @_; my %new; foreach my $u (@all_units) { $new{$u} = $self->{$u}; # avoid -0 bug $new{$u} *= -1 if $new{$u}; } $new{end_of_month} = $p{end_of_month} if exists $p{end_of_month}; return ( ref $self )->new(%new); } sub add_duration { my ( $self, $dur ) = @_; foreach my $u (@all_units) { $self->{$u} += $dur->{$u}; } $self->_normalize_nanoseconds if $self->{nanoseconds}; return $self; } sub add { my $self = shift; return $self->add_duration( $self->_duration_object_from_args(@_) ); } sub subtract { my $self = shift; return $self->subtract_duration( $self->_duration_object_from_args(@_) ); } # Syntactic sugar for add and subtract: use a duration object if it's # supplied, otherwise build a new one from the arguments. sub _duration_object_from_args { my $self = shift; return $_[0] if @_ == 1 && blessed( $_[0] ) && $_[0]->isa(__PACKAGE__); return __PACKAGE__->new(@_); } sub subtract_duration { return $_[0]->add_duration( $_[1]->inverse ) } { my $check = validation_for( name => '_check_multiply_params', name_is_optional => 1, params => [ { type => t('Int') }, ], ); sub multiply { my $self = shift; my ($multiplier) = $check->(@_); foreach my $u (@all_units) { $self->{$u} *= $multiplier; } $self->_normalize_nanoseconds if $self->{nanoseconds}; return $self; } } sub compare { my ( undef, $dur1, $dur2, $dt ) = @_; $dt ||= DateTime->now; return DateTime->compare( $dt->clone->add_duration($dur1), $dt->clone->add_duration($dur2) ); } sub _add_overload { my ( $d1, $d2, $rev ) = @_; ( $d1, $d2 ) = ( $d2, $d1 ) if $rev; if ( DateTime::Helpers::isa( $d2, 'DateTime' ) ) { $d2->add_duration($d1); return; } # will also work if $d1 is a DateTime.pm object return $d1->clone->add_duration($d2); } sub _subtract_overload { my ( $d1, $d2, $rev ) = @_; ( $d1, $d2 ) = ( $d2, $d1 ) if $rev; Carp::croak( 'Cannot subtract a DateTime object from a DateTime::Duration object') if DateTime::Helpers::isa( $d2, 'DateTime' ); return $d1->clone->subtract_duration($d2); } sub _multiply_overload { my $self = shift; my $new = $self->clone; return $new->multiply(shift); } sub _compare_overload { Carp::croak( 'DateTime::Duration does not overload comparison.' . ' See the documentation on the compare() method for details.' ); } 1; # ABSTRACT: Duration objects for date math __END__ =pod =encoding UTF-8 =head1 NAME DateTime::Duration - Duration objects for date math =head1 VERSION version 1.51 =head1 SYNOPSIS use DateTime::Duration; $dur = DateTime::Duration->new( years => 3, months => 5, weeks => 1, days => 1, hours => 6, minutes => 15, seconds => 45, nanoseconds => 12000 ); my ( $days, $hours, $seconds ) = $dur->in_units('days', 'hours', 'seconds'); # Human-readable accessors, always positive, but consider using # DateTime::Format::Duration instead $dur->years; $dur->months; $dur->weeks; $dur->days; $dur->hours; $dur->minutes; $dur->seconds; $dur->nanoseconds; $dur->is_wrap_mode $dur->is_limit_mode $dur->is_preserve_mode print $dur->end_of_month_mode; # Multiply all values by -1 my $opposite = $dur->inverse; my $bigger = $dur1 + $dur2; my $smaller = $dur1 - $dur2; # the result could be negative my $bigger = $dur1 * 3; my $base_dt = DateTime->new( year => 2000 ); my @sorted = sort { DateTime::Duration->compare( $a, $b, $base_dt ) } @durations; if ( $dur->is_positive ) { ... } if ( $dur->is_zero ) { ... } if ( $dur->is_negative ) { ... } =head1 DESCRIPTION This is a simple class for representing duration objects. These objects are used whenever you do date math with DateTime.pm. See the L section of the DateTime.pm documentation for more details. The short course: One cannot in general convert between seconds, minutes, days, and months, so this class will never do so. Instead, create the duration with the desired units to begin with, for example by calling the appropriate subtraction/delta method on a C object. =head1 METHODS Like C itself, C returns the object from mutator methods in order to make method chaining possible. C has the following methods: =head2 DateTime::Duration->new( ... ) This method takes the parameters "years", "months", "weeks", "days", "hours", "minutes", "seconds", "nanoseconds", and "end_of_month". All of these except "end_of_month" are numbers. If any of the numbers are negative, the entire duration is negative. All of the numbers B. Internally, years as just treated as 12 months. Similarly, weeks are treated as 7 days, and hours are converted to minutes. Seconds and nanoseconds are both treated separately. The "end_of_month" parameter must be either "wrap", "limit", or "preserve". This parameter specifies how date math that crosses the end of a month is handled. In "wrap" mode, adding months or years that result in days beyond the end of the new month will roll over into the following month. For instance, adding one year to Feb 29 will result in Mar 1. If you specify "end_of_month" mode as "limit", the end of the month is never crossed. Thus, adding one year to Feb 29, 2000 will result in Feb 28, 2001. If you were to then add three more years this will result in Feb 28, 2004. If you specify "end_of_month" mode as "preserve", the same calculation is done as for "limit" except that if the original date is at the end of the month the new date will also be. For instance, adding one month to Feb 29, 2000 will result in Mar 31, 2000. For positive durations, the "end_of_month" parameter defaults to wrap. For negative durations, the default is "preserve". This should match how most people "intuitively" expect datetime math to work. =head2 $dur->clone() Returns a new object with the same properties as the object on which this method was called. =head2 $dur->in_units( ... ) Returns the length of the duration in the units (any of those that can be passed to C) given as arguments. All lengths are integral, but may be negative. Smaller units are computed from what remains after taking away the larger units given, so for example: my $dur = DateTime::Duration->new( years => 1, months => 15 ); $dur->in_units( 'years' ); # 2 $dur->in_units( 'months' ); # 27 $dur->in_units( 'years', 'months' ); # (2, 3) $dur->in_units( 'weeks', 'days' ); # (0, 0) ! The last example demonstrates that there will not be any conversion between units which don't have a fixed conversion rate. The only conversions possible are: =over 8 =item * years <=> months =item * weeks <=> days =item * hours <=> minutes =item * seconds <=> nanoseconds =back For the explanation of why this is the case, please see the L section of the DateTime.pm documentation Note that the numbers returned by this method may not match the values given to the constructor. In list context, in_units returns the lengths in the order of the units given. In scalar context, it returns the length in the first unit (but still computes in terms of all given units). If you need more flexibility in presenting information about durations, please take a look a C. =head2 $dur->is_positive(), $dur->is_zero(), $dur->is_negative() Indicates whether or not the duration is positive, zero, or negative. If the duration contains both positive and negative units, then it will return false for B of these methods. =head2 $dur->is_wrap_mode(), $dur->is_limit_mode(), $dur->is_preserve_mode() Indicates what mode is used for end of month wrapping. =head2 $dur->end_of_month_mode() Returns one of "wrap", "limit", or "preserve". =head2 $dur->calendar_duration() Returns a new object with the same I delta (months and days only) and end of month mode as the current object. =head2 $dur->clock_duration() Returns a new object with the same I deltas (minutes, seconds, and nanoseconds) and end of month mode as the current object. =head2 $dur->inverse( ... ) Returns a new object with the same deltas as the current object, but multiple by -1. The end of month mode for the new object will be the default end of month mode, which depends on whether the new duration is positive or negative. You can set the end of month mode in the inverted duration explicitly by passing "end_of_month => ..." to the C method. =head2 $dur->add_duration( $duration_object ), $dur->subtract_duration( $duration_object ) Adds or subtracts one duration from another. =head2 $dur->add( ... ), $dur->subtract( ... ) These accept either constructor parameters for a new C object or an already-constructed duration object. =head2 $dur->multiply( $number ) Multiplies each unit in the C object by the specified integer number. =head2 DateTime::Duration->compare( $duration1, $duration2, $base_datetime ) This is a class method that can be used to compare or sort durations. Comparison is done by adding each duration to the specified C object and comparing the resulting datetimes. This is necessary because without a base, many durations are not comparable. For example, 1 month may or may not be longer than 29 days, depending on what datetime it is added to. If no base datetime is given, then the result of C<< DateTime->now >> is used instead. Using this default will give non-repeatable results if used to compare two duration objects containing different units. It will also give non-repeatable results if the durations contain multiple types of units, such as months and days. However, if you know that both objects only consist of one type of unit (months I days I hours, etc.), and each duration contains the same type of unit, then the results of the comparison will be repeatable. =head2 $dur->delta_months(), $dur->delta_days(), $dur->delta_minutes(), $dur->delta_seconds(), $dur->delta_nanoseconds() These methods provide the information C needs for doing date math. The numbers returned may be positive or negative. This is mostly useful for doing date math in L. =head2 $dur->deltas() Returns a hash with the keys "months", "days", "minutes", "seconds", and "nanoseconds", containing all the delta information for the object. This is mostly useful for doing date math in L. =head2 $dur->years(), $dur->months(), $dur->weeks(), $dur->days(), $dur->hours(), $dur->minutes(), $dur->seconds(), $dur->nanoseconds() These methods return numbers indicating how many of the given unit the object represents, after having done a conversion to any larger units. For example, days are first converted to weeks, and then the remainder is returned. These numbers are always positive. Here's what each method returns: $dur->years() == abs( $dur->in_units('years') ) $dur->months() == abs( ( $dur->in_units( 'months', 'years' ) )[0] ) $dur->weeks() == abs( $dur->in_units( 'weeks' ) ) $dur->days() == abs( ( $dur->in_units( 'days', 'weeks' ) )[0] ) $dur->hours() == abs( $dur->in_units( 'hours' ) ) $dur->minutes == abs( ( $dur->in_units( 'minutes', 'hours' ) )[0] ) $dur->seconds == abs( $dur->in_units( 'seconds' ) ) $dur->nanoseconds() == abs( ( $dur->in_units( 'nanoseconds', 'seconds' ) )[0] ) If this seems confusing, remember that you can always use the C method to specify exactly what you want. Better yet, if you are trying to generate output suitable for humans, use the C module. =head2 Overloading This class overloads addition, subtraction, and mutiplication. Comparison is B overloaded. If you attempt to compare durations using C<< <=> >> or C, then an exception will be thrown! Use the C class method instead. =head1 SEE ALSO datetime@perl.org mailing list http://datetime.perl.org/ =head1 SUPPORT Support for this module is provided via the datetime@perl.org email list. See http://lists.perl.org/ for more details. Bugs may be submitted at L. There is a mailing list available for users of this distribution, L. I am also usually active on IRC as 'autarch' on C. =head1 SOURCE The source code repository for DateTime can be found at L. =head1 AUTHOR Dave Rolsky =head1 COPYRIGHT AND LICENSE This software is Copyright (c) 2003 - 2019 by Dave Rolsky. This is free software, licensed under: The Artistic License 2.0 (GPL Compatible) The full text of the license can be found in the F file included with this distribution. =cut DateTime-1.51/lib/DateTime.pm0000644000175000017500000040342013457144251015605 0ustar autarchautarch## no critic (Modules::ProhibitExcessMainComplexity) package DateTime; use 5.008004; use strict; use warnings; use warnings::register; use namespace::autoclean 0.19; our $VERSION = '1.51'; use Carp; use DateTime::Duration; use DateTime::Helpers; use DateTime::Locale 1.06; use DateTime::TimeZone 2.02; use DateTime::Types; use POSIX qw( floor fmod ); use Params::ValidationCompiler 0.26 qw( validation_for ); use Scalar::Util qw( blessed ); use Try::Tiny; ## no critic (Variables::ProhibitPackageVars) our $IsPurePerl; { my $loaded = 0; unless ( $ENV{PERL_DATETIME_PP} ) { try { require XSLoader; XSLoader::load( __PACKAGE__, exists $DateTime::{VERSION} && ${ $DateTime::{VERSION} } ? ${ $DateTime::{VERSION} } : 42 ); $loaded = 1; $IsPurePerl = 0; } catch { die $_ if $_ && $_ !~ /object version|loadable object/; }; } if ($loaded) { ## no critic (Variables::ProtectPrivateVars) require DateTime::PPExtra unless defined &DateTime::_normalize_tai_seconds; } else { require DateTime::PP; } } # for some reason, overloading doesn't work unless fallback is listed # early. # # 3rd parameter ( $_[2] ) means the parameters are 'reversed'. # see: "Calling conventions for binary operations" in overload docs. # use overload ( fallback => 1, '<=>' => '_compare_overload', 'cmp' => '_string_compare_overload', q{""} => 'stringify', bool => sub {1}, '-' => '_subtract_overload', '+' => '_add_overload', 'eq' => '_string_equals_overload', 'ne' => '_string_not_equals_overload', ); # Have to load this after overloading is defined, after BEGIN blocks # or else weird crashes ensue require DateTime::Infinite; sub MAX_NANOSECONDS () {1_000_000_000} # 1E9 = almost 32 bits sub INFINITY () { 100**100**100**100 } sub NEG_INFINITY () { -1 * ( 100**100**100**100 ) } sub NAN () { INFINITY - INFINITY } sub SECONDS_PER_DAY () {86400} sub duration_class () {'DateTime::Duration'} my ( @MonthLengths, @LeapYearMonthLengths, @QuarterLengths, @LeapYearQuarterLengths, ); BEGIN { @MonthLengths = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ); @LeapYearMonthLengths = @MonthLengths; $LeapYearMonthLengths[1]++; @QuarterLengths = ( 90, 91, 92, 92 ); @LeapYearQuarterLengths = @QuarterLengths; $LeapYearQuarterLengths[0]++; } { # I'd rather use Class::Data::Inheritable for this, but there's no # way to add the module-loading behavior to an accessor it # creates, despite what its docs say! my $DefaultLocale; sub DefaultLocale { shift; if (@_) { my $lang = shift; $DefaultLocale = DateTime::Locale->load($lang); } return $DefaultLocale; } } __PACKAGE__->DefaultLocale('en-US'); { my $validator = validation_for( name => '_check_new_params', name_is_optional => 1, params => { year => { type => t('Year') }, month => { type => t('Month'), default => 1, }, day => { type => t('DayOfMonth'), default => 1, }, hour => { type => t('Hour'), default => 0, }, minute => { type => t('Minute'), default => 0, }, second => { type => t('Second'), default => 0, }, nanosecond => { type => t('Nanosecond'), default => 0, }, locale => { type => t('Locale'), optional => 1, }, formatter => { type => t('Formatter'), optional => 1, }, time_zone => { type => t('TimeZone'), optional => 1, }, }, ); sub new { my $class = shift; my %p = $validator->(@_); Carp::croak( "Invalid day of month (day = $p{day} - month = $p{month} - year = $p{year})\n" ) if $p{day} > 28 && $p{day} > $class->_month_length( $p{year}, $p{month} ); return $class->_new(%p); } } sub _new { my $class = shift; my %p = @_; Carp::croak('Constructor called with reference, we expected a package') if ref $class; # If this method is called from somewhere other than new(), then some of # these defaults may not get applied. $p{month} = 1 unless exists $p{month}; $p{day} = 1 unless exists $p{day}; $p{hour} = 0 unless exists $p{hour}; $p{minute} = 0 unless exists $p{minute}; $p{second} = 0 unless exists $p{second}; $p{nanosecond} = 0 unless exists $p{nanosecond}; $p{time_zone} = $class->_default_time_zone unless exists $p{time_zone}; my $self = bless {}, $class; $self->_set_locale( $p{locale} ); $self->{tz} = ( ref $p{time_zone} ? $p{time_zone} : DateTime::TimeZone->new( name => $p{time_zone} ) ); $self->{local_rd_days} = $class->_ymd2rd( @p{qw( year month day )} ); $self->{local_rd_secs} = $class->_time_as_seconds( @p{qw( hour minute second )} ); $self->{offset_modifier} = 0; $self->{rd_nanosecs} = $p{nanosecond}; $self->{formatter} = $p{formatter}; $self->_normalize_nanoseconds( $self->{local_rd_secs}, $self->{rd_nanosecs} ); # Set this explicitly since it can't be calculated accurately # without knowing our time zone offset, and it's possible that the # offset can't be calculated without having at least a rough guess # of the datetime's year. This year need not be correct, as long # as its equal or greater to the correct number, so we fudge by # adding one to the local year given to the constructor. $self->{utc_year} = $p{year} + 1; $self->_maybe_future_dst_warning( $p{year}, $p{time_zone} ); $self->_calc_utc_rd; $self->_handle_offset_modifier( $p{second} ); $self->_calc_local_rd; if ( $p{second} > 59 ) { if ( $self->{tz}->is_floating || # If true, this means that the actual calculated leap # second does not occur in the second given to new() ( $self->{utc_rd_secs} - 86399 < $p{second} - 59 ) ) { Carp::croak("Invalid second value ($p{second})\n"); } } return $self; } # Warning: do not use this environment variable unless you have no choice in # the matter. sub _default_time_zone { return $ENV{PERL_DATETIME_DEFAULT_TZ} || 'floating'; } sub _set_locale { my $self = shift; my $locale = shift; if ( defined $locale && ref $locale ) { $self->{locale} = $locale; } else { $self->{locale} = $locale ? DateTime::Locale->load($locale) : $self->DefaultLocale(); } return; } # This method exists for the benefit of internal methods which create # a new object based on the current object, like set() and truncate(). sub _new_from_self { my $self = shift; my %p = @_; my %old = map { $_ => $self->$_() } qw( year month day hour minute second nanosecond locale time_zone ); $old{formatter} = $self->formatter() if defined $self->formatter(); my $method = delete $p{_skip_validation} ? '_new' : 'new'; return ( ref $self )->$method( %old, %p ); } sub _handle_offset_modifier { my $self = shift; $self->{offset_modifier} = 0; return if $self->{tz}->is_floating; my $second = shift; my $utc_is_valid = shift; my $utc_rd_days = $self->{utc_rd_days}; my $offset = $utc_is_valid ? $self->offset : $self->_offset_for_local_datetime; if ( $offset >= 0 && $self->{local_rd_secs} >= $offset ) { if ( $second < 60 && $offset > 0 ) { $self->{offset_modifier} = $self->_day_length( $utc_rd_days - 1 ) - SECONDS_PER_DAY; $self->{local_rd_secs} += $self->{offset_modifier}; } elsif ( $second == 60 && ( ( $self->{local_rd_secs} == $offset && $offset > 0 ) || ( $offset == 0 && $self->{local_rd_secs} > 86399 ) ) ) { my $mod = $self->_day_length( $utc_rd_days - 1 ) - SECONDS_PER_DAY; unless ( $mod == 0 ) { $self->{utc_rd_secs} -= $mod; $self->_normalize_seconds; } } } elsif ($offset < 0 && $self->{local_rd_secs} >= SECONDS_PER_DAY + $offset ) { if ( $second < 60 ) { $self->{offset_modifier} = $self->_day_length( $utc_rd_days - 1 ) - SECONDS_PER_DAY; $self->{local_rd_secs} += $self->{offset_modifier}; } elsif ($second == 60 && $self->{local_rd_secs} == SECONDS_PER_DAY + $offset ) { my $mod = $self->_day_length( $utc_rd_days - 1 ) - SECONDS_PER_DAY; unless ( $mod == 0 ) { $self->{utc_rd_secs} -= $mod; $self->_normalize_seconds; } } } } sub _calc_utc_rd { my $self = shift; delete $self->{utc_c}; if ( $self->{tz}->is_utc || $self->{tz}->is_floating ) { $self->{utc_rd_days} = $self->{local_rd_days}; $self->{utc_rd_secs} = $self->{local_rd_secs}; } else { my $offset = $self->_offset_for_local_datetime; $offset += $self->{offset_modifier}; $self->{utc_rd_days} = $self->{local_rd_days}; $self->{utc_rd_secs} = $self->{local_rd_secs} - $offset; } # We account for leap seconds in the new() method and nowhere else # except date math. $self->_normalize_tai_seconds( $self->{utc_rd_days}, $self->{utc_rd_secs} ); } sub _normalize_seconds { my $self = shift; return if $self->{utc_rd_secs} >= 0 && $self->{utc_rd_secs} <= 86399; if ( $self->{tz}->is_floating ) { $self->_normalize_tai_seconds( $self->{utc_rd_days}, $self->{utc_rd_secs} ); } else { $self->_normalize_leap_seconds( $self->{utc_rd_days}, $self->{utc_rd_secs} ); } } sub _calc_local_rd { my $self = shift; delete $self->{local_c}; # We must short circuit for UTC times or else we could end up with # loops between DateTime.pm and DateTime::TimeZone if ( $self->{tz}->is_utc || $self->{tz}->is_floating ) { $self->{local_rd_days} = $self->{utc_rd_days}; $self->{local_rd_secs} = $self->{utc_rd_secs}; } else { my $offset = $self->offset; $self->{local_rd_days} = $self->{utc_rd_days}; $self->{local_rd_secs} = $self->{utc_rd_secs} + $offset; # intentionally ignore leap seconds here $self->_normalize_tai_seconds( $self->{local_rd_days}, $self->{local_rd_secs} ); $self->{local_rd_secs} += $self->{offset_modifier}; } $self->_calc_local_components; } sub _calc_local_components { my $self = shift; @{ $self->{local_c} }{ qw( year month day day_of_week day_of_year quarter day_of_quarter) } = $self->_rd2ymd( $self->{local_rd_days}, 1 ); @{ $self->{local_c} }{qw( hour minute second )} = $self->_seconds_as_components( $self->{local_rd_secs}, $self->{utc_rd_secs}, $self->{offset_modifier} ); } { my $validator = validation_for( name => '_check_from_epoch_params', name_is_optional => 1, params => { epoch => { type => t('Num') }, formatter => { type => t('Formatter'), optional => 1 }, locale => { type => t('Locale'), optional => 1 }, time_zone => { type => t('TimeZone'), optional => 1 }, }, ); sub from_epoch { my $class = shift; my %p = $validator->(@_); my %args; # This does two things. First, if given a negative non-integer epoch, # it will round the epoch _down_ to the next second and then adjust # the nanoseconds to be positive. In other words, -0.5 corresponds to # a second of -1 and a nanosecond value of 500,000. Before this code # was implemented our handling of negative non-integer epochs was # quite broken, and would end up rounding some values up, so that -0.5 # become 0.5 (which is obviously wrong!). # # Second, it rounds any decimal values to the nearest microsecond # (1E6). Here's what Christian Hansen, who wrote this patch, says: # # Perl is typically compiled with NV as a double. A double with a # significand precision of 53 bits can only represent a nanosecond # epoch without loss of precision if the duration from zero epoch # is less than ≈ ±104 days. With microseconds the duration is # ±104,000 days, which is ≈ ±285 years. if ( int $p{epoch} != $p{epoch} ) { my ( $floor, $nano, $second ); $floor = $nano = fmod( $p{epoch}, 1.0 ); $second = floor( $p{epoch} - $floor ); if ( $nano < 0 ) { $nano += 1; } $p{epoch} = $second + floor( $floor - $nano ); $args{nanosecond} = floor( $nano * 1E6 + 0.5 ) * 1E3; } # Note, for very large negative values this may give a # blatantly wrong answer. @args{qw( second minute hour day month year )} = ( gmtime( $p{epoch} ) )[ 0 .. 5 ]; $args{year} += 1900; $args{month}++; my $self = $class->_new( %p, %args, time_zone => 'UTC' ); $self->_maybe_future_dst_warning( $self->year(), $p{time_zone} ); $self->set_time_zone( $p{time_zone} ) if exists $p{time_zone}; return $self; } } sub now { my $class = shift; return $class->from_epoch( epoch => $class->_core_time(), @_ ); } sub _maybe_future_dst_warning { shift; my $year = shift; my $tz = shift; return unless $year >= 5000 && $tz; my $tz_name = ref $tz ? $tz->name() : $tz; return if $tz_name eq 'floating' || $tz_name eq 'UTC'; warnings::warnif( "You are creating a DateTime object with a far future year ($year) and a time zone ($tz_name)." . ' If the time zone you specified has future DST changes this will be very slow.' ); } # use scalar time in case someone's loaded Time::Piece sub _core_time { return scalar time; } sub today { shift->now(@_)->truncate( to => 'day' ) } { my $validator = validation_for( name => '_check_from_object_params', name_is_optional => 1, params => { object => { type => t('ConvertibleObject') }, locale => { type => t('Locale'), optional => 1, }, formatter => { type => t('Formatter'), optional => 1, }, }, ); sub from_object { my $class = shift; my %p = $validator->(@_); my $object = delete $p{object}; if ( $object->isa('DateTime::Infinite') ) { return $object->clone; } my ( $rd_days, $rd_secs, $rd_nanosecs ) = $object->utc_rd_values; # A kludge because until all calendars are updated to return all # three values, $rd_nanosecs could be undef $rd_nanosecs ||= 0; # This is a big hack to let _seconds_as_components operate naively # on the given value. If the object _is_ on a leap second, we'll # add that to the generated seconds value later. my $leap_seconds = 0; if ( $object->can('time_zone') && !$object->time_zone->is_floating && $rd_secs > 86399 && $rd_secs <= $class->_day_length($rd_days) ) { $leap_seconds = $rd_secs - 86399; $rd_secs -= $leap_seconds; } my %args; @args{qw( year month day )} = $class->_rd2ymd($rd_days); @args{qw( hour minute second )} = $class->_seconds_as_components($rd_secs); $args{nanosecond} = $rd_nanosecs; $args{second} += $leap_seconds; my $new = $class->new( %p, %args, time_zone => 'UTC' ); if ( $object->can('time_zone') ) { $new->set_time_zone( $object->time_zone ); } else { $new->set_time_zone( $class->_default_time_zone ); } return $new; } } { my $validator = validation_for( name => '_check_last_day_of_month_params', name_is_optional => 1, params => { year => { type => t('Year') }, month => { type => t('Month') }, day => { type => t('DayOfMonth'), default => 1, }, hour => { type => t('Hour'), default => 0, }, minute => { type => t('Minute'), default => 0, }, second => { type => t('Second'), default => 0, }, nanosecond => { type => t('Nanosecond'), default => 0, }, locale => { type => t('Locale'), optional => 1, }, formatter => { type => t('Formatter'), optional => 1, }, time_zone => { type => t('TimeZone'), optional => 1, }, }, ); sub last_day_of_month { my $class = shift; my %p = $validator->(@_); my $day = $class->_month_length( $p{year}, $p{month} ); return $class->_new( %p, day => $day ); } } sub _month_length { return ( $_[0]->_is_leap_year( $_[1] ) ? $LeapYearMonthLengths[ $_[2] - 1 ] : $MonthLengths[ $_[2] - 1 ] ); } { my $validator = validation_for( name => '_check_from_day_of_year_params', name_is_optional => 1, params => { year => { type => t('Year') }, day_of_year => { type => t('DayOfYear') }, hour => { type => t('Hour'), default => 0, }, minute => { type => t('Minute'), default => 0, }, second => { type => t('Second'), default => 0, }, nanosecond => { type => t('Nanosecond'), default => 0, }, locale => { type => t('Locale'), optional => 1, }, formatter => { type => t('Formatter'), optional => 1, }, time_zone => { type => t('TimeZone'), optional => 1, }, }, ); sub from_day_of_year { my $class = shift; my %p = $validator->(@_); Carp::croak("$p{year} is not a leap year.\n") if $p{day_of_year} == 366 && !$class->_is_leap_year( $p{year} ); my $month = 1; my $day = delete $p{day_of_year}; if ( $day > 31 ) { my $length = $class->_month_length( $p{year}, $month ); while ( $day > $length ) { $day -= $length; $month++; $length = $class->_month_length( $p{year}, $month ); } } return $class->_new( %p, month => $month, day => $day, ); } } sub formatter { $_[0]->{formatter} } sub clone { bless { %{ $_[0] } }, ref $_[0] } sub year { Carp::carp('year() is a read-only accessor') if @_ > 1; return $_[0]->{local_c}{year}; } sub ce_year { $_[0]->{local_c}{year} <= 0 ? $_[0]->{local_c}{year} - 1 : $_[0]->{local_c}{year}; } sub era_name { $_[0]->{locale}->era_wide->[ $_[0]->_era_index() ] } sub era_abbr { $_[0]->{locale}->era_abbreviated->[ $_[0]->_era_index() ] } # deprecated *era = \&era_abbr; sub _era_index { $_[0]->{local_c}{year} <= 0 ? 0 : 1 } sub christian_era { $_[0]->ce_year > 0 ? 'AD' : 'BC' } sub secular_era { $_[0]->ce_year > 0 ? 'CE' : 'BCE' } sub year_with_era { ( abs $_[0]->ce_year ) . $_[0]->era_abbr } sub year_with_christian_era { ( abs $_[0]->ce_year ) . $_[0]->christian_era } sub year_with_secular_era { ( abs $_[0]->ce_year ) . $_[0]->secular_era } sub month { Carp::carp('month() is a read-only accessor') if @_ > 1; return $_[0]->{local_c}{month}; } *mon = \&month; sub month_0 { $_[0]->{local_c}{month} - 1 } *mon_0 = \&month_0; sub month_name { $_[0]->{locale}->month_format_wide->[ $_[0]->month_0() ] } sub month_abbr { $_[0]->{locale}->month_format_abbreviated->[ $_[0]->month_0() ]; } sub day_of_month { Carp::carp('day_of_month() is a read-only accessor') if @_ > 1; $_[0]->{local_c}{day}; } *day = \&day_of_month; *mday = \&day_of_month; sub weekday_of_month { use integer; ( ( $_[0]->day - 1 ) / 7 ) + 1 } sub quarter { $_[0]->{local_c}{quarter} } sub quarter_name { $_[0]->{locale}->quarter_format_wide->[ $_[0]->quarter_0() ]; } sub quarter_abbr { $_[0]->{locale}->quarter_format_abbreviated->[ $_[0]->quarter_0() ]; } sub quarter_0 { $_[0]->{local_c}{quarter} - 1 } sub day_of_month_0 { $_[0]->{local_c}{day} - 1 } *day_0 = \&day_of_month_0; *mday_0 = \&day_of_month_0; sub day_of_week { $_[0]->{local_c}{day_of_week} } *wday = \&day_of_week; *dow = \&day_of_week; sub day_of_week_0 { $_[0]->{local_c}{day_of_week} - 1 } *wday_0 = \&day_of_week_0; *dow_0 = \&day_of_week_0; sub local_day_of_week { my $self = shift; return 1 + ( $self->day_of_week - $self->{locale}->first_day_of_week ) % 7; } sub day_name { $_[0]->{locale}->day_format_wide->[ $_[0]->day_of_week_0() ] } sub day_abbr { $_[0]->{locale}->day_format_abbreviated->[ $_[0]->day_of_week_0() ]; } sub day_of_quarter { $_[0]->{local_c}{day_of_quarter} } *doq = \&day_of_quarter; sub day_of_quarter_0 { $_[0]->day_of_quarter - 1 } *doq_0 = \&day_of_quarter_0; sub day_of_year { $_[0]->{local_c}{day_of_year} } *doy = \&day_of_year; sub day_of_year_0 { $_[0]->{local_c}{day_of_year} - 1 } *doy_0 = \&day_of_year_0; sub am_or_pm { $_[0]->{locale}->am_pm_abbreviated->[ $_[0]->hour() < 12 ? 0 : 1 ]; } sub ymd { my ( $self, $sep ) = @_; $sep = '-' unless defined $sep; return sprintf( '%0.4d%s%0.2d%s%0.2d', $self->year, $sep, $self->{local_c}{month}, $sep, $self->{local_c}{day} ); } *date = sub { shift->ymd(@_) }; sub mdy { my ( $self, $sep ) = @_; $sep = '-' unless defined $sep; return sprintf( '%0.2d%s%0.2d%s%0.4d', $self->{local_c}{month}, $sep, $self->{local_c}{day}, $sep, $self->year ); } sub dmy { my ( $self, $sep ) = @_; $sep = '-' unless defined $sep; return sprintf( '%0.2d%s%0.2d%s%0.4d', $self->{local_c}{day}, $sep, $self->{local_c}{month}, $sep, $self->year ); } sub hour { Carp::carp('hour() is a read-only accessor') if @_ > 1; return $_[0]->{local_c}{hour}; } sub hour_1 { $_[0]->{local_c}{hour} == 0 ? 24 : $_[0]->{local_c}{hour} } sub hour_12 { my $h = $_[0]->hour % 12; return $h ? $h : 12 } sub hour_12_0 { $_[0]->hour % 12 } sub minute { Carp::carp('minute() is a read-only accessor') if @_ > 1; return $_[0]->{local_c}{minute}; } *min = \&minute; sub second { Carp::carp('second() is a read-only accessor') if @_ > 1; return $_[0]->{local_c}{second}; } *sec = \&second; sub fractional_second { $_[0]->second + $_[0]->nanosecond / MAX_NANOSECONDS } sub nanosecond { Carp::carp('nanosecond() is a read-only accessor') if @_ > 1; return $_[0]->{rd_nanosecs}; } sub millisecond { floor( $_[0]->{rd_nanosecs} / 1000000 ) } sub microsecond { floor( $_[0]->{rd_nanosecs} / 1000 ) } sub leap_seconds { my $self = shift; return 0 if $self->{tz}->is_floating; return $self->_accumulated_leap_seconds( $self->{utc_rd_days} ); } sub stringify { my $self = shift; return $self->iso8601 unless $self->{formatter}; return $self->{formatter}->format_datetime($self); } sub hms { my ( $self, $sep ) = @_; $sep = ':' unless defined $sep; return sprintf( '%0.2d%s%0.2d%s%0.2d', $self->{local_c}{hour}, $sep, $self->{local_c}{minute}, $sep, $self->{local_c}{second} ); } # don't want to override CORE::time() *DateTime::time = sub { shift->hms(@_) }; sub iso8601 { $_[0]->datetime('T') } sub datetime { my ( $self, $sep ) = @_; $sep = 'T' unless defined $sep; return join $sep, $self->ymd('-'), $self->hms(':'); } sub is_leap_year { $_[0]->_is_leap_year( $_[0]->year ) } sub month_length { $_[0]->_month_length( $_[0]->year, $_[0]->month ); } sub quarter_length { return ( $_[0]->_is_leap_year( $_[0]->year ) ? $LeapYearQuarterLengths[ $_[0]->quarter - 1 ] : $QuarterLengths[ $_[0]->quarter - 1 ] ); } sub year_length { $_[0]->_is_leap_year( $_[0]->year ) ? 366 : 365; } sub is_last_day_of_month { $_[0]->day == $_[0]->_month_length( $_[0]->year, $_[0]->month ); } sub is_last_day_of_quarter { $_[0]->day_of_quarter == $_[0]->quarter_length; } sub is_last_day_of_year { $_[0]->day_of_year == $_[0]->year_length; } sub week { my $self = shift; $self->{utc_c}{week_year} ||= $self->_week_values; return @{ $self->{utc_c}{week_year} }[ 0, 1 ]; } # This algorithm comes from # https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_of_a_given_date sub _week_values { my $self = shift; my $week = int( ( ( $self->day_of_year - $self->day_of_week ) + 10 ) / 7 ); my $year = $self->year; if ( $week == 0 ) { $year--; return [ $year, $self->_weeks_in_year($year) ]; } elsif ( $week == 53 && $self->_weeks_in_year($year) == 52 ) { return [ $year + 1, 1 ]; } return [ $year, $week ]; } sub _weeks_in_year { my $self = shift; my $year = shift; my $dow = $self->_ymd2rd( $year, 1, 1 ) % 7; # Years starting with a Thursday and leap years starting with a Wednesday # have 53 weeks. return ( $dow == 4 || ( $dow == 3 && $self->_is_leap_year($year) ) ) ? 53 : 52; } sub week_year { ( $_[0]->week )[0] } sub week_number { ( $_[0]->week )[1] } # ISO says that the first week of a year is the first week containing # a Thursday. Extending that says that the first week of the month is # the first week containing a Thursday. ICU agrees. sub week_of_month { my $self = shift; my $thu = $self->day + 4 - $self->day_of_week; return int( ( $thu + 6 ) / 7 ); } sub time_zone { Carp::carp('time_zone() is a read-only accessor') if @_ > 1; return $_[0]->{tz}; } sub offset { $_[0]->{tz}->offset_for_datetime( $_[0] ) } sub _offset_for_local_datetime { $_[0]->{tz}->offset_for_local_datetime( $_[0] ); } sub is_dst { $_[0]->{tz}->is_dst_for_datetime( $_[0] ) } sub time_zone_long_name { $_[0]->{tz}->name } sub time_zone_short_name { $_[0]->{tz}->short_name_for_datetime( $_[0] ) } sub locale { Carp::carp('locale() is a read-only accessor') if @_ > 1; return $_[0]->{locale}; } sub utc_rd_values { @{ $_[0] }{ 'utc_rd_days', 'utc_rd_secs', 'rd_nanosecs' }; } sub local_rd_values { @{ $_[0] }{ 'local_rd_days', 'local_rd_secs', 'rd_nanosecs' }; } # NOTE: no nanoseconds, no leap seconds sub utc_rd_as_seconds { ( $_[0]->{utc_rd_days} * SECONDS_PER_DAY ) + $_[0]->{utc_rd_secs}; } # NOTE: no nanoseconds, no leap seconds sub local_rd_as_seconds { ( $_[0]->{local_rd_days} * SECONDS_PER_DAY ) + $_[0]->{local_rd_secs}; } # RD 1 is MJD 678,576 - a simple offset sub mjd { my $self = shift; my $mjd = $self->{utc_rd_days} - 678_576; my $day_length = $self->_day_length( $self->{utc_rd_days} ); return ( $mjd + ( $self->{utc_rd_secs} / $day_length ) + ( $self->{rd_nanosecs} / $day_length / MAX_NANOSECONDS ) ); } sub jd { $_[0]->mjd + 2_400_000.5 } { my %strftime_patterns = ( 'a' => sub { $_[0]->day_abbr }, 'A' => sub { $_[0]->day_name }, 'b' => sub { $_[0]->month_abbr }, 'B' => sub { $_[0]->month_name }, 'c' => sub { $_[0]->format_cldr( $_[0]->{locale}->datetime_format_default() ); }, 'C' => sub { int( $_[0]->year / 100 ) }, 'd' => sub { sprintf( '%02d', $_[0]->day_of_month ) }, 'D' => sub { $_[0]->strftime('%m/%d/%y') }, 'e' => sub { sprintf( '%2d', $_[0]->day_of_month ) }, 'F' => sub { $_[0]->strftime('%Y-%m-%d') }, 'g' => sub { substr( $_[0]->week_year, -2 ) }, 'G' => sub { $_[0]->week_year }, 'H' => sub { sprintf( '%02d', $_[0]->hour ) }, 'I' => sub { sprintf( '%02d', $_[0]->hour_12 ) }, 'j' => sub { sprintf( '%03d', $_[0]->day_of_year ) }, 'k' => sub { sprintf( '%2d', $_[0]->hour ) }, 'l' => sub { sprintf( '%2d', $_[0]->hour_12 ) }, 'm' => sub { sprintf( '%02d', $_[0]->month ) }, 'M' => sub { sprintf( '%02d', $_[0]->minute ) }, 'n' => sub {"\n"}, # should this be OS-sensitive? 'N' => \&_format_nanosecs, 'p' => sub { $_[0]->am_or_pm() }, 'P' => sub { lc $_[0]->am_or_pm() }, 'r' => sub { $_[0]->strftime('%I:%M:%S %p') }, 'R' => sub { $_[0]->strftime('%H:%M') }, 's' => sub { $_[0]->epoch }, 'S' => sub { sprintf( '%02d', $_[0]->second ) }, 't' => sub {"\t"}, 'T' => sub { $_[0]->strftime('%H:%M:%S') }, 'u' => sub { $_[0]->day_of_week }, 'U' => sub { my $sun = $_[0]->day_of_year - ( $_[0]->day_of_week + 7 ) % 7; return sprintf( '%02d', int( ( $sun + 6 ) / 7 ) ); }, 'V' => sub { sprintf( '%02d', $_[0]->week_number ) }, 'w' => sub { my $dow = $_[0]->day_of_week; return $dow % 7; }, 'W' => sub { my $mon = $_[0]->day_of_year - ( $_[0]->day_of_week + 6 ) % 7; return sprintf( '%02d', int( ( $mon + 6 ) / 7 ) ); }, 'x' => sub { $_[0]->format_cldr( $_[0]->{locale}->date_format_default() ); }, 'X' => sub { $_[0]->format_cldr( $_[0]->{locale}->time_format_default() ); }, 'y' => sub { sprintf( '%02d', substr( $_[0]->year, -2 ) ) }, 'Y' => sub { return $_[0]->year }, 'z' => sub { DateTime::TimeZone->offset_as_string( $_[0]->offset ) }, 'Z' => sub { $_[0]->{tz}->short_name_for_datetime( $_[0] ) }, '%' => sub {'%'}, ); $strftime_patterns{h} = $strftime_patterns{b}; sub strftime { my $self = shift; # make a copy or caller's scalars get munged my @patterns = @_; my @r; foreach my $p (@patterns) { $p =~ s/ (?: %\{(\w+)\} # method name like %{day_name} | %([%a-zA-Z]) # single character specifier like %d | %(\d+)N # special case for %N ) / ( $1 ? ( $self->can($1) ? $self->$1() : "\%{$1}" ) : $2 ? ( $strftime_patterns{$2} ? $strftime_patterns{$2}->($self) : "\%$2" ) : $3 ? $strftime_patterns{N}->($self, $3) : '' # this won't happen ) /sgex; return $p unless wantarray; push @r, $p; } return @r; } } { # It's an array because the order in which the regexes are checked # is important. These patterns are similar to the ones Java uses, # but not quite the same. See # http://www.unicode.org/reports/tr35/tr35-9.html#Date_Format_Patterns. my @patterns = ( qr/GGGGG/ => sub { $_[0]->{locale}->era_narrow->[ $_[0]->_era_index() ] }, qr/GGGG/ => 'era_name', qr/G{1,3}/ => 'era_abbr', qr/(y{3,5})/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->year() ) }, # yy is a weird special case, where it must be exactly 2 digits qr/yy/ => sub { my $year = $_[0]->year(); my $y2 = length $year > 2 ? substr( $year, -2, 2 ) : $year; $y2 *= -1 if $year < 0; $_[0]->_zero_padded_number( 'yy', $y2 ); }, qr/y/ => sub { $_[0]->year() }, qr/(u+)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->year() ) }, qr/(Y+)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->week_year() ) }, qr/QQQQ/ => 'quarter_name', qr/QQQ/ => 'quarter_abbr', qr/(QQ?)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->quarter() ) }, qr/qqqq/ => sub { $_[0]->{locale}->quarter_stand_alone_wide() ->[ $_[0]->quarter_0() ]; }, qr/qqq/ => sub { $_[0]->{locale}->quarter_stand_alone_abbreviated() ->[ $_[0]->quarter_0() ]; }, qr/(qq?)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->quarter() ) }, qr/MMMMM/ => sub { $_[0]->{locale}->month_format_narrow->[ $_[0]->month_0() ] } , qr/MMMM/ => 'month_name', qr/MMM/ => 'month_abbr', qr/(MM?)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->month() ) }, qr/LLLLL/ => sub { $_[0]->{locale}->month_stand_alone_narrow->[ $_[0]->month_0() ]; }, qr/LLLL/ => sub { $_[0]->{locale}->month_stand_alone_wide->[ $_[0]->month_0() ]; }, qr/LLL/ => sub { $_[0]->{locale} ->month_stand_alone_abbreviated->[ $_[0]->month_0() ]; }, qr/(LL?)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->month() ) }, qr/(ww?)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->week_number() ) }, qr/W/ => 'week_of_month', qr/(dd?)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->day_of_month() ) }, qr/(D{1,3})/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->day_of_year() ) }, qr/F/ => 'weekday_of_month', qr/(g+)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->mjd() ) }, qr/EEEEE/ => sub { $_[0]->{locale}->day_format_narrow->[ $_[0]->day_of_week_0() ]; }, qr/EEEE/ => 'day_name', qr/E{1,3}/ => 'day_abbr', qr/eeeee/ => sub { $_[0]->{locale}->day_format_narrow->[ $_[0]->day_of_week_0() ]; }, qr/eeee/ => 'day_name', qr/eee/ => 'day_abbr', qr/(ee?)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->local_day_of_week() ); }, qr/ccccc/ => sub { $_[0]->{locale} ->day_stand_alone_narrow->[ $_[0]->day_of_week_0() ]; }, qr/cccc/ => sub { $_[0]->{locale}->day_stand_alone_wide->[ $_[0]->day_of_week_0() ]; }, qr/ccc/ => sub { $_[0]->{locale} ->day_stand_alone_abbreviated->[ $_[0]->day_of_week_0() ]; }, qr/(cc?)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->day_of_week() ) }, qr/a/ => 'am_or_pm', qr/(hh?)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->hour_12() ) }, qr/(HH?)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->hour() ) }, qr/(KK?)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->hour_12_0() ) }, qr/(kk?)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->hour_1() ) }, qr/(jj?)/ => sub { my $h = $_[0]->{locale}->prefers_24_hour_time() ? $_[0]->hour() : $_[0]->hour_12(); $_[0]->_zero_padded_number( $1, $h ); }, qr/(mm?)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->minute() ) }, qr/(ss?)/ => sub { $_[0]->_zero_padded_number( $1, $_[0]->second() ) }, # The LDML spec is not 100% clear on how to truncate this field, but # this way seems as good as anything. qr/(S+)/ => sub { $_[0]->_format_nanosecs( length($1) ) }, qr/A+/ => sub { ( $_[0]->{local_rd_secs} * 1000 ) + $_[0]->millisecond() }, qr/zzzz/ => sub { $_[0]->time_zone_long_name() }, qr/z{1,3}/ => sub { $_[0]->time_zone_short_name() }, qr/ZZZZZ/ => sub { substr( my $z = DateTime::TimeZone->offset_as_string( $_[0]->offset() ), -2, 0, ':' ); $z; }, qr/ZZZZ/ => sub { $_[0]->time_zone_short_name() . DateTime::TimeZone->offset_as_string( $_[0]->offset() ); }, qr/Z{1,3}/ => sub { DateTime::TimeZone->offset_as_string( $_[0]->offset() ) }, qr/vvvv/ => sub { $_[0]->time_zone_long_name() }, qr/v{1,3}/ => sub { $_[0]->time_zone_short_name() }, qr/VVVV/ => sub { $_[0]->time_zone_long_name() }, qr/V{1,3}/ => sub { $_[0]->time_zone_short_name() }, ); sub _zero_padded_number { my $self = shift; my $size = length shift; my $val = shift; return sprintf( "%0${size}d", $val ); } sub format_cldr { my $self = shift; # make a copy or caller's scalars get munged my @p = @_; my @r; foreach my $p (@p) { $p =~ s/\G (?: '((?:[^']|'')*)' # quote escaped bit of text # it needs to end with one # quote not followed by # another | (([a-zA-Z])\3*) # could be a pattern | (.) # anything else ) / defined $1 ? $1 : defined $2 ? $self->_cldr_pattern($2) : defined $4 ? $4 : undef # should never get here /sgex; $p =~ s/\'\'/\'/g; return $p unless wantarray; push @r, $p; } return @r; } sub _cldr_pattern { my $self = shift; my $pattern = shift; ## no critic (ControlStructures::ProhibitCStyleForLoops) for ( my $i = 0; $i < @patterns; $i += 2 ) { if ( $pattern =~ /$patterns[$i]/ ) { my $sub = $patterns[ $i + 1 ]; return $self->$sub(); } } return $pattern; } } sub _format_nanosecs { my $self = shift; my $precision = @_ ? shift : 9; my $exponent = 9 - $precision; my $formatted_ns = floor( ( $exponent < 0 ? $self->{rd_nanosecs} * 10**-$exponent : $self->{rd_nanosecs} / 10**$exponent ) ); return sprintf( '%0' . $precision . 'u', $formatted_ns ); } sub epoch { my $self = shift; return $self->{utc_c}{epoch} if exists $self->{utc_c}{epoch}; return $self->{utc_c}{epoch} = ( $self->{utc_rd_days} - 719163 ) * SECONDS_PER_DAY + $self->{utc_rd_secs}; } sub hires_epoch { my $self = shift; my $epoch = $self->epoch; return undef unless defined $epoch; my $nano = $self->{rd_nanosecs} / MAX_NANOSECONDS; return $epoch + $nano; } sub is_finite {1} sub is_infinite {0} # added for benefit of DateTime::TimeZone sub utc_year { $_[0]->{utc_year} } # returns a result that is relative to the first datetime sub subtract_datetime { my $dt1 = shift; my $dt2 = shift; $dt2 = $dt2->clone->set_time_zone( $dt1->time_zone ) unless $dt1->time_zone eq $dt2->time_zone; # We only want a negative duration if $dt2 > $dt1 ($self) my ( $bigger, $smaller, $negative ) = ( $dt1 >= $dt2 ? ( $dt1, $dt2, 0 ) : ( $dt2, $dt1, 1 ) ); my $is_floating = $dt1->time_zone->is_floating && $dt2->time_zone->is_floating; my $minute_length = 60; unless ($is_floating) { my ( $utc_rd_days, $utc_rd_secs ) = $smaller->utc_rd_values; if ( $utc_rd_secs >= 86340 && !$is_floating ) { # If the smaller of the two datetimes occurs in the last # UTC minute of the UTC day, then that minute may not be # 60 seconds long. If we need to subtract a minute from # the larger datetime's minutes count in order to adjust # the seconds difference to be positive, we need to know # how long that minute was. If one of the datetimes is # floating, we just assume a minute is 60 seconds. $minute_length = $dt1->_day_length($utc_rd_days) - 86340; } } # This is a gross hack that basically figures out if the bigger of # the two datetimes is the day of a DST change. If it's a 23 hour # day (switching _to_ DST) then we subtract 60 minutes from the # local time. If it's a 25 hour day then we add 60 minutes to the # local time. # # This produces the most "intuitive" results, though there are # still reversibility problems with the resultant duration. # # However, if the two objects are on the same (local) date, and we # are not crossing a DST change, we don't want to invoke the hack # - see 38local-subtract.t my $bigger_min = $bigger->hour * 60 + $bigger->minute; if ( $bigger->time_zone->has_dst_changes && $bigger->is_dst != $smaller->is_dst ) { $bigger_min -= 60 # it's a 23 hour (local) day if ( $bigger->is_dst && do { my $prev_day = try { $bigger->clone->subtract( days => 1 ) }; $prev_day && !$prev_day->is_dst ? 1 : 0; } ); $bigger_min += 60 # it's a 25 hour (local) day if ( !$bigger->is_dst && do { my $prev_day = try { $bigger->clone->subtract( days => 1 ) }; $prev_day && $prev_day->is_dst ? 1 : 0; } ); } my ( $months, $days, $minutes, $seconds, $nanoseconds ) = $dt1->_adjust_for_positive_difference( $bigger->year * 12 + $bigger->month, $smaller->year * 12 + $smaller->month, $bigger->day, $smaller->day, $bigger_min, $smaller->hour * 60 + $smaller->minute, $bigger->second, $smaller->second, $bigger->nanosecond, $smaller->nanosecond, $minute_length, # XXX - using the smaller as the month length is # somewhat arbitrary, we could also use the bigger - # either way we have reversibility problems $dt1->_month_length( $smaller->year, $smaller->month ), ); if ($negative) { for ( $months, $days, $minutes, $seconds, $nanoseconds ) { # Some versions of Perl can end up with -0 if we do "0 * -1"!! $_ *= -1 if $_; } } return $dt1->duration_class->new( months => $months, days => $days, minutes => $minutes, seconds => $seconds, nanoseconds => $nanoseconds, ); } sub _adjust_for_positive_difference { ## no critic (Subroutines::ProhibitManyArgs) my ( $self, $month1, $month2, $day1, $day2, $min1, $min2, $sec1, $sec2, $nano1, $nano2, $minute_length, $month_length, ) = @_; if ( $nano1 < $nano2 ) { $sec1--; $nano1 += MAX_NANOSECONDS; } if ( $sec1 < $sec2 ) { $min1--; $sec1 += $minute_length; } # A day always has 24 * 60 minutes, though the minutes may vary in # length. if ( $min1 < $min2 ) { $day1--; $min1 += 24 * 60; } if ( $day1 < $day2 ) { $month1--; $day1 += $month_length; } return ( $month1 - $month2, $day1 - $day2, $min1 - $min2, $sec1 - $sec2, $nano1 - $nano2, ); } sub subtract_datetime_absolute { my $self = shift; my $dt = shift; my $utc_rd_secs1 = $self->utc_rd_as_seconds; $utc_rd_secs1 += $self->_accumulated_leap_seconds( $self->{utc_rd_days} ) if !$self->time_zone->is_floating; my $utc_rd_secs2 = $dt->utc_rd_as_seconds; $utc_rd_secs2 += $self->_accumulated_leap_seconds( $dt->{utc_rd_days} ) if !$dt->time_zone->is_floating; my $seconds = $utc_rd_secs1 - $utc_rd_secs2; my $nanoseconds = $self->nanosecond - $dt->nanosecond; if ( $nanoseconds < 0 ) { $seconds--; $nanoseconds += MAX_NANOSECONDS; } return $self->duration_class->new( seconds => $seconds, nanoseconds => $nanoseconds, ); } sub delta_md { my $self = shift; my $dt = shift; my ( $smaller, $bigger ) = sort $self, $dt; my ( $months, $days, undef, undef, undef ) = $dt->_adjust_for_positive_difference( $bigger->year * 12 + $bigger->month, $smaller->year * 12 + $smaller->month, $bigger->day, $smaller->day, 0, 0, 0, 0, 0, 0, 60, $smaller->_month_length( $smaller->year, $smaller->month ), ); return $self->duration_class->new( months => $months, days => $days ); } sub delta_days { my $self = shift; my $dt = shift; my $days = abs( ( $self->local_rd_values )[0] - ( $dt->local_rd_values )[0] ); $self->duration_class->new( days => $days ); } sub delta_ms { my $self = shift; my $dt = shift; my ( $smaller, $greater ) = sort $self, $dt; my $days = int( $greater->jd - $smaller->jd ); my $dur = $greater->subtract_datetime($smaller); my %p; $p{hours} = $dur->hours + ( $days * 24 ); $p{minutes} = $dur->minutes; $p{seconds} = $dur->seconds; return $self->duration_class->new(%p); } sub _add_overload { my ( $dt, $dur, $reversed ) = @_; if ($reversed) { ( $dur, $dt ) = ( $dt, $dur ); } unless ( DateTime::Helpers::isa( $dur, 'DateTime::Duration' ) ) { my $class = ref $dt; my $dt_string = overload::StrVal($dt); Carp::croak( "Cannot add $dur to a $class object ($dt_string).\n" . ' Only a DateTime::Duration object can ' . " be added to a $class object." ); } return $dt->clone->add_duration($dur); } sub _subtract_overload { my ( $date1, $date2, $reversed ) = @_; if ($reversed) { ( $date2, $date1 ) = ( $date1, $date2 ); } if ( DateTime::Helpers::isa( $date2, 'DateTime::Duration' ) ) { my $new = $date1->clone; $new->add_duration( $date2->inverse ); return $new; } elsif ( DateTime::Helpers::isa( $date2, 'DateTime' ) ) { return $date1->subtract_datetime($date2); } else { my $class = ref $date1; my $dt_string = overload::StrVal($date1); Carp::croak( "Cannot subtract $date2 from a $class object ($dt_string).\n" . ' Only a DateTime::Duration or DateTime object can ' . " be subtracted from a $class object." ); } } sub add { my $self = shift; return $self->add_duration( $self->_duration_object_from_args(@_) ); } sub subtract { my $self = shift; my %eom; if ( @_ % 2 == 0 ) { my %p = @_; $eom{end_of_month} = delete $p{end_of_month} if exists $p{end_of_month}; } my $dur = $self->_duration_object_from_args(@_)->inverse(%eom); return $self->add_duration($dur); } # Syntactic sugar for add and subtract: use a duration object if it's # supplied, otherwise build a new one from the arguments. sub _duration_object_from_args { my $self = shift; return $_[0] if @_ == 1 && blessed( $_[0] ) && $_[0]->isa( $self->duration_class ); return $self->duration_class->new(@_); } sub subtract_duration { return $_[0]->add_duration( $_[1]->inverse ) } { my $validator = validation_for( name => '_check_add_duration_params', name_is_optional => 1, params => [ { type => t('Duration') }, ], ); ## no critic (Subroutines::ProhibitExcessComplexity) sub add_duration { my $self = shift; my ($dur) = $validator->(@_); # simple optimization return $self if $dur->is_zero; my %deltas = $dur->deltas; # This bit isn't quite right since DateTime::Infinite::Future - # infinite duration should NaN foreach my $val ( values %deltas ) { my $inf; if ( $val == INFINITY ) { $inf = DateTime::Infinite::Future->new; } elsif ( $val == NEG_INFINITY ) { $inf = DateTime::Infinite::Past->new; } if ($inf) { %$self = %$inf; bless $self, ref $inf; return $self; } } return $self if $self->is_infinite; my %orig = %{$self}; try { $self->_add_duration($dur); } catch { %{$self} = %orig; die $_; }; } } sub _add_duration { my $self = shift; my $dur = shift; my %deltas = $dur->deltas; if ( $deltas{days} ) { $self->{local_rd_days} += $deltas{days}; $self->{utc_year} += int( $deltas{days} / 365 ) + 1; } if ( $deltas{months} ) { # For preserve mode, if it is the last day of the month, make # it the 0th day of the following month (which then will # normalize back to the last day of the new month). my ( $y, $m, $d ) = ( $dur->is_preserve_mode ? $self->_rd2ymd( $self->{local_rd_days} + 1 ) : $self->_rd2ymd( $self->{local_rd_days} ) ); $d -= 1 if $dur->is_preserve_mode; if ( !$dur->is_wrap_mode && $d > 28 ) { # find the rd for the last day of our target month $self->{local_rd_days} = $self->_ymd2rd( $y, $m + $deltas{months} + 1, 0 ); # what day of the month is it? (discard year and month) my $last_day = ( $self->_rd2ymd( $self->{local_rd_days} ) )[2]; # if our original day was less than the last day, # use that instead $self->{local_rd_days} -= $last_day - $d if $last_day > $d; } else { $self->{local_rd_days} = $self->_ymd2rd( $y, $m + $deltas{months}, $d ); } $self->{utc_year} += int( $deltas{months} / 12 ) + 1; } if ( $deltas{days} || $deltas{months} ) { $self->_calc_utc_rd; $self->_handle_offset_modifier( $self->second ); } if ( $deltas{minutes} ) { $self->{utc_rd_secs} += $deltas{minutes} * 60; # This intentionally ignores leap seconds $self->_normalize_tai_seconds( $self->{utc_rd_days}, $self->{utc_rd_secs} ); } if ( $deltas{seconds} || $deltas{nanoseconds} ) { $self->{utc_rd_secs} += $deltas{seconds}; if ( $deltas{nanoseconds} ) { $self->{rd_nanosecs} += $deltas{nanoseconds}; $self->_normalize_nanoseconds( $self->{utc_rd_secs}, $self->{rd_nanosecs} ); } $self->_normalize_seconds; # This might be some big number much bigger than 60, but # that's ok (there are tests in 19leap_second.t to confirm # that) $self->_handle_offset_modifier( $self->second + $deltas{seconds} ); } my $new = ( ref $self )->from_object( object => $self, locale => $self->{locale}, ( $self->{formatter} ? ( formatter => $self->{formatter} ) : () ), ); %$self = %$new; return $self; } sub _compare_overload { # note: $_[1]->compare( $_[0] ) is an error when $_[1] is not a # DateTime (such as the INFINITY value) return undef unless defined $_[1]; return $_[2] ? -$_[0]->compare( $_[1] ) : $_[0]->compare( $_[1] ); } sub _string_compare_overload { my ( $dt1, $dt2, $flip ) = @_; # One is a DateTime object, one isn't. Just stringify and compare. if ( !DateTime::Helpers::can( $dt2, 'utc_rd_values' ) ) { my $sign = $flip ? -1 : 1; return $sign * ( "$dt1" cmp "$dt2" ); } else { my $meth = $dt1->can('_compare_overload'); goto $meth; } } sub compare { shift->_compare( @_, 0 ); } sub compare_ignore_floating { shift->_compare( @_, 1 ); } sub _compare { my ( undef, $dt1, $dt2, $consistent ) = ref $_[0] ? ( undef, @_ ) : @_; return undef unless defined $dt2; if ( !ref $dt2 && ( $dt2 == INFINITY || $dt2 == NEG_INFINITY ) ) { return $dt1->{utc_rd_days} <=> $dt2; } unless ( DateTime::Helpers::can( $dt1, 'utc_rd_values' ) && DateTime::Helpers::can( $dt2, 'utc_rd_values' ) ) { my $dt1_string = overload::StrVal($dt1); my $dt2_string = overload::StrVal($dt2); Carp::croak( 'A DateTime object can only be compared to' . " another DateTime object ($dt1_string, $dt2_string)." ); } if ( !$consistent && DateTime::Helpers::can( $dt1, 'time_zone' ) && DateTime::Helpers::can( $dt2, 'time_zone' ) ) { my $is_floating1 = $dt1->time_zone->is_floating; my $is_floating2 = $dt2->time_zone->is_floating; if ( $is_floating1 && !$is_floating2 ) { $dt1 = $dt1->clone->set_time_zone( $dt2->time_zone ); } elsif ( $is_floating2 && !$is_floating1 ) { $dt2 = $dt2->clone->set_time_zone( $dt1->time_zone ); } } my @dt1_components = $dt1->utc_rd_values; my @dt2_components = $dt2->utc_rd_values; foreach my $i ( 0 .. 2 ) { return $dt1_components[$i] <=> $dt2_components[$i] if $dt1_components[$i] != $dt2_components[$i]; } return 0; } sub _string_equals_overload { my ( $class, $dt1, $dt2 ) = ref $_[0] ? ( undef, @_ ) : @_; if ( !DateTime::Helpers::can( $dt2, 'utc_rd_values' ) ) { return "$dt1" eq "$dt2"; } $class ||= ref $dt1; return !$class->compare( $dt1, $dt2 ); } sub _string_not_equals_overload { return !_string_equals_overload(@_); } sub _normalize_nanoseconds { use integer; # seconds, nanoseconds if ( $_[2] < 0 ) { my $overflow = 1 + $_[2] / MAX_NANOSECONDS; $_[2] += $overflow * MAX_NANOSECONDS; $_[1] -= $overflow; } elsif ( $_[2] >= MAX_NANOSECONDS ) { my $overflow = $_[2] / MAX_NANOSECONDS; $_[2] -= $overflow * MAX_NANOSECONDS; $_[1] += $overflow; } } { my $validator = validation_for( name => '_check_set_params', name_is_optional => 1, params => { year => { type => t('Year'), optional => 1, }, month => { type => t('Month'), optional => 1, }, day => { type => t('DayOfMonth'), optional => 1, }, hour => { type => t('Hour'), optional => 1, }, minute => { type => t('Minute'), optional => 1, }, second => { type => t('Second'), optional => 1, }, nanosecond => { type => t('Nanosecond'), optional => 1, }, locale => { type => t('Locale'), optional => 1, }, }, ); ## no critic (NamingConventions::ProhibitAmbiguousNames) sub set { my $self = shift; my %p = $validator->(@_); if ( $p{locale} ) { carp 'You passed a locale to the set() method.' . ' You should use set_locale() instead, as using set() may alter the local time near a DST boundary.'; } my $new_dt = $self->_new_from_self(%p); %$self = %$new_dt; return $self; } } sub set_year { $_[0]->set( year => $_[1] ) } sub set_month { $_[0]->set( month => $_[1] ) } sub set_day { $_[0]->set( day => $_[1] ) } sub set_hour { $_[0]->set( hour => $_[1] ) } sub set_minute { $_[0]->set( minute => $_[1] ) } sub set_second { $_[0]->set( second => $_[1] ) } sub set_nanosecond { $_[0]->set( nanosecond => $_[1] ) } # These two are special cased because ... if the local time is the hour of a # DST change where the same local time occurs twice then passing it through # _new() can actually change the underlying UTC time, which is bad. { my $validator = validation_for( name => '_check_set_locale_params', name_is_optional => 1, params => [ { type => t( 'Maybe', of => t('Locale') ) }, ], ); sub set_locale { my $self = shift; my ($locale) = $validator->(@_); $self->_set_locale($locale); return $self; } } { my $validator = validation_for( name => '_check_set_formatter_params', name_is_optional => 1, params => [ { type => t( 'Maybe', of => t('Formatter') ) }, ], ); sub set_formatter { my $self = shift; my ($formatter) = $validator->(@_); $self->{formatter} = $formatter; return $self; } } { my %TruncateDefault = ( month => 1, day => 1, hour => 0, minute => 0, second => 0, nanosecond => 0, ); my $validator = validation_for( name => '_check_truncate_params', name_is_optional => 1, params => { to => { type => t('TruncationLevel') }, }, ); my $re = join '|', 'year', 'week', 'local_week', 'quarter', grep { $_ ne 'nanosecond' } keys %TruncateDefault; my $spec = { to => { regex => qr/^(?:$re)$/ } }; ## no critic (Subroutines::ProhibitBuiltinHomonyms) sub truncate { my $self = shift; my %p = $validator->(@_); my %new; if ( $p{to} eq 'week' || $p{to} eq 'local_week' ) { my $first_day_of_week = ( $p{to} eq 'local_week' ) ? $self->{locale}->first_day_of_week : 1; my $day_diff = ( $self->day_of_week - $first_day_of_week ) % 7; if ($day_diff) { $self->add( days => -1 * $day_diff ); } # This can fail if the truncate ends up giving us an invalid local # date time. If that happens we need to reverse the addition we # just did. See https://rt.cpan.org/Ticket/Display.html?id=93347. try { $self->truncate( to => 'day' ); } catch { $self->add( days => $day_diff ); die $_; }; } elsif ( $p{to} eq 'quarter' ) { %new = ( year => $self->year, month => int( ( $self->month - 1 ) / 3 ) * 3 + 1, day => 1, hour => 0, minute => 0, second => 0, nanosecond => 0, ); } else { my $truncate; foreach my $f (qw( year month day hour minute second nanosecond )) { $new{$f} = $truncate ? $TruncateDefault{$f} : $self->$f(); $truncate = 1 if $p{to} eq $f; } } my $new_dt = $self->_new_from_self( %new, _skip_validation => 1 ); %$self = %$new_dt; return $self; } } sub set_time_zone { my ( $self, $tz ) = @_; if ( ref $tz ) { # This is a bit of a hack but it works because time zone objects # are singletons, and if it doesn't work all we lose is a little # bit of speed. return $self if $self->{tz} eq $tz; } else { return $self if $self->{tz}->name() eq $tz; } my $was_floating = $self->{tz}->is_floating; my $old_tz = $self->{tz}; $self->{tz} = ref $tz ? $tz : DateTime::TimeZone->new( name => $tz ); $self->_handle_offset_modifier( $self->second, 1 ); my $e; try { # if it either was or now is floating (but not both) if ( $self->{tz}->is_floating xor $was_floating ) { $self->_calc_utc_rd; } elsif ( !$was_floating ) { $self->_calc_local_rd; } } catch { $e = $_; }; # If we can't recalc the RD values then we shouldn't keep the new TZ. RT # #83940 if ($e) { $self->{tz} = $old_tz; die $e; } return $self; } sub STORABLE_freeze { my $self = shift; my $serialized = q{}; foreach my $key ( qw( utc_rd_days utc_rd_secs rd_nanosecs ) ) { $serialized .= "$key:$self->{$key}|"; } # not used yet, but may be handy in the future. $serialized .= 'version:' . ( $DateTime::VERSION || 'git' ); # Formatter needs to be returned as a reference since it may be # undef or a class name, and Storable will complain if extra # return values aren't refs return $serialized, $self->{locale}, $self->{tz}, \$self->{formatter}; } sub STORABLE_thaw { my $self = shift; shift; my $serialized = shift; my %serialized = map { split /:/ } split /\|/, $serialized; my ( $locale, $tz, $formatter ); # more recent code version if (@_) { ( $locale, $tz, $formatter ) = @_; } else { $tz = DateTime::TimeZone->new( name => delete $serialized{tz} ); $locale = DateTime::Locale->load( delete $serialized{locale} ); } delete $serialized{version}; my $object = bless { utc_vals => [ $serialized{utc_rd_days}, $serialized{utc_rd_secs}, $serialized{rd_nanosecs}, ], tz => $tz, }, 'DateTime::_Thawed'; my %formatter = defined $$formatter ? ( formatter => $$formatter ) : (); my $new = ( ref $self )->from_object( object => $object, locale => $locale, %formatter, ); %$self = %$new; return $self; } ## no critic (Modules::ProhibitMultiplePackages) package # hide from PAUSE DateTime::_Thawed; sub utc_rd_values { @{ $_[0]->{utc_vals} } } sub time_zone { $_[0]->{tz} } 1; # ABSTRACT: A date and time object for Perl __END__ =pod =encoding UTF-8 =head1 NAME DateTime - A date and time object for Perl =head1 VERSION version 1.51 =head1 SYNOPSIS use DateTime; $dt = DateTime->new( year => 1964, month => 10, day => 16, hour => 16, minute => 12, second => 47, nanosecond => 500000000, time_zone => 'Asia/Taipei', ); $dt = DateTime->from_epoch( epoch => $epoch ); $dt = DateTime->now; # same as ( epoch => time() ) $year = $dt->year; $month = $dt->month; # 1-12 $day = $dt->day; # 1-31 $dow = $dt->day_of_week; # 1-7 (Monday is 1) $hour = $dt->hour; # 0-23 $minute = $dt->minute; # 0-59 $second = $dt->second; # 0-61 (leap seconds!) $doy = $dt->day_of_year; # 1-366 (leap years) $doq = $dt->day_of_quarter; # 1.. $qtr = $dt->quarter; # 1-4 # all of the start-at-1 methods above have corresponding start-at-0 # methods, such as $dt->day_of_month_0, $dt->month_0 and so on $ymd = $dt->ymd; # 2002-12-06 $ymd = $dt->ymd('/'); # 2002/12/06 $mdy = $dt->mdy; # 12-06-2002 $mdy = $dt->mdy('/'); # 12/06/2002 $dmy = $dt->dmy; # 06-12-2002 $dmy = $dt->dmy('/'); # 06/12/2002 $hms = $dt->hms; # 14:02:29 $hms = $dt->hms('!'); # 14!02!29 $is_leap = $dt->is_leap_year; # these are localizable, see Locales section $month_name = $dt->month_name; # January, February, ... $month_abbr = $dt->month_abbr; # Jan, Feb, ... $day_name = $dt->day_name; # Monday, Tuesday, ... $day_abbr = $dt->day_abbr; # Mon, Tue, ... # May not work for all possible datetime, see the docs on this # method for more details. $epoch_time = $dt->epoch; $dt2 = $dt + $duration_object; $dt3 = $dt - $duration_object; $duration_object = $dt - $dt2; $dt->set( year => 1882 ); $dt->set_time_zone( 'America/Chicago' ); $dt->set_formatter( $formatter ); =head1 DESCRIPTION DateTime is a class for the representation of date/time combinations, and is part of the Perl DateTime project. For details on this project please see L. The DateTime site has a FAQ which may help answer many "how do I do X?" questions. The FAQ is at L. It represents the Gregorian calendar, extended backwards in time before its creation (in 1582). This is sometimes known as the "proleptic Gregorian calendar". In this calendar, the first day of the calendar (the epoch), is the first day of year 1, which corresponds to the date which was (incorrectly) believed to be the birth of Jesus Christ. The calendar represented does have a year 0, and in that way differs from how dates are often written using "BCE/CE" or "BC/AD". For infinite datetimes, please see the L module. =head1 USAGE =head2 0-based Versus 1-based Numbers The DateTime.pm module follows a simple logic for determining whether or not a given number is 0-based or 1-based. Month, day of month, day of week, and day of year are 1-based. Any method that is 1-based also has an equivalent 0-based method ending in "_0". So for example, this class provides both C and C methods. The C method still treats Monday as the first day of the week. All I