EAI-Wrap

 view release on metacpan or  search on metacpan

lib/EAI/DateUtil.pm  view on Meta::CPAN

	return undef if !$y or !$m or !$d;
	# first of following month minus 1 day is always last of current month, timegm_modern expects 0 based month, $m is the following month for timegm_modern therefore
	if ($m == 12) {
		# for December -> January next year
		$m = 0; # month 0 based
		$y++;
	}
	my $mon = (gmtime(timegm_modern(0,0,12,1,$m,$y) - 24*60*60))[4]+1;
	my $day = (gmtime(timegm_modern(0,0,12,1,$m,$y) - 24*60*60))[3];
	$y-- if $m == 0; # for December -> reset year again
	return sprintf("%04d%02d%02d",$y, $mon, $day);
}

sub weekday ($) {
	return undef if !$_[0];
	my ($y,$m,$d) = $_[0] =~ /(.{4})(..)(..)/;
	return undef if !$y or !$m or !$d;
	(gmtime(timegm_modern(0,0,12,$d,$m-1,$y)))[6]+1;
}

sub is_weekend ($) {
	return undef if !$_[0];
	my ($y,$m,$d) = $_[0] =~ /(.{4})(..)(..)/;
	return undef if !$y or !$m or !$d;
	(gmtime(timegm_modern(0,0,12,$d,$m-1,$y)))[6] =~ /(0|6)/;
}
# makeMD: argument in timegm_modern form (datetime), returns date in format DDMM (for holiday calculation)
sub makeMD ($) {
	return undef if !$_[0];
	sprintf("%02d%02d", (gmtime($_[0]))[3],(gmtime($_[0]))[4] + 1);
}

# British specialties
sub UKspecial {
	return undef if !$_[0];
	my ($y,$m,$d) = $_[0] =~ /(.{4})(..)(..)/;
	return undef if !$y or !$m or !$d;
	return 1 if (first_week($d,$m,$y,1,5) || last_week($d,$m,$y,1,5) || last_week($d,$m,$y,1,8));
	return 0;
}

# fixed holidays
my %fixedHol = ("BS"=>{"0101"=>1,"0601"=>1,"0105"=>1,"1508"=>1,"2610"=>1,"0111"=>1,"0812"=>1,"2412"=>1,"2512"=>1,"2612"=>1},
				"BF"=>{"0101"=>1,"0601"=>1,"0105"=>1,"1508"=>1,"2610"=>1,"0111"=>1,"0812"=>1,"2412"=>1,"2512"=>1,"2612"=>1},
				"AT"=>{"0101"=>1,"0601"=>1,"0105"=>1,"1508"=>1,"2610"=>1,"0111"=>1,"0812"=>1,"2512"=>1,"2612"=>1},
				"TG"=>{"0101"=>1,"0105"=>1,"2512"=>1,"2612"=>1},
				"UK"=>{"0101"=>1,"2512"=>1,"2612"=>1}
				);

# easter holidays
my %easterHol = ("BS"=>{"EM"=>1,"AS"=>1,"WM"=>1,"CC"=>1,"GF"=>1},
				 "BF"=>{"EM"=>1,"AS"=>1,"WM"=>1,"CC"=>1},
				 "AT"=>{"EM"=>1,"AS"=>1,"WM"=>1,"CC"=>1},
				 "TG"=>{"EM"=>1,"GF"=>1},
				 "UK"=>{"EM"=>1,"GF"=>1}
				);

# reference to functions for special holiday calculations
my %specialHol = ("UK" => \&UKspecial);

