[PHP] Re: [PHP-DB] how to get consistent UTC from gmmktime (w/o dst-offset) ????

2002-03-28 Thread DL Neil

Hi Patrick,
[I have put this back on the list, because greater minds might come up
with a better explanation!?]

There appears to be an issue with gm time functions. gmmktime() is
supposed to take a GMT date and return a GMT UNIX TimeStamp (as per
mktime() but with no DST parameter). Conversely date() and gmdate() take
a UNIX TimeStamp and format a string representation of the date-time.

The question is how gmmktime() should perform when working with
date-times on both sides of the summer time discontinuity.

Assuming your server is running in a timezone that will change to/from
Summer Time over the coming weekend (others may be able to adjust
dates/offsets to run 'backwards' to cover last weekend, where relevant),
try running the following code; and explaining why the gm functions do
not complement each other (see below (way on down) for Patrick's
original observations):

table border=0 cellpadding=5 width=100%
  tr
td width=20%/td
td width=20%Time Key Value/td
td width=20%Local/td
td width=20%GMT/td
td width=20%Comment/td
  /td
  tr
  tr
td colspan=5
hr
/td
  /tr

?php
$tsNow = time();
$dtLoc = date(   D d.m.Y H:i I, $tsNow );
$dtGMT = gmdate( D d.m.Y H:i I, $tsNow );
echo tr .
   tdNow TSbrproduces dates:/td .
   td$tsNow/td .
   tdbr$dtLoc/td .
   tdbr$dtGMT/td .
 tdas expected/td .
   /tr ;

$ss   = date( s, $tsNow );
$hh   = substr($dtLoc, 15, 2);
$mm   = substr($dtLoc, 18, 2);
$DD   = substr($dtLoc,  4, 2);
$MM   = substr($dtLoc,  7, 2);
$ = substr($dtLoc, 10, 4);
$DST  = substr($dtLoc, 21, 1);
$mkLoc   =   mktime( $hh, $mm, $ss, $MM, $DD, $, $DST );
$gmmkLoc = gmmktime( $hh, $mm, $ss, $MM, $DD, $ );
$hh   = substr($dtGMT, 15, 2);
$mm   = substr($dtGMT, 18, 2);
$DD   = substr($dtGMT,  4, 2);
$MM   = substr($dtGMT,  7, 2);
$ = substr($dtGMT, 10, 4);
$DST  = substr($dtGMT, 21, 1);
$mkGMT   =   mktime( $hh, $mm, $ss, $MM, $DD, $, $DST );
$gmmkGMT = gmmktime( $hh, $mm, $ss, $MM, $DD, $ );
echo tr .
   td colspan=2Run above dates through mktime() to revert to TS/td
.
   td$mkLoc/td .
   td$mkGMT/td .
 tdboth correct/td .
   /tr ;
echo tr .
   td colspan=2Run above dates through gmmktime() to revert to
TS/td .
   td$gmmkLocbr/td .
   td$gmmkGMT/td .
 tdboth incorrect???/td .
   /tr ;

echo tr .
   td colspan=2Run above (incorrect) TS through date()/td .
//$dtLoc = date(   D d.m.Y H:i I, $tsNow );
//$dtGMT = gmdate( D d.m.Y H:i I, $tsNow );
   td . date( D d.m.Y H:i I, $gmmkLoc ) . br/td .
   td . date( D d.m.Y H:i I, $gmmkGMT ) . /td .
 tdcontinue incorrect/td .
   /tr ;

echo tr .
   td colspan=2Run above (incorrect) TS through gmdate()/td .
   td . gmdate( D d.m.Y H:i I, $gmmkLoc ) . br/td .
   td . gmdate( D d.m.Y H:i I, $gmmkGMT ) . /td .
 tdcontinue incorrect/td .
   /tr ;

echo trtd colspan=5hr/td/tr ;

$ts1wk = $tsNow + ( 7 * 24 * 60 * 60 );
$dtLoc = date(   D d.m.Y H:i I, $ts1wk );
$dtGMT = gmdate( D d.m.Y H:i I, $ts1wk );
echo tr .
   tdTS in one week's timebrproduces dates:/td .
   td$ts1wk/td .
   tdbr$dtLoc/td .
   tdbr$dtGMT/td .
 tdlocal clock springs forwards/td .
   /tr ;

