Skip to content

Commit

Permalink
Item10068: Added ADDWORKINGDAYS macro. Did some bug fixing and detox
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.foswiki.org/trunk/TimeCalcPlugin@10047 0b4bb1d4-4e5a-0410-9cc4-b2b747904278
  • Loading branch information
KennethLavrsen authored and KennethLavrsen committed Nov 24, 2010
1 parent 2215e4f commit 5a3ad05
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 71 deletions.
37 changes: 33 additions & 4 deletions data/System/TimeCalcPlugin.txt
Expand Up @@ -11,16 +11,45 @@ This plugin enables various calculations of time and dates that you will often n
Some of the features are

* Calculate working/business days between two dates
* Add/subtract a number of working/business days to/from a given date (not yet implemented)
* Add/subtract a number of working/business days to/from a given date

---++ Syntax Rules

%INCLUDE{"VarWORKINGDAYS"}%

---++ Example
%INCLUDE{"VarADDWORKINGDAYS"}%

* %<nop>WORKINGDAYS{startdate="23 Nov 2010" enddate="30 Dec 2010" holidays="23 Dec 2010, 24 Dec 2010, 24 Dec 2010"}%
* Returns %WORKINGDAYS{startdate="23 Nov 2010" enddate="30 Dec 2010" holidays="23 Dec 2010, 24 Dec 2010, 24 Dec 2010"}%
---++ Time Format Tokens

For macros where a time format can be specified the following tokens are used

| *Token:* | *Unit:* | *Example* |
| =$seconds= | seconds | 59 |
| =$minutes= | minutes | 59 |
| =$hours= | hours | 23 |
| =$day= | day of month | 31 |
| =$wday= | day of the Week (Sun, Mon, Tue, Wed, Thu, Fri, Sat) | Thu |
| =$dow= | day of the week (Sun = 0) | 2 |
| =$week= | number of week in year (ISO 8601) | 34 |
| =$month= | short name of month | Dec |
| =$mo= | 2 digit month | 12 |
| =$year= | 4 digit year | 1999 |
| =$ye= | 2 digit year | 99 |
| =$tz= | either "GMT" (if set to gmtime), or "Local" (if set to servertime) | GMT |
| =$iso= | ISO format timestamp | %GMTIME{"$iso"}% |
| =$rcs= | RCS format timestamp | %GMTIME{"$rcs"}% |
| =$http= | E-mail & http format timestamp | %GMTIME{"$http"}% |
| =$epoch= | Number of seconds since 00:00 on 1st January, 1970 | %GMTIME{"$epoch"}% |

Tokens can be shortened to 3 characters

---++ Examples

* %<nop>WORKINGDAYS{startdate="23 Nov 2010" enddate="30 Dec 2010" holidays="24 Dec 2010, 25 Dec 2010, 26 Dec 2010"}%
* Returns (if installed) %WORKINGDAYS{startdate="23 Nov 2010" enddate="30 Dec 2010" holidays="24 Dec 2010, 25 Dec 2010, 26 Dec 2010"}%

* %<nop>ADDWORKINGDAYS{date="23 Nov 2010" delta="26" holidays="24 Dec 2010, 25 Dec 2010, 26 Dec 2010"}%
* Returns (if installed) %ADDWORKINGDAYS{date="23 Nov 2010" delta="26" holidays="24 Dec 2010, 25 Dec 2010, 26 Dec 2010"}%

---++ Installation

Expand Down
210 changes: 143 additions & 67 deletions lib/Foswiki/Plugins/TimeCalcPlugin.pm
Expand Up @@ -28,126 +28,145 @@ the text had been included from another topic.

package Foswiki::Plugins::TimeCalcPlugin;


# Always use strict to enforce variable scoping
use strict;
use warnings;

# $VERSION is referred to by Foswiki, and is the only global variable that
# *must* exist in this package.
use vars qw( $VERSION $RELEASE $SHORTDESCRIPTION $debug
$pluginName $NO_PREFS_IN_TOPIC
);

# This should always be $Rev: 12445$ so that TWiki can determine the checked-in
# status of the plugin. It is used by the build automation tools, so
# you should leave it alone.
$VERSION = '$Rev: 12445$';
use Foswiki::Func (); # The plugins API
use Foswiki::Plugins (); # For the API version
use Time::Local;

# This is a free-form string you can use to "name" your own plugin version.
# It is *not* used by the build automation tools, but is reported as part
# of the version number in PLUGINDESCRIPTIONS.
$RELEASE = '1.0';
# $VERSION is referred to by Foswiki, and is the only global variable that
# *must* exist in this package. This should always be in the format
# $Rev: 9771 $ so that Foswiki can determine the checked-in status of the
# extension.
our $VERSION = '$Rev: 9771 $';

# $RELEASE is used in the "Find More Extensions" automation in configure.
# It is a manually maintained string used to identify functionality steps.
# You can use any of the following formats:
# tuple - a sequence of integers separated by . e.g. 1.2.3. The numbers
# usually refer to major.minor.patch release or similar. You can
# use as many numbers as you like e.g. '1' or '1.2.3.4.5'.
# isodate - a date in ISO8601 format e.g. 2009-08-07
# date - a date in 1 Jun 2009 format. Three letter English month names only.
# Note: it's important that this string is exactly the same in the extension
# topic - if you use %$RELEASE% with BuildContrib this is done automatically.
our $RELEASE = '0.9.0';