# adds calendar to DateUtil, first arg name of $cal, second arg fixed holidays hash, third easter holidays hash and fourth special function for additional calculations
sub addCalendar ($$$$) {
	my ($cal,$fixHol,$eastHol,$specialHolSub) = @_;
	return undef if !$cal or !$fixHol or !$eastHol or !$specialHolSub;
	if (defined($fixedHol{$cal})) {
		cluck("calender <$cal> already implemented for fixed holidays !");
		return 0;
	}
	if (defined($easterHol{$cal})) {
		cluck("calender <$cal> already implemented for easter holidays !");
		return 0;
	}
	if (defined($specialHol{$cal})) {
		cluck("calender <$cal> already implemented for additional calculations !");
		return 0;
	}
	$fixedHol{$cal} = ($fixHol ? $fixHol : "");
	$easterHol{$cal} = ($eastHol ? $eastHol : "");
	$specialHol{$cal} = ($specialHolSub ? $specialHolSub : "");
	return 1;
}

# check whether second arg is easter in passed calendar (first arg).
# requires entry of calendar in %easterHol hash: "$Cal" => {"GF"=>1,"EM"=>1,"ES"=>1,"AS"=>1,"WM"=>1,"CC"=>1}
sub is_easter ($$) {
	my ($cal) = $_[0];
	return undef if !$cal or !$_[1];
	my ($y,$m,$d) = $_[1] =~ /(.{4})(..)(..)/;
	return undef if !$y or !$m or !$d;
	# first find easter sunday using year
	my $D = (((255 - 11 * ($y % 19)) - 21) % 30) + 21;
	my $easter = timegm_modern(0,0,12,1,2,$y) + ($D + ($D > 48 ? 1 : 0) + 6 - (($y + int($y / 4) + $D + ($D > 48 ? 1 : 0) + 1) % 7))*86400;
	return 1 if makeMD($easter) eq $d.$m and $easterHol{$cal}->{"EH"}; # easter sunday
	# then the rest
	return 1 if makeMD($easter-2*86400) eq $d.$m and $easterHol{$cal}->{"GF"}; # good friday
	return 1 if makeMD($easter+1*86400) eq $d.$m and $easterHol{$cal}->{"EM"}; # easter monday
	return 1 if makeMD($easter+39*86400) eq $d.$m and $easterHol{$cal}->{"AS"}; # ascension day
	return 1 if makeMD($easter+50*86400) eq $d.$m and $easterHol{$cal}->{"WM"}; # whitmonday
	return 1 if makeMD($easter+60*86400) eq $d.$m and $easterHol{$cal}->{"CC"}; # corpus christi day
	return 0;
}

# check whether second arg is holiday in passed calendar (first arg)
sub is_holiday ($$) {
	my ($cal) = $_[0];
	return undef if !$cal or $cal eq "WE" or !$_[1]; # weekends are checked with "is_weekend", so no holiday passed here! Same for empty dates passed
	my ($y,$m,$d) = $_[1] =~ /(.{4})(..)(..)/;
	return undef if !$y or !$m or !$d;
	return 1 if $fixedHol{$cal}->{$d.$m};
	return 1 if is_easter($cal,$_[1]);
	return 1 if $specialHol{$cal} and $specialHol{$cal}->($_[1]);
	unless ($fixedHol{$cal} or $easterHol{$cal} or $specialHol{$cal}) {
		cluck("calender <$cal> neither implemented in \$fixedHol{$cal} nor \$easterHol{$cal} nor \$specialHol{$cal} !");
		return 0;
	}
	return 0;
}

sub first_week ($$$$;$) {
	my ($d,$m,$y,$day,$month) = @_;
	return undef if !$y or !$m or !$d or !defined($day);
	$month = $m if !$month;
	unless ((0 <= $day) and ( $day <= 6)) {
		cluck("day <$day> is out of range 0 - 6  (sunday==0)");
		return 0;
	}
	my $date = localtime(timelocal_modern(0,0,12,$d,$m-1,$y));
	return 0 unless $m == $month; # return unless the month matches
	return 0 if $d > 7; # can't be the first week of the month if day is after the 7th
	return 0 unless $date->wday() == $day; # return unless the (week)day matches
	return 0 unless (localtime(timelocal_modern(0,0,12,$d,$m-1,$y)-7*24*60*60))->mon() != $m-1; # return unless 1 week earlier we're in a different month
	return 1;
}

