Client time settings broke readable date in javascript - php

What i'm trying to do is show date in more readable format like 3 seconds ago, 1 hours ago, yesterday, June 12 and etc.
What i did is , first calculate the timestamp for comment's date.. Then send it to client with ajax, then create two date instance on javascript one for is comment's date and other one is current date.. After that I just find differences between to date item then write on the screen with fancy words..
Everything works fine on localhost, even server.. But sometimes if client's pc date is earlier from the server date (independent from time zone)..
Let say server time is today 13.30 pm and client time is today 13.00 , it's failing with this scenario because current time is being comment's post time.. Difference will be negative value..
I'm creating date object for comment in php like this;
date("Y-m-d G:i:s")
Then write it to mysql db..
After that when i select comments i convert it to timestamp to push it on client side with ;
$comment['timestamp'] = strtotime($row['creationDate']);
And then in javascript, I make calculation for human readable date format ;
DateObject.getFormatted = function(unixtime){
d = new Date(unixtime*1000);
now = new Date();
var diff = (now.getTime()/1000- unixtime) ;
var result = "";
var MIN = 60,
HOUR = 3600,
DAY = 86400;
if(diff < 2)
result ="just now";
else if(diff < MIN)
result = Math.floor(diff) + " seconds ago";
else if(diff < HOUR)
result = Math.floor(diff/60) + " minutes ago";
else if(diff < DAY)
result = Math.floor(diff/3600) + " hours ago";
else if(diff < DAY*3)
{
var days = diff/DAY;
if(days < 2)
result = "yesterday";
else
result = Math.floor(days) + " days ago";
}
else if(now.getFullYear() == d.getFullYear())
{
formattedTime = this.getTime(d);
result = this.getSameYear(d) + " at " + formattedTime;
}
else
{
formattedDate = this.getDate(d);
formattedTime = this.getTime(d);
result = formattedDate + " at " + formattedTime;
}
return result;
};
So if clients date is earlier then the comment's date diff value is being negative, so the first case would be true
if(diff < 2)
result ="just now";
It's going behing as time difference between client and comment's date .. In my case 10 minutes.. If I set my computer time 10 minutes later it's working nice..
So how can i fix it in a better way?
Thank you.

May be better send from server to client difference between comment date and current date?(instead of creation two javascript date instances)

A third date so you can calculate the difference between server and client and use it as an offset?

Related

Splitting a time range into hours?