# Short description of this plugin
# One line description, is shown in the %SYSTEMWEB%.TextFormattingRules topic:
$SHORTDESCRIPTION = 'Perform calculations on time and dates';

# You must set $NO_PREFS_IN_TOPIC to 0 if you want your plugin to use preferences
# stored in the plugin topic. This default is required for compatibility with
# older plugins, but imposes a significant performance penalty, and
# is not recommended. Instead, use $Foswiki::cfg entries set in LocalSite.cfg, or
# if you want the users to be able to change settings, then use standard TWiki
# preferences that can be defined in your %USERSWEB%.SitePreferences and overridden
# at the web and topic level.
$NO_PREFS_IN_TOPIC = 0;

# Name of this Plugin, only used in this module
$pluginName = 'TimeCalcPlugin';
our $SHORTDESCRIPTION = 'Perform calculations on time and dates';

# You must set $NO_PREFS_IN_TOPIC to 0 if you want your plugin to use
# preferences set in the plugin topic. This is required for compatibility
# with older plugins, but imposes a significant performance penalty, and
# is not recommended. Instead, leave $NO_PREFS_IN_TOPIC at 1 and use
# =$Foswiki::cfg= entries, or if you want the users
# to be able to change settings, then use standard Foswiki preferences that
# can be defined in your %USERSWEB%.SitePreferences and overridden at the web
# and topic level.
#
# %SYSTEMWEB%.DevelopingPlugins has details of how to define =$Foswiki::cfg=
# entries so they can be used with =configure=.
our $NO_PREFS_IN_TOPIC = 1;

=pod
=begin TML
---++ initPlugin($topic, $web, $user, $installWeb) -> $boolean
---++ initPlugin($topic, $web, $user) -> $boolean
* =$topic= - the name of the topic in the current CGI query
* =$web= - the name of the web in the current CGI query
* =$user= - the login name of the user
* =$installWeb= - the name of the web the plugin is installed in
* =$installWeb= - the name of the web the plugin topic is in
(usually the same as =$Foswiki::cfg{SystemWebName}=)
REQUIRED
*REQUIRED*
Called to initialise the plugin. If everything is OK, should return
a non-zero value. On non-fatal failure, should write a message
using Foswiki::Func::writeWarning and return 0. In this case
%FAILEDPLUGINS% will indicate which plugins failed.
using =Foswiki::Func::writeWarning= and return 0. In this case
%<nop>FAILEDPLUGINS% will indicate which plugins failed.
In the case of a catastrophic failure that will prevent the whole
installation from working safely, this handler may use 'die', which
will be trapped and reported in the browser.
You may also call =Foswiki::Func::registerTagHandler= here to register
a function to handle variables that have standard TWiki syntax - for example,
=%MYTAG{"my param" myarg="My Arg"}%. You can also override internal
TWiki variable handling functions this way, though this practice is unsupported
and highly dangerous!
__Note:__ Please align variables names with the Plugin name, e.g. if
your Plugin is called FooBarPlugin, name variables FOOBAR and/or
__Note:__ Please align macro names with the Plugin name, e.g. if
your Plugin is called !FooBarPlugin, name macros FOOBAR and/or
FOOBARSOMETHING. This avoids namespace issues.
=cut

