Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

evaluating time regardless of time zone

Status
Not open for further replies.

ibjdt

Programmer
Nov 25, 2002
63
0
0
i want to show 4 messages to my site users concerning my product shipping times:
Saturday and Sunday US EST - no shipping
Prior to 8 am US EST - Shipping not currently available
After 12 noon US EST - call immediately if shipping required today
After 3:30 pm US EST - shipping is no longer available today

i have played around with the following, but i can't get it right and don't understand enough to do anything other than manipulate variables and hope i stumble on the solution.
any help would be greatly appreciated.

my site users are global so it has to consider their time zone.

thanks.

Code:
	($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = gmtime();
	if (($dayOfWeek == '0') || ($dayOfWeek == '6')) {
		$info{'SHIP_MSG'} = 'Shipping is not available today<br><br>';
	}
	elsif ($hour > '20') {
		$info{'SHIP_MSG'} = 'Shipping is no longer available today<br><br>';
	}
	elsif ($hour >= '17') {
		$info{'SHIP_MSG'} = 'If you need product shipped today, <b>CALL</b> immediately<br><br>';
	}
	elsif ($hour < '12') {
		$info{'SHIP_MSG'} = 'Shipping is not availble during this time.<br><br>';
	}

 
this is probably a naive approach but it might work:

Code:
    ($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = gmtime(time-(60*60*5));
    if (($dayOfWeek == '0') || ($dayOfWeek == '6')) {
        $info{'SHIP_MSG'} = 'Shipping is not available today<br><br>';
    }
    elsif ($hour > '20') {
        $info{'SHIP_MSG'} = 'Shipping is no longer available today<br><br>';
    }
    elsif ($hour >= '17') {
        $info{'SHIP_MSG'} = 'If you need product shipped today, <b>CALL</b> immediately<br><br>';
    }
    elsif ($hour < '12') {
        $info{'SHIP_MSG'} = 'Shipping is not availble during this time.<br><br>';
    }

the [red]time-(60*60*5)[/red] tells perl to use what should be EST (ignoring daylight savings time which is -4 hours offset from GMTIME or UTC instead of -5).

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Shouldn't you be using localtime() with the appropriate time zone set?

Annihilannic.
 
e.g.
Code:
$ENV{"TZ"}="EST5EDT";
($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime();

Annihilannic.
 
You can't depend on $ENV{TZ} to do the right thing but on any one server it might work like you would hope it does. On the other hand, offsetting gmtime should always work.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
When can't you depend on it to do the right thing? If the server is poorly configured or missing curent TZ related patches perhaps... but that's something that should be fixed anyway. And offsetting gmtime, as you said yourself, only works when DST is not in effect...

Annihilannic.
 
sorry, too lazy to look up the links discussing TZ and other time related issues. A google search should find some info if interested.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
I have this code that I put together for a content management system a while back, which handles time zones:

Code:
=head1 TIME FUNCTIONS

=head2 Structure getTimezones ([Boolean asArray])

Retrieve the list of supported time zones. By default it will return a hash,
where the keys are the time zone labels and the values as the offsets in
seconds. When C<asArray> is true, it returns an ordered hash reference (or, a
paired array reference) in which the keys are sorted by their time offset, from
least to greatest.

  Array format:
  [
    "(GMT -11:00) Midway Island, Samoa" => -11 * 3600,
    "(GMT -10:00) Hawaii"               => -10 * 3600,
    "(GMT -9:00) Alaska"                => -9  * 3600,
    ...
  ];

=cut

sub getTimezones {
   my ($self,$asArray) = @_;

   # Time zone structure.
   my $zones = [
      "(GMT -11:00) Midway Island, Samoa"                    => (-11 * 3600),
      "(GMT -10:00) Hawaii"                                  => (-10 * 3600),
      "(GMT -9:00) Alaska"                                   => (-9 * 3600),
      "(GMT -8:00) Pacific Time (US &amp; Canada)"           => (-8 * 3600),
      "(GMT -7:00) Mountain Time (US &amp; Canada)"          => (-7 * 3600),
      "(GMT -6:00) Central Time (US &amp; Canada)"           => (-6 * 3600),
      "(GMT -5:00) Eastern Time (US &amp; Canada)"           => (-5 * 3600),
      "(GMT -4:30) Caracas"                                  => (-5 * 3600 - 1800),
      "(GMT -4:00) Atlantic Time (Canada), La Paz, Santiago" => (-4 * 3600),
      "(GMT -3:30) Newfoundland"                             => (-4 * 3600 - 1800),
      "(GMT -3:00) Brazil, Buenos Aires, Georgetown"         => (-3 * 3600),
      "(GMT -2:00) Mid-Atlantic"                             => (-2 * 3600),
      "(GMT -1:00 hour) Azores, Cape Verde Islands"          => (-1 * 3600),
      "(GMT) Western Europe Time, London, Lisbon, Casablanca" => 0,
      "(GMT +1:00 hour) Brussels, Copenhagen, Madrid, Paris" => (1 * 3600),
      "(GMT +2:00) Kaliningrad, South Africa"                => (2 * 3600),
      "(GMT +3:00) Baghdad, Riyadh, Moscow, St. Petersburg"  => (3 * 3600),
      "(GMT +3:30) Tehran"                                   => (3 * 3600 + 1800),
      "(GMT +4:00) Abu Dhabi, Muscat, Baku, Tbilisi"         => (4 * 3600),
      "(GMT +4:30) Kabul"                                    => (4 * 3600 + 1800),
      "(GMT +5:00) Ekaterinburg, Islamabad, Karachi, Tashkent" => (5 * 3600),
      "(GMT +5:30) Mumbai, Kolkata, Chennai, New Delhi"      => (5 * 3600 + 1800),
      "(GMT +5:45) Kathmandu"                                => (5 * 3600 + 2700),
      "(GMT +6:00) Almaty, Dhaka, Colombo"                   => (6 * 3600),
      "(GMT +6:30) Yangon, Cocos Islands"                    => (6 * 3600 + 1800),
      "(GMT +7:00) Bangkok, Hanoi, Jakarta"                  => (7 * 3600),
      "(GMT +8:00) Beijing, Perth, Singapore, Hong Kong"     => (8 * 3600),
      "(GMT +9:00) Tokyo, Seoul, Osaka, Sapporo, Yakutsk"    => (9 * 3600),
      "(GMT +9:30) Adelaide, Darwin"                         => (9 * 3600 + 1800),
      "(GMT +10:00) Eastern Australia, Guam, Vladivostok"    => (10 * 3600),
      "(GMT +11:00) Megadan, Solomon Islands, New Caledonia" => (11 * 3600),
      "(GMT +12:00) Auckland, Wellington, Fiji, Kamhatka"    => (12 * 3600),
   ];

   if (defined $asArray && $asArray) {
      return $zones;
   }
   else {
      my $hash = {};
      for (my $i = 0; $i < scalar @{$zones}; $i += 2) {
         $hash->{ $zones->[$i] } = $zones->[$i + 1];
      }
      return $hash;
   }
}

=head2 String getTimestamp (String format[, Int epoch])

Get a pretty-formatted time stamp. C<format> is the format that you want the
time to be returned in, in a format that C<Time::Format> understands. C<epoch>
is the Unix time stamp that you want to be formatted, or else the current
C<time()>.

The time stamp returned from this function directly will be relative to the
local time of the web server. To get an offset time for a specific time zone,
use the C<getLocalTimestamp()> function instead.

The fields recognized for C<format> are as follows:

  yyyy       4-digit year
  yy         2-digit year

  m          1- or 2-digit month, 1-12
  mm         2-digit month, 01-12
  ?m         month with leading space if < 10

  Month      full month name, mixed-case
  MONTH      full month name, uppercase
  month      full month name, lowercase
  Mon        3-letter month abbreviation, mixed-case
  MON  mon   ditto, uppercase and lowercase versions

  d          day number, 1-31
  dd         day number, 01-31
  ?d         day with leading space if < 10
  th         day suffix (st, nd, rd, or th)
  TH         uppercase suffix

  Weekday    weekday name, mixed-case
  WEEKDAY    weekday name, uppercase
  weekday    weekday name, lowercase
  Day        3-letter weekday name, mixed-case
  DAY  day   ditto, uppercase and lowercase versions

  h          hour, 0-23
  hh         hour, 00-23
  ?h         hour, 0-23 with leading space if < 10

  H          hour, 1-12
  HH         hour, 01-12
  ?H         hour, 1-12 with leading space if < 10

  m          minute, 0-59
  mm         minute, 00-59
  ?m         minute, 0-59 with leading space if < 10

  s          second, 0-59
  ss         second, 00-59
  ?s         second, 0-59 with leading space if < 10
  mmm        millisecond, 000-999
  uuuuuu     microsecond, 000000-999999

  am   a.m.  The string "am" or "pm" (second form with periods)
  pm   p.m.  same as "am" or "a.m."
  AM   A.M.  same as "am" or "a.m." but uppercase
  PM   P.M.  same as "AM" or "A.M."

  tz         time zone abbreviation

=cut

sub getTimestamp {
   my ($self,$format,$epoch) = @_;

   # If no epoch time was given, use the current time.
   if (!defined $epoch || (defined $epoch && $epoch =~ /[^0-9]/)) {
      $epoch = time();
   }

   # Format the time.
   return Time::Format::time_format ($format,$epoch);
}

=head2 String getLocalTimestamp (String format[, Int epoch[, Int offset]])

This is like C<getTimestamp()>, except it will offset the time returned to match
the local time of a specific time zone.

If C<offset> is not provided, and the end user is logged in, the time zone
from the user's settings will be used. Otherwise, the website's time zone is
used (note that this is B<NOT> necessarily the server's local time zone; this
is the zone defined in the configuration files!).

=cut

sub getLocalTimestamp {
   my ($self,$format,$epoch,$tz) = @_;

   # If no epoch time, use the current time.
   if (!defined $epoch || (defined $epoch && $epoch =~ /[^0-9]/)) {
      $epoch = time();
   }

   # No timezone specified?
   if (!defined $tz) {
      # Is the end user logged in?
      if ($self->{auth}) {
         # Get the end user's time zone.
         # TODO
      }
      else {
         # Use the server's time zone.
         $tz = $self->{conf}->{site}->{timezone};
      }
   }

   # Get the current GMT time based on the server's localtime.
   my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime ($epoch);

   # Get the adjust epoch time back from this.
   my $gm = Time::Local::timelocal ($sec,$min,$hour,$mday,$mon,$year);
   $gm = $epoch unless defined $tz;

   # Offset the epoch time.
   if (defined $tz) {
      # Need to apply daylight saving time?
      if ($self->isDST()) {
         $tz += 3600;
      }
      $gm += $tz;
   }

   # Format the time.
   return $self->getTimestamp ($format,$gm);
}

=head2 Boolean isDST ()

Returns 1 if daylight saving time is currently being observed. Undef
otherwise.

=cut

sub isDST {
	my ($self) = @_;

	my ($isdst) = (localtime(time()))[8];
	return $isdst ? 1 : undef;
}

These were members of an object but you can surely adapt the code to work how you want it.

So you'd call $self->getLocalTimestamp(format, epoch, tz offset) where the tz offset is one of the values from getTimezones().

You could also use the Time::Zone module from CPAN to use names like "PST" to get time zone offsets.

Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top