Skip to content

Instantly share code, notes, and snippets.

@masak
Last active December 11, 2015 15:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save masak/4621729 to your computer and use it in GitHub Desktop.
Save masak/4621729 to your computer and use it in GitHub Desktop.
DateTime.delta implementation
use MONKEY_TYPING;
enum TimeUnit <
second seconds minute minutes hour hours
day days week weeks month months year years
>;
augment class DateTime {
method delta($amount, TimeUnit $unit) {
my ($hour, $minute) = $!hour, $!minute;
my $date;
given $unit {
when second | seconds {
return DateTime.new(self.Instant + $amount);
}
when minute | minutes { $minute += $amount; proceed }
$hour += floor($minute / 60);
$minute %= 60;
when hour | hours { $hour += $amount; proceed }
my $day-delta += floor($hour / 24);
$hour %= 24;
when day | days { $day-delta += $amount; proceed }
when week | weeks { $day-delta += 7 * $amount; proceed }
when month | months {
my ($month, $year) = $!month, $!year;
$month += $amount;
$year += floor(($month - 1) / 12);
$month = ($month - 1) % 12 + 1;
$date = Date.new(:$year, :$month, :$!day);
succeed;
}
when year | years {
my $year = $!year + $amount;
$date = Date.new(:$year, :$!month, :$!day);
succeed;
}
my $daycount = Date.new(self).daycount;
$daycount += $day-delta;
$date = Date.new-from-daycount($daycount);
}
my $second = $!second;
if $second > 59 && $date ne any(tai-utc::leap-second-dates) {
$second -= 60;
$minute++;
if $minute > 59 {
$minute -= 60;
$hour++;
if $hour > 23 {
$hour -= 24;
$date++;
}
}
}
self.new(:$date, :$hour, :$minute, :$second);
}
}
use Test;
is DateTime.new('2013-12-23T12:34:36Z').delta(1, second),
DateTime.new('2013-12-23T12:34:37Z'),
'adding 1 second';
is DateTime.new('2013-12-23T12:34:36Z').delta(10, seconds),
DateTime.new('2013-12-23T12:34:46Z'),
'adding 10 seconds';
is DateTime.new('2013-12-23T12:34:56Z').delta(14, seconds),
DateTime.new('2013-12-23T12:35:10Z'),
'adding 14 seconds, overflowing to minutes';
is DateTime.new('2013-12-23T12:59:56Z').delta(74, seconds),
DateTime.new('2013-12-23T13:01:10Z'),
'adding 74 seconds, overflowing to hours';
is DateTime.new('2013-12-23T23:59:59Z').delta(1, second),
DateTime.new('2013-12-24T00:00:00Z'),
'adding 1 second, overflowing to days';
is DateTime.new('2013-12-31T23:59:59Z').delta(1, second),
DateTime.new('2014-01-01T00:00:00Z'),
'adding 1 second, overflowing to years';
is DateTime.new('2012-06-30T23:59:59Z').delta(1, second),
DateTime.new('2012-06-30T23:59:60Z'),
'delting to a leap second';
is DateTime.new('2008-12-31T23:59:60Z').delta(1, second),
DateTime.new('2009-01-01T00:00:00Z'),
'delting from a leap second';
is DateTime.new('2013-12-23T12:34:36Z').delta(1, minute),
DateTime.new('2013-12-23T12:35:36Z'),
'adding 1 minute';
is DateTime.new('2013-12-23T12:34:36Z').delta(10, minutes),
DateTime.new('2013-12-23T12:44:36Z'),
'adding 10 minutes';
is DateTime.new('2013-12-23T12:56:34Z').delta(14, minutes),
DateTime.new('2013-12-23T13:10:34Z'),
'adding 14 minutes, overflowing to hours';
is DateTime.new('2013-12-23T12:34:36Z').delta(1, hour),
DateTime.new('2013-12-23T13:34:36Z'),
'adding 1 hour';
is DateTime.new('2013-12-23T12:34:36Z').delta(10, hours),
DateTime.new('2013-12-23T22:34:36Z'),
'adding 10 hours';
is DateTime.new('2013-12-23T12:56:34Z').delta(14, hours),
DateTime.new('2013-12-24T02:56:34Z'),
'adding 14 horus, overflowing to days';
is DateTime.new('2013-12-23T12:34:36Z').delta(1, day),
DateTime.new('2013-12-24T12:34:36Z'),
'adding 1 day';
is DateTime.new('2014-01-31T12:34:36Z').delta(1, day),
DateTime.new('2014-02-01T12:34:36Z'),
'adding 1 day, overflowing to February';
is DateTime.new('2014-02-28T12:56:34Z').delta(2, days),
DateTime.new('2014-03-02T12:56:34Z'),
'adding 2 days, overflowing to March';
is DateTime.new('2008-12-31T23:59:60Z').delta(1, day),
DateTime.new('2009-01-02T00:00:00Z'),
'adding a day to a leap second';
is DateTime.new('1972-12-31T23:59:60Z').delta(1, year),
DateTime.new('1973-12-31T23:59:60Z'),
'adding a year to a leap second, landing on another leap second';
is DateTime.new('2013-12-23T12:34:36Z').delta(1, week),
DateTime.new('2013-12-30T12:34:36Z'),
'adding 1 week';
is DateTime.new('2014-01-31T12:34:36Z').delta(1, week),
DateTime.new('2014-02-07T12:34:36Z'),
'adding 1 week, overflowing to February';
is DateTime.new('2014-02-28T12:56:34Z').delta(2, weeks),
DateTime.new('2014-03-14T12:56:34Z'),
'adding 2 weeks, overflowing to March';
is DateTime.new('2014-12-30T12:56:34Z').delta(3, weeks),
DateTime.new('2015-01-20T12:56:34Z'),
'adding 3 weeks, overflowing to years';
is DateTime.new('2013-12-23T12:34:37Z').delta(-1, second),
DateTime.new('2013-12-23T12:34:36Z'),
'subtracting 1 second';
is DateTime.new('2013-12-23T12:34:46Z').delta(-10, seconds),
DateTime.new('2013-12-23T12:34:36Z'),
'subtracting 10 seconds';
is DateTime.new('2013-12-23T12:35:10Z').delta(-14, seconds),
DateTime.new('2013-12-23T12:34:56Z'),
'subtracting 14 seconds, overflowing to minutes';
is DateTime.new('2013-12-23T13:01:10Z').delta(-74, seconds),
DateTime.new('2013-12-23T12:59:56Z'),
'subtracting 74 seconds, overflowing to hours';
is DateTime.new('2013-12-24T00:00:00Z').delta(-1, second),
DateTime.new('2013-12-23T23:59:59Z'),
'subtracting 1 second, overflowing to days';
is DateTime.new('2014-01-01T00:00:00Z').delta(-1, second),
DateTime.new('2013-12-31T23:59:59Z'),
'subtracting 1 second, overflowing to years';
is DateTime.new('2013-12-23T12:35:36Z').delta(-1, minute),
DateTime.new('2013-12-23T12:34:36Z'),
'subtracting 1 minute';
is DateTime.new('2013-12-23T12:44:36Z').delta(-10, minutes),
DateTime.new('2013-12-23T12:34:36Z'),
'subtracting 10 minutes';
is DateTime.new('2013-12-23T13:10:34Z').delta(-14, minutes),
DateTime.new('2013-12-23T12:56:34Z'),
'subtracting 14 minutes, overflowing to hours';
is DateTime.new('2013-12-23T13:34:36Z').delta(-1, hour),
DateTime.new('2013-12-23T12:34:36Z'),
'subtracting 1 hour';
is DateTime.new('2013-12-23T22:34:36Z').delta(-10, hours),
DateTime.new('2013-12-23T12:34:36Z'),
'subtracting 10 hours';
is DateTime.new('2013-12-24T02:56:34Z').delta(-14, hours),
DateTime.new('2013-12-23T12:56:34Z'),
'subtracting 14 horus, overflowing to days';
is DateTime.new('2013-12-24T12:34:36Z').delta(-1, day),
DateTime.new('2013-12-23T12:34:36Z'),
'subtracting 1 day';
is DateTime.new('2014-02-01T12:34:36Z').delta(-1, day),
DateTime.new('2014-01-31T12:34:36Z'),
'subtracting 1 day, overflowing to February';
is DateTime.new('2014-03-02T12:56:34Z').delta(-2, days),
DateTime.new('2014-02-28T12:56:34Z'),
'subtracting 2 days, overflowing to March';
is DateTime.new('2013-12-30T12:34:36Z').delta(-1, week),
DateTime.new('2013-12-23T12:34:36Z'),
'subtracting 1 week';
is DateTime.new('2014-02-07T12:34:36Z').delta(-1, week),
DateTime.new('2014-01-31T12:34:36Z'),
'subtracting 1 week, overflowing to February';
is DateTime.new('2014-03-14T12:56:34Z').delta(-2, weeks),
DateTime.new('2014-02-28T12:56:34Z'),
'subtracting 2 weeks, overflowing to March';
is DateTime.new('2015-01-20T12:56:34Z').delta(-3, weeks),
DateTime.new('2014-12-30T12:56:34Z'),
'subtracting 3 weeks, overflowing to years';
done;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment