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