Display "time ago" instead of datetime in PHP Codeigniter - codeigniter

I would like to display a time format like twitter and FB (Posted 3 hours ago, Posted 2 minutes ago and so on...)
I've tried this piece of code without success :
function format_interval($timestamp, $granularity = 2) {
$units = array('1 year|#count years' => 31536000, '1 week|#count weeks' => 604800, '1 day|#count days' => 86400, '1 hour|#count hours' => 3600, '1 min|#count min' => 60, '1 sec|#count sec' => 1);
$output = '';
foreach ($units as $key => $value) {
$key = explode('|', $key);
if ($timestamp >= $value) {
$floor = floor($timestamp / $value);
$output .= ($output ? ' ' : '') . ($floor == 1 ? $key[0] : str_replace('#count', $floor, $key[1]));
$timestamp %= $value;
$granularity--;
}
if ($granularity == 0) {
break;
}
}
I use this function with a callback into another function like : $this->format_interval(); and pass it to my View
My current format date is : 2012-07-26 09:31:pm and already stored in my DB
Any help will be very appreciated!

The Date Helper's timespan() method just does that:
The most common purpose for this function is to show how much time has elapsed from some point in time in the past to now.
Given a timestamp, it will show how much time has elapsed in this format:
1 Year, 10 Months, 2 Weeks, 5 Days, 10 Hours, 16 Minutes
So, in your example, all you need to do is convert your date to a timestamp and do something like this:
$post_date = '13436714242';
$now = time();
// will echo "2 hours ago" (at the time of this post)
echo timespan($post_date, $now) . ' ago';

Try something like this in a my_date_helper.php file (source: Codeigniter Forums):
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
if( ! function_exists('relative_time'))
{
function relative_time($datetime)
{
$CI =& get_instance();
$CI->lang->load('date');
if(!is_numeric($datetime))
{
$val = explode(" ",$datetime);
$date = explode("-",$val[0]);
$time = explode(":",$val[1]);
$datetime = mktime($time[0],$time[1],$time[2],$date[1],$date[2],$date[0]);
}
$difference = time() - $datetime;
$periods = array("second", "minute", "hour", "day", "week", "month", "year", "decade");
$lengths = array("60","60","24","7","4.35","12","10");
if ($difference > 0)
{
$ending = $CI->lang->line('date_ago');
}
else
{
$difference = -$difference;
$ending = $CI->lang->line('date_to_go');
}
for($j = 0; $difference >= $lengths[$j]; $j++)
{
$difference /= $lengths[$j];
}
$difference = round($difference);
if($difference != 1)
{
$period = strtolower($CI->lang->line('date_'.$periods[$j].'s'));
} else {
$period = strtolower($CI->lang->line('date_'.$periods[$j]));
}
return "$difference $period $ending";
}
}
The format is a little different than the one you're using in your database (why do you mark times with pm/am rather than just use 24 hour times and convert for the frontend?). Either way, shouldn't take much work to get it working.

I had a function that solved this like this:
$int_diff = (time() - $int_time);
$str_this_year = date('Y-01-01', $int_time);
$str_weekday = t('time_weekday_'.strtolower(date('l', $int_time)));
$str_month = t('time_month_'.strtolower(date('F', $int_time)));
$arr_time_formats = array( '-90 seconds' => t('time_a_minute_at_most'),
'-45 minutes' => t('time_minutes_ago', ceil($int_diff / (60))),
'-70 minutes' => t('time_an_hour_at_most'),
'-8 hours' => t('time_hours_ago', ceil($int_diff / (60 * 60))),
'today' => t('time_hours_ago', ceil($int_diff / (60 * 60))),
'yesterday' => t('time_yesterday', date('H:i', $int_time)),
'-4 days' => t('time_week_ago', $str_weekday, date('H:i', $int_time)),
$str_this_year => t('time_date', date('j', $int_time), $str_month, date('H:i', $int_time)),
0 => t('time_date_year', date('j', $int_time), $str_month, date('Y', $int_time), date('H:i', $int_time)));
if ($boo_whole)
return $arr_time_formats[0];
foreach(array_keys($arr_time_formats) as $h)
if ($int_time >= strtotime($h))
return $arr_time_formats[$h];
Basicly t() is a function combined with $this->lang->line() and sprintf(). The idea here is to give keys that's runned through strtotime() till you reach the closest time, with 0 being the fallback.
This approach is really good since you can easy adjust the times with a nice overview. I could give more piece of the code, but it feels like doing too much of the work :) Basicly this is just the theory behind how you can do it.

