12 hour clock and offset problem

K

Kenetic

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.

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;
}
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";
print "Adjust ".$offset." hours\n";
print "Adjusted to: $theTime\n";
 
B

Brian McCauley

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";
print "Adjust $offset hours\n";
print "Adjusted to: $theTime\n";
__END__
 
C

Charlton Wilbur

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
 
P

Paul Lalli

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.

Maybe I'm missing something about your requirements. If so, please
correct me. But I'm not seeing why this is as complicated as you've
made it. It's a fairly simple task for strftime:

$ 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
 
J

John W. Krahn

Kenetic said:
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",
"Adjust $offset hours\n",
"Adjusted to: $theTime\n";
'

Current time: 10:00 pm
Adjust -3 hours
Adjusted to: 01:00 am




John
 
P

Paul Lalli

(snipped a lot)



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
 
K

Kenetic

Let me know if you find any glitches.

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,
 
M

Mumia W.

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::parse;
require POSIX;
Date::parse->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::parse is a very useful CPAN module, and POSIX is part of Perl.
 
K

Kenetic

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";
print "Adjust $offset hours\n";
print "Adjusted to: $theTime\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,
 
K

Kenetic

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,
 
K

Kenetic

Sounds good. I am definitely learning more then I bargained for as I
didn't expect such a in-depth response. Of course, time is a rather
complex thing. I'm certainly interested in learning this rather then
just copy and paste and have it work--my first perl script was a lot
of fun to put together and it didn't dawn on me to seek out a group
like this one. In fact, I enjoy doing the research and teaching
myself. The reason I was wondering if you could handle minutes was
under the assumption others knew it was part of the original problem.
I didn't make that clear enough in my comments.

Anyway, I think I should have more then enough information, as you
mentioned, to complete this even if it takes a little while longer.
Would love to have the satisfaction of finally seeing the results I
want.

Thanks again,
 
R

Randal L. Schwartz

Purl> You are, again, running into convention problems. Convention is to
Purl> adjust time by hours, only, to determine a local time.

Almost correct. There are, in fact, timezones that vary by non-whole hours,
and places that use mean solar time instead.

Take a glance at <http://en.wikipedia.org/wiki/Time_zone>, noting the time
zones for such places as India, Burma, and the center of Australia.
 
R

Randal L. Schwartz

Purl> Larry Wall, Randal Schwartz, Joseph Hall, Brigitte Jellinek and others
Purl> like them, did not become masters of Perl through using modules.

That statement is incorrect. Please don't speak for me like that.

A large part of being a master is knowing the tool thoroughly. For Perl, part
of the "tool" is in fact the CPAN. Knowing what modules exist, and how to use
them, is part of the proper mastery of Perl.
 
J

Jürgen Exner

Kenetic said:
On Jun 17, 1:47 am, "Mumia W." <paduille.4061.mumia.w

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

Then good luck in dealing with the added/missing hour during the switch
to/from daylight saving time, of course adjusted to the proper locale.

jue
 
D

Dr.Ruud

Kenetic schreef:
perl's mod doesn't work very well with fractions

<quote src="perlop">
Binary "%" computes the modulus of two numbers. Given
integer operands $a and $b: If $b is positive, then "$a %
$b" is $a minus the largest multiple of $b that is not
greater than $a. If $b is negative, then "$a % $b" is $a
minus the smallest multiple of $b that is not less than $a
(i.e. the result will be less than or equal to zero).
Note that when "use integer" is in scope, "%" gives you
direct access to the modulus operator as implemented by
your C compiler. This operator is not as well defined for
negative operands, but it will execute faster.
</quote>

Nothing is mentioned there about fractional behaviour. But I was never
surprised because *in my world*, "modulus" operates on integers. So
AFAIK, Perl's mod works perfectly with fractions.
 
E

Emmanuel Florac

Le Sun, 17 Jun 2007 07:52:20 -0700, Purl Gurl a écrit :
Do you want to be known as a Perl Programmer or a Copy And Paste Baby?

This is preposterous. Just like saying "if you want to be a real C
programmer, don't use any existing library, not even libc".

To deserve the title of "programmer", you have to get the job
done, writing software that actually works. reinventing the wheel isn't
the right way to get things done...

--
A thing of beauty is a joy forever.
J. Keats.

Ah! Singe débotté, hisse un jouet fort et vert!
Marcel Bénabou.
 
R

Randal L. Schwartz

Purl> I know about a cello. I am a professional cellist. I can make my cello
Purl> weep, scream, cry, laugh and sing in voice which will bring you tears
Purl> to your eyes.

Purl> I sure as heck do not know how to build a cello.

Purl> Should I snap my chubby fingers and magically make all Perl modules
Purl> and all knowledge of Perl modules vanish, almost all Perl "programmers"
Purl> would no longer be able to program in Perl.

Your analogy is flawed, and in fact demonstrates precisely the opposite of
what you intended.

Since you don't know how to build a cello, if somone were to provide you with
blocks of wood, some metal, and even plans for building a cello, you would
not, in any reasonable amount of time, be playing cello music.

Perl modules would be akin to having one box with the cello, another box with
the strings, and a third box with the bow, and all you have to do is snap them
together, and there's your music.

So, without modules would be like having raw wood. *With* modules, you're
making music.
 
E

Emmanuel Florac

Le Sun, 17 Jun 2007 10:45:17 -0700, Purl Gurl a écrit :
Ha! Ha! Your lame claim about reinventing the wheel is a flat tire.

Purl Gurl, you're wonderful, but nonetheless wrong about CPAN and
modules :)

--
Le commissaire : Comment vous appelez-vous?
Garance : Moi je ne m'appelle jamais, je suis toujours là. J'ai pas
besoin de m'appeler. Mais les autres m'appellent Garance, si ça peut
vous intéresser.
Prévert,"les enfants du Paradis".
 
B

Brian McCauley

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.

When dealing with time, currency, or anything like that never work
with fractions if you can avoid it. Always convert to a unit that will
keep all your numbers integer (cents, seconds, whatever).
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');
Other then that, I think your scripts works to the extent that 12 pm
and 12 am don't work properly.

Sorry, yes.

$hours += 12 if $ampm eq 'pm';

Should, of course, read:

$hours += 12 if $ampm eq 'pm' xor $hours eq '12';
 
A

anno4000

Dr.Ruud said:
Kenetic schreef:
perl's mod doesn't work very well with fractions
[...]

Nothing is mentioned there about fractional behaviour. But I was never
surprised because *in my world*, "modulus" operates on integers. ...

That's customary, but it's an unnecessary restriction. The "x mod y"
operation can be consistently defined for all real x and y through

x mod y = x - y*floor(x/y) (y != 0)
y mod 0 = x

(Yes, a zero "denominator" is admissible.) Cf. Knuth, _TAOCP_, 1.2.4
(Vol 1).

Anno
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top