sub initPlugin {
my( $topic, $web, $user, $installWeb ) = @_;

# check for Plugins.pm versions
if( $Foswiki::Plugins::VERSION < 1.026 ) {
Foswiki::Func::writeWarning( "Version mismatch between $pluginName and Plugins.pm" );
if ( $Foswiki::Plugins::VERSION < 2.0 ) {
Foswiki::Func::writeWarning( 'Version mismatch between ',
__PACKAGE__, ' and Plugins.pm' );
return 0;
}

# Set plugin preferences in LocalSite.cfg
$debug = $Foswiki::cfg{Plugins}{TimeCalcPlugin}{Debug} || 0;

Foswiki::Func::registerTagHandler( 'WORKINGDAYS', \&_WORKINGDAYS );

Foswiki::Func::registerTagHandler( 'ADDWORKINGDAYS', \&_ADDWORKINGDAYS );


# Plugin correctly initialized
return 1;
}

sub _returnNoonOfDate {
my ( $indate ) = @_;

my ( $sec, $min, $hour, $day, $mon, $year, $wday, $yday ) = gmtime($indate);
return timegm( 0, 0, 12, $day, $mon, $year );
}

sub _WORKINGDAYS {
my($session, $params, $theTopic, $theWeb) = @_;
# $session - a reference to the TWiki session object (if you don't know
# what this is, just ignore it)
# $params= - a reference to a Foswiki::Attrs object containing parameters.
# This can be used as a simple hash that maps parameter names
# to values, with _DEFAULT being the name for the default
# parameter.
# $theTopic - name of the topic in the query
# $theWeb - name of the web in the query
# Return: the result of processing the variable

# For example, %EXAMPLETAG{'hamburger' sideorder="onions"}%
# $params->{_DEFAULT} will be 'hamburger'
# $params->{sideorder} will be 'onions'
# # $session - a reference to the Foswiki session object
# # (you probably won't need it, but documented in Foswiki.pm)
# # $params= - a reference to a Foswiki::Attrs object containing
# # parameters.
# # This can be used as a simple hash that maps parameter names
# # to values, with _DEFAULT being the name for the default
# # (unnamed) parameter.
# # $topic - name of the topic in the query
# # $web - name of the web in the query
# # $topicObject - a reference to a Foswiki::Meta object containing the
# # topic the macro is being rendered in (new for foswiki 1.1.x)
# # Return: the result of processing the macro. This will replace the
# # macro call in the final text.
#
# # For example, %EXAMPLETAG{'hamburger' sideorder="onions"}%
# # $params->{_DEFAULT} will be 'hamburger'
# # $params->{sideorder} will be 'onions'


# To do - all dates must be normalized towards noon on the day in case
# people enter time.
# To do - we need to be able to also accept serialized date
my $startdate = defined $params->{startdate} ?
Foswiki::Time::parseTime( $params->{startdate} ) :
time();
_returnNoonOfDate( Foswiki::Time::parseTime( $params->{startdate} ) ) :
_returnNoonOfDate( time() );
my $enddate = defined $params->{enddate} ?
Foswiki::Time::parseTime( $params->{enddate} ) :
time();
_returnNoonOfDate( Foswiki::Time::parseTime( $params->{enddate} ) ) :
_returnNoonOfDate( time() );
my $holidaysin = defined $params->{holidays} ?
$params->{holidays} : '';
my $includestart = defined $params->{includestart} ?
Foswiki::Func::isTrue( $params->{includestart} ) : 0;
my $includeend = defined $params->{includeend} ?
Foswiki::Func::isTrue( $params->{includeend} ) : 1;


# To do - all dates must be normalized towards noon on the day in case
# people enter time.
# To do - we need to be able to also accept serialized date
my %holidays = ();
if ( $holidaysin ) {
foreach my $holiday ( split( /\s*,\s*/, $holidaysin ) ) {
$holidays{ Foswiki::Time::parseTime( $holiday ) } = 1;
$holidays{ _returnNoonOfDate( Foswiki::Time::parseTime( $holiday ) ) } = 1;
}
}

Expand Down Expand Up @@ -186,4 +205,61 @@ sub _WORKINGDAYS {

}

sub _ADDWORKINGDAYS {
my($session, $params, $theTopic, $theWeb) = @_;
# # $session - a reference to the Foswiki session object
# # (you probably won't need it, but documented in Foswiki.pm)
# # $params= - a reference to a Foswiki::Attrs object containing
# # parameters.
# # This can be used as a simple hash that maps parameter names
# # to values, with _DEFAULT being the name for the default
# # (unnamed) parameter.
# # $topic - name of the topic in the query
# # $web - name of the web in the query
# # $topicObject - a reference to a Foswiki::Meta object containing the
# # topic the macro is being rendered in (new for foswiki 1.1.x)
# # Return: the result of processing the macro. This will replace the
# # macro call in the final text.
#
# # For example, %EXAMPLETAG{'hamburger' sideorder="onions"}%
# # $params->{_DEFAULT} will be 'hamburger'
# # $params->{sideorder} will be 'onions'


my $formatString = defined $params->{_DEFAULT} ?
$params->{_DEFAULT} :
$Foswiki::cfg{DefaultDateFormat};

my $date = defined $params->{date} ?
_returnNoonOfDate( Foswiki::Time::parseTime( $params->{date} ) ) :
_returnNoonOfDate( time() );
my $delta = defined $params->{delta} ? $params->{delta} : 0;
my $holidaysin = defined $params->{holidays} ?
$params->{holidays} : '';


my %holidays = ();
if ( $holidaysin ) {
foreach my $holiday ( split( /\s*,\s*/, $holidaysin ) ) {
$holidays{ _returnNoonOfDate( Foswiki::Time::parseTime( $holiday ) ) } = 1;
}
}

my $direction = $delta < 0 ? -1 : 1;

while ( $delta !=0 ) {
$date += $direction * 86400;

my $tempwday = ( gmtime( $date ) )[6];
if ( $tempwday != 6 && $tempwday != 0 && !$holidays{ $date } ) {
print STDERR "$delta\n";
$delta -= $direction;
}
}

return Foswiki::Time::formatTime($date, $formatString, gmtime);
}

1;

__END__
1 change: 1 addition & 0 deletions lib/Foswiki/Plugins/TimeCalcPlugin/MANIFEST
@@ -1,5 +1,6 @@
# Release manifest for TimeCalcPlugin
data/System/TimeCalcPlugin.txt 0644 Documentation
data/System/VarWORKINGDAYS.txt 0644 Documentation
data/System/VarADDWORKINGDAYS.txt 0644 Documentation
lib/Foswiki/Plugins/TimeCalcPlugin.pm 0644 Perl module

0 comments on commit 5a3ad05

Please sign in to comment.