rline has asked for the wisdom of the Perl Monks concerning the following question:
Hello,
I have a perl cgi that saves form data to a flatfile database. One of the form fields asks the user to say whether they need to move (rental property company) in 10 days, 20 days, etc.
Anyway, next to that field in the database, I want to add another field which gives a date equal to the date the user submits the form plus the number of days the user selects.
So if they submitted it on October 2nd, and selected to move in 20 days, I'd want the field to say "October 22".
Can this be done? If so, how?
Thankyou very much.
Re: Add A Number of Days to Today's Date
by davorg (Chancellor) on Sep 28, 2001 at 12:31 UTC
|
Perl finds it all much easier if you deal with dates as
the number of seconds since 00:00 Jan 1 1970 (this number,
incidently, has just passed one billion). The function
time gives this value for the current time and
the timelocal function (from the Time::Local
module) can convert any date or time into this format.
You can then use the POSIX::strftime to convert
that value into a human-readable string. Here's an
example:
use POSIX 'strftime';
my $now = time;
my $then = $now + (20 * 86_400); # 86,400 seconds in a day
my $then_str = strftime('%d %B %Y', localtime($then));
print "In 20 days time it will be $then_str\n";
Of course, it's possible to write that more
compactly :)
use POSIX 'strftime';
print "In 20 days time it will be ",
strftime('%d %B %Y', localtime(time + 20 * 86_400)),
"\n";
--
<http://www.dave.org.uk>
"The first rule of Perl club is you don't talk about
Perl club."
| [reply] [d/l] [select] |
|
Hey,
Thanks y'all for your time and effort in replying to my question! I really appreciate it.
OK. So I understand how to get the date in x days time. How can I automatically insert the variable $then_str into my flatfile database? The database is appended every time a user fills out a form. So there are about 20 fields which are appended. How do I automatically insert the variable $then_str next to, say, the 15th field in the database? So the script needs to pull the 20 user-filled-in values, and then add my created $then_str value next to the 15th value, to make a total of 21 values in the database?
Thanks in advance!
| [reply] |
Re: Add A Number of Days to Today's Date
by clemburg (Curate) on Sep 28, 2001 at 13:14 UTC
|
You should also have a look at Date::Manip and Date::Calc. Both offer a large range of features that will probably cover your needs. Especially Date::Manip's ParseDate() function is a real time saver for tasks like this.
Example:
> perl -MDate::Manip -e 'print UnixDate(ParseDate("October 2nd"), "%Y-
+%
m-%d"), "\n"'
2001-10-02
> perl -MDate::Manip -e 'print UnixDate(DateCalc("October 2nd", "+ 20
+days", \$err), "%Y-%m-%d"), "\n"'
2001-10-22
> perl -MDate::Manip -e 'print UnixDate(ParseDate("today"), "%Y-%m-%d"
+)
, "\n"'
2001-09-28
> perl -MDate::Manip -e 'print UnixDate(ParseDate("10 days"), "%Y-%m-%
+d
"), "\n"'
2001-10-08
> perl -MDate::Manip -e 'print UnixDate(ParseDate("10 days ago"), "%Y-
+%
m-%d"), "\n"'
2001-09-18
> perl -MDate::Manip -e 'print UnixDate(ParseDate("Monday 1 week ago")
+,
"%Y-%m-%d"), "\n"'
2001-09-17
Christian Lemburg
Brainbench MVP for Perl
http://www.brainbench.com | [reply] [d/l] |
|
I really don't like Date::Manip. Sure it does a
lot, but that's it's downfall. In tests I've seen it take
fifteen times as long to do simple date manipulations than
an equivalent script written using Perl's built-in
functions.
There are times when that's a worthwhile hit to take,
but in cases like this where it's very simple to do with
built-ins I really don't think it's worthwhile.
--
<http://www.dave.org.uk>
"The first rule of Perl club is you don't talk about
Perl club."
| [reply] |
|
Sure, Date::Manip is slow compared to hand-rolled stuff.
It even says so in the POD (see below). So there is no
reason to complain about this, you have been warned.
OTOH, I really think re-solving all those common date calculating problems again and again is a big waste of time,
and a big source of errors in programs, too.
From the Date::Manip POD:
Date::Manip is certainly the most powerful of the Date modules.
To the best of my knowledge, it will do everything that any
other date module will do (not just the ones I listed above),
and there are a number of features that Date::Manip has that
none of the other modules have. Date::Manip is the "Swiss Army
Knife" of Date modules. I'm trying to build a library which can
do _EVERY_ conceivable date/time manipulation that you'll run
into in everyday life.
Although I am working on making Date::Manip faster, it will
never be as fast as other modules. And before anyone asks,
Date::Manip will never be translated to C (at least by me). I
write C because I have to. I write perl because I like to.
Date::Manip is something I do because it interests me, not
something I'm paid for.
Date::Manip is also big. The last time I looked, it's one of the
largest CPAN modules there is. If you ignore modules like Tk,
LWP, etc. which are actually packages of modules, it may be the
largest. It's true that Date::Manip will do almost every date
operation you could imagine... but you rarely need all that
power. I'm working on reducing the footprint of Date::Manip, but
even at it's slimmest, it'll outweigh the other modules by a
good bit.
If you are going to be using the module in cases where
performance is an important factor (started up in a CGI program
being run by your web server 5,000 times a second), you should
check out one of the other Date or Time modules in CPAN. If
you're only doing fairly simple date operations (parsing common
date formats, finding the difference between two dates, etc.),
the other modules will almost certainly suffice. If you're doing
one operation very repetitively (parsing 10,000 dates from a
database), you are probably better off writing your own
functions (perhaps bypassing all date modules entirely) designed
specifically for your needs.
On the other hand, if you want one solution for all your date
needs, don't need peak speed, or are trying to do more exotic
date operations, Date::Manip is for you. Operations on things
like business dates, foreign language dates, holidays and other
recurring events, etc. are available more-or-less exclusively in
Date::Manip.
Christian Lemburg
Brainbench MVP for Perl
http://www.brainbench.com | [reply] [d/l] |
Re: Add A Number of Days to Today's Date
by tachyon (Chancellor) on Sep 28, 2001 at 14:47 UTC
|
$days = 10;
$then = localtime ( time() + $days * 24*60*60 );
print $then;
cheers
tachyon
s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print
| [reply] [d/l] |
|
Except when the day is 23 or 25 hours long.
| [reply] |
|
Probably not noticable but it is slightly faster to do
$days = 10;
$then = localtime(time() + $days * 86400);
print $then;
| [reply] [d/l] |
|
* 24 * 60 *60
slightly faster to do
... * 86400
No, any good optimizer should optimize away those multiplications (in any language) anyway (so if its done in a loop it shouldn't matter, and if its only done once then it makes too little difference to matter), and its better self-documentation IMHO to leave it as '24*60*60' because those numbers mean something to me, whereas 86400 does not. Someone could inadvertently change it to 84600 and I wouldn't notice the difference until many wrong calculations had been done. In any case, this is a bad place for micro-optimizations...
| [reply] |
|
use Benchmark;
$yours = '
$days = 10;
$then = localtime(time() + $days * 86400);';
$mine = '
$days = 10;
$then = localtime(time() + $days * 24*60*60 );';
timethese ( 100000, { 'yours' => $yours, 'mine' => $mine } );
__END__
Benchmark: timing 100000 iterations of mine, yours...
mine: 30 wallclock secs (29.95 usr + 0.00 sys = 29.95 CPU) @ 33
+38.89/s (n=100000)
yours: 30 wallclock secs (29.94 usr + 0.00 sys = 29.94 CPU) @ 33
+40.01/s (n=100000)
sleep 28800 :-) cheers
tachyon
s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print
| [reply] [d/l] |
|
Re: Add A Number of Days to Today's Date
by Zaxo (Archbishop) on Sep 28, 2001 at 13:16 UTC
|
I like davorg's way, but you might also look at Date::Calc (adapted from perldoc):
my $Dd = 10;
($year,$month,$day) = Add_Delta_Days($year,$month,$day,$Dd);
There are lots more ways to choose from
After Compline, Zaxo | [reply] [d/l] |
(tye)Re: Add A Number of Days to Today's Date
by tye (Sage) on Sep 28, 2001 at 21:16 UTC
|
Note that using time()+$nDays*24*60*60 can fail when done near midnight near transitions to or from daylight savings time. This is fairly easy to fix, tho:
my $now= time();
my($y,$m,$d)= (localtime(
$now + 60*60*(12-(localtime($now))[2])
+ $nDays*24*60*60
))[5,4,3];
print sprintf "%04d-%02d-%02d", 1900+$y, 1+$m, $d;
print $/;
Note that the use of $now is required to avoid one race condition but that it isn't enough since doing this calculation near midnight still has a race condition of whether "today" ends up being before mignight or after midnight. So you need to use $now to set all of the dates that get recorded. For this reason, I prefer {NULE}'s solution. But I wanted to point out the problem with two of the other solutions.
-
tye
(but my friends call me "Tye") | [reply] [d/l] [select] |
Re: Add A Number of Days to Today's Date
by {NULE} (Hermit) on Sep 28, 2001 at 17:18 UTC
|
Hi rline,
My approach differs a bit from what other's have posted here, so I'll offer it. I like to avoid modules that others might have to download, because I know first hand that process doesn't always go smoothly. So here is an example that accomplishes two things - first allows your user to specify a date (which are fed to $mday,$mon,$year) and a number of days (fed to $daysFromNow) and using the built-in Time::Local module will return th date you desire. Second it avoids having to specify non-standard modules, or having to manually getting date manipulation right.
The idea is the same as what the other monks are telling you, I just "like my way better(tm)". I also find it much safer than trusting my dumb brain to handle manipulating dates by hand.
#! /usr/local/bin/perl -w
use strict;
use Time::Local;
my ($sec,$min,$hour,$mday,$mon,$year) =
(0,0,0,22,11,2001);
my $daysFromNow = 99;
$year-=1900; $mon-=1; $daysFromNow*=86400;
my $givenTime =
timelocal($sec,$min,$hour,$mday,$mon,$year);
$givenTime+=$daysFromNow;
($sec,$min,$hour,$mday,$mon,$year) =
localtime($givenTime);
$year+=1900;$mon+=1;
print "$year-$mon-$mday $hour:$min:$sec\n";
Good luck!
{NULE}
P.S. Opera appears to add carriage returns by itself to these posts - so my apologies if this is mis-formatted. | [reply] [d/l] |
|
|