$ss   = date( s, $ts1wk );
$hh   = substr($dtLoc, 15, 2);
$mm   = substr($dtLoc, 18, 2);
$DD   = substr($dtLoc,  4, 2);
$MM   = substr($dtLoc,  7, 2);
$ = substr($dtLoc, 10, 4);
$DST  = substr($dtLoc, 21, 1);
$mkLoc   =   mktime( $hh, $mm, $ss, $MM, $DD, $, $DST );
$gmmkLoc = gmmktime( $hh, $mm, $ss, $MM, $DD, $ );
$hh   = substr($dtGMT, 15, 2);
$mm   = substr($dtGMT, 18, 2);
$DD   = substr($dtGMT,  4, 2);
$MM   = substr($dtGMT,  7, 2);
$ = substr($dtGMT, 10, 4);
$DST  = substr($dtGMT, 21, 1);
$mkGMT   =   mktime( $hh, $mm, $ss, $MM, $DD, $, $DST );
$gmmkGMT = gmmktime( $hh, $mm, $ss, $MM, $DD, $ );
echo tr .
   td colspan=2Run above dates through mktime() to revert to TS/td
.
   td$mkLoc/td .
   td$mkGMT/td .
 tdboth correct - using dst!/td .
   /tr ;
echo tr .
   td colspan=2Run above dates through gmmktime() to revert to
TS/td .
   td$gmmkLocbr/td .
   tdbr$gmmkGMT/td .
 tdlocal incorrectbr- GMT correct/td .
   /tr ;

echo tr .
   td colspan=2Run above (correct) gmTS through date()/td .
   td . date( D d.m.Y H:i I, $gmmkGMT ) . /td .
   td/td .
 tdcontinues correct/td .
   /tr ;

echo tr .
   td colspan=2Run above (correct) gmTS through gmdate()/td .
   td/td .
   td . gmdate( D d.m.Y H:i I, $gmmkGMT ) . /td .
 tdcontinues correct/td .
   /tr ;

echo tr .
   td colspan=2Run above (incorrect) gmTS through date()/td .
   td . date( D d.m.Y H:i I, $gmmkLoc ) . /td .
   td/td .
 tdcontinues incorrect/td .
   /tr ;

echo tr .
   td colspan=2Run above (incorrect) gmTS through gmdate()/td .
   td/td .
   td . gmdate( D d.m.Y H:i I, $gmmkLoc ) . /td .
 tdcontinues incorrect/td .
   /tr ;

echo trtd colspan=5hr/td/tr ;

$tsLoc = mktime( );
$tsGMT = gmmktime( );
echo tr .
   td*mktime( NOW)/td .
   td . date( 'D d.m.Y H:i I' ) . /td .
   td$tsLoc/td .
   td$tsGMT/td .
 tdthink they should be 

[PHP] Re: [PHP-DB] how to get consistent UTC from gmmktime (w/o dst-offset) ????

2002-03-26 Thread DL Neil

BTW for all who are following this, Patrick has cleverly illustrated
that most of the northern hemisphere locations where summer time is
observed will 'spring forward' this weekend. Most of the southern
hemisphere locations that were in summer time did their 'fall back' last
weekend!
NB the two uses of the word most!


Hi Patrick,

References from the manual:
-
gmmktime -- Get UNIX timestamp for a GMT date
-
gmdate -- Format a GMT/CUT date/time

Identical to the date() function except that the time returned is
Greenwich Mean Time (GMT). For example, when run in Finland (GMT +0200),
the first line below prints Jan 01 1998 00:00:00, while the second
prints Dec 31 1997 22:00:00.
echo date (M d Y H:i:s, mktime (0,0,0,1,1,1998));
echo gmdate (M d Y H:i:s, mktime (0,0,0,1,1,1998));
-

The definition of the Unix Epoch is itself in GMT (and adjusted from
there to local time using the +/-TZ difference): the current time
measured in the number of seconds since the Unix Epoch (January 1 1970
00:00:00 GMT).

When playing around with UNIX epoch seconds it is important to keep them
time-zone separated. So try working your test backwards and putting in a
data/time and then asking for the GMT and the local timestamp values.
They will also be separated by the one hour/two hours.

Question answered, or in my haste to get to my dinner...?
Regards,
=dn



 i'm storing events in a mysql-db, using epoch timestamps to pinpoint
