Velocity Reviews > Perl > 12 hour clock and offset problem

# 12 hour clock and offset problem

Kenetic
Guest
Posts: n/a

 06-16-2007
I'm trying to convert an input time to the offset time in a 12 hour
clock system. It's giving me a headache. The am and pm must be the
right ones when the offset is added to the input time (\$temptime). I
understand it's better to use a 24 hour clock, but unfortunately I
can't in this situation. Everything needs to be done in 12-hour
format.

In short, 10:00 am with an offset of -3 should result in 1:00 pm;
10:00 pm with an offset of -3 should result in 1:00 am.
I've been at this for awhile, sadly, and cannot wrap my head around
it. Any help to point me in the right direction would be fantastic.

difficulty is the AM/PM to switch.

my \$offset = -3;
my \$tempTime = "10:00 pm";
sub myMod {
my ( \$a, \$b ) = @_;
my \$div = \$a / \$b;
return \$a - int( \$div ) * \$b;
}
sub getutc {
my \$time = shift;
my \$GMTOffset = shift;
\$time =~ /(\d{1,2})\d\d)\s(.+)*/;
# Is UTC a .5 remainder? if so, chop it off--we use
# it later regardless
my \$hours = \$1;
if (myMod(\$hours,int(\$hours)) == -0.5) {
\$hours - 0.5;
}
my \$minutes = \$2;
my \$ampm = \$3;
#Take hours and subtract whole number in Offset Time
\$hours = \$hours - int(\$GMTOffset);
if (\$hours >= 12) {
\$ampm = "pm";
\$hours = \$hours - 12
}
# If 0.5 on the Offset, then add 30 minutes and wrap
if (myMod(\$GMTOffset, int(\$GMTOffset)) == -0.5) {
\$minutes = \$minutes + 30;
if (\$minutes >= 60) {
\$minutes = \$minutes % 60;
\$hours = \$hours + 1;
}
}
\$minutes = sprintf("%02d", \$minutes);
\$hours = sprintf("%2d", \$hours);
if (\$hours == 0) { \$hours = "12";}
return \$hours.":".\$minutes." ".\$ampm;
}

my \$theTime = getutc(\$tempTime, \$offset);
print "\nCurrent time: \$tempTime\n";

Brian McCauley
Guest
Posts: n/a

 06-16-2007
On Jun 16, 4:40 pm, Kenetic <(E-Mail Removed)> wrote:
> I'm trying to convert an input time to the offset time in a 12 hour
> clock system. It's giving me a headache. The am and pm must be the
> right ones when the offset is added to the input time (\$temptime). I
> understand it's better to use a 24 hour clock, but unfortunately I
> can't in this situation. Everything needs to be done in 12-hour
> format.

What makes you think that _everything_ needs to be done in 12-hour
format?

Maybe input and output needs to be in 12-hour format but I can see no
reason why intermediate values should not be in, say, seconds or
minutes since midnight.

> In short, 10:00 am with an offset of -3 should result in 1:00 pm;
> 10:00 pm with an offset of -3 should result in 1:00 am.
> I've been at this for awhile, sadly, and cannot wrap my head around
> it. Any help to point me in the right direction would be fantastic.
>
> This is my latest version, which works to a certain extent--the
> difficulty is the AM/PM to switch.
>
> my \$offset = -3;
> my \$tempTime = "10:00 pm";
> sub myMod {
> my ( \$a, \$b ) = @_;
> my \$div = \$a / \$b;
> return \$a - int( \$div ) * \$b;
> }

Perl has a mod operator.

> sub getutc {
> my \$time = shift;
> my \$GMTOffset = shift;
> \$time =~ /(\d{1,2})\d\d)\s(.+)*/;

You should always check the match succeeds before you use the result.
At least say "or die".
> # Is UTC a .5 remainder? if so, chop it off--we use
> # it later regardless

I don't get all that, I'll ignore it.

> my \$hours = \$1;

It's usually preferable you use the return value of the m// operator
rather than \$1 etc.

> if (myMod(\$hours,int(\$hours)) == -0.5) {
> \$hours - 0.5;
> }
> my \$minutes = \$2;
> my \$ampm = \$3;
> #Take hours and subtract whole number in Offset Time
> \$hours = \$hours - int(\$GMTOffset);
> if (\$hours >= 12) {
> \$ampm = "pm";
> \$hours = \$hours - 12
> }
> # If 0.5 on the Offset, then add 30 minutes and wrap
> if (myMod(\$GMTOffset, int(\$GMTOffset)) == -0.5) {
> \$minutes = \$minutes + 30;
> if (\$minutes >= 60) {
> \$minutes = \$minutes % 60;
> \$hours = \$hours + 1;
> }
> }
> \$minutes = sprintf("%02d", \$minutes);
> \$hours = sprintf("%2d", \$hours);