I'm currently working with a data set containing a start time, date, and a duration in seconds, and need to be able to split the range of times from start time to (start time + duration, e.g. end time) into hour "buckets" if you will.
So for instance, a start time of 08:30:00 with duration 9000 seconds (2.5 hours) covers hour 08 from 8:30:00 to 09:00:00 for 1800 seconds, hour 09 until 10:00:00 for 3600 seconds, etc. up to the end time of 11:00:00.
What would be the best way possible to do this? I'm working in PHP however a general algorithmic solution would still be incredibly helpful.
My current approach is as follows:
1. Calculate the hour difference between both times (round up to next hour if there's a non-zero number of minutes)
2. Let session progress = 0
3. Iterate the range from 1 to hour difference:
1. Let the current bucket duration = min(3600, duration)
2. Let the duration = max(0, duration - current bucket duration)
3. Let bucket start time = start time + session progress
4. Let bucket end time = bucket start time + current bucket duration
5. Do work based on these values
6. Let session progress += current bucket duration
My PHP implementation of this is as follows:
foreach ($csv as $listen_record) {
$start_dt = $listen_record['Date'] . ' ' . $listen_record['Time'];
$session_duration = $listen_record['Duration'];
$session_start_time = date_create_from_format($datetime_format, $start_dt);
$session_end_time = clone $session_start_time;
date_add($session_end_time, date_interval_create_from_date_string($session_duration . ' seconds'));
$diff = date_diff($session_end_time, $session_start_time);
$hourdiff = $diff->h;
if ($diff->m > 0)
$hourdiff += 1;
$session_progress = 0;
foreach (range(1, $hourdiff) as $hour) {
$record_duration = min(3600, $session_duration);
$session_duration = max(0, $session_duration - $record_duration);
$record_start_time = clone $session_start_time;
date_add($record_start_time, date_interval_create_from_date_string($session_progress . ' seconds'));
$record_end_time = clone $record_start_time;
date_add($record_end_time, date_interval_create_from_date_string($record_duration . ' seconds'));
if ($record_start_time == $record_end_time)
continue;
// DO WORK...
$session_progress += $record_duration;
}
}
This kind of works to separate each record into hour long buckets however gives some weird results for some cases (particularly cases where the range crosses into a new day) and doesn't align to actual wall clock hours.
Is there a better way to do this that can actually align to wall clock hours and not freak out when it has to cope with durations that cross over midnight?
Thanks!
Update: I managed to solve this on my own so I'm posting how I did it just in case anyone else needs to do similar.
Basically I did it by creating a range between the start and end timestamp, and filtering out every time stamp apart from start and end that isnt a multiple of 3600 or just before 3600. This gives me the wall clock hours in the middle of the range as timestamps. I can then split the array into chunks of 2 which contains the slot start time and end time.
My PHP code is as follows and now actually works:
function is_wall_clock_aligned_hour_boundary($timestamp) {
return ($timestamp % (60*60) === 0) || (($timestamp + 1) % (60*60) === 0);
}
function create_slot_object($slot) {
$start_time = reset($slot);
$end_time = end($slot);
$duration = $end_time - $start_time;
return array(
'startTime' => convert_timestamp_to_datetime($start_time),
'endTime' => convert_timestamp_to_datetime($end_time),
'duration' => $duration
);
}
function make_slots(DateTime $start_time, $duration) {
$start_timestamp = $start_time->getTimestamp();
$end_time = clone $start_time;
date_add($end_time, date_interval_create_from_date_string("$duration seconds"));
$end_timestamp = $end_time->getTimestamp();
$time_sequence = range($start_timestamp, $end_timestamp);
$slot_boundaries = array_filter($time_sequence, 'is_wall_clock_aligned_hour_boundary');
array_unshift($slot_boundaries, $start_timestamp);
array_push($slot_boundaries, $end_timestamp);
$slots = array_chunk($slot_boundaries, 2);
return array_map('create_slot_object', $slots);
}

Compare PHP server time with JavaScript time (client browser time)

I am making a notification system which require the time since functionality.
I am using this script for timesince function(jQuery):
$.fn.updateSince = function(interval) {
var times = this.map(function(){ return { e: $(this), t: parseInt($(this).html()) }; });
var format = function(t) {
if(t > 86400) {
return Math.floor(t / 86400) + ' days ago';
} else if (t > 3600) {
return Math.floor(t / 3600) + ' hours ago';
} else if (t > 60) {
return Math.floor(t / 60) + ' minute ago';
} else if (t > 50) {
return '50 seconds ago';
} else if (t > 40) {
return '40 seconds ago';
} else if (t > 30) {
return '30 seconds ago';
} else if (t > 25) {
return '25 seconds ago';
} else if (t > 15) {
return '15 seconds ago';
} else if (t > 10) {
return '10 seconds ago';
} else {
return 'a few seconds ago';
}
}
var update = function(){
var now = new Date().getTime();
$.each(times, function(i, o){
o.e.html(format(Math.round((now - o.t) / 1000)));
});
};
window.setInterval(update, interval);
update();
return this;
}
The notifications are stored in MySQL database , each notification has a timestamp on it that is in this format: 2012-12-26 06:21:28
I use PHP strtotime and change it into UTC format when obtaining the time out of the database for each notificaiton item:(php)
$rows['time']= strtotime($temp_time." UTC");
When I pass it back to the client browser , using ajax. I will multiply the UTC time(from database) with 1000(javascript)
var time = parseInt(dbtime * 1000);
Then I can use the jQuery timesince function to turn it into time ago.
Problem:
My server time varies with client browser time.
How do I make them "compatible" with each other.
For example , a notification is made 2 hours ago according to client browser.
But PHP says its made 7 hours ago.
because client browser timezone is different with my server's
My logic is:
1. [PHP] Get current time , and use the notification time obtained from database to subtract with it.
database time - current time = time difference on server end
[PHP] Then we get a time difference. in this case 7 hours.
[PHP] How do i turn 7 hours into UTC format?
[Javascript] Send the current client browser time , also in UTC format to php script.
[PHP] client browser time - 7 hours(UTC?) = actual time of notification created for javascript use.
[PHP] Send back the results to Javascript , so now the time can be 2 hours ago on client browser's end.
How do I do this?
Just for info , UTC format is like(multiplied with 1000) : 1314952284779
Your logic could be:
Convert the notification time to UNIX timestamp using strtotime (or any similar function)
Use JavaScript Date function with this value (multiplied by 1000) to re-build the date
Use (new Date) - thatDate to calculate the difference
Convert to hours, minutes and seconds
The problem I see here is in the first step. You mention that the dates are stored as 2012-12-26 06:21:28 but what timezone does this date correspond to? If it is the same time as the server timezone then using strtotime("2012-12-26 06:21:28") is sufficient to generate correct timestamp.
i had the same problem to i store the ip of the user in the db and then convert that to location and get the timezone then uses this functionality. main reason of doing that is that i future you might me considering to get info about your user so that approach also gonna help then. You can use interval triggered function to run the code
j(document).ready(function () {
window.initial = 0;
window.setInterval(timeincrement, 60000);
function timeincrement() {
initial = initial + 60;
j('.coment').each(function () {
var timefromserver = j(this).find('input[type=hidden]').val();
timefromserver = parseInt(timefromserver);
if ((timefromserver / 216000) < 1) {
var secgone = timefromserver + initial;
var timeelasped = secgone / 60;
if (Math.floor(timeelasped) < 1) {
j(this).find('.lightgrey').text("Few seconds ago");
} else if (Math.floor(timeelasped) < 60) {
var innertext = timeelasped + " minutes ago";
j(this).find('.lightgrey').text(innertext);
} else if (Math.floor(timeelasped / 60) > 0) {
var hourgone = Math.floor(timeelasped / 60);
var innertext = hourgone + " hours ago";
j(this).find('.fdlightgrey').text(innertext);
}
}
});
}
});
For your info new Date().getTime() in JavaScript return UTC time, as far as the client clocks are right this means that you don't have to deal with different time zones of users, all you have to do is to provide the times from your server in UTC.
In PHP you should either use the gmdate function to create UTC time strings or simply don't format it and just ship the raw UNIX UTC time that you get from the time function.
In short UTC everywhere, then it works. As a bonus it works like daylight savings didn't exist.
You could also also do an adjustment to account for incorrect times on the client by sending a "now" time stamp when the page is first loaded, calculate how long ago that is on the client, and subtract this result from all future calculations. But given that practically all computers automatically adjust their clock to that of a time server it is quite rare that a computer clock is off by more than a few seconds.
if mysql data is UTC, i use Date.getTimezoneOffset() in JavaScript and apply it (offset is in minutes: -120 = GMT+2) to the time stored in mysql (obtained via php) when displaying historical time (when event happened) for a user.
RAMBLINGS:
also serves to compare current time with mysql data (never trust a user's clock, but their timezone is usually correct [except for frequent-flyers' laptops, ouch]).
i take care to tell the user what her timezone difference is (either by publishing GMT +/- XX or something like "HH:MM this should be your local time, please fix clock if it isnt") and asking them to confirm it, if necessary. your code will deal with the situation according to your relationship with user ("fix that clock, darnit" or "yes, hmmmm, would you like us to fix our clocks to fit paris time [though we are in argentina], madame?")