sub first_weekYYYYMMDD ($$;$) {
	my ($date,$day,$month) = @_;
	return undef if !$date or !defined($day);
	my ($y,$m,$d) = $date =~ /(.{4})(..)(..)/;
	return undef if !$y or !$m or !$d;
	$month = $m if !$month;
	return first_week ($d,$m,$y,$day,$month);
}

sub last_week ($$$$;$) {
	my ($d,$m,$y,$day,$month) = @_;
	return undef if !$y or !$m or !$d or !defined($day);
	$month = $m if !$month;
	unless ((0 <= $day) and ( $day <= 6)) {
		cluck("day <$day> is out of range 0 - 6  (sunday==0)");
		return 0;
	}
	my $date = localtime(timelocal_modern(0,0,12,$d,$m-1,$y));
	return 0 unless $m == $month; # return unless the month matches
	return 0 unless $date->wday() == $day; # return unless the (week)day matches
	return 0 unless (localtime(timelocal_modern(0,0,12,$d,$m-1,$y)+7*24*60*60))->mon() != $m-1; # return unless 1 week later we're in a different month
	return 1;
}

sub last_weekYYYYMMDD ($$;$) {
	my ($date,$day,$month) = @_;
	return undef if !$date or !defined($day);
	my ($y,$m,$d) = $date =~ /(.{4})(..)(..)/;
	$month = $m if !$month;

lib/EAI/DateUtil.pm  view on Meta::CPAN

		} else {
			push @dateseries, $datestr;
		}
	}
	return @dateseries;
}

sub parseFromDDMMYYYY ($) {
	my ($dateStr) = @_;
	return undef if !$dateStr;
	my ($df,$mf,$yf) = $dateStr =~ /(..*)\.(..*)\.(.{4})/;
	return undef if !$yf or !$mf or !$df;
	return undef if !($yf >= 1900) or !($mf >= 1 and $mf <= 12) or !($df >= 1 and $df <= 31);
	return timelocal_modern(0,0,0,$df,$mf-1,$yf);
}

sub parseFromYYYYMMDD ($) {
	my ($dateStr) = @_;
	return undef if !$dateStr;
	my ($yf,$mf,$df) = $dateStr =~ /(.{4})(..)(..)/;
	return undef if !$yf or !$mf or !$df;
	return undef if !$dateStr or !($yf >= 1900) or !($mf >= 1 and $mf <= 12) or !($df >= 1 and $df <= 31);
	return timelocal_modern(0,0,0,$df,$mf-1,$yf);
}

sub convertEpochToYYYYMMDD ($) {
	my ($arg) = @_;
	if (ref($arg) eq 'Time::Piece') {
		return sprintf("%04d%02d%02d",$arg->year(),$arg->mon(),$arg->mday());
	} elsif($arg) {
		my $date = localtime($arg);
		return sprintf("%04d%02d%02d",$date->year()+1900,$date->mon()+1,$date->mday());
	}
}

sub convertJulianToYYYYMMDD ($) {
	my ($arg) = @_;
	# excel calculates 0 as being 00.01.1900 which would be an invalid time object, so take 31.12.1899 instead
	my $date = localtime(timelocal_modern(0,0,0,31,11,1899) + $arg * 60 * 60 * 24 - 1);
	# why subtract 1 before getting localtime for $date ? excel wrongly assumes 1900 is a leap year: https://learn.microsoft.com/en-us/office/troubleshoot/excel/wrongly-assumes-1900-is-leap-year
	return sprintf("%04d%02d%02d",$date->year()+1900,$date->mon()+1,$date->mday());
}