<?php
$this->load->helper('date');
//client created date get from database
$date=$client_list->created_date;
// Declare timestamps
$last = new DateTime($date);
$now = new DateTime( date( 'Y-m-d h:i:s', time() )) ;
// Find difference
$interval = $last->diff($now);
// Store in variable to be used for calculation etc
$years = (int)$interval->format('%Y');
$months = (int)$interval->format('%m');
$days = (int)$interval->format('%d');
$hours = (int)$interval->format('%H');
$minutes = (int)$interval->format('%i');
// $now = date('Y-m-d H:i:s');
if($years > 0)
{
echo $years.' Years '.$months.' Months '.$days.' Days '. $hours.' Hours '.$minutes.' minutes ago.' ;
}
else if($months > 0)
{
echo $months.' Months '.$days.' Days '. $hours.' Hours '.$minutes.' minutes ago.' ;
}
else if($days > 0)
{
echo $days.' Days '.$hours.' Hours '.$minutes.' minutes ago.' ;
}
else if($hours > 0)
{
echo $hours.' Hours '.$minutes.' minutes ago.' ;
}
else
{
echo $minutes.' minutes ago.' ;
}
?>

Related

Getting non overlapping between two dates with Carbon

UseCase: Admin assigns tasks to People. Before we assign them we can see their tasks in a gantt chart. According to the task assign date and deadline, conflict days (overlap days) are generated between tasks.
I wrote this function to get overlapping dates between two dates. But now I need to get non overlapping days between two dates, below is the function I wrote.
$tasks = Assign_review_tasks::where('assigned_to', $employee)
->where('is_active', \Constants::$REVIEW_ACTIVE)
->whereNotNull('permit_id')->get();
$obj['task'] = count($tasks);
// count($tasks));
if (count($tasks) > 0) {
if (count($tasks) > 1) {
$start_one = $tasks[count($tasks) - 1]->start_date;
$end_one = $tasks[count($tasks) - 1]->end_date;
$end_two = $tasks[count($tasks) - 2]->end_date;
$start_two = $tasks[count($tasks) - 2]->start_date;
if ($start_one <= $end_two && $end_one >= $start_two) { //If the dates overlap
$obj['day'] = Carbon::parse(min($end_one, $end_two))->diff(Carbon::parse(max($start_two, $start_one)))->days + 1; //return how many days overlap
} else {
$obj['day'] = 0;
}
// $arr[] = $obj;
} else {
$obj['day'] = 0;
}
} else {
$obj['day'] = 0;
}
$arr[] = $obj;
start_date and end_date are taken from database,
I tried modifying it to,
(Carbon::parse((min($end_one, $end_two))->add(Carbon::parse(max($start_two, $start_one))))->days)->diff(Carbon::parse(min($end_one, $end_two))->diff(Carbon::parse(max($start_two, $start_one)))->days + 1);
But it didn't work, in simple terms this is what I want,
Non conflicting days = (end1-start1 + end2-start2)- Current overlapping days
I'm having trouble translate this expression . Could you help me? Thanks in advance
before trying to reimplement complex stuff I recommend you take a look at enhanced-period for Carbon
composer require cmixin/enhanced-period
CarbonPeriod::diff macro method is what I think you're looking for:
use Carbon\CarbonPeriod;
use Cmixin\EnhancedPeriod;
CarbonPeriod::mixin(EnhancedPeriod::class);
$a = CarbonPeriod::create('2018-01-01', '2018-01-31');
$b = CarbonPeriod::create('2018-02-10', '2018-02-20');
$c = CarbonPeriod::create('2018-02-11', '2018-03-31');
$current = CarbonPeriod::create('2018-01-20', '2018-03-15');
foreach ($current->diff($a, $b, $c) as $period) {
foreach ($period as $day) {
echo $day . "\n";
}
}
This will output all the days that are in $current but not in any of the other periods. (E.g. non-conflicting days)

Add two times laravel

I have two times $first = 16 (seconds or minutes) & $second = 10 (seconds or minutes)
What i want to achieve - I want to add this two times like $result = $first + $second & the result is in seconds & minutes formet
like
$first = 16 seconds;
$second = 2 minutes;
$result = $first + $second; // 2 minutes, 16 seconds
so, how can we do this in code
I have this refrence code to get the time interval of two times
$in1 = explode(' ', "clock in time = 20 minutes");
$out1 = explode(' ', "clock out time = 10 minutes");
$start_time1 = $in1[4] . ' ' . $in1[5];
$end_time1 = $out1[4] . ' ' . $out1[5];
$start1 = Carbon::parse($start_time1);
$end1 = Carbon::parse($end_time1);
$dd1 = $end1->diffForHumans($start1, [
'parts' => 2,
'join' => ', ',
'syntax' => CarbonInterface::DIFF_ABSOLUTE,
]);
Carbon intervals allow you to create an interval instance from strings like 20 minutes or 10 seconds so you can leverage that with some date operations to get what you need:
$in1 = explode('=', "clock in time = 20 minutes");
$out1 = explode('=', "clock out time = 10 minutes");
$startinterval = CarbonInterval::fromString(trim($in1[1]));
$endinterval = CarbonInterval::fromString(trim($out1[1]));
$now = CarbonImmutable::now();
$interval = $now->add($startinterval)->add($endinterval)->diffAsCarbonInterval($now);
You can convert your times in seconds, do the addition, then convert to time again.
$start = $in1[5] === 'seconds' ? $int1[4] : $int1[4] * 60;
$end = $out1[5] === 'seconds' ? $out1[4] : $out1[4] * 60;
$totalInSeconds = (int) $start + (int) $end;
$dd1 = gmdate('i', $totalInSeconds) .' minutes, '. gmdate('s', $totalInSeconds) .' seconds';
echo $dd1;