the
 exact date/time for an event.

 so far, I have been using localtime, being aware that there are
 inconsistencies
 in the number of epoch-seconds, when DST flips on and off.
nevertheless, that
 works fine as long as you stick to mktime() and date() for all the
date-math
 as in mktime(0,0,0,$month,$day+$offset,$year)

 but as soon as you leave php and have to do some calculation in
javascript,
 you will encounter functions that behave differently on the pc and mac
 platforms. so you have to revert back to the 'add 86400-seconds' to
calculate
 the next day.

 so I thought it would be nice to have all the timestamps as linear,
 non-dst-epoch-seconds (UTC) and I went into the gmmktime() and
gmdate()
 functions, assuming they would do the math in a linear second-based
timespace
 (in GMT, without DST). That seems to be the case for the output of
'gmdate',
 that remains correct, if you count up seconds across the DST boundary
(see
 second example).

 but it seems that there is no way to calculate the gmt-epoch for a
given
 date using gmmktime without having to add/subtract the TZ manually.
gmmktime
 will always take your local DST-settings into calculation and upon
conversion
 back with gmdate, you will be off by the number of hours of your
timezone.
 I thought gmmktime() would handle this as if the computer would be in
 Greenwich
 (TZ=0), which would then leave us with the two functions
encoding/decoding
 consistently.

 anyone having solved this properly?

 -
 print count days:br\n;
 for($day=0; $day7; $day++){
 $timgmt = gmmktime(0,0,0,3,28+$day,2002);
 $timloc = mktime(0,0,0,3,28+$day,2002);
 print $timgmt . = gmmktim epoch -  . gmdate(D d.m.Y H:i I,$timgmt)
.
 br\n;
 print $timloc . = mktim epoch -  . date(D d.m.Y H:i  I,$timloc) .
 br\n;
 print BR\n;
 }

 
 count days:
 101727= gmmktim epoch - Wed 27.03.2002 23:00 0
 101727= mktim epoch - Thu 28.03.2002 00:00 0

 1017356400= gmmktim epoch - Thu 28.03.2002 23:00 0
 1017356400= mktim epoch - Fri 29.03.2002 00:00 0

 1017442800= gmmktim epoch - Fri 29.03.2002 23:00 0
 1017442800= mktim epoch - Sat 30.03.2002 00:00 0

 1017529200= gmmktim epoch - Sat 30.03.2002 23:00 0
 1017529200= mktim epoch - Sun 31.03.2002 00:00 0
 dst on
 1017619200= gmmktim epoch - Mon 01.04.2002 00:00 0   off by one
hour due to
 DST
 1017612000= mktim epoch - Mon 01.04.2002 00:00 1

 1017705600= gmmktim epoch - Tue 02.04.2002 00:00 0
 1017698400= mktim epoch - Tue 02.04.2002 00:00 1

 1017792000= gmmktim epoch - Wed 03.04.2002 00:00 0
 1017784800= mktim epoch - Wed 03.04.2002 00:00 1


 -
 print count seconds:br\n;
 $baseepoch = $timloc = mktime(0,0,0,3,28,2002);
 for($day=0; $day7; $day++){
 $epochnow = $baseepoch + (60 * 60 * 24 * $day);
 print $epochnow . = gmmktim epoch -  . gmdate(D d.m.Y H:i
I,$epochnow) .
 br\n;
 print $epochnow . = mktim epoch -  . date(D d.m.Y H:i
I,$epochnow) .
 br\n;
 print BR\n;
 }
 
 count seconds:
 101727= gmmktim epoch - Wed 27.03.2002 23:00 0   consistent,
but off by
 -1 (your TZ)
 101727= mktim epoch - Thu 28.03.2002 00:00 0

 1017356400= gmmktim epoch - Thu 28.03.2002 23:00 0
 1017356400= mktim epoch - Fri 29.03.2002 00:00 0

 1017442800= gmmktim epoch - Fri 29.03.2002 23:00 0
 1017442800= mktim epoch - Sat 30.03.2002 00:00 0

 1017529200= gmmktim epoch - Sat 30.03.2002 23:00 0
 1017529200= mktim epoch - Sun 31.03.2002 00:00 0

 1017615600= gmmktim epoch - Sun 31.03.2002 23:00 0