PHP Checking if timestamp is less than 30 minutes old

I'm getting a list of items from my database, each has a CURRENT_TIMESTAMP which i have changed into 'x minutes ago' with the help of timeago. So that's working fine. But the problem is i also want a "NEW" banner on items which are less than 30 minutes old. How can i take the generated timestamp (for example: 2012-07-18 21:11:12) and say if it's less than 30 minutes from the current time, then echo the "NEW" banner on that item.
Use strtotime("-30 minutes") and then see if your row's timestamp is greater than that.
Example:
<?php
if(strtotime($mysql_timestamp) > strtotime("-30 minutes")) {
$this_is_new = true;
}
?>
I'm using strtotime() twice here to get unix timestamps for your mysql date, and then again to get what the timestamp was 30 minutes ago. If the timestamp from 30 mins ago is greater than the timestamp of the mysql record, then it must have been created more than 30 minutes go.
Try something like this, using PHP's DateTime object:
$now = new DateTime();
$then = DateTime($timestamp); // "2012-07-18 21:11:12" for example
$diff = $now->diff($then);
$minutes = ($diff->format('%a') * 1440) + // total days converted to minutes
($diff->format('%h') * 60) + // hours converted to minutes
$diff->format('%i'); // minutes
if ($minutes <= 30) {
echo "NEW";
}
Edit: Mike is right, I forgot that for whatever reason, only %a actually returns the total of its type (in this case days). All the others are for displaying time formatting. I've extended the above to actually work.
You can do like this also -
$currentTime=time();
to check the last updated time is 30 minute old or not
last_updated_at < $currentTime - (60*30)