How to get 1st, 2nd, 3rd week format carbon laravel

I need to get 1st, 2nd, 3rd and 4th week format from CarbonPeriod. What should i do to make it in text?
$carbonPeriod = CarbonPeriod::create($startDate, '1 week', $endDate);
foreach ($carbonPeriod as $period) {
$startPeriod = clone $period;
$endPeriod = clone $period;
$startRange = $parsedStartDate->gt($startPeriod->startOfWeek()) ? $startDate : $startPeriod->startOfWeek()->format('Y-m-d');
$endRange = $parsedEndDate->lt($endPeriod->endOfWeek()) ? $endDate : $endPeriod->endOfWeek()->format('Y-m-d');
$labels[] = $period->translatedFormat('F D Y'); //i need Jan 1st week 2021, Jan 2nd week 2021 and etc for the labels
}
$carbonPeriod = CarbonPeriod::create($startDate, '1 week', $endDate);
foreach ($carbonPeriod as $index => $period) {
$startPeriod = clone $period;
$endPeriod = clone $period;
$startRange = $parsedStartDate->gt($startPeriod->startOfWeek()) ? $startDate : $startPeriod->startOfWeek()->format('Y-m-d');
$endRange = $parsedEndDate->lt($endPeriod->endOfWeek()) ? $endDate : $endPeriod->endOfWeek()->format('Y-m-d');
$labels[] = $carbonPeriod->translate('ordinal', [':number' => $index + 1]);
}
If I understand you correctly you want the ordinal week within the given period. If that's indeed the case then you can do what you need using:
$locale = 'xxx'; // Replace with your locale here
$nf = new NumberFormatter($locale, NumberFormatter::ORDINAL);
$carbonPeriod = CarbonPeriod::create($startDate, '1 week', $endDate);
foreach ($carbonPeriod as $i => $period) {
$startPeriod = clone $period;
$endPeriod = clone $period;
$startRange = $parsedStartDate->gt($startPeriod->startOfWeek()) ? $startDate : $startPeriod->startOfWeek()->format('Y-m-d');
$endRange = $parsedEndDate->lt($endPeriod->endOfWeek()) ? $endDate : $endPeriod->endOfWeek()->format('Y-m-d');
$ordWeek = $nf->format($i);
$labels[] = $period->translatedFormat('F')." $ordWeek". __("week")." ".$period->translatedFormat('Y'); // Should say "January 1st week 2021
}
Note this requires the intl extension
$CarbonPeriod = Carbon::now()->subDays(20);
$today = Carbon::now();
$weeks = intval(floor(($CarbonPeriod->diff($today)->days) / 7)) . 'st';
Result "2st"

Timepicker that removes times as they're selected (ajax)

I'm building a booking form for a moving business that uses a calendar combined with a start and end time. I built the timepicker with Formidable Pro, and it allows me to check "unique" on time fields which automatically removes them on the selected date. However it doesn't automatically remove the times from within the range between start and end times (ie: if someone chooses to rent a truck from 1am-3am I need 1am,2am,and 3am to be removed from future options but right now it only removes 1am and 3am) . I need to write ajax to remove the in-between times from the options. I'm not sure where to begin. This is the current ajax_time_ options function. Any push in the right direction would be appreciated.
function ajax_time_options(){
global $frmpro_settings, $frmdb, $wpdb;
//posted vars = $time_field, $date_field, $step, $start, $end, $date, $clock
extract($_POST);
$time_key = str_replace('field_', '', $time_field);
$date_key = str_replace('field_', '', $date_field);
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', trim($date)))
$date = FrmProAppHelper::convert_date($date, $frmpro_settings->date_format, 'Y-m-d');
$date_entries = FrmEntryMeta::getEntryIds("fi.field_key='$date_key' and meta_value='$date'");
$opts = array('' => '');
$time = strtotime($start);
$end = strtotime($end);
$step = explode(':', $step);
$step = (isset($step[1])) ? ($step[0] * 3600 + $step[1] * 60) : ($step[0] * 60);
$format = ($clock) ? 'H:i' : 'h:i A';
while($time <= $end){
$opts[date($format, $time)] = date($format, $time);
$time += $step;
}
if($date_entries and !empty($date_entries)){
$used_times = $wpdb->get_col("SELECT meta_value FROM $frmdb->entry_metas it LEFT JOIN $frmdb->fields fi ON (it.field_id = fi.id) WHERE fi.field_key='$time_key' and it.item_id in (". implode(',', $date_entries).")");
if($used_times and !empty($used_times)){
$number_allowed = apply_filters('frm_allowed_time_count', 1, $time_key, $date_key);
$count = array();
foreach($used_times as $used){
if(!isset($opts[$used]))
continue;
if(!isset($count[$used]))
$count[$used] = 0;
$count[$used]++;
if((int)$count[$used] >= $number_allowed)
unset($opts[$used]);
}
unset($count);
}
}
echo json_encode($opts);
die();
}

