2010-07-01 23:48:07 +00:00
< ? php
2016-02-03 18:48:09 +00:00
/**
* @ file include / datetime . php
* @ brief Some functions for date and time related tasks .
*/
2010-07-01 23:48:07 +00:00
2017-04-30 04:29:14 +00:00
use Friendica\Core\Config ;
2018-01-21 16:38:01 +00:00
use Friendica\Core\L10n ;
2017-11-07 02:22:52 +00:00
use Friendica\Core\PConfig ;
2017-11-08 03:57:46 +00:00
use Friendica\Database\DBM ;
2010-09-27 07:38:26 +00:00
2016-02-03 18:48:09 +00:00
/**
* @ brief Two - level sort for timezones .
*
* @ param string $a
* @ param string $b
* @ return int
*/
2010-07-01 23:48:07 +00:00
function timezone_cmp ( $a , $b ) {
2017-04-04 17:47:32 +00:00
if ( strstr ( $a , '/' ) && strstr ( $b , '/' )) {
2018-01-21 18:33:59 +00:00
if ( L10n :: t ( $a ) == L10n :: t ( $b )) {
2017-04-04 17:47:32 +00:00
return 0 ;
}
2018-01-21 18:33:59 +00:00
return ( L10n :: t ( $a ) < L10n :: t ( $b )) ? - 1 : 1 ;
2010-07-01 23:48:07 +00:00
}
2017-04-04 17:47:32 +00:00
if ( strstr ( $a , '/' )) {
return - 1 ;
} elseif ( strstr ( $b , '/' )) {
return 1 ;
2018-01-21 18:33:59 +00:00
} elseif ( L10n :: t ( $a ) == L10n :: t ( $b )) {
2017-04-04 17:47:32 +00:00
return 0 ;
}
2016-02-03 18:48:09 +00:00
2018-01-21 18:33:59 +00:00
return ( L10n :: t ( $a ) < L10n :: t ( $b )) ? - 1 : 1 ;
2016-02-03 18:48:09 +00:00
}
2010-07-01 23:48:07 +00:00
2016-02-03 18:48:09 +00:00
/**
* @ brief Emit a timezone selector grouped ( primarily ) by continent
2017-04-30 04:29:14 +00:00
*
2016-02-03 18:48:09 +00:00
* @ param string $current Timezone
* @ return string Parsed HTML output
*/
2010-07-01 23:48:07 +00:00
function select_timezone ( $current = 'America/Los_Angeles' ) {
$timezone_identifiers = DateTimeZone :: listIdentifiers ();
2014-03-11 22:52:32 +00:00
2010-07-01 23:48:07 +00:00
$o = '<select id="timezone_select" name="timezone">' ;
usort ( $timezone_identifiers , 'timezone_cmp' );
$continent = '' ;
2017-04-04 17:47:32 +00:00
foreach ( $timezone_identifiers as $value ) {
2010-07-01 23:48:07 +00:00
$ex = explode ( " / " , $value );
2017-04-04 17:47:32 +00:00
if ( count ( $ex ) > 1 ) {
if ( $ex [ 0 ] != $continent ) {
if ( $continent != '' ) {
2010-07-01 23:48:07 +00:00
$o .= '</optgroup>' ;
2017-04-04 17:47:32 +00:00
}
2010-07-01 23:48:07 +00:00
$continent = $ex [ 0 ];
2018-01-21 18:33:59 +00:00
$o .= '<optgroup label="' . L10n :: t ( $continent ) . '">' ;
2010-07-01 23:48:07 +00:00
}
2017-04-04 17:47:32 +00:00
if ( count ( $ex ) > 2 ) {
2010-07-01 23:48:07 +00:00
$city = substr ( $value , strpos ( $value , '/' ) + 1 );
2017-04-04 17:47:32 +00:00
} else {
2010-07-01 23:48:07 +00:00
$city = $ex [ 1 ];
2017-04-04 17:47:32 +00:00
}
} else {
2010-07-01 23:48:07 +00:00
$city = $ex [ 0 ];
2018-01-21 18:33:59 +00:00
if ( $continent != L10n :: t ( 'Miscellaneous' )) {
2010-07-01 23:48:07 +00:00
$o .= '</optgroup>' ;
2018-01-21 18:33:59 +00:00
$continent = L10n :: t ( 'Miscellaneous' );
$o .= '<optgroup label="' . L10n :: t ( $continent ) . '">' ;
2010-07-01 23:48:07 +00:00
}
}
2018-01-21 18:33:59 +00:00
$city = str_replace ( '_' , ' ' , L10n :: t ( $city ));
2010-07-01 23:48:07 +00:00
$selected = (( $value == $current ) ? " selected= \" selected \" " : " " );
$o .= " <option value= \" $value\ " $selected > $city </ option > " ;
2015-10-17 08:48:13 +00:00
}
2010-07-01 23:48:07 +00:00
$o .= '</optgroup></select>' ;
return $o ;
2016-02-03 18:48:09 +00:00
}
2010-07-01 23:48:07 +00:00
2016-02-03 18:48:09 +00:00
/**
* @ brief Generating a Timezone selector
2017-04-30 04:29:14 +00:00
*
2016-02-03 18:48:09 +00:00
* Return a select using 'field_select_raw' template , with timezones
* groupped ( primarily ) by continent
2016-02-08 00:59:05 +00:00
* arguments follow convetion as other field_ * template array :
* 'name' , 'label' , $value , 'help'
2017-04-30 04:29:14 +00:00
*
2016-02-03 18:48:09 +00:00
* @ param string $name Name of the selector
* @ param string $label Label for the selector
* @ param string $current Timezone
* @ param string $help Help text
2017-04-30 04:29:14 +00:00
*
2016-02-03 18:48:09 +00:00
* @ return string Parsed HTML
*/
2012-01-02 19:09:25 +00:00
function field_timezone ( $name = 'timezone' , $label = '' , $current = 'America/Los_Angeles' , $help ){
$options = select_timezone ( $current );
$options = str_replace ( '<select id="timezone_select" name="timezone">' , '' , $options );
$options = str_replace ( '</select>' , '' , $options );
2015-10-17 08:48:13 +00:00
2012-01-02 19:09:25 +00:00
$tpl = get_markup_template ( 'field_select_raw.tpl' );
2018-01-15 13:05:12 +00:00
return replace_macros ( $tpl , [
'$field' => [ $name , $label , $current , $help , $options ],
]);
2015-10-17 08:48:13 +00:00
2016-02-03 18:48:09 +00:00
}
2010-07-01 23:48:07 +00:00
2016-02-03 18:48:09 +00:00
/**
* @ brief General purpose date parse / convert function .
*
* @ param string $from Source timezone
* @ param string $to Dest timezone
* @ param string $s Some parseable date / time string
* @ param string $fmt Output format recognised from php ' s DateTime class
* http :// www . php . net / manual / en / datetime . format . php
2017-04-30 04:29:14 +00:00
*
2016-02-06 00:08:10 +00:00
* @ return string Formatted date according to given format
2016-02-03 18:48:09 +00:00
*/
2010-07-01 23:48:07 +00:00
function datetime_convert ( $from = 'UTC' , $to = 'UTC' , $s = 'now' , $fmt = " Y-m-d H:i:s " ) {
2010-09-09 03:14:17 +00:00
2012-04-09 01:09:21 +00:00
// Defaults to UTC if nothing is set, but throws an exception if set to empty string.
// Provide some sane defaults regardless.
2012-04-09 01:01:49 +00:00
2017-04-04 17:47:32 +00:00
if ( $from === '' ) {
2012-04-09 01:01:49 +00:00
$from = 'UTC' ;
2017-04-04 17:47:32 +00:00
}
if ( $to === '' ) {
2012-04-09 01:01:49 +00:00
$to = 'UTC' ;
2017-04-04 17:47:32 +00:00
}
if ( ( $s === '' ) || ( ! is_string ( $s )) ) {
2012-04-09 01:09:21 +00:00
$s = 'now' ;
2017-04-04 17:47:32 +00:00
}
2012-04-09 01:01:49 +00:00
2017-04-04 17:47:32 +00:00
/*
* Slight hackish adjustment so that 'zero' datetime actually returns what is intended
* otherwise we end up with - 0001 - 11 - 30 ...
* add 32 days so that we at least get year 00 , and then hack around the fact that
* months and days always start with 1.
*/
2010-09-09 03:14:17 +00:00
2017-04-04 17:47:32 +00:00
if ( substr ( $s , 0 , 10 ) <= '0001-01-01' ) {
2010-09-09 03:14:17 +00:00
$d = new DateTime ( $s . ' + 32 days' , new DateTimeZone ( 'UTC' ));
return str_replace ( '1' , '0' , $d -> format ( $fmt ));
}
2012-07-16 04:00:11 +00:00
try {
$from_obj = new DateTimeZone ( $from );
2017-04-04 17:47:32 +00:00
} catch ( Exception $e ) {
2012-07-16 04:00:11 +00:00
$from_obj = new DateTimeZone ( 'UTC' );
}
try {
$d = new DateTime ( $s , $from_obj );
2017-04-04 17:47:32 +00:00
} catch ( Exception $e ) {
2012-07-16 04:00:11 +00:00
logger ( 'datetime_convert: exception: ' . $e -> getMessage ());
$d = new DateTime ( 'now' , $from_obj );
}
try {
$to_obj = new DateTimeZone ( $to );
2017-04-04 17:47:32 +00:00
} catch ( Exception $e ) {
2012-07-16 04:00:11 +00:00
$to_obj = new DateTimeZone ( 'UTC' );
}
$d -> setTimeZone ( $to_obj );
2016-02-06 00:08:10 +00:00
2017-04-04 17:47:32 +00:00
return $d -> format ( $fmt );
2016-02-03 18:48:09 +00:00
}
2012-07-16 04:00:11 +00:00
2010-09-27 07:38:26 +00:00
2016-02-03 18:48:09 +00:00
/**
* @ brief Wrapper for date selector , tailored for use in birthday fields .
*
* @ param string $dob Date of Birth
2016-06-10 09:24:38 +00:00
* @ return string Formatted html
2016-02-03 18:48:09 +00:00
*/
2018-01-04 02:12:19 +00:00
function dob ( $dob )
{
list ( $year , $month , $day ) = sscanf ( $dob , '%4d-%2d-%2d' );
2016-02-03 18:48:09 +00:00
2017-04-04 17:47:32 +00:00
if ( $dob <= '0001-01-01' ) {
2015-05-22 16:53:18 +00:00
$value = '' ;
2017-04-04 17:47:32 +00:00
} else {
2015-05-22 16:53:18 +00:00
$value = (( $year ) ? datetime_convert ( 'UTC' , 'UTC' , $dob , 'Y-m-d' ) : datetime_convert ( 'UTC' , 'UTC' , $dob , 'm-d' ));
2017-04-04 17:47:32 +00:00
}
2016-02-03 18:48:09 +00:00
2016-06-10 09:24:38 +00:00
$age = (( intval ( $value )) ? age ( $value , $a -> user [ " timezone " ], $a -> user [ " timezone " ]) : " " );
2018-01-15 13:05:12 +00:00
$o = replace_macros ( get_markup_template ( " field_input.tpl " ), [
'$field' => [
2016-06-10 09:24:38 +00:00
'dob' ,
t ( 'Birthday:' ),
$value ,
2018-01-21 18:33:59 +00:00
((( intval ( $age )) > 0 ) ? L10n :: t ( 'Age: ' ) . $age : " " ),
2016-06-10 09:24:38 +00:00
'' ,
2018-01-21 18:33:59 +00:00
'placeholder="' . L10n :: t ( 'YYYY-MM-DD or MM-DD' ) . '"'
2018-01-15 13:05:12 +00:00
]
]);
2016-02-03 18:48:09 +00:00
2011-07-26 03:59:25 +00:00
return $o ;
}
2015-05-22 16:53:18 +00:00
/**
2016-02-03 18:48:09 +00:00
* @ brief Returns a date selector
2017-04-30 04:29:14 +00:00
*
2016-02-03 18:48:09 +00:00
* @ param string $min
* Unix timestamp of minimum date
* @ param string $max
* Unix timestap of maximum date
* @ param string $default
* Unix timestamp of default date
* @ param string $id
* ID and name of datetimepicker ( defaults to " datetimepicker " )
2017-04-30 04:29:14 +00:00
*
2016-02-03 18:48:09 +00:00
* @ return string Parsed HTML output .
2015-05-22 16:53:18 +00:00
*/
2018-01-04 02:04:52 +00:00
function datesel ( $min , $max , $default , $id = 'datepicker' )
{
return datetimesel ( $min , $max , $default , '' , $id , true , false , '' , '' );
2016-02-03 18:48:09 +00:00
}
2010-07-01 23:48:07 +00:00
2015-05-22 16:53:18 +00:00
/**
2016-02-03 18:48:09 +00:00
* @ brief Returns a time selector
2017-04-30 04:29:14 +00:00
*
2015-05-22 16:53:18 +00:00
* @ param $h
2016-02-03 18:48:09 +00:00
* Already selected hour
2015-05-22 16:53:18 +00:00
* @ param $m
2016-02-03 18:48:09 +00:00
* Already selected minute
* @ param string $id
* ID and name of datetimepicker ( defaults to " timepicker " )
2017-04-30 04:29:14 +00:00
*
2016-02-03 18:48:09 +00:00
* @ return string Parsed HTML output .
2015-05-22 16:53:18 +00:00
*/
2018-01-04 02:04:52 +00:00
function timesel ( $h , $m , $id = 'timepicker' )
{
return datetimesel ( new DateTime (), new DateTime (), new DateTime ( " $h : $m " ), '' , $id , false , true );
2016-02-03 18:48:09 +00:00
}
2011-06-07 02:59:20 +00:00
2015-05-22 16:53:18 +00:00
/**
* @ brief Returns a datetime selector .
*
2016-02-03 18:48:09 +00:00
* @ param string $min
2015-05-22 16:53:18 +00:00
* unix timestamp of minimum date
2016-02-03 18:48:09 +00:00
* @ param string $max
2015-05-22 16:53:18 +00:00
* unix timestap of maximum date
2016-02-03 18:48:09 +00:00
* @ param string $default
2015-05-22 16:53:18 +00:00
* unix timestamp of default date
* @ param string $id
* id and name of datetimepicker ( defaults to " datetimepicker " )
2016-02-03 18:48:09 +00:00
* @ param bool $pickdate
2015-05-22 16:53:18 +00:00
* true to show date picker ( default )
* @ param boolean $picktime
* true to show time picker ( default )
* @ param $minfrom
* set minimum date from picker with id $minfrom ( none by default )
* @ param $maxfrom
* set maximum date from picker with id $maxfrom ( none by default )
2016-02-03 18:48:09 +00:00
* @ param bool $required default false
2017-04-30 04:29:14 +00:00
*
2015-05-22 16:53:18 +00:00
* @ return string Parsed HTML output .
2015-10-17 08:48:13 +00:00
*
2015-05-22 16:53:18 +00:00
* @ todo Once browser support is better this could probably be replaced with
* native HTML5 date picker .
*/
2018-01-04 02:04:52 +00:00
function datetimesel ( $min , $max , $default , $label , $id = 'datetimepicker' , $pickdate = true , $picktime = true , $minfrom = '' , $maxfrom = '' , $required = false )
{
2015-10-17 08:48:13 +00:00
// First day of the week (0 = Sunday)
2017-11-07 21:48:41 +00:00
$firstDay = PConfig :: get ( local_user (), 'system' , 'first_day_of_week' , 0 );
2015-10-17 08:48:13 +00:00
2018-01-21 16:38:01 +00:00
$lang = substr ( L10n :: getBrowserLanguage (), 0 , 2 );
2015-10-17 08:48:13 +00:00
// Check if the detected language is supported by the picker
2018-01-15 13:05:12 +00:00
if ( ! in_array ( $lang , [ " ar " , " ro " , " id " , " bg " , " fa " , " ru " , " uk " , " en " , " el " , " de " , " nl " , " tr " , " fr " , " es " , " th " , " pl " , " pt " , " ch " , " se " , " kr " , " it " , " da " , " no " , " ja " , " vi " , " sl " , " cs " , " hu " ])) {
2017-01-17 19:21:46 +00:00
$lang = Config :: get ( 'system' , 'language' , 'en' );
}
2015-10-17 08:48:13 +00:00
2015-05-22 16:53:18 +00:00
$o = '' ;
$dateformat = '' ;
2016-02-03 18:48:09 +00:00
2017-04-04 17:47:32 +00:00
if ( $pickdate ) {
$dateformat .= 'Y-m-d' ;
}
if ( $pickdate && $picktime ) {
$dateformat .= ' ' ;
}
if ( $picktime ) {
$dateformat .= 'H:i' ;
}
2016-02-03 18:48:09 +00:00
2015-05-22 16:53:18 +00:00
$minjs = $min ? " ,minDate: new Date( { $min -> getTimestamp () } *1000), yearStart: " . $min -> format ( 'Y' ) : '' ;
$maxjs = $max ? " ,maxDate: new Date( { $max -> getTimestamp () } *1000), yearEnd: " . $max -> format ( 'Y' ) : '' ;
2015-10-17 08:48:13 +00:00
2016-06-16 18:16:16 +00:00
$input_text = $default ? date ( $dateformat , $default -> getTimestamp ()) : '' ;
2015-05-22 16:53:18 +00:00
$defaultdatejs = $default ? " ,defaultDate: new Date( { $default -> getTimestamp () } *1000) " : '' ;
2016-02-03 18:48:09 +00:00
2015-05-22 16:53:18 +00:00
$pickers = '' ;
2017-04-04 17:47:32 +00:00
if ( ! $pickdate ) {
2017-04-04 17:47:32 +00:00
$pickers .= ', datepicker: false' ;
2017-04-04 17:47:32 +00:00
}
if ( ! $picktime ) {
$pickers .= ',timepicker: false' ;
}
2016-02-03 18:48:09 +00:00
2015-05-22 16:53:18 +00:00
$extra_js = '' ;
2017-04-04 17:47:32 +00:00
$pickers .= " ,dayOfWeekStart: " . $firstDay . " ,lang:' " . $lang . " ' " ;
2017-04-04 17:47:32 +00:00
if ( $minfrom != '' ) {
2016-06-16 18:16:16 +00:00
$extra_js .= " \$ ('#id_ $minfrom ').data('xdsoft_datetimepicker').setOptions( { onChangeDateTime: function (currentDateTime) { \$ ('#id_ $id ').data('xdsoft_datetimepicker').setOptions( { minDate: currentDateTime})}}) " ;
2017-04-04 17:47:32 +00:00
}
if ( $maxfrom != '' ) {
2016-06-13 08:19:38 +00:00
$extra_js .= " \$ ('#id_ $maxfrom ').data('xdsoft_datetimepicker').setOptions( { onChangeDateTime: function (currentDateTime) { \$ ('#id_ $id ').data('xdsoft_datetimepicker').setOptions( { maxDate: currentDateTime})}}) " ;
2017-04-04 17:47:32 +00:00
}
2016-02-03 18:48:09 +00:00
2015-05-22 16:53:18 +00:00
$readable_format = $dateformat ;
$readable_format = str_replace ( 'Y' , 'yyyy' , $readable_format );
$readable_format = str_replace ( 'm' , 'mm' , $readable_format );
$readable_format = str_replace ( 'd' , 'dd' , $readable_format );
$readable_format = str_replace ( 'H' , 'HH' , $readable_format );
$readable_format = str_replace ( 'i' , 'MM' , $readable_format );
2016-02-03 18:48:09 +00:00
2016-06-13 08:19:38 +00:00
$tpl = get_markup_template ( 'field_input.tpl' );
2018-01-15 13:05:12 +00:00
$o .= replace_macros ( $tpl , [
'$field' => [ $id , $label , $input_text , '' , (( $required ) ? '*' : '' ), 'placeholder="' . $readable_format . '"' ],
]);
2016-06-17 12:27:33 +00:00
2015-10-17 08:48:13 +00:00
$o .= " <script type='text/javascript'> " ;
2016-06-13 08:19:38 +00:00
$o .= " \$ (function () { var picker = \$ ('#id_ $id ').datetimepicker( { step:5,format:' $dateformat ' $minjs $maxjs $pickers $defaultdatejs }); $extra_js }) " ;
2015-10-17 08:48:13 +00:00
$o .= " </script> " ;
2011-06-07 02:59:20 +00:00
2016-02-03 18:48:09 +00:00
return $o ;
}
2010-07-01 23:48:07 +00:00
2016-02-03 18:48:09 +00:00
/**
* @ brief Returns a relative date string .
*
* Implements " 3 seconds ago " etc .
* Based on $posted_date , ( UTC ) .
* Results relative to current timezone .
* Limited to range of timestamps .
*
2016-11-01 06:04:59 +00:00
* @ param string $posted_date MySQL - formatted date string ( YYYY - MM - DD HH : MM : SS )
2016-02-03 18:48:09 +00:00
* @ param string $format ( optional ) Parsed with sprintf ()
* < tt >% 1 $d % 2 $s ago </ tt > , e . g . 22 hours ago , 1 minute ago
2016-10-28 09:54:26 +00:00
*
2016-02-03 18:48:09 +00:00
* @ return string with relative date
*/
2016-10-28 09:54:26 +00:00
function relative_date ( $posted_date , $format = null ) {
2010-07-01 23:48:07 +00:00
2016-10-28 09:54:26 +00:00
$localtime = $posted_date . ' UTC' ;
2010-07-01 23:48:07 +00:00
2010-08-16 04:49:29 +00:00
$abs = strtotime ( $localtime );
2015-10-17 08:48:13 +00:00
2018-01-21 18:33:59 +00:00
if ( is_null ( $posted_date ) || $posted_date <= NULL_DATE || $abs === false ) {
return L10n :: t ( 'never' );
2011-06-29 10:05:09 +00:00
}
2011-06-29 10:54:29 +00:00
$etime = time () - $abs ;
2015-10-17 08:48:13 +00:00
2010-08-16 04:49:29 +00:00
if ( $etime < 1 ) {
2018-01-21 18:33:59 +00:00
return L10n :: t ( 'less than a second ago' );
2010-08-16 04:49:29 +00:00
}
2015-10-17 08:48:13 +00:00
2018-01-21 18:33:59 +00:00
$a = [ 12 * 30 * 24 * 60 * 60 => [ L10n :: t ( 'year' ), L10n :: t ( 'years' )],
30 * 24 * 60 * 60 => [ L10n :: t ( 'month' ), L10n :: t ( 'months' )],
7 * 24 * 60 * 60 => [ L10n :: t ( 'week' ), L10n :: t ( 'weeks' )],
24 * 60 * 60 => [ L10n :: t ( 'day' ), L10n :: t ( 'days' )],
60 * 60 => [ L10n :: t ( 'hour' ), L10n :: t ( 'hours' )],
60 => [ L10n :: t ( 'minute' ), L10n :: t ( 'minutes' )],
1 => [ L10n :: t ( 'second' ), L10n :: t ( 'seconds' )]
2018-01-15 13:05:12 +00:00
];
2015-10-17 08:48:13 +00:00
2010-08-16 04:49:29 +00:00
foreach ( $a as $secs => $str ) {
2012-02-13 01:15:09 +00:00
$d = $etime / $secs ;
if ( $d >= 1 ) {
$r = round ( $d );
// translators - e.g. 22 hours ago, 1 minute ago
2016-11-01 06:04:59 +00:00
if ( ! $format ) {
2018-01-21 18:33:59 +00:00
$format = L10n :: t ( '%1$d %2$s ago' );
2016-10-28 09:54:26 +00:00
}
2010-07-10 05:47:32 +00:00
2016-11-01 06:04:59 +00:00
return sprintf ( $format , $r , (( $r == 1 ) ? $str [ 0 ] : $str [ 1 ]));
2016-02-03 18:48:09 +00:00
}
}
}
2010-09-27 07:38:26 +00:00
2016-02-03 18:48:09 +00:00
/**
* @ brief Returns timezone correct age in years .
*
* Returns the age in years , given a date of birth , the timezone of the person
* whose date of birth is provided , and the timezone of the person viewing the
* result .
*
* Why ? Bear with me . Let ' s say I live in Mittagong , Australia , and my birthday
* is on New Year ' s . You live in San Bruno , California .
* When exactly are you going to see my age increase ?
*
* A : 5 : 00 AM Dec 31 San Bruno time . That ' s precisely when I start celebrating
* and become a year older . If you wish me happy birthday on January 1
* ( San Bruno time ), you ' ll be a day late .
*
* @ param string $dob Date of Birth
* @ param string $owner_tz ( optional ) Timezone of the person of interest
* @ param string $viewer_tz ( optional ) Timezone of the person viewing
2017-04-30 04:29:14 +00:00
*
2016-02-06 00:08:10 +00:00
* @ return int Age in years
2016-02-03 18:48:09 +00:00
*/
2017-04-04 17:47:32 +00:00
function age ( $dob , $owner_tz = '' , $viewer_tz = '' ) {
if ( ! intval ( $dob )) {
2010-07-10 05:47:32 +00:00
return 0 ;
2017-04-04 17:47:32 +00:00
}
if ( ! $owner_tz ) {
2010-07-10 05:47:32 +00:00
$owner_tz = date_default_timezone_get ();
2017-04-04 17:47:32 +00:00
}
if ( ! $viewer_tz ) {
2010-07-10 05:47:32 +00:00
$viewer_tz = date_default_timezone_get ();
2017-04-04 17:47:32 +00:00
}
2010-07-10 05:47:32 +00:00
2017-04-04 17:47:32 +00:00
$birthdate = datetime_convert ( 'UTC' , $owner_tz , $dob . ' 00:00:00+00:00' , 'Y-m-d' );
list ( $year , $month , $day ) = explode ( " - " , $birthdate );
$year_diff = datetime_convert ( 'UTC' , $viewer_tz , 'now' , 'Y' ) - $year ;
$curr_month = datetime_convert ( 'UTC' , $viewer_tz , 'now' , 'm' );
$curr_day = datetime_convert ( 'UTC' , $viewer_tz , 'now' , 'd' );
2010-07-10 05:47:32 +00:00
2017-04-04 17:47:32 +00:00
if (( $curr_month < $month ) || (( $curr_month == $month ) && ( $curr_day < $day ))) {
2010-07-10 05:47:32 +00:00
$year_diff -- ;
2017-04-04 17:47:32 +00:00
}
2016-02-03 18:48:09 +00:00
2010-07-10 05:47:32 +00:00
return $year_diff ;
}
2011-02-23 04:08:15 +00:00
2016-02-03 18:48:09 +00:00
/**
* @ brief Get days of a month in a given year .
*
* Returns number of days in the month of the given year .
* $m = 1 is 'January' to match human usage .
*
* @ param int $y Year
* @ param int $m Month ( 1 = January , 12 = December )
2017-04-30 04:29:14 +00:00
*
2016-02-03 18:48:09 +00:00
* @ return int Number of days in the given month
*/
2017-04-04 17:47:32 +00:00
function get_dim ( $y , $m ) {
2011-02-23 04:08:15 +00:00
2018-01-15 13:05:12 +00:00
$dim = [ 0 ,
2016-02-03 18:48:09 +00:00
31 , 28 , 31 , 30 , 31 , 30 ,
2018-01-15 13:05:12 +00:00
31 , 31 , 30 , 31 , 30 , 31 ];
2011-02-23 04:08:15 +00:00
2017-04-04 17:47:32 +00:00
if ( $m != 2 ) {
2016-02-03 18:48:09 +00:00
return $dim [ $m ];
2017-04-04 17:47:32 +00:00
} elseif (((( $y % 4 ) == 0 ) && (( $y % 100 ) != 0 )) || (( $y % 400 ) == 0 )) {
2016-02-03 18:48:09 +00:00
return 29 ;
2017-04-04 17:47:32 +00:00
}
2011-02-23 04:08:15 +00:00
2016-02-03 18:48:09 +00:00
return $dim [ 2 ];
}
2011-02-23 04:08:15 +00:00
2016-02-03 18:48:09 +00:00
/**
* @ brief Returns the first day in month for a given month , year .
*
* Months start at 1.
*
* @ param int $y Year
* @ param int $m Month ( 1 = January , 12 = December )
2017-04-30 04:29:14 +00:00
*
2016-02-03 18:48:09 +00:00
* @ return string day 0 = Sunday through 6 = Saturday
*/
function get_first_dim ( $y , $m ) {
$d = sprintf ( '%04d-%02d-01 00:00' , intval ( $y ), intval ( $m ));
2011-02-23 04:08:15 +00:00
2016-02-03 18:48:09 +00:00
return datetime_convert ( 'UTC' , 'UTC' , $d , 'w' );
}
2011-02-23 04:08:15 +00:00
2016-02-03 18:48:09 +00:00
/**
* @ brief Output a calendar for the given month , year .
*
* If $links are provided ( array ), e . g . $links [ 12 ] => 'http://mylink' ,
* date 12 will be linked appropriately . Today ' s date is also noted by
* altering td class .
* Months count from 1.
*
2018-01-05 00:42:48 +00:00
* @ param int $y Year
* @ param int $m Month
* @ param array $links ( default null )
2016-02-03 18:48:09 +00:00
* @ param string $class
2017-04-30 04:29:14 +00:00
*
2016-02-03 18:48:09 +00:00
* @ return string
*
* @ todo Provide ( prev , next ) links , define class variations for different size calendars
*/
2018-01-05 00:42:48 +00:00
function cal ( $y = 0 , $m = 0 , $links = null , $class = '' )
{
2011-02-23 04:08:15 +00:00
// month table - start at 1 to match human usage.
2018-01-15 13:05:12 +00:00
$mtab = [ ' ' ,
2017-04-04 17:47:32 +00:00
'January' , 'February' , 'March' ,
'April' , 'May' , 'June' ,
'July' , 'August' , 'September' ,
'October' , 'November' , 'December'
2018-01-15 13:05:12 +00:00
];
2011-02-23 04:08:15 +00:00
2018-01-05 00:42:48 +00:00
$thisyear = datetime_convert ( 'UTC' , date_default_timezone_get (), 'now' , 'Y' );
$thismonth = datetime_convert ( 'UTC' , date_default_timezone_get (), 'now' , 'm' );
if ( ! $y ) {
2011-02-23 04:08:15 +00:00
$y = $thisyear ;
2017-04-04 17:47:32 +00:00
}
2018-01-05 00:42:48 +00:00
if ( ! $m ) {
2011-02-23 04:08:15 +00:00
$m = intval ( $thismonth );
2017-04-04 17:47:32 +00:00
}
2011-02-23 04:08:15 +00:00
2018-01-15 13:05:12 +00:00
$dn = [ 'Sunday' , 'Monday' , 'Tuesday' , 'Wednesday' , 'Thursday' , 'Friday' , 'Saturday' ];
2018-01-05 00:42:48 +00:00
$f = get_first_dim ( $y , $m );
$l = get_dim ( $y , $m );
2016-02-03 18:48:09 +00:00
$d = 1 ;
$dow = 0 ;
$started = false ;
2011-02-23 04:08:15 +00:00
2017-04-04 17:47:32 +00:00
if (( $y == $thisyear ) && ( $m == $thismonth )) {
2017-04-04 17:47:32 +00:00
$tddate = intval ( datetime_convert ( 'UTC' , date_default_timezone_get (), 'now' , 'j' ));
2017-04-04 17:47:32 +00:00
}
2011-02-23 04:08:15 +00:00
$str_month = day_translate ( $mtab [ $m ]);
2016-02-03 18:48:09 +00:00
$o = '<table class="calendar' . $class . '">' ;
$o .= " <caption> $str_month $y </caption><tr> " ;
2017-04-04 17:47:32 +00:00
for ( $a = 0 ; $a < 7 ; $a ++ ) {
2017-04-04 17:47:32 +00:00
$o .= '<th>' . mb_substr ( day_translate ( $dn [ $a ]), 0 , 3 , 'UTF-8' ) . '</th>' ;
2017-04-04 17:47:32 +00:00
}
2016-02-03 18:48:09 +00:00
$o .= '</tr><tr>' ;
2017-04-04 17:47:32 +00:00
while ( $d <= $l ) {
2018-01-05 03:51:38 +00:00
if (( $dow == $f ) && ( ! $started )) {
$started = true ;
}
2016-02-03 18:48:09 +00:00
$today = ((( isset ( $tddate )) && ( $tddate == $d )) ? " class= \" today \" " : '' );
$o .= " <td $today > " ;
2017-04-04 17:47:32 +00:00
$day = str_replace ( ' ' , ' ' , sprintf ( '%2.2d' , $d ));
2017-04-04 17:47:32 +00:00
if ( $started ) {
2018-01-05 00:42:48 +00:00
if ( x ( $links , $d ) !== false ) {
$o .= " <a href= \" { $links [ $d ] } \" > $day </a> " ;
2017-04-04 17:47:32 +00:00
} else {
2016-02-03 18:48:09 +00:00
$o .= $day ;
2017-04-04 17:47:32 +00:00
}
2011-10-14 07:20:37 +00:00
2016-02-03 18:48:09 +00:00
$d ++ ;
} else {
$o .= ' ' ;
}
$o .= '</td>' ;
$dow ++ ;
2017-04-04 17:47:32 +00:00
if (( $dow == 7 ) && ( $d <= $l )) {
2016-02-03 18:48:09 +00:00
$dow = 0 ;
$o .= '</tr><tr>' ;
}
}
2017-04-04 17:47:32 +00:00
if ( $dow ) {
for ( $a = $dow ; $a < 7 ; $a ++ ) {
2016-02-03 18:48:09 +00:00
$o .= '<td> </td>' ;
2017-04-04 17:47:32 +00:00
}
}
2011-10-14 07:20:37 +00:00
2018-01-05 00:42:48 +00:00
$o .= '</tr></table>' . " \r \n " ;
2016-02-03 18:48:09 +00:00
return $o ;
}
/**
* @ brief Create a birthday event .
*
* Update the year and the birthday .
*/
2011-10-14 07:20:37 +00:00
function update_contact_birthdays () {
// This only handles foreign or alien networks where a birthday has been provided.
// In-network birthdays are handled within local_delivery
2017-04-04 17:47:32 +00:00
$r = q ( " SELECT * FROM `contact` WHERE `bd` != '' AND `bd` > '0001-01-01' AND SUBSTRING(`bd`, 1, 4) != `bdyear` " );
2017-11-08 03:57:46 +00:00
if ( DBM :: is_result ( $r )) {
2016-12-20 20:13:50 +00:00
foreach ( $r as $rr ) {
2011-10-14 07:20:37 +00:00
logger ( 'update_contact_birthday: ' . $rr [ 'bd' ]);
2017-04-04 17:47:32 +00:00
$nextbd = datetime_convert ( 'UTC' , 'UTC' , 'now' , 'Y' ) . substr ( $rr [ 'bd' ], 4 );
2011-10-14 07:20:37 +00:00
2017-04-04 17:47:32 +00:00
/*
2011-10-14 07:20:37 +00:00
* Add new birthday event for this person
*
* $bdtext is just a readable placeholder in case the event is shared
* with others . We will replace it during presentation to our $importer
2015-10-17 08:48:13 +00:00
* to contain a sparkle link and perhaps a photo .
2011-10-14 07:20:37 +00:00
*/
2015-10-17 08:48:13 +00:00
2017-01-27 17:04:52 +00:00
// Check for duplicates
$s = q ( " SELECT `id` FROM `event` WHERE `uid` = %d AND `cid` = %d AND `start` = '%s' AND `type` = '%s' LIMIT 1 " ,
intval ( $rr [ 'uid' ]),
intval ( $rr [ 'id' ]),
dbesc ( datetime_convert ( 'UTC' , 'UTC' , $nextbd )),
dbesc ( 'birthday' ));
2017-11-08 03:57:46 +00:00
if ( DBM :: is_result ( $s )) {
2017-01-27 17:04:52 +00:00
continue ;
}
2018-01-24 02:59:16 +00:00
$bdtext = L10n :: t ( '%s\'s birthday' , $rr [ 'name' ]);
$bdtext2 = L10n :: t ( 'Happy Birthday %s' , ' [url=' . $rr [ 'url' ] . ']' . $rr [ 'name' ] . '[/url]' );
2011-10-14 07:20:37 +00:00
2018-01-04 02:12:19 +00:00
q ( " INSERT INTO `event` (`uid`,`cid`,`created`,`edited`,`start`,`finish`,`summary`,`desc`,`type`,`adjust`)
2012-06-26 04:37:38 +00:00
VALUES ( % d , % d , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%s' , '%d' ) " ,
2011-10-14 07:20:37 +00:00
intval ( $rr [ 'uid' ]),
intval ( $rr [ 'id' ]),
dbesc ( datetime_convert ()),
dbesc ( datetime_convert ()),
dbesc ( datetime_convert ( 'UTC' , 'UTC' , $nextbd )),
dbesc ( datetime_convert ( 'UTC' , 'UTC' , $nextbd . ' + 1 day ' )),
dbesc ( $bdtext ),
2012-06-26 04:37:38 +00:00
dbesc ( $bdtext2 ),
2011-10-14 07:20:37 +00:00
dbesc ( 'birthday' ),
intval ( 0 )
);
2014-03-11 22:52:32 +00:00
2011-10-14 07:20:37 +00:00
// update bdyear
2014-03-11 22:52:32 +00:00
q ( " UPDATE `contact` SET `bdyear` = '%s', `bd` = '%s' WHERE `uid` = %d AND `id` = %d " ,
2011-10-14 07:20:37 +00:00
dbesc ( substr ( $nextbd , 0 , 4 )),
dbesc ( $nextbd ),
intval ( $rr [ 'uid' ]),
intval ( $rr [ 'id' ])
);
}
}
2012-01-02 19:09:25 +00:00
}