Permalink
Browse files

Added DateTime::Math library, with many infixes and helper functions.

  • Loading branch information...
supernovus committed Sep 20, 2010
1 parent b213c02 commit 75524e8140f017e48d03388f1a63ccacadd6cc77
Showing with 158 additions and 0 deletions.
  1. +121 −0 lib/DateTime/Math.pm
  2. +37 −0 t/DateTime-math.t
View
@@ -0,0 +1,121 @@
+module DateTime::Math;
+
+my subset DurationUnits of Str where -> $unit { $unit ~~ /^<[smhdwMy]>$/ }
+
+## to-seconds: takes a value and a unit string, and converts the value
+# into seconds.
+#
+# The value must be a number, the unit string must be one of:
+#
+# 's' Seconds, this is redundant it returns the string without the 's'.
+# 'm' Minutes, so 1m will return 60.
+# 'h' Hour, so 1h will return 3600.
+# 'd' Day, so 1d will return 86400.
+# 'w' Week, so 1w will return 604800.
+# 'M' Month, so 1M will return 2592000. This is based on 30 days.
+# 'y' Year, so 1y will return 31449600. Uses a round 365 days.
+#
+# The Month estimation is not very accurate as it assumes 30 days regardless
+# of month, if you need more accuracy, use a day count instead.
+#
+# The Year estimation is based on a round 365 days, and does not take into
+# account leap years or anything else. Again, if you need more accuracy,
+# use a smaller unit.
+#
+#
+sub to-seconds ( Numeric $value, DurationUnits $in ) is export {
+ my $minute = $value * 60;
+ my $hour = $minute * 60;
+ my $day = $hour * 24;
+ my $week = $day * 7;
+ my $month = $day * 30;
+ my $year = $day * 365;
+ given $in {
+ when 's' { return $value }
+ when 'm' { return $minute }
+ when 'h' { return $hour }
+ when 'd' { return $day }
+ when 'w' { return $week }
+ when 'M' { return $month }
+ when 'y' { return $year }
+ }
+}
+
+## from-seconds: takes a value in seconds and converts it into the
+# specified unit.
+#
+# The value and unit must be specified using the same rules as to-seconds().
+#
+sub from-seconds ( Numeric $value, DurationUnits $to ) is export {
+ my $minute = $value / 60;
+ my $hour = $minute / 60;
+ my $day = $hour / 24;
+ my $week = $day / 7;
+ my $month = $day / 30;
+ my $year = $day / 365;
+ given $to {
+ when 's' { return $value }
+ when 'm' { return $minute }
+ when 'h' { return $hour }
+ when 'd' { return $day }
+ when 'w' { return $week }
+ when 'M' { return $month }
+ when 'y' { return $year }
+ }
+}
+
+## duration-from-to: takes a value, the unit string the value is currently in,
+## and the unit string you want to covert the value to.
+sub duration-from-to( Numeric $value, DurationUnits $in, DurationUnits $to)
+ is export
+{
+ from-seconds(to-seconds($value, $in), $to);
+}
+
+multi infix:<+>(DateTime $dt, Numeric $x) is export {
+ DateTime.new(($dt.posix + $x).Int, :timezone($dt.timezone), :formatter($dt.formatter))
+}
+
+multi infix:<+>(Numeric $x, DateTime $dt) is export {
+ $dt + $x;
+}
+
+multi infix:<->(DateTime $dt, Numeric $x) is export {
+ DateTime.new(($dt.posix - $x).Int, :timezone($dt.timezone), :formatter($dt.formatter))
+}
+
+multi infix:<->(DateTime $a, DateTime $b) is export {
+ $a.posix - $b.posix;
+}
+
+multi infix:<cmp>(DateTime $a, DateTime $b) is export {
+ $a.posix cmp $b.posix;
+}
+
+multi infix:«<=>»(DateTime $a, DateTime $b) is export {
+ $a.posix <=> $b.posix;
+}
+
+multi infix:<==>(DateTime $a, DateTime $b) is export {
+ $a.posix == $b.posix;
+}
+
+multi infix:<!=>(DateTime $a, DateTime $b) is export {
+ $a.posix != $b.posix;
+}
+
+multi infix:«<=»(DateTime $a, DateTime $b) is export {
+ $a.posix <= $b.posix;
+}
+
+multi infix:«<»(DateTime $a, DateTime $b) is export {
+ $a.posix < $b.posix;
+}
+
+multi infix:«>=»(DateTime $a, DateTime $b) is export {
+ $a.posix >= $b.posix;
+}
+
+multi infix:«>»(DateTime $a, DateTime $b) is export {
+ $a.posix > $b.posix;
+}
View
@@ -0,0 +1,37 @@
+use v6;
+
+BEGIN { @*INC.unshift: 'lib' }
+
+use Test;
+use DateTime::Math;
+
+plan 17;
+
+my $d = DateTime.new(:year(2010), :month(12), :day(31));
+
+my $t1 = $d + to-seconds(1, 'd');
+
+is $t1.year, 2011, 'year changed correctly, add 1d';
+is $t1.month, 1, 'month changed correctly, add 1d';
+is $t1.day, 1, 'day changed correctly, add 1d';
+
+my $t2 = $d - to-seconds(1, 'y');
+
+is $t2.year, 2009, 'year changed correctly, subtract 1y';
+is $t2.month, 12, 'month changed correctly, subtract 1y';
+is $t2.day, 31, 'day changed correctly, subtract 1y';
+
+is $t1 - $t2, 31622400, 'DateTime - DateTime';
+is from-seconds($t1 - $t2, 'd'), 366, 'from-seconds to days';
+
+ok $t1 > $t2, 'DateTime > DateTime';
+ok $t2 < $t1, 'DateTime < DateTime';
+ok $t1 >= $t2, 'DateTime >= DateTime';
+ok $t2 <= $t1, 'DateTime <= DateTime';
+ok !($t1 == $t2), 'DateTime == DateTime';
+is $t1 cmp $t2, 1, 'DateTime cmp DateTime';
+is $t1 <=> $t2, 1, 'DateTime <=> DateTime';
+ok $t1 != $t2, 'DateTime != DateTime';
+
+is duration-from-to(30, 'm', 'h'), 0.5, 'duration-to-from() works.';
+

0 comments on commit 75524e8

Please sign in to comment.