sprintf can format several arguments at once.

> if (\$hours == 0) { \$hours = "12";}
> return \$hours.":".\$minutes." ".\$ampm;
>
> }
>
> my \$theTime = getutc(\$tempTime, \$offset);
> print "\nCurrent time: \$tempTime\n";

#!perl
use strict;
use warnings;

my \$offset = -3;
my \$tempTime = "10:00 pm";

sub getutc {
my \$time = shift;
my \$GMTOffset = shift;
my (\$hours,\$minutes,\$ampm) =
\$time =~ /(\d{1,2})\d\d)\s*([ap]m)/ or die;
\$hours += 12 if \$ampm eq 'pm';
my \$m = ((\$hours - \$GMTOffset) * 60 + \$minutes ) % ( 24 * 60 );
return sprintf("%2d:%02d %s",
int(\$m / 60 + 11 ) % 12 + 1,
\$m % 60,
\$m < 12 * 60 ? 'am' : 'pm');
}

my \$theTime = getutc(\$tempTime, \$offset);
print "\nCurrent time: \$tempTime\n";
__END__

Charlton Wilbur
Guest
Posts: n/a

 06-16-2007
>>>>> "K" == Kenetic <(E-Mail Removed)> writes:

K> I've been at this for awhile, sadly, and cannot wrap my head
K> around it. Any help to point me in the right direction would be
K> fantastic.

You will drive yourself crazy trying to write your own date and time
handling code, and even if you think you've gotten it right, there's a
near certainty you'll find out after the fact you forgot about
something. You're far better off using something like DateTime.pm.

Charlton

--
Charlton Wilbur
http://www.velocityreviews.com/forums/(E-Mail Removed)

Paul Lalli
Guest
Posts: n/a

 06-16-2007
On Jun 16, 11:40 am, Kenetic <(E-Mail Removed)> wrote:
> I'm trying to convert an input time to the offset time in a 12 hour
> clock system. It's giving me a headache. The am and pm must be the
> right ones when the offset is added to the input time (\$temptime). I
> understand it's better to use a 24 hour clock, but unfortunately I
> can't in this situation. Everything needs to be done in 12-hour
> format.
>
> In short, 10:00 am with an offset of -3 should result in 1:00 pm;
> 10:00 pm with an offset of -3 should result in 1:00 am.
> I've been at this for awhile, sadly, and cannot wrap my head around
> it. Any help to point me in the right direction would be fantastic.

correct me. But I'm not seeing why this is as complicated as you've

\$ perl -MPOSIX=strftime -le'
sub getutc {
my (\$time, \$offset) = @_;
my (\$h, \$m, \$ap) = (\$time =~ /^(\d+)\\d+)\s*([ap])m/i);
\$h += 12 if lc \$ap eq "p";
strftime("%I:%M %p", 0, \$m, \$h + \$offset, 1, 0, 107);
}

print getutc("10:00 am", -3);
print getutc("10:00 pm", -3);
print getutc("12:00 pm", -3);
print getutc("12:00 am", -3);
print getutc("4:00am", -3);
print getutc("4:00pm", -3);
'
07:00 AM
07:00 PM
09:00 PM
09:00 AM
01:00 AM
01:00 PM

Am I not understanding something?

Paul Lalli

John W. Krahn
Guest
Posts: n/a

 06-16-2007
Kenetic wrote:
> I'm trying to convert an input time to the offset time in a 12 hour
> clock system. It's giving me a headache. The am and pm must be the
> right ones when the offset is added to the input time (\$temptime). I
> understand it's better to use a 24 hour clock, but unfortunately I
> can't in this situation. Everything needs to be done in 12-hour
> format.
>
> In short, 10:00 am with an offset of -3 should result in 1:00 pm;
> 10:00 pm with an offset of -3 should result in 1:00 am.
> I've been at this for awhile, sadly, and cannot wrap my head around
> it. Any help to point me in the right direction would be fantastic.

\$ perl -le'
use POSIX q/strftime/;
use Time::Local;

my \$offset = -3;
my \$tempTime = "10:00 pm";