sub skipOnDate ($$;$) {
	my ($onlyPassIf,$checkDate,$checkHoliday) = @_;
	$checkHoliday = "AT" if !$checkHoliday;
	my $is_weekend = is_weekend($checkDate); $is_weekend = "" if !$is_weekend;
	my ($onlyPassIfCal, $checkCal) = ($onlyPassIf =~ /(..)(..)*/); $onlyPassIfCal = "" if !$onlyPassIfCal; $checkCal = "AT" if !$checkCal;
	my $is_holiday = is_holiday($checkCal,$checkDate); $is_holiday = "" if !$is_holiday;
	my $is_last_day_of_month = is_last_day_of_month($checkDate,$checkCal); $is_last_day_of_month = "" if !$is_last_day_of_month;

	if ($onlyPassIf eq "B" and ($is_weekend || $is_holiday)) {
		return "skipping as \$onlyPassIf eq B and is_weekend($checkDate)=".$is_weekend." || is_holiday(".$checkHoliday.",$checkDate)=".$is_holiday;
	}
	if ($onlyPassIf eq "M1" and $checkDate !~ /\d{4}\d{2}01/) {
		return "skipping as \$onlyPassIf eq M1 and curDate ($checkDate) !~ /\\d{4}\\d{2}01/";
	}
	if ($onlyPassIf eq "Q" and $checkDate !~ /\d{4}010[12]/ and $checkDate !~ /\d{4}0401/ and $checkDate !~ /\d{4}0701/ and $checkDate !~ /\d{4}1001/) {
		return "skipping as \$onlyPassIf eq Q and curDate ($checkDate) !~ /\\d{4}0102/ and curDate !~ /\\d{4}0401/ and curDate !~ /\\d{4}0701/ and curDate !~ /\\d{4}1001/";
	}
	# skip if checkDate is not on the last day of month, or in case a calendar is given, on the last day of month regarding the calendar (in this case, skip also on weekends and holidays!)
	if ($onlyPassIfCal eq "ML" and (!$is_last_day_of_month or ($checkCal and ($is_weekend or $is_holiday)))) {
		return "skipping as \$onlyPassIf eq ML".($checkCal ? $checkCal : "")." and (!is_last_day_of_month($checkDate".($checkCal ? ",$checkCal" : "").")=".$is_last_day_of_month." or (\$checkCal(=".($checkCal ? $checkCal : "").") and (is_weekend($checkDate)...
	}
	if (substr($onlyPassIf,0,1) eq "W" and !(weekday($checkDate) eq substr($onlyPassIf,1,1))) {
		return "skipping as substr($onlyPassIf,0,1) eq W and !(weekday($checkDate) (".weekday($checkDate).") eq substr($onlyPassIf,1,1))";
	}
	if (substr($onlyPassIf,0,2) eq "MW" and !(first_weekYYYYMMDD($checkDate,substr($onlyPassIf,2,1)))) {
		return "skipping as substr($onlyPassIf,0,2) eq MW and !(first_weekYYYYMMDD($checkDate,substr($onlyPassIf,2,1)))";
	}
	return "";
}

1;
__END__

=encoding utf8

=head1 NAME

EAI::DateUtil - Date and Time helper functions for L<EAI::Wrap>

