mktime pre 1970 confusion (linux)

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
User avatar
mchaggis
Forum Contributor
Posts: 150
Joined: Mon Mar 24, 2003 10:31 am
Location: UK

mktime pre 1970 confusion (linux)

Post by mchaggis »

Hi,

I have read a few post on this, but they all seem to be windows, so appologies for repeat post, but not answers as far as I can see.

Now, I'm sure that this never used to do this, as I have had scripts running for a couple of years now that display date of birth infomation, without any complaints (but maybe it's just never been spotted)

But it would appear that I have discovered the pre 1970 bug... Now the PHP manual states that time_t must be 32bit, but I'm using Mandrake 9.2 and Redhat 8, both 32bit platforms as far as I am aware(?) , so surely they shouldn't have this problem.

My advantage is that I have 100's of scripts that reference the following funtion (which is now the one failing) so I only have to replace this code:

Code: Select all

function formatdate ($format, $dt)
{
   /*
    * Formats MySQL datetime format to normal format
    */
   list($mydate, $mytime) = split(" ", $dt);

   if ($mydate == "0000-00-00" || $mydate == "") return "";

   list($y, $m, $d) = split("-",$mydate);
   list($h, $i, $s) = split(":",$mytime);
   return date($format,
               mktime(intval($h),
                      intval($i),
                      intval($s),
                      intval($m),
                      intval($d),
                      intval($y)
                     )
              );
}
It work appear that I can infact pass the date function a valid timestamp that pre date 1970, it is just mktime that is failling.

Is there any solution?
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

looks like mktime will only accept a year range from the epoch.
User avatar
markl999
DevNet Resident
Posts: 1972
Joined: Thu Oct 16, 2003 5:49 pm
Location: Manchester (UK)

Post by markl999 »

The user comments for mktime offer a few pre 1970 solutions. PEAR's DATE package can also do the same thing.
User avatar
mchaggis
Forum Contributor
Posts: 150
Joined: Mon Mar 24, 2003 10:31 am
Location: UK

Post by mchaggis »

They do give examples, but they all seem to say that Unix systems should have the range 1901 - 2038.

Anyway, I have used one of the functions in the examples, but still would like to know why linux does this and how i can fix the system?

Ah well :?
User avatar
markl999
DevNet Resident
Posts: 1972
Joined: Thu Oct 16, 2003 5:49 pm
Location: Manchester (UK)

Post by markl999 »

but still would like to know why linux does this and how i can fix the system?
You can't really fix it as it isn't broken, it just the way it is :o
http://www.nationmaster.com/encyclopedia/Unix-epoch
User avatar
mchaggis
Forum Contributor
Posts: 150
Joined: Mon Mar 24, 2003 10:31 am
Location: UK

Post by mchaggis »

I'm not saying that it's broken technically... But the docs suggest that unix systems should have a range from 1901 and it mainly affects windose servers.

It is all to do with the time system var being 32-bit, and as far as I was aware this was true on my systems, but obviously not :D
User avatar
mchaggis
Forum Contributor
Posts: 150
Joined: Mon Mar 24, 2003 10:31 am
Location: UK

Post by mchaggis »

Oh, just for reference, the function I have used is:

Code: Select all

function &mktime ($hour = false, $minute = false, $second = false, $month = false, $date = false, $year = false)
   {
       // For centuries, the Egyptians used a (12 * 30 + 5)-day calendar
       // The Greek began using leap-years in around 400 BC
       // Ceasar adjusted the Roman calendar to start with Januari rather than March
       // All knowledge was passed on by the Arabians, who showed an error in leaping
       // In 1232 Sacrobosco (Eng.) calculated the error at 1 day per 288 years
       //    In 1582, Pope Gregory XIII removed 10 days (Oct 15-24) to partially undo the
       // error, and he instituted the 400-year-exception in the 100-year-exception,
       // (notice 400 rather than 288 years) to undo the rest of the error
       // From about 2044, spring will again coincide with the tropic of Cancer
       // Around 4100, the calendar will need some adjusting again
  
       if ($hour === false)  $hour  = Date ("G");
       if ($minute === false) $minute = Date ("i");
       if ($second === false) $second = Date ("s");
       if ($month === false)  $month  = Date ("n");
       if ($date === false)  $date  = Date ("j");
       if ($year === false)  $year  = Date ("Y");
  
       if ($year >= 1970) return mktime ($hour, $minute, $second, $month, $date, $year);
  
       //    date before 1-1-1970 (Win32 Fix)
       $m_days = Array (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
       if ($year % 4 == 0 && ($year % 100 > 0 || $year % 400 == 0))
       {
           $m_days[1] = 29; // non leap-years can be: 1700, 1800, 1900, 2100, etc.
       }
  
       //    go backward (-), based on $year
       $d_year = 1970 - $year;
       $days = 0 - $d_year * 365;
       $days -= floor ($d_year / 4);          // compensate for leap-years
       $days += floor (($d_year - 70) / 100);  // compensate for non-leap-years
       $days -= floor (($d_year - 370) / 400); // compensate again for giant leap-years
          
       //    go forward (+), based on $month and $date
       for ($i = 1; $i < $month; $i++)
       {
           $days += $m_days [$i - 1];
       }
       $days += $date - 1;
  
       //    go forward (+) based on $hour, $minute and $second
       $stamp = $days * 86400;
       $stamp += $hour * 3600;
       $stamp += $minute * 60;
       $stamp += $second;
  
       return $stamp;
   }
I renamed it to maketime tho as of course it conflicts with the built in one and I've not figured out a way of over riding the build in function mktime yet.
User avatar
feyd
Neighborhood Spidermoddy
Posts: 31559
Joined: Mon Mar 29, 2004 3:24 pm
Location: Bothell, Washington, USA

Post by feyd »

it is a signed 32-bit integer.. the same on Windows machines. They just handle negative values differently.
Post Reply