From 22b962906fecebd5527487150f6dd79d69fb8246 Mon Sep 17 00:00:00 2001 From: TizenOpenSource Date: Tue, 13 Feb 2024 13:46:26 +0900 Subject: [PATCH] Imported Upstream version 1.65 --- CODE_OF_CONDUCT.md | 75 + CONTRIBUTING.md | 115 + CREDITS | 25 + Changes | 2017 +++ DateTime.xs | 308 + INSTALL | 75 + LICENSE | 207 + MANIFEST | 151 + META.json | 1324 ++ META.yml | 1004 ++ Makefile.PL | 146 + README.md | 2286 ++++ TODO | 27 + azure-pipelines.yml | 31 + cpanfile | 89 + dev-bin/install-xt-tools.sh | 19 + dist.ini | 70 + git/hooks/pre-commit.sh | 15 + git/setup.pl | 27 + inc/LeapSecondsHeader.pm | 184 + leap_seconds.h | 108 + leaptab.txt | 27 + lib/DateTime.pm | 4809 +++++++ lib/DateTime/Conflicts.pm | 64 + lib/DateTime/Duration.pm | 700 + lib/DateTime/Helpers.pm | 27 + lib/DateTime/Infinite.pm | 287 + lib/DateTime/LeapSecond.pm | 204 + lib/DateTime/PP.pm | 233 + lib/DateTime/PPExtra.pm | 83 + lib/DateTime/Types.pm | 207 + perlcriticrc | 75 + perltidyrc | 22 + ppport.h | 18463 +++++++++++++++++++++++++++ precious.toml | 65 + t/00-report-prereqs.dd | 95 + t/00-report-prereqs.t | 197 + t/00load.t | 10 + t/01sanity.t | 46 + t/02last-day.t | 52 + t/03components.t | 564 + t/04epoch.t | 246 + t/05set.t | 92 + t/06add.t | 497 + t/07compare.t | 252 + t/09greg.t | 122 + t/10subtract.t | 486 + t/11duration.t | 472 + t/12week.t | 55 + t/13strftime.t | 465 + t/14locale.t | 103 + t/15jd.t | 101 + t/16truncate.t | 347 + t/17set-return.t | 40 + t/18today.t | 23 + t/19leap-second.t | 1195 ++ t/20infinite.t | 213 + t/21bad-params.t | 75 + t/22from-doy.t | 69 + t/23storable.t | 107 + t/24from-object.t | 105 + t/25add-subtract.t | 36 + t/26dt-leapsecond-pm.t | 58 + t/27delta.t | 106 + t/28dow.t | 67 + t/29overload.t | 148 + t/30future-tz.t | 55 + t/31formatter.t | 113 + t/32leap-second2.t | 333 + t/33seconds-offset.t | 88 + t/34set-tz.t | 84 + t/35rd-values.t | 54 + t/36invalid-local.t | 74 + t/37local-add.t | 228 + t/38local-subtract.t | 660 + t/39no-so.t | 42 + t/40leap-years.t | 19 + t/41cldr-format.t | 335 + t/42duration-class.t | 31 + t/43new-params.t | 103 + t/44set-formatter.t | 37 + t/45core-time.t | 22 + t/46warnings.t | 89 + t/47default-time-zone.t | 92 + t/48rt-115983.t | 27 + t/49-without-sub-util.t | 11 + t/zzz-check-breaks.t | 36 + xt/author/clean-namespaces.t | 16 + xt/author/eol.t | 74 + xt/author/mojibake.t | 9 + xt/author/no-tabs.t | 74 + xt/author/pod-coverage.t | 72 + xt/author/pod-spell.t | 207 + xt/author/pod-syntax.t | 7 + xt/author/portability.t | 8 + xt/author/pp-00load.t | 15 + xt/author/pp-01sanity.t | 51 + xt/author/pp-02last-day.t | 57 + xt/author/pp-03components.t | 569 + xt/author/pp-04epoch.t | 251 + xt/author/pp-05set.t | 97 + xt/author/pp-06add.t | 502 + xt/author/pp-07compare.t | 257 + xt/author/pp-09greg.t | 127 + xt/author/pp-10subtract.t | 491 + xt/author/pp-11duration.t | 477 + xt/author/pp-12week.t | 60 + xt/author/pp-13strftime.t | 470 + xt/author/pp-14locale.t | 108 + xt/author/pp-15jd.t | 106 + xt/author/pp-16truncate.t | 352 + xt/author/pp-17set-return.t | 45 + xt/author/pp-18today.t | 28 + xt/author/pp-19leap-second.t | 1200 ++ xt/author/pp-20infinite.t | 218 + xt/author/pp-21bad-params.t | 80 + xt/author/pp-22from-doy.t | 74 + xt/author/pp-23storable.t | 112 + xt/author/pp-24from-object.t | 110 + xt/author/pp-25add-subtract.t | 41 + xt/author/pp-27delta.t | 111 + xt/author/pp-28dow.t | 72 + xt/author/pp-29overload.t | 153 + xt/author/pp-30future-tz.t | 60 + xt/author/pp-31formatter.t | 118 + xt/author/pp-32leap-second2.t | 338 + xt/author/pp-33seconds-offset.t | 93 + xt/author/pp-34set-tz.t | 89 + xt/author/pp-35rd-values.t | 59 + xt/author/pp-36invalid-local.t | 79 + xt/author/pp-37local-add.t | 233 + xt/author/pp-38local-subtract.t | 665 + xt/author/pp-40leap-years.t | 24 + xt/author/pp-41cldr-format.t | 340 + xt/author/pp-42duration-class.t | 36 + xt/author/pp-43new-params.t | 108 + xt/author/pp-44set-formatter.t | 42 + xt/author/pp-45core-time.t | 27 + xt/author/pp-46warnings.t | 94 + xt/author/pp-47default-time-zone.t | 97 + xt/author/pp-48rt-115983.t | 32 + xt/author/pp-49-without-sub-util.t | 16 + xt/author/precious.t | 24 + xt/author/test-version.t | 23 + xt/extra/pp-is-loaded.t | 19 + xt/extra/test-all-my-deps.t | 28 + xt/extra/test-ignores-env-vars.t | 22 + xt/extra/xs-is-loaded.t | 14 + xt/release/cpan-changes.t | 10 + xt/release/meta-json.t | 4 + 150 files changed, 51941 insertions(+) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 CREDITS create mode 100644 Changes create mode 100644 DateTime.xs create mode 100644 INSTALL create mode 100644 LICENSE create mode 100644 MANIFEST create mode 100644 META.json create mode 100644 META.yml create mode 100644 Makefile.PL create mode 100644 README.md create mode 100644 TODO create mode 100644 azure-pipelines.yml create mode 100644 cpanfile create mode 100755 dev-bin/install-xt-tools.sh create mode 100644 dist.ini create mode 100755 git/hooks/pre-commit.sh create mode 100755 git/setup.pl create mode 100644 inc/LeapSecondsHeader.pm create mode 100644 leap_seconds.h create mode 100644 leaptab.txt create mode 100644 lib/DateTime.pm create mode 100644 lib/DateTime/Conflicts.pm create mode 100644 lib/DateTime/Duration.pm create mode 100644 lib/DateTime/Helpers.pm create mode 100644 lib/DateTime/Infinite.pm create mode 100644 lib/DateTime/LeapSecond.pm create mode 100644 lib/DateTime/PP.pm create mode 100644 lib/DateTime/PPExtra.pm create mode 100644 lib/DateTime/Types.pm create mode 100644 perlcriticrc create mode 100644 perltidyrc create mode 100644 ppport.h create mode 100644 precious.toml create mode 100644 t/00-report-prereqs.dd create mode 100644 t/00-report-prereqs.t create mode 100644 t/00load.t create mode 100644 t/01sanity.t create mode 100644 t/02last-day.t create mode 100644 t/03components.t create mode 100644 t/04epoch.t create mode 100644 t/05set.t create mode 100644 t/06add.t create mode 100644 t/07compare.t create mode 100644 t/09greg.t create mode 100644 t/10subtract.t create mode 100644 t/11duration.t create mode 100644 t/12week.t create mode 100644 t/13strftime.t create mode 100644 t/14locale.t create mode 100644 t/15jd.t create mode 100644 t/16truncate.t create mode 100644 t/17set-return.t create mode 100644 t/18today.t create mode 100644 t/19leap-second.t create mode 100644 t/20infinite.t create mode 100644 t/21bad-params.t create mode 100644 t/22from-doy.t create mode 100644 t/23storable.t create mode 100644 t/24from-object.t create mode 100644 t/25add-subtract.t create mode 100644 t/26dt-leapsecond-pm.t create mode 100644 t/27delta.t create mode 100644 t/28dow.t create mode 100644 t/29overload.t create mode 100644 t/30future-tz.t create mode 100644 t/31formatter.t create mode 100644 t/32leap-second2.t create mode 100644 t/33seconds-offset.t create mode 100644 t/34set-tz.t create mode 100644 t/35rd-values.t create mode 100644 t/36invalid-local.t create mode 100644 t/37local-add.t create mode 100644 t/38local-subtract.t create mode 100644 t/39no-so.t create mode 100644 t/40leap-years.t create mode 100644 t/41cldr-format.t create mode 100644 t/42duration-class.t create mode 100644 t/43new-params.t create mode 100644 t/44set-formatter.t create mode 100644 t/45core-time.t create mode 100644 t/46warnings.t create mode 100644 t/47default-time-zone.t create mode 100644 t/48rt-115983.t create mode 100644 t/49-without-sub-util.t create mode 100644 t/zzz-check-breaks.t create mode 100644 xt/author/clean-namespaces.t create mode 100644 xt/author/eol.t create mode 100644 xt/author/mojibake.t create mode 100644 xt/author/no-tabs.t create mode 100644 xt/author/pod-coverage.t create mode 100644 xt/author/pod-spell.t create mode 100644 xt/author/pod-syntax.t create mode 100644 xt/author/portability.t create mode 100644 xt/author/pp-00load.t create mode 100644 xt/author/pp-01sanity.t create mode 100644 xt/author/pp-02last-day.t create mode 100644 xt/author/pp-03components.t create mode 100644 xt/author/pp-04epoch.t create mode 100644 xt/author/pp-05set.t create mode 100644 xt/author/pp-06add.t create mode 100644 xt/author/pp-07compare.t create mode 100644 xt/author/pp-09greg.t create mode 100644 xt/author/pp-10subtract.t create mode 100644 xt/author/pp-11duration.t create mode 100644 xt/author/pp-12week.t create mode 100644 xt/author/pp-13strftime.t create mode 100644 xt/author/pp-14locale.t create mode 100644 xt/author/pp-15jd.t create mode 100644 xt/author/pp-16truncate.t create mode 100644 xt/author/pp-17set-return.t create mode 100644 xt/author/pp-18today.t create mode 100644 xt/author/pp-19leap-second.t create mode 100644 xt/author/pp-20infinite.t create mode 100644 xt/author/pp-21bad-params.t create mode 100644 xt/author/pp-22from-doy.t create mode 100644 xt/author/pp-23storable.t create mode 100644 xt/author/pp-24from-object.t create mode 100644 xt/author/pp-25add-subtract.t create mode 100644 xt/author/pp-27delta.t create mode 100644 xt/author/pp-28dow.t create mode 100644 xt/author/pp-29overload.t create mode 100644 xt/author/pp-30future-tz.t create mode 100644 xt/author/pp-31formatter.t create mode 100644 xt/author/pp-32leap-second2.t create mode 100644 xt/author/pp-33seconds-offset.t create mode 100644 xt/author/pp-34set-tz.t create mode 100644 xt/author/pp-35rd-values.t create mode 100644 xt/author/pp-36invalid-local.t create mode 100644 xt/author/pp-37local-add.t create mode 100644 xt/author/pp-38local-subtract.t create mode 100644 xt/author/pp-40leap-years.t create mode 100644 xt/author/pp-41cldr-format.t create mode 100644 xt/author/pp-42duration-class.t create mode 100644 xt/author/pp-43new-params.t create mode 100644 xt/author/pp-44set-formatter.t create mode 100644 xt/author/pp-45core-time.t create mode 100644 xt/author/pp-46warnings.t create mode 100644 xt/author/pp-47default-time-zone.t create mode 100644 xt/author/pp-48rt-115983.t create mode 100644 xt/author/pp-49-without-sub-util.t create mode 100644 xt/author/precious.t create mode 100644 xt/author/test-version.t create mode 100644 xt/extra/pp-is-loaded.t create mode 100644 xt/extra/test-all-my-deps.t create mode 100644 xt/extra/test-ignores-env-vars.t create mode 100644 xt/extra/xs-is-loaded.t create mode 100644 xt/release/cpan-changes.t create mode 100644 xt/release/meta-json.t diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..ac28652 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,75 @@ +# 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 + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..53d4435 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,115 @@ +# 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. Please update the +Changes file with a user-facing description of your changes as part of your +work. 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). + +## Continuous Integration + +All pull requests for this distribution will be automatically tested using +[Azure Pipelines](https://dev.azure.com/houseabsolute/houseabsolute/_build). + +All CI results will be visible in the pull request on GitHub. Follow the +appropriate links for details when tests fail. PRs cannot be merged until tests +pass. + +## Precious + +This distribution uses [precious](https://github.com/houseabsolute/precious) +to enforce a uniform coding style. This is tested as part of the author +testing suite. You can install this and any other necessary non-Perl tools by +running `./dev-bin/install-xt-tools.sh`. + +Then you can use `precious` to tidy and lint your code: + + $> precious tidy -a + $> precious lint -a + +Please run `precious tidy -a` and `precious lint -a` before committing your +changes and address any issues that it reports. + +You can also set up a git pre-commit hook that checks all changed files for +linting issues by running `./git/setup.pl`. + +## 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.015 from a +template file originating in Dist-Zilla-PluginBundle-DROLSKY-1.22. diff --git a/CREDITS b/CREDITS new file mode 100644 index 0000000..d2cbbba --- /dev/null +++ b/CREDITS @@ -0,0 +1,25 @@ +The 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. diff --git a/Changes b/Changes new file mode 100644 index 0000000..8961aed --- /dev/null +++ b/Changes @@ -0,0 +1,2017 @@ +1.65 2023-11-05 + +- This release is the same as 1.64. This release fixes builds on macOS with + Perls before 5.22.0. Reported by Simon Sawert. GH #141. + + +1.64 2023-10-29 (TRIAL RELEASE) + +- Fix builds on macOS with Perls before 5.22.0. This seems to have the same + issue as Windows on older Perls. Reported by Simon Sawert. GH #141. + + +1.63 2023-10-22 + +- This release is the same as 1.62. This releases fixes quadmath builds on + Windows. Reported by @sisyphus. GH #139. + + +1.62 2023-09-04 (TRIAL RELEASE) + +- This is take 3 of trying to use `Perl_isfinite` where it's available. Now we + simply don't use it on Windows unless the Perl version is 5.22.0 or later. + + +1.61 2023-09-02 (TRIAL RELEASE) + +- Fix use of the `Perl_isfinite` function on platforms where this is + broken. On Windows with Perl <= 5.20, it seems like `Perl_isfinite` exists + but it calls `Perl_isinf` and `Perl_isnan`, which don't exist. + + +1.60 2023-08-19 (TRIAL RELEASE) + +- Switched to using the `Perl_isfinite` function instead of trying to + implement this ourselves in XS code. This should fix quadmath builds on + Windows. Reported by @sisyphus. GH #139. + + +1.59 2022-10-23 + +- Fixed tests to pass with DateTime::Locale 1.37+. Reported by Slaven + Rezić. GH #34. + + +1.58 2022-04-18 + +- Fixed tests so that they ignore the value set in the + `PERL_DATETIME_DEFAULT_TZ` env var, if one exists. Reported by Ian Gibbs. GH + #128. + + +1.57 2022-03-03 + +- The last release would die if Sub::Util was not available, but this should + just be an optional requirement. Fixed by Paul Howarth. GH #131. + +- This is the second time I've introduced this bug, so now there's a test to + make sure that DateTime can be loaded if Sub::Util is not + installed. Hopefully this will prevent a third occurrence of this bug. + + +1.56 2022-03-02 + +- The DateTime->from_epoch constructor now accepts a single, non-hashref + argument, and validates it as an epoch value. Requested by Neil Bowers. GH + #119. + + +1.55 2021-12-23 + +- Another documentation fix release. This fixes some mistakes, fixes some + broken links, and removes all references to the long-dead datetime.perl.org + site. + + +1.54 2020-12-04 + +- This release contains a lot of small documentation revisions, both to + formatting and content. + + +1.53 2020-11-08 + +- Added a $dt->rfc3339 method. Based on discussion in GH #109 by worthmine. + + +1.52 2020-02-29 + +- Added a $dt->is_between($dt1, $dt2) method. Based on GH #97 by philip r + brenan. + +- Simplify the calculation of leap seconds in XS. This is a little more + efficient for most use cases (anything with future or recent past + datetimes). Contributed by Mark Overmeer. GH #91. + + +1.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 separator + 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 be 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, the 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. diff --git a/DateTime.xs b/DateTime.xs new file mode 100644 index 0000000..59370d9 --- /dev/null +++ b/DateTime.xs @@ -0,0 +1,308 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" +#include "ppport.h" + +#include + +/* This file is generated by tools/leap_seconds_header.pl */ +#include "leap_seconds.h" + +# if defined(WIN32) || defined(PERL_DARWIN) +# if PERL_VERSION_GE(5, 22, 0) +# define dt_isfinite Perl_isfinite +# endif +# else +# define dt_isfinite Perl_isfinite +# 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 dt_isfinite +void +_normalize_tai_seconds(self, days, secs) + SV* days; + SV* secs; + + PPCODE: + if (dt_isfinite(SvNV(days)) && dt_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 (dt_isfinite(SvNV(days)) && dt_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 dt_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); diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..06a4c36 --- /dev/null +++ b/INSTALL @@ -0,0 +1,75 @@ +This is the Perl distribution DateTime. + +Installing DateTime is straightforward. + +## Installation with cpanm + +If you have cpanm, you only need one line: + + % cpanm DateTime + +If it does not have permission to install modules to the current perl, cpanm +will automatically set up and install to a local::lib in your home directory. +See the local::lib documentation (https://metacpan.org/pod/local::lib) for +details on enabling it in your environment. + +## Installing with the CPAN shell + +Alternatively, if your CPAN shell is set up, you should just be able to do: + + % cpan DateTime + +## Manual installation + +As a last resort, you can manually install it. If you have not already +downloaded the release tarball, you can find the download link on the module's +MetaCPAN page: https://metacpan.org/pod/DateTime + +Untar the tarball, install configure prerequisites (see below), then build it: + + % perl Makefile.PL + % make && make test + +Then install it: + + % make install + +On Windows platforms, you should use `dmake` or `nmake`, instead of `make`. + +If your perl is system-managed, you can create a local::lib in your home +directory to install modules to. For details, see the local::lib documentation: +https://metacpan.org/pod/local::lib + +The prerequisites of this distribution will also have to be installed manually. The +prerequisites are listed in one of the files: `MYMETA.yml` or `MYMETA.json` generated +by running the manual build process described above. + +## Configure Prerequisites + +This distribution requires other modules to be installed before this +distribution's installer can be run. They can be found under the +"configure_requires" key of META.yml or the +"{prereqs}{configure}{requires}" key of META.json. + +## Other Prerequisites + +This distribution may require additional modules to be installed after running +Makefile.PL. +Look for prerequisites in the following phases: + +* to run make, PHASE = build +* to use the module code itself, PHASE = runtime +* to run tests, PHASE = test + +They can all be found in the "PHASE_requires" key of MYMETA.yml or the +"{prereqs}{PHASE}{requires}" key of MYMETA.json. + +## Documentation + +DateTime documentation is available as POD. +You can run `perldoc` from a shell to read the documentation: + + % perldoc DateTime + +For more information on installing Perl modules via CPAN, please see: +https://www.cpan.org/modules/INSTALL.html diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6d8e0db --- /dev/null +++ b/LICENSE @@ -0,0 +1,207 @@ +This software is Copyright (c) 2003 - 2023 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. diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..1c137d7 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,151 @@ +# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.030. +CODE_OF_CONDUCT.md +CONTRIBUTING.md +CREDITS +Changes +DateTime.xs +INSTALL +LICENSE +MANIFEST +META.json +META.yml +Makefile.PL +README.md +TODO +azure-pipelines.yml +cpanfile +dev-bin/install-xt-tools.sh +dist.ini +git/hooks/pre-commit.sh +git/setup.pl +inc/LeapSecondsHeader.pm +leap_seconds.h +leaptab.txt +lib/DateTime.pm +lib/DateTime/Conflicts.pm +lib/DateTime/Duration.pm +lib/DateTime/Helpers.pm +lib/DateTime/Infinite.pm +lib/DateTime/LeapSecond.pm +lib/DateTime/PP.pm +lib/DateTime/PPExtra.pm +lib/DateTime/Types.pm +perlcriticrc +perltidyrc +ppport.h +precious.toml +t/00-report-prereqs.dd +t/00-report-prereqs.t +t/00load.t +t/01sanity.t +t/02last-day.t +t/03components.t +t/04epoch.t +t/05set.t +t/06add.t +t/07compare.t +t/09greg.t +t/10subtract.t +t/11duration.t +t/12week.t +t/13strftime.t +t/14locale.t +t/15jd.t +t/16truncate.t +t/17set-return.t +t/18today.t +t/19leap-second.t +t/20infinite.t +t/21bad-params.t +t/22from-doy.t +t/23storable.t +t/24from-object.t +t/25add-subtract.t +t/26dt-leapsecond-pm.t +t/27delta.t +t/28dow.t +t/29overload.t +t/30future-tz.t +t/31formatter.t +t/32leap-second2.t +t/33seconds-offset.t +t/34set-tz.t +t/35rd-values.t +t/36invalid-local.t +t/37local-add.t +t/38local-subtract.t +t/39no-so.t +t/40leap-years.t +t/41cldr-format.t +t/42duration-class.t +t/43new-params.t +t/44set-formatter.t +t/45core-time.t +t/46warnings.t +t/47default-time-zone.t +t/48rt-115983.t +t/49-without-sub-util.t +t/zzz-check-breaks.t +xt/author/clean-namespaces.t +xt/author/eol.t +xt/author/mojibake.t +xt/author/no-tabs.t +xt/author/pod-coverage.t +xt/author/pod-spell.t +xt/author/pod-syntax.t +xt/author/portability.t +xt/author/pp-00load.t +xt/author/pp-01sanity.t +xt/author/pp-02last-day.t +xt/author/pp-03components.t +xt/author/pp-04epoch.t +xt/author/pp-05set.t +xt/author/pp-06add.t +xt/author/pp-07compare.t +xt/author/pp-09greg.t +xt/author/pp-10subtract.t +xt/author/pp-11duration.t +xt/author/pp-12week.t +xt/author/pp-13strftime.t +xt/author/pp-14locale.t +xt/author/pp-15jd.t +xt/author/pp-16truncate.t +xt/author/pp-17set-return.t +xt/author/pp-18today.t +xt/author/pp-19leap-second.t +xt/author/pp-20infinite.t +xt/author/pp-21bad-params.t +xt/author/pp-22from-doy.t +xt/author/pp-23storable.t +xt/author/pp-24from-object.t +xt/author/pp-25add-subtract.t +xt/author/pp-27delta.t +xt/author/pp-28dow.t +xt/author/pp-29overload.t +xt/author/pp-30future-tz.t +xt/author/pp-31formatter.t +xt/author/pp-32leap-second2.t +xt/author/pp-33seconds-offset.t +xt/author/pp-34set-tz.t +xt/author/pp-35rd-values.t +xt/author/pp-36invalid-local.t +xt/author/pp-37local-add.t +xt/author/pp-38local-subtract.t +xt/author/pp-40leap-years.t +xt/author/pp-41cldr-format.t +xt/author/pp-42duration-class.t +xt/author/pp-43new-params.t +xt/author/pp-44set-formatter.t +xt/author/pp-45core-time.t +xt/author/pp-46warnings.t +xt/author/pp-47default-time-zone.t +xt/author/pp-48rt-115983.t +xt/author/pp-49-without-sub-util.t +xt/author/precious.t +xt/author/test-version.t +xt/extra/pp-is-loaded.t +xt/extra/test-all-my-deps.t +xt/extra/test-ignores-env-vars.t +xt/extra/xs-is-loaded.t +xt/release/cpan-changes.t +xt/release/meta-json.t diff --git a/META.json b/META.json new file mode 100644 index 0000000..5f4dcc4 --- /dev/null +++ b/META.json @@ -0,0 +1,1324 @@ +{ + "abstract" : "A date and time object for Perl", + "author" : [ + "Dave Rolsky " + ], + "dynamic_config" : 0, + "generated_by" : "Dist::Zilla version 6.030, 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" : { + "Capture::Tiny" : "0", + "Cwd" : "0", + "Devel::PPPort" : "3.23", + "Encode" : "0", + "File::Basename" : "0", + "File::Spec" : "0", + "FindBin" : "0", + "Perl::Critic" : "1.138", + "Perl::Critic::Moose" : "1.05", + "Perl::Tidy" : "20210111", + "Pod::Checker" : "1.74", + "Pod::Coverage::TrustPod" : "0", + "Pod::Tidy" : "0.10", + "Pod::Wordlist" : "0", + "Storable" : "0", + "Test::CPAN::Changes" : "0.19", + "Test::CPAN::Meta::JSON" : "0.16", + "Test::CleanNamespaces" : "0.15", + "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::Version" : "2.05", + "Test::Warnings" : "0.005", + "Test::Without::Module" : "0", + "autodie" : "0", + "utf8" : "0" + } + }, + "runtime" : { + "requires" : { + "Carp" : "0", + "DateTime::Locale" : "1.06", + "DateTime::TimeZone" : "2.44", + "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", + "Specio::Subs" : "0", + "Try::Tiny" : "0", + "XSLoader" : "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", + "Test::Without::Module" : "0", + "utf8" : "0" + } + } + }, + "provides" : { + "DateTime" : { + "file" : "lib/DateTime.pm", + "version" : "1.65" + }, + "DateTime::Duration" : { + "file" : "lib/DateTime/Duration.pm", + "version" : "1.65" + }, + "DateTime::Helpers" : { + "file" : "lib/DateTime/Helpers.pm", + "version" : "1.65" + }, + "DateTime::Infinite" : { + "file" : "lib/DateTime/Infinite.pm", + "version" : "1.65" + }, + "DateTime::Infinite::Future" : { + "file" : "lib/DateTime/Infinite.pm", + "version" : "1.65" + }, + "DateTime::Infinite::Past" : { + "file" : "lib/DateTime/Infinite.pm", + "version" : "1.65" + }, + "DateTime::LeapSecond" : { + "file" : "lib/DateTime/LeapSecond.pm", + "version" : "1.65" + }, + "DateTime::PP" : { + "file" : "lib/DateTime/PP.pm", + "version" : "1.65" + }, + "DateTime::PPExtra" : { + "file" : "lib/DateTime/PPExtra.pm", + "version" : "1.65" + }, + "DateTime::Types" : { + "file" : "lib/DateTime/Types.pm", + "version" : "1.65" + } + }, + "release_status" : "stable", + "resources" : { + "bugtracker" : { + "web" : "https://github.com/houseabsolute/DateTime.pm/issues" + }, + "homepage" : "https://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.65", + "x_Dist_Zilla" : { + "perl" : { + "version" : "5.032001" + }, + "plugins" : [ + { + "class" : "Dist::Zilla::Plugin::PruneCruft", + "name" : "PruneCruft", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::BundleAuthordep", + "name" : "@DROLSKY/DROLSKY::BundleAuthordep", + "version" : "1.22" + }, + { + "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.048" + }, + { + "class" : "Dist::Zilla::Plugin::ManifestSkip", + "name" : "@DROLSKY/ManifestSkip", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::License", + "name" : "@DROLSKY/License", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::ExecDir", + "name" : "@DROLSKY/ExecDir", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::ShareDir", + "name" : "@DROLSKY/ShareDir", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::Manifest", + "name" : "@DROLSKY/Manifest", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::CheckVersionIncrement", + "name" : "@DROLSKY/CheckVersionIncrement", + "version" : "0.121750" + }, + { + "class" : "Dist::Zilla::Plugin::TestRelease", + "name" : "@DROLSKY/TestRelease", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::ConfirmRelease", + "name" : "@DROLSKY/ConfirmRelease", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::UploadToCPAN", + "name" : "@DROLSKY/UploadToCPAN", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::VersionFromMainModule", + "config" : { + "Dist::Zilla::Role::ModuleMetadata" : { + "Module::Metadata" : "1.000037", + "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.030" + }, + { + "class" : "Dist::Zilla::Plugin::CopyFilesFromBuild", + "name" : "@DROLSKY/CopyFilesFromBuild", + "version" : "0.170880" + }, + { + "class" : "Dist::Zilla::Plugin::GitHub::Meta", + "name" : "@DROLSKY/GitHub::Meta", + "version" : "0.49" + }, + { + "class" : "Dist::Zilla::Plugin::GitHub::Update", + "config" : { + "Dist::Zilla::Plugin::GitHub::Update" : { + "metacpan" : 1 + } + }, + "name" : "@DROLSKY/GitHub::Update", + "version" : "0.49" + }, + { + "class" : "Dist::Zilla::Plugin::MetaResources", + "name" : "@DROLSKY/MetaResources", + "version" : "6.030" + }, + { + "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.030" + } + ], + "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.000037", + "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.030" + }, + { + "class" : "Dist::Zilla::Plugin::MetaJSON", + "name" : "@DROLSKY/MetaJSON", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::MetaYAML", + "name" : "@DROLSKY/MetaYAML", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::NextRelease", + "name" : "@DROLSKY/NextRelease", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::Prereqs", + "config" : { + "Dist::Zilla::Plugin::Prereqs" : { + "phase" : "test", + "type" : "requires" + } + }, + "name" : "@DROLSKY/Test::More with subtest", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::Prereqs", + "config" : { + "Dist::Zilla::Plugin::Prereqs" : { + "phase" : "develop", + "type" : "requires" + } + }, + "name" : "@DROLSKY/Tools for use with precious", + "version" : "6.030" + }, + { + "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.030" + }, + { + "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.058" + }, + { + "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::BundleAuthordep", + "Dist::Zilla::Plugin::DROLSKY::Contributors", + "Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch", + "Dist::Zilla::Plugin::DROLSKY::License", + "Dist::Zilla::Plugin::DROLSKY::MakeMaker", + "Dist::Zilla::Plugin::DROLSKY::PerlLinterConfigFiles", + "Dist::Zilla::Plugin::DROLSKY::Precious", + "Dist::Zilla::Plugin::DROLSKY::Test::Precious", + "Dist::Zilla::Plugin::DROLSKY::WeaverConfig", + "Pod::Weaver::PluginBundle::DROLSKY" + ] + } + }, + "name" : "@DROLSKY/PromptIfStale", + "version" : "0.058" + }, + { + "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", + "DateTimeX", + "DateTimes", + "Domini", + "EEEE", + "EEEEE", + "Fl\u00e1vio", + "Formatters", + "GGGG", + "GGGGG", + "Glock", + "Hant", + "IEEE", + "LLL", + "LLLL", + "LLLLL", + "Liang", + "Liang's", + "MMM", + "MMMM", + "MMMMM", + "Measham", + "Measham's", + "MetaCPAN", + "POSIX", + "PayPal", + "PayPal", + "Postgres", + "QQQ", + "QQQQ", + "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", + "env", + "fallback", + "formatter", + "hh", + "iCal", + "ji", + "mutiplication", + "na", + "namespace", + "ni", + "nitty", + "other's", + "proleptic", + "qqq", + "qqqq", + "sexagesimal", + "subclasses", + "tidyable", + "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.030" + }, + { + "class" : "Dist::Zilla::Plugin::MojibakeTests", + "name" : "@DROLSKY/MojibakeTests", + "version" : "0.8" + }, + { + "class" : "Dist::Zilla::Plugin::RunExtraTests", + "config" : { + "Dist::Zilla::Role::TestRunner" : { + "default_jobs" : "12" + } + }, + "name" : "@DROLSKY/RunExtraTests", + "version" : "0.029" + }, + { + "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.001001" + }, + { + "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs", + "name" : "@DROLSKY/Test::ReportPrereqs", + "version" : "0.029" + }, + { + "class" : "Dist::Zilla::Plugin::Test::Version", + "name" : "@DROLSKY/Test::Version", + "version" : "1.09" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::Test::Precious", + "name" : "@DROLSKY/DROLSKY::Test::Precious", + "version" : "1.22" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::Contributors", + "name" : "@DROLSKY/DROLSKY::Contributors", + "version" : "1.22" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Contributors", + "config" : { + "Dist::Zilla::Plugin::Git::Contributors" : { + "git_version" : "2.42.0", + "include_authors" : 0, + "include_releaser" : 1, + "order_by" : "name", + "paths" : [] + } + }, + "name" : "@DROLSKY/Git::Contributors", + "version" : "0.036" + }, + { + "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.018" + }, + { + "class" : "Pod::Weaver::Plugin::H1Nester", + "name" : "@CorePrep/H1Nester", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Plugin::SingleEncoding", + "name" : "@DROLSKY/SingleEncoding", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Plugin::Transformer", + "name" : "@DROLSKY/List", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Plugin::Transformer", + "name" : "@DROLSKY/Verbatim", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Region", + "name" : "@DROLSKY/header", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Name", + "name" : "@DROLSKY/Name", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Version", + "name" : "@DROLSKY/Version", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Region", + "name" : "@DROLSKY/prelude", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Generic", + "name" : "SYNOPSIS", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Generic", + "name" : "DESCRIPTION", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Generic", + "name" : "OVERVIEW", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Collect", + "name" : "ATTRIBUTES", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Collect", + "name" : "METHODS", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Collect", + "name" : "FUNCTIONS", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Collect", + "name" : "TYPES", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Leftovers", + "name" : "@DROLSKY/Leftovers", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Region", + "name" : "@DROLSKY/postlude", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::GenerateSection", + "name" : "@DROLSKY/generate SUPPORT", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::AllowOverride", + "name" : "@DROLSKY/allow override SUPPORT", + "version" : "0.05" + }, + { + "class" : "Pod::Weaver::Section::GenerateSection", + "name" : "@DROLSKY/generate SOURCE", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::GenerateSection", + "name" : "@DROLSKY/generate DONATIONS", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Authors", + "name" : "@DROLSKY/Authors", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::Contributors", + "name" : "@DROLSKY/Contributors", + "version" : "0.009" + }, + { + "class" : "Pod::Weaver::Section::Legal", + "name" : "@DROLSKY/Legal", + "version" : "4.018" + }, + { + "class" : "Pod::Weaver::Section::AllowOverride", + "name" : "@DROLSKY/allow override Legal", + "version" : "0.05" + }, + { + "class" : "Pod::Weaver::Section::Region", + "name" : "@DROLSKY/footer", + "version" : "4.018" + } + ] + } + }, + "name" : "@DROLSKY/SurgicalPodWeaver", + "version" : "0.0023" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::WeaverConfig", + "name" : "@DROLSKY/DROLSKY::WeaverConfig", + "version" : "1.22" + }, + { + "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.015" + }, + { + "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.015" + }, + { + "class" : "Dist::Zilla::Plugin::InstallGuide", + "config" : { + "Dist::Zilla::Role::ModuleMetadata" : { + "Module::Metadata" : "1.000037", + "version" : "0.006" + } + }, + "name" : "@DROLSKY/InstallGuide", + "version" : "1.200014" + }, + { + "class" : "Dist::Zilla::Plugin::CPANFile", + "name" : "@DROLSKY/CPANFile", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::PPPort", + "name" : "@DROLSKY/PPPort", + "version" : "0.010" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::License", + "name" : "@DROLSKY/DROLSKY::License", + "version" : "1.22" + }, + { + "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.000037", + "version" : "0.006" + } + }, + "name" : "@DROLSKY/CheckSelfDependency", + "version" : "0.011" + }, + { + "class" : "Dist::Zilla::Plugin::CheckPrereqsIndexed", + "name" : "@DROLSKY/CheckPrereqsIndexed", + "version" : "0.022" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch", + "config" : { + "Dist::Zilla::Role::Git::Repo" : { + "git_version" : "2.42.0", + "repo_root" : "." + } + }, + "name" : "@DROLSKY/DROLSKY::Git::CheckFor::CorrectBranch", + "version" : "1.22" + }, + { + "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.42.0", + "repo_root" : "." + } + }, + "name" : "@DROLSKY/Git::CheckFor::MergeConflicts", + "version" : "0.014" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::PerlLinterConfigFiles", + "name" : "@DROLSKY/DROLSKY::PerlLinterConfigFiles", + "version" : "1.22" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::DevTools", + "name" : "@DROLSKY/DROLSKY::DevTools", + "version" : "1.22" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::Precious", + "name" : "@DROLSKY/DROLSKY::Precious", + "version" : "1.22" + }, + { + "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", + "precious.toml" + ], + "allow_dirty_match" : [], + "changelog" : "Changes" + }, + "Dist::Zilla::Role::Git::Repo" : { + "git_version" : "2.42.0", + "repo_root" : "." + } + }, + "name" : "@DROLSKY/Git::Check", + "version" : "2.048" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Commit", + "config" : { + "Dist::Zilla::Plugin::Git::Commit" : { + "add_files_in" : [], + "commit_msg" : "v%V%n%n%c", + "signoff" : 0 + }, + "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", + "precious.toml" + ], + "allow_dirty_match" : [], + "changelog" : "Changes" + }, + "Dist::Zilla::Role::Git::Repo" : { + "git_version" : "2.42.0", + "repo_root" : "." + }, + "Dist::Zilla::Role::Git::StringFormatter" : { + "time_zone" : "local" + } + }, + "name" : "@DROLSKY/Commit generated files", + "version" : "2.048" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Tag", + "config" : { + "Dist::Zilla::Plugin::Git::Tag" : { + "branch" : null, + "changelog" : "Changes", + "signed" : 0, + "tag" : "v1.65", + "tag_format" : "v%V", + "tag_message" : "v%V" + }, + "Dist::Zilla::Role::Git::Repo" : { + "git_version" : "2.42.0", + "repo_root" : "." + }, + "Dist::Zilla::Role::Git::StringFormatter" : { + "time_zone" : "local" + } + }, + "name" : "@DROLSKY/Git::Tag", + "version" : "2.048" + }, + { + "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.42.0", + "repo_root" : "." + } + }, + "name" : "@DROLSKY/Git::Push", + "version" : "2.048" + }, + { + "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", + "signoff" : 0 + }, + "Dist::Zilla::Role::Git::DirtyFiles" : { + "allow_dirty" : [ + "Changes", + "dist.ini" + ], + "allow_dirty_match" : [ + "(?^:.+)" + ], + "changelog" : "Changes" + }, + "Dist::Zilla::Role::Git::Repo" : { + "git_version" : "2.42.0", + "repo_root" : "." + }, + "Dist::Zilla::Role::Git::StringFormatter" : { + "time_zone" : "local" + } + }, + "name" : "@DROLSKY/Commit version bump", + "version" : "2.048" + }, + { + "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.42.0", + "repo_root" : "." + } + }, + "name" : "@DROLSKY/Push version bump", + "version" : "2.048" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::MakeMaker", + "config" : { + "Dist::Zilla::Plugin::MakeMaker" : { + "make_path" : "make", + "version" : "6.030" + }, + "Dist::Zilla::Plugin::MakeMaker::Awesome" : { + "version" : "0.49" + }, + "Dist::Zilla::Role::TestRunner" : { + "default_jobs" : "12", + "version" : "6.030" + } + }, + "name" : "@DROLSKY/DROLSKY::MakeMaker", + "version" : "1.22" + }, + { + "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.030" + }, + { + "class" : "Dist::Zilla::Plugin::Prereqs", + "config" : { + "Dist::Zilla::Plugin::Prereqs" : { + "phase" : "develop", + "type" : "requires" + } + }, + "name" : "DevelopRequires", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::PurePerlTests", + "name" : "PurePerlTests", + "version" : "0.06" + }, + { + "class" : "Dist::Zilla::Plugin::Conflicts", + "name" : "Conflicts", + "version" : "0.20" + }, + { + "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.000037", + "version" : "0.006" + } + }, + "name" : "Test::CheckBreaks", + "version" : "0.019" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":InstallModules", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":IncModules", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":TestFiles", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":ExtraTestFiles", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":ExecFiles", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":PerlExecFiles", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":ShareFiles", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":MainModule", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":AllFiles", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":NoFiles", + "version" : "6.030" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : "@DROLSKY/MetaProvides::Package/AUTOVIV/:InstallModulesPM", + "version" : "6.030" + } + ], + "zilla" : { + "class" : "Dist::Zilla::Dist::Builder", + "config" : { + "is_trial" : 0 + }, + "version" : "6.030" + } + }, + "x_authority" : "cpan:DROLSKY", + "x_breaks" : { + "DateTime::Format::Mail" : "<= 0.402" + }, + "x_contributors" : [ + "Ben Bennett ", + "Christian Hansen ", + "Daisuke Maki ", + "Dan Book ", + "Dan Stewart ", + "David Dyck ", + "David E. Wheeler ", + "David Precious ", + "Doug Bell ", + "Fl\u00e1vio Soibelmann Glock ", + "Gianni Ceccarelli ", + "Gregory Oschwald ", + "Hauke D ", + "Iain Truskett ", + "James Raspass ", + "Jason McIntosh ", + "Joshua Hoblitt ", + "Karen Etheridge ", + "Mark Overmeer ", + "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) ", + "philip r brenan ", + "Ricardo Signes ", + "Richard Bowen ", + "Ron Hill ", + "Sam Kington ", + "viviparous " + ], + "x_generated_by_perl" : "v5.32.1", + "x_serialization_backend" : "Cpanel::JSON::XS version 4.26", + "x_spdx_expression" : "Artistic-2.0" +} + diff --git a/META.yml b/META.yml new file mode 100644 index 0000000..ca365e2 --- /dev/null +++ b/META.yml @@ -0,0 +1,1004 @@ +--- +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' + Test::Without::Module: '0' + utf8: '0' +configure_requires: + Dist::CheckConflicts: '0.02' + ExtUtils::MakeMaker: '0' +dynamic_config: 0 +generated_by: 'Dist::Zilla version 6.030, 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.65' + DateTime::Duration: + file: lib/DateTime/Duration.pm + version: '1.65' + DateTime::Helpers: + file: lib/DateTime/Helpers.pm + version: '1.65' + DateTime::Infinite: + file: lib/DateTime/Infinite.pm + version: '1.65' + DateTime::Infinite::Future: + file: lib/DateTime/Infinite.pm + version: '1.65' + DateTime::Infinite::Past: + file: lib/DateTime/Infinite.pm + version: '1.65' + DateTime::LeapSecond: + file: lib/DateTime/LeapSecond.pm + version: '1.65' + DateTime::PP: + file: lib/DateTime/PP.pm + version: '1.65' + DateTime::PPExtra: + file: lib/DateTime/PPExtra.pm + version: '1.65' + DateTime::Types: + file: lib/DateTime/Types.pm + version: '1.65' +requires: + Carp: '0' + DateTime::Locale: '1.06' + DateTime::TimeZone: '2.44' + 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' + Specio::Subs: '0' + Try::Tiny: '0' + XSLoader: '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: https://metacpan.org/release/DateTime + repository: git://github.com/houseabsolute/DateTime.pm.git +version: '1.65' +x_Dist_Zilla: + perl: + version: '5.032001' + plugins: + - + class: Dist::Zilla::Plugin::PruneCruft + name: PruneCruft + version: '6.030' + - + class: Dist::Zilla::Plugin::DROLSKY::BundleAuthordep + name: '@DROLSKY/DROLSKY::BundleAuthordep' + version: '1.22' + - + 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.048' + - + class: Dist::Zilla::Plugin::ManifestSkip + name: '@DROLSKY/ManifestSkip' + version: '6.030' + - + class: Dist::Zilla::Plugin::License + name: '@DROLSKY/License' + version: '6.030' + - + class: Dist::Zilla::Plugin::ExecDir + name: '@DROLSKY/ExecDir' + version: '6.030' + - + class: Dist::Zilla::Plugin::ShareDir + name: '@DROLSKY/ShareDir' + version: '6.030' + - + class: Dist::Zilla::Plugin::Manifest + name: '@DROLSKY/Manifest' + version: '6.030' + - + class: Dist::Zilla::Plugin::CheckVersionIncrement + name: '@DROLSKY/CheckVersionIncrement' + version: '0.121750' + - + class: Dist::Zilla::Plugin::TestRelease + name: '@DROLSKY/TestRelease' + version: '6.030' + - + class: Dist::Zilla::Plugin::ConfirmRelease + name: '@DROLSKY/ConfirmRelease' + version: '6.030' + - + class: Dist::Zilla::Plugin::UploadToCPAN + name: '@DROLSKY/UploadToCPAN' + version: '6.030' + - + class: Dist::Zilla::Plugin::VersionFromMainModule + config: + Dist::Zilla::Role::ModuleMetadata: + Module::Metadata: '1.000037' + 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.030' + - + class: Dist::Zilla::Plugin::CopyFilesFromBuild + name: '@DROLSKY/CopyFilesFromBuild' + version: '0.170880' + - + class: Dist::Zilla::Plugin::GitHub::Meta + name: '@DROLSKY/GitHub::Meta' + version: '0.49' + - + class: Dist::Zilla::Plugin::GitHub::Update + config: + Dist::Zilla::Plugin::GitHub::Update: + metacpan: 1 + name: '@DROLSKY/GitHub::Update' + version: '0.49' + - + class: Dist::Zilla::Plugin::MetaResources + name: '@DROLSKY/MetaResources' + version: '6.030' + - + 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.030' + 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.000037' + 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.030' + - + class: Dist::Zilla::Plugin::MetaJSON + name: '@DROLSKY/MetaJSON' + version: '6.030' + - + class: Dist::Zilla::Plugin::MetaYAML + name: '@DROLSKY/MetaYAML' + version: '6.030' + - + class: Dist::Zilla::Plugin::NextRelease + name: '@DROLSKY/NextRelease' + version: '6.030' + - + class: Dist::Zilla::Plugin::Prereqs + config: + Dist::Zilla::Plugin::Prereqs: + phase: test + type: requires + name: '@DROLSKY/Test::More with subtest' + version: '6.030' + - + class: Dist::Zilla::Plugin::Prereqs + config: + Dist::Zilla::Plugin::Prereqs: + phase: develop + type: requires + name: '@DROLSKY/Tools for use with precious' + version: '6.030' + - + 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.030' + - + 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.058' + - + 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::BundleAuthordep + - Dist::Zilla::Plugin::DROLSKY::Contributors + - Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch + - Dist::Zilla::Plugin::DROLSKY::License + - Dist::Zilla::Plugin::DROLSKY::MakeMaker + - Dist::Zilla::Plugin::DROLSKY::PerlLinterConfigFiles + - Dist::Zilla::Plugin::DROLSKY::Precious + - Dist::Zilla::Plugin::DROLSKY::Test::Precious + - Dist::Zilla::Plugin::DROLSKY::WeaverConfig + - Pod::Weaver::PluginBundle::DROLSKY + name: '@DROLSKY/PromptIfStale' + version: '0.058' + - + 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 + - DateTimeX + - DateTimes + - Domini + - EEEE + - EEEEE + - Flávio + - Formatters + - GGGG + - GGGGG + - Glock + - Hant + - IEEE + - LLL + - LLLL + - LLLLL + - Liang + - "Liang's" + - MMM + - MMMM + - MMMMM + - Measham + - "Measham's" + - MetaCPAN + - POSIX + - PayPal + - PayPal + - Postgres + - QQQ + - QQQQ + - 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 + - env + - fallback + - formatter + - hh + - iCal + - ji + - mutiplication + - na + - namespace + - ni + - nitty + - "other's" + - proleptic + - qqq + - qqqq + - sexagesimal + - subclasses + - tidyable + - 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.030' + - + class: Dist::Zilla::Plugin::MojibakeTests + name: '@DROLSKY/MojibakeTests' + version: '0.8' + - + class: Dist::Zilla::Plugin::RunExtraTests + config: + Dist::Zilla::Role::TestRunner: + default_jobs: '12' + name: '@DROLSKY/RunExtraTests' + version: '0.029' + - + 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.001001' + - + class: Dist::Zilla::Plugin::Test::ReportPrereqs + name: '@DROLSKY/Test::ReportPrereqs' + version: '0.029' + - + class: Dist::Zilla::Plugin::Test::Version + name: '@DROLSKY/Test::Version' + version: '1.09' + - + class: Dist::Zilla::Plugin::DROLSKY::Test::Precious + name: '@DROLSKY/DROLSKY::Test::Precious' + version: '1.22' + - + class: Dist::Zilla::Plugin::DROLSKY::Contributors + name: '@DROLSKY/DROLSKY::Contributors' + version: '1.22' + - + class: Dist::Zilla::Plugin::Git::Contributors + config: + Dist::Zilla::Plugin::Git::Contributors: + git_version: 2.42.0 + include_authors: 0 + include_releaser: 1 + order_by: name + paths: [] + name: '@DROLSKY/Git::Contributors' + version: '0.036' + - + 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.018' + - + class: Pod::Weaver::Plugin::H1Nester + name: '@CorePrep/H1Nester' + version: '4.018' + - + class: Pod::Weaver::Plugin::SingleEncoding + name: '@DROLSKY/SingleEncoding' + version: '4.018' + - + class: Pod::Weaver::Plugin::Transformer + name: '@DROLSKY/List' + version: '4.018' + - + class: Pod::Weaver::Plugin::Transformer + name: '@DROLSKY/Verbatim' + version: '4.018' + - + class: Pod::Weaver::Section::Region + name: '@DROLSKY/header' + version: '4.018' + - + class: Pod::Weaver::Section::Name + name: '@DROLSKY/Name' + version: '4.018' + - + class: Pod::Weaver::Section::Version + name: '@DROLSKY/Version' + version: '4.018' + - + class: Pod::Weaver::Section::Region + name: '@DROLSKY/prelude' + version: '4.018' + - + class: Pod::Weaver::Section::Generic + name: SYNOPSIS + version: '4.018' + - + class: Pod::Weaver::Section::Generic + name: DESCRIPTION + version: '4.018' + - + class: Pod::Weaver::Section::Generic + name: OVERVIEW + version: '4.018' + - + class: Pod::Weaver::Section::Collect + name: ATTRIBUTES + version: '4.018' + - + class: Pod::Weaver::Section::Collect + name: METHODS + version: '4.018' + - + class: Pod::Weaver::Section::Collect + name: FUNCTIONS + version: '4.018' + - + class: Pod::Weaver::Section::Collect + name: TYPES + version: '4.018' + - + class: Pod::Weaver::Section::Leftovers + name: '@DROLSKY/Leftovers' + version: '4.018' + - + class: Pod::Weaver::Section::Region + name: '@DROLSKY/postlude' + version: '4.018' + - + class: Pod::Weaver::Section::GenerateSection + name: '@DROLSKY/generate SUPPORT' + version: '4.018' + - + class: Pod::Weaver::Section::AllowOverride + name: '@DROLSKY/allow override SUPPORT' + version: '0.05' + - + class: Pod::Weaver::Section::GenerateSection + name: '@DROLSKY/generate SOURCE' + version: '4.018' + - + class: Pod::Weaver::Section::GenerateSection + name: '@DROLSKY/generate DONATIONS' + version: '4.018' + - + class: Pod::Weaver::Section::Authors + name: '@DROLSKY/Authors' + version: '4.018' + - + class: Pod::Weaver::Section::Contributors + name: '@DROLSKY/Contributors' + version: '0.009' + - + class: Pod::Weaver::Section::Legal + name: '@DROLSKY/Legal' + version: '4.018' + - + class: Pod::Weaver::Section::AllowOverride + name: '@DROLSKY/allow override Legal' + version: '0.05' + - + class: Pod::Weaver::Section::Region + name: '@DROLSKY/footer' + version: '4.018' + name: '@DROLSKY/SurgicalPodWeaver' + version: '0.0023' + - + class: Dist::Zilla::Plugin::DROLSKY::WeaverConfig + name: '@DROLSKY/DROLSKY::WeaverConfig' + version: '1.22' + - + 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.015' + - + 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.015' + - + class: Dist::Zilla::Plugin::InstallGuide + config: + Dist::Zilla::Role::ModuleMetadata: + Module::Metadata: '1.000037' + version: '0.006' + name: '@DROLSKY/InstallGuide' + version: '1.200014' + - + class: Dist::Zilla::Plugin::CPANFile + name: '@DROLSKY/CPANFile' + version: '6.030' + - + class: Dist::Zilla::Plugin::PPPort + name: '@DROLSKY/PPPort' + version: '0.010' + - + class: Dist::Zilla::Plugin::DROLSKY::License + name: '@DROLSKY/DROLSKY::License' + version: '1.22' + - + 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.000037' + version: '0.006' + name: '@DROLSKY/CheckSelfDependency' + version: '0.011' + - + class: Dist::Zilla::Plugin::CheckPrereqsIndexed + name: '@DROLSKY/CheckPrereqsIndexed' + version: '0.022' + - + class: Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch + config: + Dist::Zilla::Role::Git::Repo: + git_version: 2.42.0 + repo_root: . + name: '@DROLSKY/DROLSKY::Git::CheckFor::CorrectBranch' + version: '1.22' + - + 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.42.0 + repo_root: . + name: '@DROLSKY/Git::CheckFor::MergeConflicts' + version: '0.014' + - + class: Dist::Zilla::Plugin::DROLSKY::PerlLinterConfigFiles + name: '@DROLSKY/DROLSKY::PerlLinterConfigFiles' + version: '1.22' + - + class: Dist::Zilla::Plugin::DROLSKY::DevTools + name: '@DROLSKY/DROLSKY::DevTools' + version: '1.22' + - + class: Dist::Zilla::Plugin::DROLSKY::Precious + name: '@DROLSKY/DROLSKY::Precious' + version: '1.22' + - + 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 + - precious.toml + allow_dirty_match: [] + changelog: Changes + Dist::Zilla::Role::Git::Repo: + git_version: 2.42.0 + repo_root: . + name: '@DROLSKY/Git::Check' + version: '2.048' + - + class: Dist::Zilla::Plugin::Git::Commit + config: + Dist::Zilla::Plugin::Git::Commit: + add_files_in: [] + commit_msg: v%V%n%n%c + signoff: 0 + 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 + - precious.toml + allow_dirty_match: [] + changelog: Changes + Dist::Zilla::Role::Git::Repo: + git_version: 2.42.0 + repo_root: . + Dist::Zilla::Role::Git::StringFormatter: + time_zone: local + name: '@DROLSKY/Commit generated files' + version: '2.048' + - + class: Dist::Zilla::Plugin::Git::Tag + config: + Dist::Zilla::Plugin::Git::Tag: + branch: ~ + changelog: Changes + signed: 0 + tag: v1.65 + tag_format: v%V + tag_message: v%V + Dist::Zilla::Role::Git::Repo: + git_version: 2.42.0 + repo_root: . + Dist::Zilla::Role::Git::StringFormatter: + time_zone: local + name: '@DROLSKY/Git::Tag' + version: '2.048' + - + 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.42.0 + repo_root: . + name: '@DROLSKY/Git::Push' + version: '2.048' + - + 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' + signoff: 0 + Dist::Zilla::Role::Git::DirtyFiles: + allow_dirty: + - Changes + - dist.ini + allow_dirty_match: + - (?^:.+) + changelog: Changes + Dist::Zilla::Role::Git::Repo: + git_version: 2.42.0 + repo_root: . + Dist::Zilla::Role::Git::StringFormatter: + time_zone: local + name: '@DROLSKY/Commit version bump' + version: '2.048' + - + 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.42.0 + repo_root: . + name: '@DROLSKY/Push version bump' + version: '2.048' + - + class: Dist::Zilla::Plugin::DROLSKY::MakeMaker + config: + Dist::Zilla::Plugin::MakeMaker: + make_path: make + version: '6.030' + Dist::Zilla::Plugin::MakeMaker::Awesome: + version: '0.49' + Dist::Zilla::Role::TestRunner: + default_jobs: '12' + version: '6.030' + name: '@DROLSKY/DROLSKY::MakeMaker' + version: '1.22' + - + 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.030' + - + class: Dist::Zilla::Plugin::Prereqs + config: + Dist::Zilla::Plugin::Prereqs: + phase: develop + type: requires + name: DevelopRequires + version: '6.030' + - + class: Dist::Zilla::Plugin::PurePerlTests + name: PurePerlTests + version: '0.06' + - + class: Dist::Zilla::Plugin::Conflicts + name: Conflicts + version: '0.20' + - + 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.000037' + version: '0.006' + name: Test::CheckBreaks + version: '0.019' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':InstallModules' + version: '6.030' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':IncModules' + version: '6.030' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':TestFiles' + version: '6.030' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':ExtraTestFiles' + version: '6.030' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':ExecFiles' + version: '6.030' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':PerlExecFiles' + version: '6.030' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':ShareFiles' + version: '6.030' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':MainModule' + version: '6.030' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':AllFiles' + version: '6.030' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':NoFiles' + version: '6.030' + - + class: Dist::Zilla::Plugin::FinderCode + name: '@DROLSKY/MetaProvides::Package/AUTOVIV/:InstallModulesPM' + version: '6.030' + zilla: + class: Dist::Zilla::Dist::Builder + config: + is_trial: '0' + version: '6.030' +x_authority: cpan:DROLSKY +x_breaks: + DateTime::Format::Mail: '<= 0.402' +x_contributors: + - 'Ben Bennett ' + - 'Christian Hansen ' + - 'Daisuke Maki ' + - 'Dan Book ' + - 'Dan Stewart ' + - 'David Dyck ' + - 'David E. Wheeler ' + - 'David Precious ' + - 'Doug Bell ' + - 'Flávio Soibelmann Glock ' + - 'Gianni Ceccarelli ' + - 'Gregory Oschwald ' + - 'Hauke D ' + - 'Iain Truskett ' + - 'James Raspass ' + - 'Jason McIntosh ' + - 'Joshua Hoblitt ' + - 'Karen Etheridge ' + - 'Mark Overmeer ' + - '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) ' + - 'philip r brenan ' + - 'Ricardo Signes ' + - 'Richard Bowen ' + - 'Ron Hill ' + - 'Sam Kington ' + - 'viviparous ' +x_generated_by_perl: v5.32.1 +x_serialization_backend: 'YAML::Tiny version 1.73' +x_spdx_expression: Artistic-2.0 diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..0d8506d --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,146 @@ +# This Makefile.PL for DateTime was generated by +# Dist::Zilla::Plugin::DROLSKY::MakeMaker 1.22 +# and Dist::Zilla::Plugin::MakeMaker::Awesome 0.49. +# 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.44", + "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, + "Specio::Subs" => 0, + "Try::Tiny" => 0, + "XSLoader" => 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", + "Test::Without::Module" => 0, + "utf8" => 0 + }, + "VERSION" => "1.65", + "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.44", + "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, + "Specio::Subs" => 0, + "Storable" => 0, + "Test::Fatal" => 0, + "Test::More" => "0.96", + "Test::Warnings" => "0.005", + "Test::Without::Module" => 0, + "Try::Tiny" => 0, + "XSLoader" => 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; +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..e794611 --- /dev/null +++ b/README.md @@ -0,0 +1,2286 @@ +# NAME + +DateTime - A date and time object for Perl + +# VERSION + +version 1.65 + +# 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. + +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%3A%3AInfinite) +module. + +# USAGE + +## 0-based Versus 1-based Numbers + +The `DateTime` 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: + + my $local_time_zone = DateTime::TimeZone->new( name => 'local' ); + + # then everywhere else + + my $dt = DateTime->new( ..., time_zone => $local_time_zone ); + +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. + +## Far Future DST + +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, to year +(+/-)12,626,367,463,883,278 (12.626 quadrillion). + +# METHODS + +DateTime provides 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%3A%3ATimeZone) is made much +faster. + +### DateTime->new( ... ) + + my $dt = DateTime->new( + year => 1966, + month => 10, + day => 25, + hour => 7, + minute => 15, + second => 47, + nanosecond => 500000000, + time_zone => 'America/Chicago', + ); + +This class method accepts the following parameters: + +- year + + An integer year for the DateTime. This can be any integer number within the + valid range for your system (See ["Upper and Lower Bounds"](#upper-and-lower-bounds)). This is required. + +- month + + An integer from 1-12. Defaults to 1. + +- day + + An integer from 1-31. The value will be validated based on the month, to + prevent creating invalid dates like February 30. Defaults to 1. + +- hour + + An integer from 0-23. Hour 0 is midnight at the beginning of the given date. + Defaults to 0. + +- minute + + An integer from 0-59. Defaults to 0. + +- second + + An integer from 0-61. Values of 60 or 61 are only allowed when the specified + date and time have a leap second. Defaults to 0. + +- nanosecond + + An integer that is greater than or equal to 0. If this number is greater than 1 + billion, it will be normalized into the second value for the DateTime object. + Defaults to 0 + +- locale + + 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%3A%3ALocale) + documentation for details. Defaults to the value of `DateTime->DefaultLocale`, or `"en-US"` if the class default has not been set. + +- time\_zone + + A string containing a time zone name like "America/Chicago" or a + [DateTime::TimeZone](https://metacpan.org/pod/DateTime%3A%3ATimeZone) object. Defaults to the value of + `$ENV{PERL_DATETIME_DEFAULT_TZ}` or "floating" if that env var is not set. See + ["Globally Setting a Default Time Zone"](#globally-setting-a-default-time-zone) for more details on that env var (and + why you should not use it). + + 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. + +- formatter + + An object or class name with a `format_datetime` method. This will be used to + stringify the DateTime object. This is optional. If it is not specified, then + stringification calls `$self->iso8601`. + +Invalid parameter types (like an array reference) will cause the constructor to +die. + +#### 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::\*](https://metacpan.org/search?q=datetime%3A%3Aformat) +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 from 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 changed 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. + +### 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. + +You can also call it with a single unnamed argument, which will be treated as +the epoch value. + +If the epoch value is a non-integral value, it will be rounded to nearest +microsecond. + +By default, the returned object will be in the UTC time zone. + +If you pass a `time_zone`, then this time zone will be applied _after_ the +object is constructed. In other words, the epoch value is always interpreted as +being in the UTC time zone. Here's an example: + + my $dt = DateTime->from_epoch( + epoch => 0, + time_zone => 'Asia/Tokyo' + ); + say $dt; # Prints 1970-01-01T09:00:00 as Asia/Tokyo is +09:00 from UTC. + $dt->set_time_zone('UTC'); + say $dt; # Prints 1970-01-01T00:00:00 + +### 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. + +If you want sub-second resolution, use the [DateTime::HiRes](https://metacpan.org/pod/DateTime%3A%3AHiRes) module's `DateTime::HiRes->now` method instead. + +### DateTime->today( ... ) + +This class method is equivalent to: + + DateTime->now(@_)->truncate( to => 'day' ); + +### 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. + +### 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` object. + +Otherwise, the returned object will be in the floating time zone. + +### $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 the appropriate +era abbreviation, based on the object's locale. The year is the absolute value +of `ce_year`, so that year 1 is "1" and year 0 is "1BC". See the ["Locales"](#locales) +section for more details. + +### $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. See the ["Locales"](#locales) section for more details. + +### $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 date. + +### $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->rfc3339 + +This formats a datetime in RFC3339 format. This is the same as `$dt->datetime` with an added offset at the end of the string except if the +time zone is the floating time zone. + +If the offset is '+00:00' then this is represented as 'Z'. Otherwise the offset +is formatted with a leading sign (+/-) and a colon separated numeric offset +with hours and minutes. If the offset has a non-zero seconds component, that is +also included. + +### $dt->stringify + +This method returns a stringified version of the object. It is also 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 boolean value indicating whether or not the datetime +object is in a leap year. + +### $dt->is\_last\_day\_of\_month + +This method returns a boolean 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 boolean 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 boolean 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 + + my ( $week_year, $week_number ) = $dt->week; + +Returns information about the calendar week for the date. The values returned +by this method are also available separately through the `$dt->week_year` +and `$dt->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. + +The Julian Day is a count of days since the beginning of the Julian Period, +which starts with day 0 at noon on January 1, -4712. + +The Modified Julian Day is a count of days since midnight on November 17, 1858. + +These methods always refer to the local time, so the Julian Day is the same for +a given datetime regardless of its time zone. Or in other words, +2020-12-04T13:01:57 in "America/Chicago" has the same Julian Day as +2020-12-04T13:01:57 in "Asia/Taipei". + +### $dt->time\_zone + +This returns the [DateTime::TimeZone](https://metacpan.org/pod/DateTime%3A%3ATimeZone) object for the datetime object. + +### $dt->offset + +This returns the offset from UTC, in seconds, of the datetime object's time +zone. + +### $dt->is\_dst + +Returns a boolean indicating whether or not the datetime's time zone 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. That's +because it's possible for multiple time zones to have the same abbreviation. + +### $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 + +Returns 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 number of seconds. + +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%3A%3AInfinite). + +### $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](https://metacpan.org/pod/DateTime%3A%3AEvent%3A%3ARecurrence). + +### $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 datetime's [DateTime::Locale](https://metacpan.org/pod/DateTime%3A%3ALocale) object. + +### $dt->formatter + +Returns the current formatter object or class. See ["Formatters And +Stringification"](#formatters-and-stringification) for details. + +## "Set" Methods + +The remaining methods provided by `DateTime`, 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 ji2 dian3?" + +### $dt->set\_formatter($formatter) + +Sets 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"`](https://metacpan.org/pod/DateTime%3A%3ADuration), but exists so that +a subclass of `DateTime` can provide a different value. + +### $dt->add\_duration($duration\_object) + +This method adds a [DateTime::Duration](https://metacpan.org/pod/DateTime%3A%3ADuration) to the current datetime. See the +[DateTime::Duration](https://metacpan.org/pod/DateTime%3A%3ADuration) docs for more details. + +### $dt->add( parameters for DateTime::Duration ) + +This method is syntactic sugar around the `$dt->add_duration` method. It +simply creates a new [DateTime::Duration](https://metacpan.org/pod/DateTime%3A%3ADuration) object using the parameters given, +and then calls the `$dt->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](https://metacpan.org/pod/DateTime%3A%3ADuration) object, this method simply calls `$dur->inverse` on that object and passes that new duration to the `$self->add_duration` method. + +### $dt->subtract( DateTime::Duration->new parameters ) + +Like `$dt->add`, this is syntactic sugar for the `$dt->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](https://metacpan.org/pod/DateTime%3A%3ADuration) 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](https://metacpan.org/pod/DateTime%3A%3ADuration) object representing +some portion of the difference between two datetimes. The `$dt->delta_md` +method returns a duration which contains only the month and day portions of the +duration is represented. The `$dt->delta_days` method returns a duration +which contains only days. + +The `$dt->delta_md` and `$dt->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 are converted to minutes and seconds. This method **always returns +a positive (or zero) duration**. + +### $dt->subtract\_datetime\_absolute($datetime) + +This method returns a new [DateTime::Duration](https://metacpan.org/pod/DateTime%3A%3ADuration) 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`. + +### $dt->is\_between( $lower, $upper ) + +Checks whether `$dt` is strictly between two other DateTime objects. + +"Strictly" means that `$dt` must be greater than `$lower` and less than +`$upper`. If it is _equal_ to either object then this method returns false. + +## 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. + +This exists for backwards compatibility, but is probably best avoided. This +will change the default locale for every `DateTime` object created in your +application, even those created by third party libraries which also use +`DateTime`. + +### DateTime->compare( $dt1, $dt2 ), DateTime->compare\_ignore\_floating( $dt1, $dt2 ) + + $cmp = DateTime->compare( $dt1, $dt2 ); + + $cmp = DateTime->compare_ignore_floating( $dt1, $dt2 ); + +This method 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 an array 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 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](https://metacpan.org/pod/DateTime%3A%3ADuration). + +### 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` produces are predictable, + 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 `$dt->delta_md` or `$dt->delta_days`, not `$dt->subtract_datetime`. This will give predictable, unsurprising results, + free from DST-related complications. + +- $dt->subtract\_datetime and $dt->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 `$dt->delta_days` ensures that this formula always works, + regardless of the time zones of the objects involved, as does using `$dt->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 most pairs of units. That is +because of things like leap seconds, DST changes, etc. + +`DateTime` 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 [DateTime::Duration](https://metacpan.org/pod/DateTime%3A%3ADuration) 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 [DateTime::Duration](https://metacpan.org/pod/DateTime%3A%3ADuration) 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%3A%3ADuration) 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 following 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%3A%3ADuration) for a detailed explanation of +these algorithms. + +If you need to do lots of work with durations, take a look at the +[DateTime::Format::Duration](https://metacpan.org/pod/DateTime%3A%3AFormat%3A%3ADuration) module, which lets you present information from +durations in many useful ways. + +There are other subtract/delta methods in `DateTime` to generate different +types of durations. These methods are `$dt->subtract_datetime`, `$dt->subtract_datetime_absolute`, `$dt->delta_md`, `$dt->delta_days`, and `$dt->delta_ms`. + +### DateTime Subtraction + +Date subtraction is done based solely 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: + + # not DST + my $dt1 = DateTime->new( + year => 2003, + month => 5, + day => 6, + time_zone => 'America/Chicago', + ); + + # is DST + my $dt2 = DateTime->new( + year => 2003, + month => 11, + day => 6, + time_zone => 'America/Chicago', + ); + + # 6 months + my $dur = $dt2->subtract_datetime($dt1); + +Nice and simple. + +This one is a little trickier, but still fairly logical: + + # is DST + my $dt1 = DateTime->new( + year => 2003, + month => 4, + day => 5, + hour => 1, + minute => 58, + time_zone => "America/Chicago", + ); + + # not DST + my $dt2 = DateTime->new( + year => 2003, + month => 4, + day => 7, + hour => 2, + minute => 1, + time_zone => "America/Chicago", + ); + + # 2 days and 3 minutes + my $dur = $dt2->subtract_datetime($dt1); + +Which contradicts the result this one gives, even though they both make sense: + + # is DST + my $dt1 = DateTime->new( + year => 2003, + month => 4, + day => 5, + hour => 1, + minute => 58, + time_zone => "America/Chicago", + ); + + # not DST + my $dt2 = DateTime->new( + year => 2003, + month => 4, + day => 6, + hour => 3, + minute => 1, + time_zone => "America/Chicago", + ); + + # 1 day and 3 minutes + my $dur = $dt2->subtract_datetime($dt1); + +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 ); + + # 60 minutes + my $dur = $dt2->subtract_datetime($dt1); + +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 `$dt->add` is not the same as first adding 3 +minutes and 1 day in two separate calls. + +If we take a duration returned from `$dt->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", + ); + + # 1 day and 3 minutes + my $dur = $dt2->subtract_datetime($dt1); + + # gives us $dt2 + $dt1->add_duration($dur); + + # gives us 2003-04-05 02:58:00 - 1 hour later than $dt1 + $dt2->subtract_duration($dur); + +The `$dt->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 the [DateTime::Duration](https://metacpan.org/pod/DateTime%3A%3ADuration) class's `$dur->calendar_duration` and `$dur->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 add one month ... + + $dt->add( months => 1 ); + +... 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 + my $dt = DateTime->new( + year => 1972, + month => 12, + day => 31, + hour => 23, + minute => 59, + second => 30, + time_zone => 'UTC' + ); + + # 1973-01-01 00:00:30 - one minute later + $dt->clone->add( minutes => 1 ); + + # 1973-01-01 00:00:29 - 60 seconds later + $dt->clone->add( seconds => 60 ); + + # 1973-01-01 00:00:30 - 61 seconds later + $dt->clone->add( seconds => 61 ); + +### 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; + + for 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 or 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 +in Postgres format. + +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 (''). + + my $pattern1 = q{'Today is ' EEEE}; + my $pattern2 = q{'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 hours 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. + +There are many cases where CLDR patterns distinguish 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. + +There are also many cases where CLDR 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 (but 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` object method. + +## DateTime and Storable + +`DateTime` implements [Storable](https://metacpan.org/pod/Storable) hooks in order to reduce the size of a +serialized `DateTime` object. + +# DEVELOPMENT TOOLS + +If you're working on the `DateTIme` code base, there are a few extra non-Perl +tools that you may find useful, notably +[precious](https://github.com/houseabsolute/precious), a meta-linter/tidier. +You can install all the necessary tools in `$HOME/bin` by running +`./dev-bin/install-dev-tools.sh`. + +Try running `precious tidy -a` to tidy all the tidyable files in the repo, and +`precious lint -a` to run all the lint checks. + +You can enable a git pre-commit hook for linting by running `./git/setup.pl`. + +Note that linting will be checked in CI, and it's okay to submit a PR which +fails the linting check, but it's extra nice to fix these yourself. + +# 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%3A%3ASet) + +The [DateTime::Set](https://metacpan.org/pod/DateTime%3A%3ASet) 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%3A%3AFormat%3A%3AHTTP) 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::](https://metacpan.org/search?q=datetime%3A%3Aformat). + +## 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::](https://metacpan.org/search?q=datetime%3A%3Acalendar). + +## 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::](https://metacpan.org/search?q=datetime%3A%3Aevent). + +## Others + +There are many other modules that work with DateTime, including modules in the +[DateTimeX namespace](https://metacpan.org/search?q=datetimex) namespace, as +well as others. + +See [MetaCPAN](https://metacpan.org/search?q=datetime) for more modules. + +# 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://presentations.houseabsolute.com/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) + +# 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). + +# 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 [https://houseabsolute.com/foss-donations/](https://houseabsolute.com/foss-donations/). + +# AUTHOR + +Dave Rolsky + +# CONTRIBUTORS + +- Ben Bennett +- Christian Hansen +- Daisuke Maki +- Dan Book +- Dan Stewart +- David Dyck +- David E. Wheeler +- David Precious +- Doug Bell +- Flávio Soibelmann Glock +- Gianni Ceccarelli +- Gregory Oschwald +- Hauke D +- Iain Truskett <deceased> +- James Raspass +- Jason McIntosh +- Joshua Hoblitt +- Karen Etheridge +- Mark Overmeer +- 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) +- philip r brenan +- Ricardo Signes +- Richard Bowen +- Ron Hill +- Sam Kington +- viviparous <viviparous@prc> + +# COPYRIGHT AND LICENSE + +This software is Copyright (c) 2003 - 2023 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. diff --git a/TODO b/TODO new file mode 100644 index 0000000..9d18239 --- /dev/null +++ b/TODO @@ -0,0 +1,27 @@ +TODO 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. diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000..4b4cb68 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,31 @@ +resources: + repositories: + - repository: ci-perl-helpers + type: github + name: houseabsolute/ci-perl-helpers + endpoint: houseabsolute + +stages: + - template: templates/helpers/build.yml@ci-perl-helpers + parameters: + debug: true + + - template: templates/helpers/linux.yml@ci-perl-helpers + parameters: + coverage: codecov + debug: true + include_threads: true + test_xt: true + use_default_perls: true + + - template: templates/helpers/macos.yml@ci-perl-helpers + parameters: + debug: true + include_threads: true + use_default_perls: true + + - template: templates/helpers/windows.yml@ci-perl-helpers + parameters: + debug: true + use_default_perls: true + diff --git a/cpanfile b/cpanfile new file mode 100644 index 0000000..6722900 --- /dev/null +++ b/cpanfile @@ -0,0 +1,89 @@ +# This file is generated by Dist::Zilla::Plugin::CPANFile v6.030 +# Do not edit this file directly. To change prereqs, edit the `dist.ini` file. + +requires "Carp" => "0"; +requires "DateTime::Locale" => "1.06"; +requires "DateTime::TimeZone" => "2.44"; +requires "Dist::CheckConflicts" => "0.02"; +requires "POSIX" => "0"; +requires "Params::ValidationCompiler" => "0.26"; +requires "Scalar::Util" => "0"; +requires "Specio" => "0.18"; +requires "Specio::Declare" => "0"; +requires "Specio::Exporter" => "0"; +requires "Specio::Library::Builtins" => "0"; +requires "Specio::Library::Numeric" => "0"; +requires "Specio::Library::String" => "0"; +requires "Specio::Subs" => "0"; +requires "Try::Tiny" => "0"; +requires "XSLoader" => "0"; +requires "integer" => "0"; +requires "namespace::autoclean" => "0.19"; +requires "overload" => "0"; +requires "parent" => "0"; +requires "perl" => "5.008004"; +requires "strict" => "0"; +requires "warnings" => "0"; +requires "warnings::register" => "0"; + +on 'test' => sub { + requires "CPAN::Meta::Check" => "0.011"; + requires "CPAN::Meta::Requirements" => "0"; + requires "ExtUtils::MakeMaker" => "0"; + requires "File::Spec" => "0"; + requires "Storable" => "0"; + requires "Test::Fatal" => "0"; + requires "Test::More" => "0.96"; + requires "Test::Warnings" => "0.005"; + requires "Test::Without::Module" => "0"; + requires "utf8" => "0"; +}; + +on 'test' => sub { + recommends "CPAN::Meta" => "2.120900"; +}; + +on 'configure' => sub { + requires "Dist::CheckConflicts" => "0.02"; + requires "ExtUtils::MakeMaker" => "0"; +}; + +on 'configure' => sub { + suggests "JSON::PP" => "2.27300"; +}; + +on 'develop' => sub { + requires "Capture::Tiny" => "0"; + requires "Cwd" => "0"; + requires "Devel::PPPort" => "3.23"; + requires "Encode" => "0"; + requires "File::Basename" => "0"; + requires "File::Spec" => "0"; + requires "FindBin" => "0"; + requires "Perl::Critic" => "1.138"; + requires "Perl::Critic::Moose" => "1.05"; + requires "Perl::Tidy" => "20210111"; + requires "Pod::Checker" => "1.74"; + requires "Pod::Coverage::TrustPod" => "0"; + requires "Pod::Tidy" => "0.10"; + requires "Pod::Wordlist" => "0"; + requires "Storable" => "0"; + requires "Test::CPAN::Changes" => "0.19"; + requires "Test::CPAN::Meta::JSON" => "0.16"; + requires "Test::CleanNamespaces" => "0.15"; + requires "Test::DependentModules" => "0"; + requires "Test::EOL" => "0"; + requires "Test::Fatal" => "0"; + requires "Test::Mojibake" => "0"; + requires "Test::More" => "0.96"; + requires "Test::NoTabs" => "0"; + requires "Test::Pod" => "1.41"; + requires "Test::Pod::Coverage" => "1.08"; + requires "Test::Portability::Files" => "0"; + requires "Test::Spelling" => "0.12"; + requires "Test::Version" => "2.05"; + requires "Test::Warnings" => "0.005"; + requires "Test::Without::Module" => "0"; + requires "autodie" => "0"; + requires "utf8" => "0"; +}; diff --git a/dev-bin/install-xt-tools.sh b/dev-bin/install-xt-tools.sh new file mode 100755 index 0000000..0f3e7b6 --- /dev/null +++ b/dev-bin/install-xt-tools.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +set -e + +TARGET="$HOME/bin" +if [ $(id -u) -eq 0 ]; then + TARGET="/usr/local/bin" +fi +echo "Installing dev tools to $TARGET" + +mkdir -p $TARGET +curl --silent --location \ + https://raw.githubusercontent.com/houseabsolute/ubi/master/bootstrap/bootstrap-ubi.sh | + sh + +"$TARGET/ubi" --project houseabsolute/precious --in "$TARGET" +"$TARGET/ubi" --project houseabsolute/omegasort --in "$TARGET" + +echo "Add $TARGET to your PATH in order to use precious for linting and tidying" diff --git a/dist.ini b/dist.ini new file mode 100644 index 0000000..8295edd --- /dev/null +++ b/dist.ini @@ -0,0 +1,70 @@ +name = DateTime +author = Dave Rolsky +license = Artistic_2_0 +copyright_holder = Dave Rolsky +copyright_year = 2003 + +[PruneCruft] + +; authordep Dist::Zilla::PluginBundle::DROLSKY = 1.22 +[@DROLSKY] +dist = DateTime +exclude_files = leap_seconds.h +next_release_width = 6 +pod_coverage_skip = DateTime::Conflicts +pod_coverage_skip = DateTime::Helpers +pod_coverage_skip = DateTime::PP +pod_coverage_skip = DateTime::PPExtra +pod_coverage_trustme = DateTime => qr/^[A-Z_]+$/ +pod_coverage_trustme = DateTime => qr/0$/ +pod_coverage_trustme = DateTime => qr/^STORABLE/ +pod_coverage_trustme = DateTime => qr/^utc_year$/ +pod_coverage_trustme = DateTime => qr/^timegm$/ +pod_coverage_trustme = DateTime => qr/^day_of_month$/ +pod_coverage_trustme = DateTime => qr/^doq$/ +pod_coverage_trustme = DateTime => qr/^dow$/ +pod_coverage_trustme = DateTime => qr/^doy$/ +pod_coverage_trustme = DateTime => qr/^iso8601$/ +pod_coverage_trustme = DateTime => qr/^local_rd_as_seconds$/ +pod_coverage_trustme = DateTime => qr/^mday$/ +pod_coverage_trustme = DateTime => qr/^min$/ +pod_coverage_trustme = DateTime => qr/^mon$/ +pod_coverage_trustme = DateTime => qr/^sec$/ +pod_coverage_trustme = DateTime => qr/^wday$/ +pod_coverage_trustme = DateTime::Duration => qr/^[A-Z_]+$/ +pod_coverage_trustme = DateTime::Infinite => qr/^.+$/ +; deprecated methods +pod_coverage_trustme = DateTime => qr/^DefaultLanguage$/ +pod_coverage_trustme = DateTime => qr/^era$/ +pod_coverage_trustme = DateTime => qr/^language$/ +stopwords_file = .stopwords +Test::CleanNamespaces.skip = DateTime::Conflicts +use_github_issues = 1 +-remove = Test::Compile +-remove = Test::Pod::No404s +-remove = Test::Synopsis + +[lib] +lib = . + +[=inc::LeapSecondsHeader] + +[CopyFilesFromBuild] +copy = leap_seconds.h + +[MetaResources] +x_MailingList = datetime@perl.org + +[Prereqs / DevelopRequires] +autodie = 0 + +[PurePerlTests] +:version = 0.06 +env_var = PERL_DATETIME_PP + +[Conflicts] +:version = 0.18 +DateTime::Format::Mail = 0.402 + +[Test::CheckBreaks] +conflicts_module = DateTime::Conflicts diff --git a/git/hooks/pre-commit.sh b/git/hooks/pre-commit.sh new file mode 100755 index 0000000..63595ad --- /dev/null +++ b/git/hooks/pre-commit.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +status=0 + +PRECIOUS=$(which precious) +if [[ -z $PRECIOUS ]]; then + PRECIOUS=./bin/precious +fi + +"$PRECIOUS" lint -s +if (( $? != 0 )); then + status+=1 +fi + +exit $status diff --git a/git/setup.pl b/git/setup.pl new file mode 100755 index 0000000..8c99cb8 --- /dev/null +++ b/git/setup.pl @@ -0,0 +1,27 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Cwd qw( abs_path ); + +symlink_hook('pre-commit'); + +sub symlink_hook { + my $hook = shift; + + my $dot = ".git/hooks/$hook"; + my $file = "git/hooks/$hook.sh"; + my $link = "../../$file"; + + if ( -e $dot ) { + if ( -l $dot ) { + return if readlink $dot eq $link; + } + warn "You already have a hook at $dot!\n"; + return; + } + + symlink $link, $dot + or die "Could not link $dot => $link: $!"; +} diff --git a/inc/LeapSecondsHeader.pm b/inc/LeapSecondsHeader.pm new file mode 100644 index 0000000..f8e3528 --- /dev/null +++ b/inc/LeapSecondsHeader.pm @@ -0,0 +1,184 @@ +package inc::LeapSecondsHeader; + +use strict; +use warnings; +use namespace::autoclean; +use autodie; + +my $VERSION = 0.04; + +use Dist::Zilla::File::InMemory; + +use Moose; + +has _leap_second_data => ( + traits => ['Array'], + is => 'bare', + isa => 'ArrayRef', + lazy => 1, + builder => '_build_leap_second_data', + handles => { _leap_second_data => 'elements' }, +); + +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; + my @steps; + + open my $fh, '<', 'leaptab.txt' or die $!; + while (<$fh>) { + my ( $year, $mon, $day, $leap_seconds ) = split /\s+/; + + $mon =~ s/\W//; + my $utc_epoch = _ymd2rd( $year, $months{$mon}, $day ); + + push @steps, [ $utc_epoch => $leap_seconds ]; + } + close $fh; + + return \@steps; +} + +sub _macro_lines { + join "\n", map { sprintf( ' %-37s\\', $_ ) } @_; +} + +sub set_leap_seconds { + my $self = shift; + + # The most recent leaps have a higher chance to match + my $count = 0; + my @checks = "$count;"; + foreach my $step ( $self->_leap_second_data ) { + $count += $step->[1]; + unshift @checks, "utc_rd >= $step->[0] ? $count :"; + } + my $checks = _macro_lines(@checks); + + return <<"__LEAP"; + +/* utc_rd must be a simple variable */ +#define SET_LEAP_SECONDS(utc_rd, leaps) \\ + (leaps) = \\ +$checks\ +__LEAP +} + +sub set_extra_seconds { + my $self = shift; + + my @checks; + foreach my $step ( $self->_leap_second_data ) { + push @checks, "case $step->[0]: es = $step->[1]; break;"; + } + + my $checks = _macro_lines(@checks); + + return <<"__EXTRA_SECONDS"; +#define SET_EXTRA_SECONDS(utc_rd, es) \\ + switch (utc_rd +1) { \\ +$checks\ + default: es = 0; \\ + } +__EXTRA_SECONDS +} + +sub set_day_length { + my $self = shift; + + my @checks; + foreach my $step ( $self->_leap_second_data ) { + push @checks, "case $step->[0]: dl = 86400 + $step->[1]; break;"; + } + my $checks = _macro_lines(@checks); + + return <<"__DAY_LENGTH"; +#define SET_DAY_LENGTH(utc_rd, dl) \\ + switch (utc_rd +1) { \\ +$checks\ + default: dl = 86400; \\ + } +__DAY_LENGTH +} + +sub _header { + my $self = shift; + + my $generator = ref $self; + my $header = <<"__HEADER"; +/* + +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. + +*/ +__HEADER + + return join "\n", + $header, + $self->set_leap_seconds, + $self->set_extra_seconds, + $self->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; +} + +__PACKAGE__->meta->make_immutable; + +1; diff --git a/leap_seconds.h b/leap_seconds.h new file mode 100644 index 0000000..bebf7b4 --- /dev/null +++ b/leap_seconds.h @@ -0,0 +1,108 @@ +/* + +This file is auto-generated by the leap second code generator (0.04). This +code generator comes with the DateTime.pm module distribution in the tools/ +directory + +Generated inc::LeapSecondsHeader. + +Do not edit this file directly. + +*/ + + +/* utc_rd must be a simple variable */ +#define SET_LEAP_SECONDS(utc_rd, leaps) \ + (leaps) = \ + utc_rd >= 736330 ? 27 : \ + utc_rd >= 735780 ? 26 : \ + utc_rd >= 734685 ? 25 : \ + utc_rd >= 733408 ? 24 : \ + utc_rd >= 732312 ? 23 : \ + utc_rd >= 729755 ? 22 : \ + utc_rd >= 729206 ? 21 : \ + utc_rd >= 728659 ? 20 : \ + utc_rd >= 728110 ? 19 : \ + utc_rd >= 727745 ? 18 : \ + utc_rd >= 727380 ? 17 : \ + utc_rd >= 726833 ? 16 : \ + utc_rd >= 726468 ? 15 : \ + utc_rd >= 725737 ? 14 : \ + utc_rd >= 724823 ? 13 : \ + utc_rd >= 724092 ? 12 : \ + utc_rd >= 723727 ? 11 : \ + utc_rd >= 723362 ? 10 : \ + utc_rd >= 722815 ? 9 : \ + utc_rd >= 722450 ? 8 : \ + utc_rd >= 722085 ? 7 : \ + utc_rd >= 721720 ? 6 : \ + utc_rd >= 721354 ? 5 : \ + utc_rd >= 720989 ? 4 : \ + utc_rd >= 720624 ? 3 : \ + utc_rd >= 720259 ? 2 : \ + utc_rd >= 720075 ? 1 : \ + 0; \ + +#define SET_EXTRA_SECONDS(utc_rd, es) \ + switch (utc_rd +1) { \ + case 720075: es = +1; break; \ + case 720259: es = +1; break; \ + case 720624: es = +1; break; \ + case 720989: es = +1; break; \ + case 721354: es = +1; break; \ + case 721720: es = +1; break; \ + case 722085: es = +1; break; \ + case 722450: es = +1; break; \ + case 722815: es = +1; break; \ + case 723362: es = +1; break; \ + case 723727: es = +1; break; \ + case 724092: es = +1; break; \ + case 724823: es = +1; break; \ + case 725737: es = +1; break; \ + case 726468: es = +1; break; \ + case 726833: es = +1; break; \ + case 727380: es = +1; break; \ + case 727745: es = +1; break; \ + case 728110: es = +1; break; \ + case 728659: es = +1; break; \ + case 729206: es = +1; break; \ + case 729755: es = +1; break; \ + case 732312: es = +1; break; \ + case 733408: es = +1; break; \ + case 734685: es = +1; break; \ + case 735780: es = +1; break; \ + case 736330: es = +1; break; \ + default: es = 0; \ + } + +#define SET_DAY_LENGTH(utc_rd, dl) \ + switch (utc_rd +1) { \ + case 720075: dl = 86400 + +1; break; \ + case 720259: dl = 86400 + +1; break; \ + case 720624: dl = 86400 + +1; break; \ + case 720989: dl = 86400 + +1; break; \ + case 721354: dl = 86400 + +1; break; \ + case 721720: dl = 86400 + +1; break; \ + case 722085: dl = 86400 + +1; break; \ + case 722450: dl = 86400 + +1; break; \ + case 722815: dl = 86400 + +1; break; \ + case 723362: dl = 86400 + +1; break; \ + case 723727: dl = 86400 + +1; break; \ + case 724092: dl = 86400 + +1; break; \ + case 724823: dl = 86400 + +1; break; \ + case 725737: dl = 86400 + +1; break; \ + case 726468: dl = 86400 + +1; break; \ + case 726833: dl = 86400 + +1; break; \ + case 727380: dl = 86400 + +1; break; \ + case 727745: dl = 86400 + +1; break; \ + case 728110: dl = 86400 + +1; break; \ + case 728659: dl = 86400 + +1; break; \ + case 729206: dl = 86400 + +1; break; \ + case 729755: dl = 86400 + +1; break; \ + case 732312: dl = 86400 + +1; break; \ + case 733408: dl = 86400 + +1; break; \ + case 734685: dl = 86400 + +1; break; \ + case 735780: dl = 86400 + +1; break; \ + case 736330: dl = 86400 + +1; break; \ + default: dl = 86400; \ + } diff --git a/leaptab.txt b/leaptab.txt new file mode 100644 index 0000000..e9fb846 --- /dev/null +++ b/leaptab.txt @@ -0,0 +1,27 @@ +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 diff --git a/lib/DateTime.pm b/lib/DateTime.pm new file mode 100644 index 0000000..b371665 --- /dev/null +++ b/lib/DateTime.pm @@ -0,0 +1,4809 @@ +## no critic (Modules::ProhibitExcessMainComplexity) +package DateTime; + +use 5.008004; + +use strict; +use warnings; +use warnings::register; +use namespace::autoclean 0.19; + +our $VERSION = '1.65'; + +use Carp; +use DateTime::Duration; +use DateTime::Helpers; +use DateTime::Locale 1.06; +use DateTime::TimeZone 2.44; +use DateTime::Types; +use POSIX qw( floor fmod ); +use Params::ValidationCompiler 0.26 qw( validation_for ); +use Scalar::Util qw( blessed ); +use Specio::Subs qw( Specio::Library::Builtins ); +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 $named_validator = validation_for( + name => '_check_named_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 + }, + }, + ); + + my $one_param_validator = validation_for( + name => '_check_one_from_epoch_param', + name_is_optional => 1, + params => [ { type => t('Num') } ], + ); + + sub from_epoch { + my $class = shift; + my %p; + if ( @_ == 1 && !is_HashRef( $_[0] ) ) { + ( $p{epoch} ) = $one_param_validator->(@_); + } + else { + %p = $named_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 rfc3339 { + my $self = shift; + + return $self->datetime('T') + if $self->{tz}->is_floating; + + my $secs = $self->offset; + my $offset + = $secs + ? DateTime::TimeZone->offset_as_string( $secs, q{:} ) + : 'Z'; + + return $self->datetime('T') . $offset; +} + +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; + for 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/ => '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/ => 'time_zone_long_name', + qr/z{1,3}/ => 'time_zone_short_name', + qr/ZZZZZ/ => sub { + DateTime::TimeZone->offset_as_string( $_[0]->offset, q{:} ); + }, + 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/ => 'time_zone_long_name', + qr/v{1,3}/ => 'time_zone_short_name', + qr/VVVV/ => 'time_zone_long_name', + qr/V{1,3}/ => '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; + for 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, + ); +} + +## no critic (Subroutines::ProhibitManyArgs) +sub _adjust_for_positive_difference { + 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 + for 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; + + for my $i ( 0 .. 2 ) { + return $dt1_components[$i] <=> $dt2_components[$i] + if $dt1_components[$i] != $dt2_components[$i]; + } + + return 0; +} + +sub is_between { + my $self = shift; + my $lower = shift; + my $upper = shift; + + return $self->compare($lower) > 0 && $self->compare($upper) < 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; + for 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{}; + for 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.65 + +=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. + +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 C 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 C<_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