Converting user's day and time to server's day and time in php

I have a scenario in which the user selects a time and day (or multiple days) and that value must be converted to whatever that day and time would be in UTC time. I have the gmt offset amount for each user (the users set it when they signup). For instance:
A user in the eastern timezone selects:
3:15 pm, Monday, Tuesday, Friday
I need to know what time and days that information would be in UTC time. The solution has to take into situations such Monday in one timezone can be a different day in UTC time. Also, if the time can be converted to 24 hour format, that would be a plus.
For the sake of clarity, something along the lines of an array should be returned such as:
Array('<3:15 pm eastern adjusted for utc>', '<Monday adjusted for UTC>', '<Tuesday adjusted for UTC>', '<Friday adjusted for UTC>');
I don't need the result to be directly formatted into an array like that - that's just the end goal.
I am guessing it involves using strtotime, but I just can't quite my finger out how to go about it.
$timestamp = strtotime($input_time) + 3600*$time_adjustment;
The result will be a timestamp, here's an example:
$input_time = "3:15PM 14th March";
$time_adjustment = +3;
$timestamp = strtotime($input_time) + 3600*$time_adjustment;
echo date("H:i:s l jS F", $timestamp);
// 16:15:00 Monday 14th March
EDIT: kept forgetting little things, that should be working perfectly now.
Made a function to do the job:
<?
/*
* The function week_times() converts a a time and a set of days into an array of week times. Week times are how many seconds into the week
* the given time is. The $offset arguement is the users offset from GMT time, which will serve as the approximation to their
* offset from UTC time
*/
// If server time is not already set for UTC, uncomment the following line
//date_default_timezone_set('UTC');
function week_times($hours, $minutes, $days, $offset)
{
$timeUTC = time(); // Retrieve server time
$hours += $offset; // Add offset to user time to make it UTC time
if($hours > 24) // Time is more than than 24 hours. Increment all days by 1
{
$dayOffset = 1;
$hours -= 24; // Find out what the equivelant time would be for the next day
}
else if($hours < 0) // Time is less than 0 hours. Decrement all days by 1
{
$dayOffset = -1;
$hours += 24; // Find out what the equivelant time would be for the prior day
}
$return = Array(); // Times to return
foreach($days as $k => $v) // Iterate through each day and find out the week time
{
$days[$k] += $dayOffset;
// Ensure that day has a value from 0 - 6 (0 = Sunday, 1 = Monday, .... 6 = Saturday)
if($days[$k] > 6) { $days[$k] = 0; } else if($days[$k] < 0) { $days[$k] = 6; }
$days[$k] *= 1440; // Find out how many minutes into the week this day is
$days[$k] += ($hours*60) + $minutes; // Find out how many minutes into the day this time is
}
return $days;
}
?>

Calculating the time difference in an PHP/MySQL/JavaScript system

