http://www.perlmonks.org?node_id=543058

jesuashok has asked for the wisdom of the Perl Monks concerning the following question:

Hi all

\$input= "200604131145" #( yyyymmddhhmi)
I would like to add 15 with the \$input
I should get the output as \$output = "200604130200"
I would like to get this done in simpler way.
I am already advised by the perlmonks that using perl module will make the work very simple.
But people who are sitting above me, strictly told that I should not use modules.

```(\$YY, \$MM, \$DD, \$hh, \$mm) = (\$dtstamp =~ /(\d\d\d\d)(\d\d)(\d\d)(\d\d)
+(\d\d)/);
\$period1 =sprintf("%02d/%02d/%04d %02d:%02d",
\$MM, \$DD, \$YY, \$hh, \$mm+15);
\$period2 =sprintf("%02d/%02d/%04d %02d:%02d",
\$MM, \$DD, \$YY, \$hhm2, \$hm2-\$hhm2*60);

\$period3 =sprintf("%02d/%02d/%04d %02d:%02d",
\$MM, \$DD, \$YY, \$hh, \$mm);

\$period4 =sprintf("%02d/%02d/%04d %02d:%02d",
\$MM, \$DD, \$YY, \$hhm2, \$hm2-((\$hhm2*60)-15));
Existing code is given in the above lines.
How to simplify that one.

Replies are listed 'Best First'.
Re: getting Date calculation in simpler way
by dragonchild (Archbishop) on Apr 13, 2006 at 13:03 UTC
But people who are sitting above me, strictly told that I should not use modules.

Are you not allowed to use a keyboard, either? I mean, punchcards should be sufficient, right?

Modules are written for a reason. You will want to use DateTime, Date::Calc, or Date::Manip. They have been written by people with an interest in the topic and the code has been vetted on over 100 different OSes by people with an interest in the topic. In other words, the code is nearly bug-free, fast, and completely useful.

My criteria for good software:
1. Does it work?
2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: getting Date calculation in simpler way
by davidrw (Prior) on Apr 13, 2006 at 13:17 UTC
first, your post says 1145 + 15 ==> 0200 ...
I would like to get this done in simpler way.
Second, the only way to do it in a simple way (w.r.t to you) is to use a module and let it do all the work for you .. you don't want to be adding the time in there yourself and dealing w/the gregorian calendar .. e.g. add 15 minutes to each of these: 200002282345, 200402282345, 200602282345 ; and also 200512312345

Tell the people above you that you can a) spend a lot of time reinventing the wheel, then more time testing your code, and probably still have a bug or 2, or b) spend 5 min looking at modules docs and write a 2-line, very robust, very maintainable snippet.
Do we even want to know their "reasoning" for not wanting to use modules?

As for solutions, see these two threads:
Re: getting Date calculation in simpler way
by johngg (Canon) on Apr 13, 2006 at 14:25 UTC
I would be amazed if your bosses disallow use of modules that come as part of the standard Perl distribution. You need to use Time::Local to turn a date into seconds since the epoch. Other than using this module, the following script does pretty much as ff suggests.

```use strict;
use warnings;

# Need this to turn date into seconds since epoch. Standard
# part of Perl distribution.
#
use Time::Local;

# Initialise date string, print it and then increment by
# fifteen minutes and print ten times just to show it works.
#
our \$dateStr = "200604132341";
print "\$dateStr\n";
\$dateStr = plus15(\$dateStr), print "\$dateStr\n" for 1 .. 10;

sub plus15
{
# Get date string, set seconds to zero, pull the rest of
# the date from the string with a match;
#
my \$dateStr = shift;
my \$sec = 0;
my (\$year, \$mth, \$day, \$hr, \$min) =
\$dateStr =~ /^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)\$/;

# Get seconds since the epoch, note months start from zero for
# January to 11 for December. Add 15 minutes-worth of seconds.
#
my \$timeVal = timelocal(\$sec, \$min, \$hr, \$day, \$mth - 1, \$year);
\$timeVal += 15 * 60;

# Turn back in to separate parts, year, month etc. Note that
# localtime() returns years since 1900. Construct a new date
# string and return it.
#
my @timeParts = localtime(\$timeVal);
my \$newStr =
\$timeParts[5] + 1900 .
sprintf("%02d", \$timeParts[4] + 1) .
sprintf("%02d", \$timeParts[3]) .
sprintf("%02d", \$timeParts[2]) .
sprintf("%02d", \$timeParts[1]);
return \$newStr;
}

I you can't even use this module then you are forced to increment the minutes, roll the hour and set back the minutes if they go over 59, etc., etc. Painful, but character building.

Best of luck,

JohnGG

Re: getting Date calculation in simpler way
by ff (Hermit) on Apr 13, 2006 at 13:35 UTC
How accurate does your resulting timestamp need to be? Perhaps you just need a unique number that looks like a timestamp. Add 15 to a valid timestamp and there you have it, e.g. 200604131155 becomes 200604131170 (which of course means 200604131210). Oh, you want minutes to roll to hours to roll to days to roll to months to roll to years? Get ready to write up a bunch of special cases, write incrementing routines for those various flavors, and put them together. Though if what you have above works for you, it looks pretty simple to me.

Quick, another approach: use time to generate what time it is 'now', add 15 minutes worth of seconds to that number, and feed that number back as a parameter to localtime and get the figures you want out of the array.

Re: getting Date calculation in simpler way
by salva (Abbot) on Apr 13, 2006 at 14:39 UTC
without using any module...
```#!/usr/bin/perl

use strict;
use warnings;

sub time_to_str {
my (\$sec, \$min, \$hour, \$mday, \$mon, \$year) = localtime(shift);
return sprintf "%04d%02d%02d%02d%02d%02d", \$year+1900, \$mon+1, \$mday
+, \$hour, \$min, \$sec;
}

sub find_time {
my \$tstr = shift;
my \$max = 2**31;
my \$min = 0;
while (\$max != \$min) {
my \$mid = int ((\$max + \$min) / 2);
my \$midstr = time_to_str \$mid;
if (\$tstr gt \$midstr) {
\$min = \$mid + 1;
}
else {
\$max = \$mid;
}
}
return \$max;
}

my (\$timestr, \$seconds) = @_;
my \$time = find_time \$timestr;
return time_to_str(\$time + \$seconds)
}

while (<DATA>) {
next if /^\s*(?:#.*)?\$/;

my (\$date, \$seconds) = split;
printf "%s + %ds = %s\n", \$date, \$seconds, add_seconds(\$date, \$secon
+ds);
}

__DATA__
# YYYYMMDDhhmmss        seconds
20060413020000          900
20060413024500          900
20061231235700          900
```perl -we 'use Date::Manip;