=head1 SYNOPSIS

 monthsToInt ($mmm, $locale)
 intToMonths ($m, $locale)
 addLocaleMonths ($locale, $monthsArray)
 get_curdate ()
 get_curdatetime ()
 get_curdate_dot ()
 formatDate ($y, $m, $d, [$template])
 formatDateFromYYYYMMDD ($date, [$template])
 get_curdate_gen ([$template])
 get_curdate_dash ()
 get_curdate_dash_plus_X_years ($years)
 get_curtime_epochs ()
 make_time ($time, [$secondsToAdd])
 formatTime ($timeval [$format])
 get_curtime ([$format, $secondsToAdd])
 get_curtime_HHMM ()
 is_first_day_of_month ($date YYYYMMDD)
 is_last_day_of_month ($date YYYYMMDD, [$cal])
 get_last_day_of_month ($date YYYYMMDD)
 weekday ($date YYYYMMDD)
 is_weekend ($date YYYYMMDD)
 is_holiday ($cal, $date YYYYMMDD)
 is_easter ($cal, $date YYYYMMDD)
 addCalendar ($cal, $fixedHol hash, $easterHol .. hash, $specialFunction)
 first_week ($d,$m,$y,$day,[$month])
 first_weekYYYYMMDD ($date,$day,[$month])
 last_week ($d,$m,$y,$day,[$month])
 last_weekYYYYMMDD ($date,$day,[$month])
 convertDate ($date YYYY.MM.DD or YYYY/MM/DD)
 convertDateFromMMM ($inDate dd-mmm-yyyy, out $day, out $mon, out $year, [$locale])
 convertDateToMMM ($day, $mon, $year, [$locale])
 convertToDDMMYYYY ($date YYYYMMDD)
 addDays ($day, $mon, $year, $dayDiff, [$locale])
 subtractDays ($date, $days)
 addDaysHol ($date, $days, [$template, $cal])
 subtractDaysHol ($date, $days, [$template, $cal])
 addDatePart ($date, $count, $datepart, [$template])

lib/EAI/DateUtil.pm  view on Meta::CPAN

 $template .. same as in formatDate above

=item get_curdate_gen (;$)

returns current date in format as defined in $template

 $template .. same as in formatDate above

=item get_curdate_dash

returns current date in format DD-MM-YYYY

=item get_curdate_dash_plus_X_years ($;$$)

 $y .. years to be added to the current or given date
 $date .. optional date to which X years should be added (if not given, then current date is taken instead).
 $daysToSubtract .. optional days that should be subtracted from above result

returns (current or given) date + X years in format DD-MM-YYYY

=item get_curtime_epochs

returns current time in epochs as from builtin function time()

=item get_curtime (;$$)

returns current time in format HH:MM:SS + optional $secondsToAdd (or as given in formatstring $format, however ordering of format is always hour, minute and second). Additionally 1 is put in front if adding $secondsToAdd lead to a day overflow.

 $format .. optional sprintf format string (e.g. %02d:%02d:%02d) for hour, minute and second. If less than three tags are passed then a warning is "Redundant argument in sprintf at ..." is thrown here.
 $secondsToAdd .. optional seconds to add to current time before returning

=item get_curtime_HHMM

returns current time in format HHMM

=item make_time ($;$)

returns localtime datastructure from given $time argument (format HHMMSS) optionally adding $secondsToAdd

 $time .. time in format HHMMSS to make a localtime datastructure
 $secondsToAdd .. optional seconds to add to current time before returning

=item formatTime ($;$)

returns formatted time from localtime datastructure $timeval using optional format string $format (defaulting to %02d:%02d:%02d). Supported are format strings containing 1, 2, 3 or 4 %d placeholders.

 $timeval .. localtime datastructure that should be formatted
 $format .. optional sprintf format string (e.g. %02d %02d:%02d:%02d) for (maximum) day, hour, minute and second to return. There can also be three decimals, (hour, minute and second), two (hour, minute) and one (only hour).

=item is_first_day_of_month ($)

returns 1 if first day of months, 0 else

 $date .. date in format YYYYMMDD

=item is_last_day_of_month ($;$)

returns 1 if last day of month, 0 else

 $date .. date in format YYYYMMDD
 $cal .. optional, calendar for holidays used to get the last of month

=item get_last_day_of_month ($)

returns last day of month of passed date

 $date .. date in format YYYYMMDD

=item weekday ($)

returns 1..sunday to 7..saturday

 $date .. date in format YYYYMMDD

=item is_weekend ($)

returns 1 if saturday or sunday

 $date .. date in format YYYYMMDD

=item is_holiday ($$)

returns 1 if weekend or holiday

 $cal .. holiday calendar; currently supported: AT (Austria), TG (Target), UK (see is_holiday) and WE (for only weekends).
         throws warning if calendar not supported (fixed lookups or additionally added). To add a calendar use addCalendar.
 $date .. date in format YYYYMMDD