How to iterate through range of Dates?

In my script, I need to iterate through a range of dates given the start date and end date. How can I do this in Perl?
Use DateTime module. Here is a simple example which lists the ten previous days:
use 5.012;
use warnings;
use DateTime;
my $end = DateTime->now;
my $day = $end->clone->subtract( days => 10 ); # ten days ago
while ($day < $end) {
say $day;
$day->add( days => 1 ); # move along to next day
}
Update (after seeing your comment/update):
To parse in a date string then look at the DateTime::Format on modules CPAN.
Here is an example using DateTime::Format::DateParse which does parse YYYY/MM/DD:
use DateTime::Format::DateParse;
my $d = DateTime::Format::DateParse->parse_datetime( '2010/06/23' );
One easy approach is to use the Date::Simple module, which makes use of operator-overloading:
use strict;
use warnings;
use Date::Simple;
my $date = Date::Simple->new ( '2010-01-01' ); # Stores Date::Simple object
my $endDate = Date::Simple->today; # Today's date
while ( ++$date < $endDate ) {
print ( $date - $endDate ) , "day",
( ( $date-$endDate) == 1 ? '' : 's' ), " ago\n";
}
use DateTime::Format::Strptime qw();
my $start = DateTime::Format::Strptime->new(pattern => '%Y/%m/%d')->parse_datetime('2010/08/16');
my $end = DateTime::Format::Strptime->new(pattern => '%Y/%m/%d')->parse_datetime('2010/11/24');
while ($start < $end) {
$start->add(days => 1);
say $start->ymd('/');
}
I like to use the fact that strftime will normalize the date for me:
#!/usr/bin/perl
use strict;
use warnings;
use POSIX qw/strftime/;
my $start = "2010/08/16";
my $end = "2010/09/16";
my #time = (0, 0, 0);
my ($y, $m, $d) = split "/", $start;
$y -= 1900;
$m--;
my $offset = 0;
while ((my $date = strftime "%Y/%m/%d", #time, $d + $offset, $m, $y) le $end) {
print "$date\n";
} continue {
$offset++;
}
You can try Date::Calc::Iterator
# This puts all the dates from Dec 1, 2003 to Dec 10, 2003 in #dates1
# #dates1 will contain ([2003,12,1],[2003,12,2] ... [2003,12,10]) ;
my $i1 = Date::Calc::Iterator->new(from => [2003,12,1], to => [2003,12,10]) ;
my #dates1 ;
push #dates1,$_ while $_ = $i1->next ;
If installing extra perl modules is not preferable, one can use this approach, based on a core perl library POSIX:
#!/usr/bin/perl
use strict;
use warnings;
use POSIX qw(strftime);
# CREATE CALENDAR
my #Calendar = ();
my $years = 3;
my #Now = localtime(); # An array of 9 date-time parameters.
for my $count ( 0 .. ( 365 * $years ) ) {
# If date is January 1st, manual shift to December 31st is needed,
# because days ([yday][2]) are counted from January 31st and never shift back one year.
if( $Now[4] == 0 && $Now[3] == 1 ) {
unshift #Calendar, strftime( "%Y-%m-%d", #Now );
$Now[5] --; # Reduce by one the sixth array element #5 - year.
$Now[4] = 11; # Set fifth array element № 4 - to December.
$Now[3] = 31; # Set fourth array element № 3 - to 31st.
} else {
unshift #Calendar, strftime( "%Y-%m-%d", #Now );
$Now[3] --;
}
}
# Print out.
my $size = #Calendar;
for (my $i = 0; $i < $size; $i++) {
print $Calendar[$i]."\n";
}
Perl has a rich array of time and date manipulation modules, as seen here:
http://datetime.perl.org/?Modules
And there are some examples of date and time problems there as well.
With Perl, there's always more than one way to do it.

Resources