sub getutc {
my ( \$time, \$GMTOffset ) = @_;
my ( \$hours, \$minutes, \$ampm ) = \$time =~ /(\d\d?)\d\d?)\s+([ap]m)*/i;
\$hours = "am" eq lc \$ampm ? \$hours : \$hours == 12 ? 0 : \$hours + 12;
return strftime "%I:%M %P", gmtime timegm( 0, \$minutes, \$hours, 1, 1, 1 )
+ -\$GMTOffset * 3600;
}

my \$theTime = getutc( \$tempTime, \$offset );

print "\nCurrent time: \$tempTime\n",
'

Current time: 10:00 pm

John
--
Perl isn't a toolbox, but a small machine shop where you
can special-order certain sorts of tools at low cost and
in short order. -- Larry Wall

Paul Lalli
Guest
Posts: n/a

 06-17-2007
On Jun 16, 10:40 pm, Purl Gurl <(E-Mail Removed)> wrote:
> Paul Lalli wrote:
> > Kenetic wrote:

>
> (snipped a lot)
>

> >> In short, 10:00 am with an offset of -3 should result in 1:00 pm;

> > Am I not understanding something?

>
> Input Time: 10:00 am
>
> Expected Results: 1:00 pm
>
> Printed Results: 07:00 AM

Hrm. Right you are. I misread the OP's requirements. My mistake.
Corrected subroutine:

sub getutc {
my (\$time, \$offset) = @_;
my (\$h, \$m, \$ap) = (\$time =~ /^(\d+)\\d+)\s*([ap])m/i);
\$h += 12 if lc \$ap eq "p";
strftime("%I:%M %p", 0, \$m, \$h - \$offset, 1, 0, 107);
}

Thanks for the correction,
Paul Lalli

Kenetic
Guest
Posts: n/a

 06-17-2007
On Jun 16, 9:40 pm, Purl Gurl <(E-Mail Removed)> wrote:

>
> Let me know if you find any glitches.
>
> --
> Purl Gurl
> --