=item is_easter ($$)

returns 1 if date is an easter holiday for that calendar

 $cal .. holiday calendar;
 $date .. date in format YYYYMMDD

=item addCalendar ($$$$)

add an additional calendar for calendar holiday dependent calculations

 $cal .. name of holiday calendar to be added, warns if already existing (builtin)
 $fixedHol .. hash of fixed holiday dates for that calendar (e.g. {"0105"=>1,"2512"=>1} for may day and christmas day)
 $easterHol .. hash of easter holidays for that calendar (possible: {"GF"=>1,"EM"=>1,"ES"=>1,"AS"=>1,"WM"=>1,"CC"=>1}) = good friday,easter monday, easter sunday, ascension day, whitmonday, corpus christi day
 $specialFunction .. pass ref to sub used for additional calculations; this sub should receive a date (YYYYMMDD) and return 1 for holiday, 0 otherwise.

Example:

 sub testCalSpecial {
   my ($y,$m,$d) = $_[0] =~ /(.{4})(..)(..)/;
   return 1 if $y eq "2002" and $m eq "09" and $d eq "08";
   return 0;
 }
 addCalendar("TC",{"0101"=>1,"0105"=>1,"2512"=>1,"2612"=>1},{"EM"=>1,"GF"=>1},\&testCalSpecial);

=item first_week ($$$$;$)

returns 1 if given date ($d,$m,$y) is the first given weekday ($day: 0 - 6, sunday==0) in given month ($month),
 if $month is not passed, then it is taken from passed date.

 $d .. day part
 $m .. month part
 $y .. year part
 $day .. given weekday
 $month .. optional, given month

=item first_weekYYYYMMDD ($$;$)

returns 1 if given date ($date in Format YYYYMMDD) is the first given weekday ($day: 0 - 6, sunday==0) in given month ($month),
 if $month is not passed, then it is taken from passed date.

 $date .. given date
 $day .. given weekday
 $month .. optional, given month

=item last_week ($$$$;$)

returns 1 if given date ($d,$m,$y) is the last given weekday ($day: 0 - 6, sunday==0) in given month ($month),
 if $month is not passed, then it is taken from passed date.

 $d .. day part
 $m .. month part
 $y .. year part
 $day .. given weekday
 $month .. optional, given month

=item last_weekYYYYMMDD ($$;$)

returns 1 if given date ($date in Format YYYYMMDD) is the last given weekday ($day: 0 - 6, sunday==0) in given month ($month),
 if $month is not passed, then it is taken from passed date.
 
 $date .. given date
 $day .. given weekday
 $month .. optional, given month

=item convertDate ($)

converts given date to format YYYYMMDD

 $date .. date in format YYYY.MM.DD or YYYY/MM/DD

=item convertDateFromMMM ($$$$;$)

converts date from format dd-mmm-yyyy (mmm as defined in $locale, defaults to "en"glish), returns date in format DD.MM.YYYY ($day, $mon, $year are returned by ref as well)

 $inDate .. date to be converted
 $day .. ref for day part
 $mon .. ref for month part
 $year ..  ref for year part
 $locale .. optional locale as defined in monthsToInt (builtin "en" and "ge", can be added with addLocaleMonths)

=item convertDateToMMM ($$$;$)

converts date into format dd-mmm-yyyy (mmm as defined in $locale, defaults to "en"glish) from ($day, $mon, $year)

 $day .. day part
 $mon .. month part
 $year .. year part
 $locale .. optional locale as defined in monthsToInt (builtin "en" and "ge", can be added with addLocaleMonths)

=item convertToDDMMYYYY ($)

converts date into $datestring (dd.mm.yyyy) from format YYYYMMDD

 $date .. date in format YYYYMMDD

=item addDays ($$$$;$)

