5

First of all, i know this question has been sort of asked/sort-of answered here: Calculate day number from an unix-timestamp in a math way? .

I need a custom function/formula for this. so it only returns a ISO format date. "YYYY-MM-DD".

eg. 1316278442 = 2011-09-17

EDIT by Ext! THIS IS WRONG ! Please don't read this.

I've been at this all day! The only thing i managed to get out is the day of the week.

$dayOfWeek=($timestamp/86400)%7; //And here 1 is Saturday, 7 is Friday

Speed is the issue, that is why i don't want to use date('Y-m-d',$timestamp);

If you cannot help me whit a custom function or formula, at least give me a better explanation on how to do this. It was done in so many languages, there must be someone out there that knows how to do this.

Thank you in advance for your help.

Community
  • 1
  • 1
Ext
  • 657
  • 1
  • 8
  • 13
  • 3
    what makes you think that `date('Y-m-d',$timestamp)` would be slower than computing the date yourself ? – Arnaud Le Blanc Sep 17 '11 at 16:04
  • 6
    if `date` isnt fast enough for you consider using another language – Gordon Sep 17 '11 at 16:05
  • possible duplicate of [Best way to convert epoch time to "real" date/time](http://stackoverflow.com/questions/1692184/best-way-to-convert-epoch-time-to-real-date-time) – Joe Sep 17 '11 at 16:06
  • 1
    Can people just ignore the 'speed' issue and answer the questing regarding unix timestamp.. Im glad this has been asked, and i need to know as well. So people plz... – arijeet Sep 17 '11 at 16:06
  • @David, as far as i know, it does not matter. unix timestamp counds seconds from 1970-01-01. But let's make it GTM. arnaud because i made tons of test. time difference between: $nDate=($timestamp/$secondsInADay)%7; AND $nDate=date('N',$timestamp); in HUGE ! Gordon, Come on, why do you have to comment such stuff ? If you don't know don't say anything. i MUST do it in PHP. Is that good enought? – Ext Sep 17 '11 at 16:10
  • @Ext: You are comparing apples to oranges. Of course it's more expensive to compute lots of information when you only need a tiny piece of it. But in your actual outer problem, you need most of that information. – David Schwartz Sep 17 '11 at 16:12
  • 1
    @Ext, your two codes don't do the same thing, and your calculation is inexact. That might explain this ;) – Arnaud Le Blanc Sep 17 '11 at 16:13
  • @redskins80: Ignoring the speed issue, the answer is given in the question. So this question really reduces to whether the speed issue is a real issue or not. – David Schwartz Sep 17 '11 at 16:14
  • @Ext The native function vs your function, which is fast do you think? If you want to know how to do it, you can read the source code of the date lib of what ever language. – xdazz Sep 17 '11 at 16:14
  • @xdazz i believe i can make a faster one by stripping the original. In reality my head is so fried atm, i could not find the PHP Date function. I know my bad:( Arnaud576875 sorry. I tough the computation was right.But it's not, how could i have not seen that.... – Ext Sep 17 '11 at 16:26

3 Answers3

6

Here is the function that date() and DateTime::setTimestamp() use to compute the date from a unix timestamp:

https://github.com/php/php-src/blob/d57eefe6227081001978c3a63224065af8b5728e/ext/date/lib/unixtime2tm.c#L39

As you can see, this is a bit complicated by leap years, etc.

--

That said, if you need only the day of the week, it seems that you can safely ignore leap years, and just use the formula you given in the question: $dayOfWeek=($timestamp/86400)%7

Arnaud Le Blanc
  • 98,321
  • 23
  • 206
  • 194
  • 1
    At least there are no leap seconds! – Nicholas Wilson Sep 17 '11 at 16:17
  • THANK YOU for answering (even though its a reference) rather than rambling on about errors in the question like others! – arijeet Sep 17 '11 at 16:18
  • @Nicholas apparently you don't need to care about leap seconds when using unix timestamps (http://derickrethans.nl/leap-seconds-and-what-to-do-with-them.html) – Arnaud Le Blanc Sep 17 '11 at 16:28
  • 1
    Yes, that's what I said: you have to worry about leap years, but with unix timestamps at least there are no leap seconds. – Nicholas Wilson Sep 17 '11 at 16:30
  • @NicholasWilson there are leap seconds due to the variation in the earths rotation: http://en.wikipedia.org/wiki/Leap_second the most recent one was added on June 30, 2012 – rgvcorley Sep 17 '13 at 13:15
1

Ok. The function is complete. It takes a unix timestamp and returns a YYYY-MM-DD. This was all i needed. I hope it helps anyone ...

<?php
$t=1325522004;//return 2011-09-19
/*
 * Transform a Unix Timestamp to ISO 8601 Date format YYYY-MM-DD 
 * @param unix timestamp
 * @return Returns a formated date (YYYY-MM-DD) or false
 */
function unixToIso8601($timestamp){
    if($timestamp<0){return false;}//Do not accept negative values
    /* Too many constants, add this to a class to speed things up. */
    $year=1970;//Unix Epoc begins 1970-01-01
    $dayInSeconds=86400;//60secs*60mins*24hours
    $daysInYear=365;//Non Leap Year
    $daysInLYear=$daysInYear+1;//Leap year
    $days=(int)($timestamp/$dayInSeconds);//Days passed since UNIX Epoc
    $tmpDays=$days+1;//If passed (timestamp < $dayInSeconds), it will return 0, so add 1
    $monthsInDays=array();//Months will be in here ***Taken from the PHP source code***
    $month=11;//This will be the returned MONTH NUMBER.
    $day;//This will be the returned day number. 

    while($tmpDays>=$daysInYear){//Start adding years to 1970
        $year++;
        if(isLeap($year)){
            $tmpDays-=$daysInLYear;
        }
        else{
            $tmpDays-=$daysInYear;
        }
    }

    if(isLeap($year)){//The year is a leap year
        $tmpDays--;//Remove the extra day
        $monthsInDays=array(-1,30,59,90,120,151,181,212,243,273,304,334);
    }
    else{
        $monthsInDays=array(0,31,59,90,120,151,181,212,243,273,304,334);
    }

    while($month>0){
        if($tmpDays>$monthsInDays[$month]){
            break;//$month+1 is now the month number.
        }
        $month--;
    }
    $day=$tmpDays-$monthsInDays[$month];//Setup the date
    $month++;//Increment by one to give the accurate month

    return $year.'-'.(($month<10)?'0'.$month:$month).'-'.(($day<10)?'0'.$day:$day);
}
function isLeap($y){
    return (($y)%4==0&&(($y)%100!=0||($y)%400==0));
}
echo unixToIso8601($t);
?>
Ext
  • 657
  • 1
  • 8
  • 13
0

You could convert to julian first with unixtojd() and then use cal_from_jd to split into year,month,day. It's a little faster. The code below gives me this result:

2009-02-13 0.13018703460693 seconds  using date()
2009-02-13 0.037487983703613 seconds using unixtojd(),cal_from_jd(),and sprintf()



function microtime_float(){
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}
$time_start = microtime_float();
$unix_timestamp = 1234567890;
for($i=0;$i<10000;$i++) {
    $d = date('Y-m-d',$unix_timestamp);
}
$time_stop = microtime_float();
echo $d . " " . ($time_stop - $time_start) . " seconds using date()<br>\n";

//////////////////////////


$time_start = microtime_float();

$unix_timestamp = 1234567890;
for($i=0;$i<10000;$i++) {
    $julian_date = unixtojd($unix_timestamp);
    $date_array = cal_from_jd($julian_date, CAL_GREGORIAN);
    $d = sprintf('%d-%02d-%02d',$date_array['year'],$date_array['month'],$date_array['day']);
}

$time_stop = microtime_float();
echo $d . " " . ($time_stop - $time_start) . " seconds using unixtojd(),cal_from_jd(),and sprintf()<br>\n";
Charlie
  • 1,062
  • 6
  • 9