I was wondering what the best way is to calculate the difference in time from now to a certain point, let's say the countdown time.
I have an auction that has a closetime at a certain point, this time is stored in a MySQL record in the format " DATETIME 00-00-000 00:00:00 ". This record is called closetime.
Now on my website I have JavaScript code that gets this time via a PHP file. The JavaScript loops every second using setInterval 1000. The PHP file gets the closetime from the db, and sends it back in this format
strtotime($result['closetime']);
And I get the time of the request, I want to use the server time, and not the time in JavaScript, because the clock of the user can be off.
strtotime(date("H:i:s", $_SERVER['REQUEST_TIME']))
I send back these two timestamps and calculate the time difference between them in JavaScript. I use this function to do it, the values send back from PHP I call currentTime and closeTime, I think this should be clear.
function auctionDelayTime(currentTime,closeTime){
totaldelay = closeTime - currentTime;
if(totaldelay <= 0){
return 'ended';
}else{
if( days=parseInt((Math.floor(totaldelay/86400))) )
totaldelay = totaldelay % 86400;
if( hours=parseInt((Math.floor(totaldelay/3600))) )
totaldelay = totaldelay % 3600;
if( minutes=parseInt((Math.floor(totaldelay/60))) )
totaldelay = totaldelay % 60;
if( seconds=parseInt((Math.floor(totaldelay/1))) )
totaldelay = totaldelay % 1;
return hours+':'+formatTimes(minutes)+':'+formatTimes(seconds);
}
}
function formatTimes(value){
return value < 10 ? '0'+value : value;
}
I think this is an awful lot of code do something so simple. Does anyone have a better solution or maybe more 'beautiful' code.
Enjoy!
There is a jquery Countdown Plugin that supports server sync through AJAX:
From the docs:
Synchronise the client's time with
that of the server by providing a
function that returns the current
server date and time. This date and
time should take into account the
server's timezone and any difference
between that time and the client's is
applied to the countdown when it is
started or changed.
The following example uses a PHP
program on the server to return the
current server time in a format that
can be used directly by the JavaScript
callback. You should make sure that
your server call is synchronous.
$(selector).countdown({
until:liftoffTime, serverSync: serverTime});
function serverTime() {
var time = null;
$.ajax({url: 'http://myserver.com/serverTime.php',
async: false, dataType: 'text',
success: function(text) {
time = new Date(text);
}, error: function(http, message, exc) {
time = new Date();
}});
return time;
}
serverTime.php:
<?php
$now = new DateTime();
echo $now->format("M j, Y H:i:s O")."\n";
?>
Use Date object.
var d = new Date(difference_in_milliseconds);
var seconds = d.getSeconds();
var minutes = d.getMinutes();
var hours = d.getHours() - 1; //See note
Note: Strangely, hours value is bigger by one than I would expect for reason I don't understand. It looks like "midnight Jan 1, 1970" was at 1 AM :-)
UPDATE: The difference of 1 is due to the offset of my timezone (GMT +1).
Slight change that will solve this:
var d = new Date();
var offset = d.getTimezoneOffset() * 60000;
var d = new Date(difference_in_milliseconds + offset);
var seconds = d.getSeconds();
var minutes = d.getMinutes();
var hours = d.getHours();
This JavaScript library is easy to use and will likely serve you well.
Why not have the php page give you the difference?
$sql = "SELECT UNIX_TIMESTAMP(NOW()) as currentTime, UNIX_TIMESTAMP(closeTime) as closeTime FROM yourTable WHERE yourRecordId = '123'";
$query = mysql_query($sql);
$result = mysql_fetch_assoc($query);
echo timeRemaining($result['currentTime'], $result['closeTime']);
function timeRemaining($start, $end) {
$dateDiff = $end - $start;
if ($dateDiff <= 0) { return 'Ended'; }
$fullDays = floor($dateDiff/(60*60*24));
$fullHours = floor(($dateDiff-($fullDays*60*60*24))/(60*60));
$fullMinutes = floor(($dateDiff-($fullDays*60*60*24)-($fullHours*60*60))/60);
return "Ending in $fullDays days, $fullHours hours and $fullMinutes minutes.";
}
Do you really have to get the time through AJAX every 1000 ms?
(i suppose that you're hoping for closetime changes? ...)
But if you really must do it this way, i'd suggest getting the time difference directly in MySQL for code simplicity.
$sql = "SELECT TIMEDIFF(NOW(), `CreateTime`) from `Table` WHERE `id`=1;"

Categories