parent
f4b11e9a0d
commit
23b8756f2b
@ -1,235 +0,0 @@ |
|||||||
package Time::Fake; |
|
||||||
use Carp; |
|
||||||
use strict; |
|
||||||
use vars '$VERSION'; |
|
||||||
$VERSION = "0.11"; |
|
||||||
|
|
||||||
##################### |
|
||||||
|
|
||||||
my $OFFSET = 0; |
|
||||||
|
|
||||||
*CORE::GLOBAL::time = sub() { CORE::time() + $OFFSET }; |
|
||||||
|
|
||||||
*CORE::GLOBAL::localtime = sub(;$) { |
|
||||||
@_ ? CORE::localtime($_[0]) |
|
||||||
: CORE::localtime(CORE::time() + $OFFSET); |
|
||||||
}; |
|
||||||
|
|
||||||
*CORE::GLOBAL::gmtime = sub(;$) { |
|
||||||
@_ ? CORE::gmtime($_[0]) |
|
||||||
: CORE::gmtime(CORE::time() + $OFFSET); |
|
||||||
}; |
|
||||||
|
|
||||||
sub import { |
|
||||||
my $pkg = shift; |
|
||||||
$pkg->offset(shift); |
|
||||||
} |
|
||||||
|
|
||||||
sub offset { |
|
||||||
my $pkg = shift; |
|
||||||
return $OFFSET if !@_; |
|
||||||
|
|
||||||
my $old_offset = $OFFSET; |
|
||||||
$OFFSET = _to_offset(shift); |
|
||||||
return $old_offset; |
|
||||||
} |
|
||||||
|
|
||||||
sub reset { |
|
||||||
shift->offset(0); |
|
||||||
} |
|
||||||
|
|
||||||
my %mult = ( |
|
||||||
s => 1, |
|
||||||
m => 60, |
|
||||||
h => 60*60, |
|
||||||
d => 60*60*24, |
|
||||||
M => 60*60*24*30, |
|
||||||
y => 60*60*24*365, |
|
||||||
); |
|
||||||
|
|
||||||
sub _to_offset { |
|
||||||
my $t = shift || return 0; |
|
||||||
|
|
||||||
if ($t =~ m/^([+-]\d+)([smhdMy]?)$/) { |
|
||||||
$t = $1 * $mult{ $2 || "s" }; |
|
||||||
|
|
||||||
} elsif ($t !~ m/\D/) { |
|
||||||
$t = $t - CORE::time; |
|
||||||
|
|
||||||
} else { |
|
||||||
croak "Invalid time offset: `$t'"; |
|
||||||
} |
|
||||||
|
|
||||||
return $t; |
|
||||||
} |
|
||||||
|
|
||||||
1; |
|
||||||
|
|
||||||
__END__ |
|
||||||
|
|
||||||
=head1 NAME |
|
||||||
|
|
||||||
Time::Fake - Simulate different times without changing your system clock |
|
||||||
|
|
||||||
=head1 SYNOPSIS |
|
||||||
|
|
||||||
Pretend we are running 1 day in the future: |
|
||||||
|
|
||||||
use Time::Fake '+1d'; |
|
||||||
|
|
||||||
Pretend we are running 1 year in the past: |
|
||||||
|
|
||||||
use Time::Fake '-1y'; |
|
||||||
|
|
||||||
Pretend the script started at epoch time 1234567: |
|
||||||
|
|
||||||
use Time::Fake 1234567; |
|
||||||
|
|
||||||
See what an existing script would do if run 20 years in the future: |
|
||||||
|
|
||||||
% perl -MTime::Fake="+20y" test.pl |
|
||||||
|
|
||||||
Run a section of code in a time warp: |
|
||||||
|
|
||||||
use Time::Fake; |
|
||||||
|
|
||||||
# do some setup |
|
||||||
|
|
||||||
Time::Fake->offset("+1y"); |
|
||||||
run_tests(); # thinks it's a year ahead |
|
||||||
|
|
||||||
Time::Fake->reset; # back to the present |
|
||||||
|
|
||||||
=head1 DESCRIPTION |
|
||||||
|
|
||||||
Use this module to achieve the effect of changing your system clock, but |
|
||||||
without actually changing your system clock. It overrides the Perl builtin |
|
||||||
subs C<time>, C<localtime>, and C<gmtime>, causing them to return a |
|
||||||
"faked" time of your choice. From the script's point of view, time still |
|
||||||
flows at the normal rate, but it is just offset as if it were executing |
|
||||||
in the past or present. |
|
||||||
|
|
||||||
You may find this module useful in writing test scripts for code that has |
|
||||||
time-sensitive logic. |
|
||||||
|
|
||||||
=head1 USAGE |
|
||||||
|
|
||||||
=head2 Using and importing: |
|
||||||
|
|
||||||
use Time::Fake $t; |
|
||||||
|
|
||||||
Is equivalent to: |
|
||||||
|
|
||||||
use Time::Fake; |
|
||||||
Time::Fake->offset($t); |
|
||||||
|
|
||||||
See below for arguments to C<offset>. This usage makes it easy to |
|
||||||
fake the time for existing scripts, as in: |
|
||||||
|
|
||||||
% perl -MTime::Fake=+1y script.pl |
|
||||||
|
|
||||||
=head2 offset |
|
||||||
|
|
||||||
Time::Fake->offset( [$t] ); |
|
||||||
|
|
||||||
C<$t> is either an epoch time, or a relative offset of the following |
|
||||||
form: |
|
||||||
|
|
||||||
+3 # 3 seconds in the future |
|
||||||
-3s # 3 seconds in the past |
|
||||||
+1h # 1 hour in the future |
|
||||||
etc.. |
|
||||||
|
|
||||||
Relative offsets must begin with a plus or minus symbol. The supported |
|
||||||
units are: |
|
||||||
|
|
||||||
s second |
|
||||||
m minute |
|
||||||
h hour |
|
||||||
d day (24 hours) |
|
||||||
M month (30 days) |
|
||||||
y year (365 days) |
|
||||||
|
|
||||||
If C<$t> is an epoch time, then C<time>, C<localtime>, and C<gmtime> |
|
||||||
will act as though the the current time (when C<offset> was called) was |
|
||||||
actually at C<$t> epoch seconds. |
|
||||||
Otherwise, the offset C<$t> will be added to the times returned by these |
|
||||||
builtin subs. |
|
||||||
|
|
||||||
When C<$t> is false, C<time>, C<localtime>, C<gmtime> |
|
||||||
remain overridden, but their behavior resets to reflect the actual |
|
||||||
system time. |
|
||||||
|
|
||||||
When C<$t> is omitted, nothing is changed, but C<offset> returns the |
|
||||||
current additive offset (in seconds). Otherwise, its return value is |
|
||||||
the I<previous> offset. |
|
||||||
|
|
||||||
C<offset> may be called several times. However, I<The effect of multiple |
|
||||||
calls is NOT CUMULATIVE.> That is: |
|
||||||
|
|
||||||
Time::Fake->offset("+1h"); |
|
||||||
Time::Fake->offset("+1h"); |
|
||||||
|
|
||||||
## same as |
|
||||||
# Time::Fake->offset("+1h"); |
|
||||||
|
|
||||||
## NOT the same as |
|
||||||
# Time::Fake->offset("+2h"); |
|
||||||
|
|
||||||
Each call to C<offset> completely cancels out the effect of any |
|
||||||
previous calls. To make the effect cumulative, use the return value |
|
||||||
of calling C<offset> with no arguments: |
|
||||||
|
|
||||||
Time::Fake->offset("+1h"); |
|
||||||
... |
|
||||||
Time::Fake->offset( Time::Fake->offset + 3600 ); # add another hour |
|
||||||
|
|
||||||
=head2 reset |
|
||||||
|
|
||||||
Time::Fake->reset; |
|
||||||
|
|
||||||
Is the same as: |
|
||||||
|
|
||||||
Time::Fake->offset(0); |
|
||||||
|
|
||||||
That is, it returns all the affected builtin subs to their |
|
||||||
default behavior -- reporing the actual system time. |
|
||||||
|
|
||||||
=head1 KNOWN CAVEATS |
|
||||||
|
|
||||||
Time::Fake must be loaded at C<BEGIN>-time (e.g., with a standard |
|
||||||
C<use> statement). It must be loaded before perl I<compiles> any code |
|
||||||
that uses C<time>, C<localtime>, or C<gmtime>. Due to inherent |
|
||||||
limitations in overriding builtin subs, any code that was compiled |
|
||||||
before loading Time::Fake will not be affected. |
|
||||||
|
|
||||||
Because the system clock is not being changed, only Perl code that |
|
||||||
uses C<time>, C<localtime>, or C<gmtime> will be fooled about the date. |
|
||||||
In particular, the operating system is not fooled, |
|
||||||
nor are other programs. If your Perl code modifies a file for example, |
|
||||||
the file's modification time will reflect the B<actual> (not faked) time. |
|
||||||
Along the same lines, if your Perl script obtains the time from somewhere |
|
||||||
other than the affected builtins subs (e.g., C<qx/date/>), the actual |
|
||||||
(not faked) time will be reflected. |
|
||||||
|
|
||||||
Time::Fake doesn't affect -M, -A, -C filetest operators in the way you'd |
|
||||||
probably want. These still report the B<actual> (not faked) script start |
|
||||||
time minus file access time. |
|
||||||
|
|
||||||
Time::Fake has not been tested with other modules that override the time |
|
||||||
builtins, e.g., Time::HiRes. |
|
||||||
|
|
||||||
=head1 SEE ALSO |
|
||||||
|
|
||||||
Time::Warp, which uses XS to fool more of Perl. |
|
||||||
|
|
||||||
=head1 AUTHOR |
|
||||||
|
|
||||||
Time::Fake is written by Mike Rosulek E<lt>mike@mikero.comE<gt>. Feel |
|
||||||
free to contact me with comments, questions, patches, or whatever. |
|
||||||
|
|
||||||
=head1 COPYRIGHT |
|
||||||
|
|
||||||
Copyright (c) 2008 Mike Rosulek. All rights reserved. This module is free |
|
||||||
software; you can redistribute it and/or modify it under the same terms as Perl |
|
||||||
itself. |
|
@ -1,235 +0,0 @@ |
|||||||
package Time::Fake; |
|
||||||
use Carp; |
|
||||||
use strict; |
|
||||||
use vars '$VERSION'; |
|
||||||
$VERSION = "0.11"; |
|
||||||
|
|
||||||
##################### |
|
||||||
|
|
||||||
my $OFFSET = 0; |
|
||||||
|
|
||||||
*CORE::GLOBAL::time = sub() { CORE::time() + $OFFSET }; |
|
||||||
|
|
||||||
*CORE::GLOBAL::localtime = sub(;$) { |
|
||||||
@_ ? CORE::localtime($_[0]) |
|
||||||
: CORE::localtime(CORE::time() + $OFFSET); |
|
||||||
}; |
|
||||||
|
|
||||||
*CORE::GLOBAL::gmtime = sub(;$) { |
|
||||||
@_ ? CORE::gmtime($_[0]) |
|
||||||
: CORE::gmtime(CORE::time() + $OFFSET); |
|
||||||
}; |
|
||||||
|
|
||||||
sub import { |
|
||||||
my $pkg = shift; |
|
||||||
$pkg->offset(shift); |
|
||||||
} |
|
||||||
|
|
||||||
sub offset { |
|
||||||
my $pkg = shift; |
|
||||||
return $OFFSET if !@_; |
|
||||||
|
|
||||||
my $old_offset = $OFFSET; |
|
||||||
$OFFSET = _to_offset(shift); |
|
||||||
return $old_offset; |
|
||||||
} |
|
||||||
|
|
||||||
sub reset { |
|
||||||
shift->offset(0); |
|
||||||
} |
|
||||||
|
|
||||||
my %mult = ( |
|
||||||
s => 1, |
|
||||||
m => 60, |
|
||||||
h => 60*60, |
|
||||||
d => 60*60*24, |
|
||||||
M => 60*60*24*30, |
|
||||||
y => 60*60*24*365, |
|
||||||
); |
|
||||||
|
|
||||||
sub _to_offset { |
|
||||||
my $t = shift || return 0; |
|
||||||
|
|
||||||
if ($t =~ m/^([+-]\d+)([smhdMy]?)$/) { |
|
||||||
$t = $1 * $mult{ $2 || "s" }; |
|
||||||
|
|
||||||
} elsif ($t !~ m/\D/) { |
|
||||||
$t = $t - CORE::time; |
|
||||||
|
|
||||||
} else { |
|
||||||
croak "Invalid time offset: `$t'"; |
|
||||||
} |
|
||||||
|
|
||||||
return $t; |
|
||||||
} |
|
||||||
|
|
||||||
1; |
|
||||||
|
|
||||||
__END__ |
|
||||||
|
|
||||||
=head1 NAME |
|
||||||
|
|
||||||
Time::Fake - Simulate different times without changing your system clock |
|
||||||
|
|
||||||
=head1 SYNOPSIS |
|
||||||
|
|
||||||
Pretend we are running 1 day in the future: |
|
||||||
|
|
||||||
use Time::Fake '+1d'; |
|
||||||
|
|
||||||
Pretend we are running 1 year in the past: |
|
||||||
|
|
||||||
use Time::Fake '-1y'; |
|
||||||
|
|
||||||
Pretend the script started at epoch time 1234567: |
|
||||||
|
|
||||||
use Time::Fake 1234567; |
|
||||||
|
|
||||||
See what an existing script would do if run 20 years in the future: |
|
||||||
|
|
||||||
% perl -MTime::Fake="+20y" test.pl |
|
||||||
|
|
||||||
Run a section of code in a time warp: |
|
||||||
|
|
||||||
use Time::Fake; |
|
||||||
|
|
||||||
# do some setup |
|
||||||
|
|
||||||
Time::Fake->offset("+1y"); |
|
||||||
run_tests(); # thinks it's a year ahead |
|
||||||
|
|
||||||
Time::Fake->reset; # back to the present |
|
||||||
|
|
||||||
=head1 DESCRIPTION |
|
||||||
|
|
||||||
Use this module to achieve the effect of changing your system clock, but |
|
||||||
without actually changing your system clock. It overrides the Perl builtin |
|
||||||
subs C<time>, C<localtime>, and C<gmtime>, causing them to return a |
|
||||||
"faked" time of your choice. From the script's point of view, time still |
|
||||||
flows at the normal rate, but it is just offset as if it were executing |
|
||||||
in the past or present. |
|
||||||
|
|
||||||
You may find this module useful in writing test scripts for code that has |
|
||||||
time-sensitive logic. |
|
||||||
|
|
||||||
=head1 USAGE |
|
||||||
|
|
||||||
=head2 Using and importing: |
|
||||||
|
|
||||||
use Time::Fake $t; |
|
||||||
|
|
||||||
Is equivalent to: |
|
||||||
|
|
||||||
use Time::Fake; |
|
||||||
Time::Fake->offset($t); |
|
||||||
|
|
||||||
See below for arguments to C<offset>. This usage makes it easy to |
|
||||||
fake the time for existing scripts, as in: |
|
||||||
|
|
||||||
% perl -MTime::Fake=+1y script.pl |
|
||||||
|
|
||||||
=head2 offset |
|
||||||
|
|
||||||
Time::Fake->offset( [$t] ); |
|
||||||
|
|
||||||
C<$t> is either an epoch time, or a relative offset of the following |
|
||||||
form: |
|
||||||
|
|
||||||
+3 # 3 seconds in the future |
|
||||||
-3s # 3 seconds in the past |
|
||||||
+1h # 1 hour in the future |
|
||||||
etc.. |
|
||||||
|
|
||||||
Relative offsets must begin with a plus or minus symbol. The supported |
|
||||||
units are: |
|
||||||
|
|
||||||
s second |
|
||||||
m minute |
|
||||||
h hour |
|
||||||
d day (24 hours) |
|
||||||
M month (30 days) |
|
||||||
y year (365 days) |
|
||||||
|
|
||||||
If C<$t> is an epoch time, then C<time>, C<localtime>, and C<gmtime> |
|
||||||
will act as though the the current time (when C<offset> was called) was |
|
||||||
actually at C<$t> epoch seconds. |
|
||||||
Otherwise, the offset C<$t> will be added to the times returned by these |
|
||||||
builtin subs. |
|
||||||
|
|
||||||
When C<$t> is false, C<time>, C<localtime>, C<gmtime> |
|
||||||
remain overridden, but their behavior resets to reflect the actual |
|
||||||
system time. |
|
||||||
|
|
||||||
When C<$t> is omitted, nothing is changed, but C<offset> returns the |
|
||||||
current additive offset (in seconds). Otherwise, its return value is |
|
||||||
the I<previous> offset. |
|
||||||
|
|
||||||
C<offset> may be called several times. However, I<The effect of multiple |
|
||||||
calls is NOT CUMULATIVE.> That is: |
|
||||||
|
|
||||||
Time::Fake->offset("+1h"); |
|
||||||
Time::Fake->offset("+1h"); |
|
||||||
|
|
||||||
## same as |
|
||||||
# Time::Fake->offset("+1h"); |
|
||||||
|
|
||||||
## NOT the same as |
|
||||||
# Time::Fake->offset("+2h"); |
|
||||||
|
|
||||||
Each call to C<offset> completely cancels out the effect of any |
|
||||||
previous calls. To make the effect cumulative, use the return value |
|
||||||
of calling C<offset> with no arguments: |
|
||||||
|
|
||||||
Time::Fake->offset("+1h"); |
|
||||||
... |
|
||||||
Time::Fake->offset( Time::Fake->offset + 3600 ); # add another hour |
|
||||||
|
|
||||||
=head2 reset |
|
||||||
|
|
||||||
Time::Fake->reset; |
|
||||||
|
|
||||||
Is the same as: |
|
||||||
|
|
||||||
Time::Fake->offset(0); |
|
||||||
|
|
||||||
That is, it returns all the affected builtin subs to their |
|
||||||
default behavior -- reporing the actual system time. |
|
||||||
|
|
||||||
=head1 KNOWN CAVEATS |
|
||||||
|
|
||||||
Time::Fake must be loaded at C<BEGIN>-time (e.g., with a standard |
|
||||||
C<use> statement). It must be loaded before perl I<compiles> any code |
|
||||||
that uses C<time>, C<localtime>, or C<gmtime>. Due to inherent |
|
||||||
limitations in overriding builtin subs, any code that was compiled |
|
||||||
before loading Time::Fake will not be affected. |
|
||||||
|
|
||||||
Because the system clock is not being changed, only Perl code that |
|
||||||
uses C<time>, C<localtime>, or C<gmtime> will be fooled about the date. |
|
||||||
In particular, the operating system is not fooled, |
|
||||||
nor are other programs. If your Perl code modifies a file for example, |
|
||||||
the file's modification time will reflect the B<actual> (not faked) time. |
|
||||||
Along the same lines, if your Perl script obtains the time from somewhere |
|
||||||
other than the affected builtins subs (e.g., C<qx/date/>), the actual |
|
||||||
(not faked) time will be reflected. |
|
||||||
|
|
||||||
Time::Fake doesn't affect -M, -A, -C filetest operators in the way you'd |
|
||||||
probably want. These still report the B<actual> (not faked) script start |
|
||||||
time minus file access time. |
|
||||||
|
|
||||||
Time::Fake has not been tested with other modules that override the time |
|
||||||
builtins, e.g., Time::HiRes. |
|
||||||
|
|
||||||
=head1 SEE ALSO |
|
||||||
|
|
||||||
Time::Warp, which uses XS to fool more of Perl. |
|
||||||
|
|
||||||
=head1 AUTHOR |
|
||||||
|
|
||||||
Time::Fake is written by Mike Rosulek E<lt>mike@mikero.comE<gt>. Feel |
|
||||||
free to contact me with comments, questions, patches, or whatever. |
|
||||||
|
|
||||||
=head1 COPYRIGHT |
|
||||||
|
|
||||||
Copyright (c) 2008 Mike Rosulek. All rights reserved. This module is free |
|
||||||
software; you can redistribute it and/or modify it under the same terms as Perl |
|
||||||
itself. |
|
Loading…
Reference in new issue