It looks like it works particularly with 12 am and 12 pm, and since
you have a handle on the script (there are some things in here I
haven't used extensively--just a novice at perl), I wonder if you can
modify it to include, .5 of an hour. The offset can be -3 or -3.5 for
3 hours and 30 minutes. Also to be considered is how :30 past the hour
would then wrap around to the next hour, which is easy enough
(although when wrapping past 12 am or pm might pose a challenge)

Thanks for all the help so far, it's been overwhelming.

Cheers,

Mumia W.
Guest
Posts: n/a

 06-17-2007
On 06/17/2007 02:48 AM, Kenetic wrote:
>
> It looks like it works particularly with 12 am and 12 pm, and since
> you have a handle on the script (there are some things in here I
> haven't used extensively--just a novice at perl), I wonder if you can
> modify it to include, .5 of an hour. [...]

As the others have said, use already-made modules for this sort of
thing. The module writers have already worked out most of the complexities.

Is something like this what you're trying to do?

require Date:arse;
require POSIX;
Date:arse->import(qw/str2time/);
POSIX->import(qw/strftime mktime/);

local \$\ = "\n";
my \$offset = -3;
my \$data = 'June 10, 2007 10:00am';
my \$timeval = str2time(\$data)-(\$offset*3600);
print strftime('%F %r',localtime \$timeval);

On my system (Perl 5.8.4, Linux), this prints "2007-06-10 01:00:00 PM"

Date:arse is a very useful CPAN module, and POSIX is part of Perl.

Kenetic
Guest
Posts: n/a

 06-17-2007
On Jun 16, 9:19 am, Brian McCauley <(E-Mail Removed)> wrote:
> On Jun 16, 4:40 pm, Kenetic <(E-Mail Removed)> wrote:
>
> > I'm trying to convert an input time to the offset time in a 12 hour
> > clock system. It's giving me a headache. The am and pm must be the
> > right ones when the offset is added to the input time (\$temptime). I
> > understand it's better to use a 24 hour clock, but unfortunately I
> > can't in this situation. Everything needs to be done in 12-hour
> > format.

>
> What makes you think that _everything_ needs to be done in 12-hour
> format?
>
> Maybe input and output needs to be in 12-hour format but I can see no
> reason why intermediate values should not be in, say, seconds or
> minutes since midnight.
>
> > In short, 10:00 am with an offset of -3 should result in 1:00 pm;
> > 10:00 pm with an offset of -3 should result in 1:00 am.
> > I've been at this for awhile, sadly, and cannot wrap my head around
> > it. Any help to point me in the right direction would be fantastic.

>
> > This is my latest version, which works to a certain extent--the
> > difficulty is the AM/PM to switch.

>
> > my \$offset = -3;
> > my \$tempTime = "10:00 pm";
> > sub myMod {
> > my ( \$a, \$b ) = @_;
> > my \$div = \$a / \$b;
> > return \$a - int( \$div ) * \$b;
> > }

>
> Perl has a mod operator.
>
> > sub getutc {
> > my \$time = shift;
> > my \$GMTOffset = shift;
> > \$time =~ /(\d{1,2})\d\d)\s(.+)*/;

>
> You should always check the match succeeds before you use the result.
> At least say "or die".
>
> > # Is UTC a .5 remainder? if so, chop it off--we use
> > # it later regardless

>
> I don't get all that, I'll ignore it.
>
> > my \$hours = \$1;

>
> It's usually preferable you use the return value of the m// operator
> rather than \$1 etc.
>
>
>
> > if (myMod(\$hours,int(\$hours)) == -0.5) {
> > \$hours - 0.5;
> > }
> > my \$minutes = \$2;
> > my \$ampm = \$3;
> > #Take hours and subtract whole number in Offset Time
> > \$hours = \$hours - int(\$GMTOffset);
> > if (\$hours >= 12) {
> > \$ampm = "pm";
> > \$hours = \$hours - 12
> > }
> > # If 0.5 on the Offset, then add 30 minutes and wrap
> > if (myMod(\$GMTOffset, int(\$GMTOffset)) == -0.5) {
> > \$minutes = \$minutes + 30;
> > if (\$minutes >= 60) {
> > \$minutes = \$minutes % 60;
> > \$hours = \$hours + 1;
> > }
> > }
> > \$minutes = sprintf("%02d", \$minutes);
> > \$hours = sprintf("%2d", \$hours);

>
> sprintf can format several arguments at once.
>
> > if (\$hours == 0) { \$hours = "12";}
> > return \$hours.":".\$minutes." ".\$ampm;

>
> > }

>
> > my \$theTime = getutc(\$tempTime, \$offset);
> > print "\nCurrent time: \$tempTime\n";
> > print "Adjust ".\$offset." hours\n";
> > print "Adjusted to: \$theTime\n";

>
> #!perl
> use strict;
> use warnings;
>
> my \$offset = -3;
> my \$tempTime = "10:00 pm";
>
> sub getutc {
> my \$time = shift;
> my \$GMTOffset = shift;
> my (\$hours,\$minutes,\$ampm) =
> \$time =~ /(\d{1,2})\d\d)\s*([ap]m)/ or die;
> \$hours += 12 if \$ampm eq 'pm';
> my \$m = ((\$hours - \$GMTOffset) * 60 + \$minutes ) % ( 24 * 60 );
> return sprintf("%2d:%02d %s",
> int(\$m / 60 + 11 ) % 12 + 1,
> \$m % 60,
> \$m < 12 * 60 ? 'am' : 'pm');
>
> }
>
> my \$theTime = getutc(\$tempTime, \$offset);
> print "\nCurrent time: \$tempTime\n";
> __END__

Brian, the reason why I need to use a sub for mod is that perl's mod
doesn't work very well with fractions. I picked this snippet up from
perlmonks, if you compare '3.5 % 3' and myMod(3.5, 3), the former will
result in 0, the latter is 0.5. Thank you for your tips about the
matching and strftime, those are quite valuable during this journey
through perl. It's also true that the format can take on whatever form
in the intermediary, however raw input and eventual output are in 12-
hour format. I've built a similar time conversion in excel using
minutes so I understand what your saying.

Other then that, I think your scripts works to the extent that 12 pm
and 12 am don't work properly.

Cheers,

Kenetic
Guest
Posts: n/a

 06-17-2007
On Jun 17, 1:47 am, "Mumia W." <paduille.4061.mumia.w
(E-Mail Removed)> wrote:

>
> As the others have said, use already-made modules for this sort of
> thing. The module writers have already worked out most of the complexities.
>

I'll most likely be unable to use any external modules. One of the
constraints I have unfortunately.

I've almost got the minutes to work, but I'm missing am or pm, so I
can't test it that well. Just getting the hang of substr and index, I
suppose. Looks promising though.

Cheers,