adds $dayDiff to date ($day, $mon, $year) and returns in format dd-mmm-yyyy (mmm as defined in $locale, defaults to "en"glish),
                arguments $day, $mon, $year are returned by ref as well if not passed as literal

 $day .. day part
 $mon .. month part
 $year .. year part
 $dayDiff .. days to be added
 $locale .. optional locale as defined in monthsToInt (builtin "en" and "ge", can be added with addLocaleMonths)

=item subtractDays ($$)

subtracts $days actual calendar days from $date

 $date .. date in format YYYYMMDD
 $days .. calendar days to subtract

=item addDaysHol ($$;$$)

adds $days days to $date and regards weekends and holidays of passed calendar

 $date .. date in format YYYYMMDD
 $days .. calendar days to add
 $template .. as in formatDate
 $cal .. holiday calendar; currently supported: NO (no holidays = default if not given), rest as in is_holiday

=item subtractDaysHol ($$;$$)

subtracts $days days from $date and regards weekends and holidays of passed calendar

 $date .. date in format YYYYMMDD
 $days .. calendar days to subtract
 $template .. as in formatDate
 $cal .. holiday calendar; currently supported: NO (no holidays  = default if not given), rest as in is_holiday

=item addDatePart ($$$;$)

adds $count dateparts to $date. when adding to months ends (>28 in february, >29 or >30 else), if the month end is not available in the target month, then date is moved into following month

 $date .. date in format YYYYMMDD
 $count .. count of dateparts to add
 $datepart .. can be "d" or "day" for days, "m"/"mon"/"month" for months and "y" or "year" for years
 $template .. as in formatDate

=item get_lastdateYYYYMMDD

returns the last business day (only weekends, no holiday here !) in format YYYYMMDD

=item get_lastdateDDMMYYYY

returns the last business day (only weekends, no holiday here !) in format DDMMYYYY

=item convertcomma ($$)

converts decimal point in $number to comma, also dividing by $divideBy before if $divideBy is set

 $number ..  number to be converted
 $divideBy .. number to be divided by

=item convertToThousendDecimal ($$)

converts $value into thousand separated decimal (german format) ignoring decimal places if wanted
 
 $value .. number to be converted
 $ignoreDecimal .. return number without decimal places (truncate)

=item get_dateseries ($$$)

returns date values (format YYYYMMMDD) starting at $fromDate until $toDate, if a holiday calendar is set in $cal (optional), these holidays (incl. weekends) are regarded as well.
 
 $fromDate .. start date
 $toDate .. end date
 $cal .. holiday calendar

=item parseFromDDMMYYYY ($)

returns time epoch from given datestring (dd.mm.yyyy)

 $dateStr .. datestring

=item parseFromYYYYMMDD ($)

returns time epoch from given datestring (yyyymmdd)

 $dateStr .. datestring

=item convertEpochToYYYYMMDD ($)

returns datestring (yyyymmdd) from epoch/Time::piece

 $arg .. date either as epoch (seconds since 1.1.1970) or as Time::piece object

=item convertJulianToYYYYMMDD ($)

returns datestring (yyyymmdd) from julian date (excel representation of dates)

 $arg .. date as a julian date (integer/float, counting days from 0.1.1900)

=item skipOnDate ($$;$)

 $onlyPassIf .. only pass if $checkDate is: ML..on months end (incl. optional holiday calender, eg MLAT for Austria), B.. on businessdays (optional calender: $checkHoliday, if not given: Austria), D..daily, M1..NOT at beginning of month, W{n}..on wee...
 $checkDate .. the date to check
 $checkHoliday .. optional calendar for businessdays in $onlyPassIf (eg AT for Austria)

returns explanation why $checkDate should be skipped based on $onlyPassIf (optionally $checkHoliday for $onlyPassIf=B), blank otherwise.
This can be used to skip further execution based on rules given above (e.g. exit 0 if skipOnDate("B", $curDate);).

=back

=head1 COPYRIGHT

Copyright (c) 2026 Roland Kapl

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

The full text of the license can be found in the LICENSE file included
with this module.

=cut



( run in 0.835 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )