Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

PHP/MySQL problem med timestamp

0 views
Skip to first unread message

Dennis Munding

unread,
Jan 13, 2018, 8:54:55 AM1/13/18
to

Hej!

Jeg er i gang med at lave en hjemmeside for nogle online-gamere og i
den forbindelse, er jeg stødt på et "lille" problem.

Ejeren af siden vil gerne have vist en fejring af "jubilæer" i klanen
på siden. Ikke noget problem.

Problemet består i, at han gerne vil have det vist på selve dagen og en
uge frem.
Det er "intervallet" af jubilæer, der knækker mig: 1, 3, 6, 9 og 18
mdr. samt årligt.
Havde det kun været årligt ville jeg nok selv kunne løse det, men jeg
har fået stirret mig blind.

Min php-kode til funktionen ser således ud:

<CODE>
function test_celebrate_medlem() {
global $connect;

// HENT ALLE MEDLEMMER MED UNDTAGELSE AF DUMMIES
$res = $connect->query("SELECT * FROM medlemmer WHERE NOT spillerID
REGEXP '^Dummy[0-9]$'");

if(!$res) {
die("Noget gik galt.<br />" . mysqli_error($connect));
}

$i = 1;
while($data = $res->fetch_assoc()) {
// MILEPÆLE DER SKAL FEJRES - I MÅNEDER.
$jubi = array('1', '3', '6', '9', '18');

// DAGS DATO HENTES OG OPDELES TIL VIDERE BEREGNING
$DD = strtotime(date("d-m-Y"));
$dagDD = date("j");
$mdrDD = date("n");
$aarDD = date("Y");
$iDag = date($dagDD.'/'.$mdrDD);

// DATAUDTRÆK FRA DATABASEN
$spillerID = $data['spillerID'];
$klan = $data['klan'];
$indmeldt = $data['indmeldt']; // TIMESTAMP

// OPDELING AF INDMELDSESDATO TIL BEREGNINGER.
$indArr = explode("-", date('j-n-Y', $indmeldt));
$indDag = $indArr[0];
$indMdr = $indArr[1];
$indAar = $indArr[2];

// BEREGNING AF ANTAL MÅNEDER
$jubi_mdr = $mdrDD - $indMdr;

// BEREGNING AF ANTAL ÅR
$jubi_aar = $aarDD - $indAar;

// VARIABLE TIL JUBILÆUMS-TEKST
$msg = "";

// STYLING AF OUTPUT
$class = ($i < 3) ? "col50" : "col1-3";

// DAGS DATO TJEKKES OP MOD INDMELDELSESDATOEN
if($dagDD == $indDag) { // HVIS SAMME DAG
if($mdrDD == $indMdr) { // HVIS SAMME MÅNED
if($aarDD == $indAar) { // HVIS SAMME ÅR = 0 DAGE I KLANEN
continue; // SPRING VIDERE TIL NÆSTE MEDLEM
} elseif($jubi_aar > 0) { // ÅRSDAG FOR MEDLEMSKAB - UDSKRIV
LYKØNSKNING
$msg .= "<div class='".$class." celebox'>
<h2><span class='celebrate'>T I L L Y K K E</span><br />
til <span class='celebrate'>".$spillerID."</span> med<br />
<span class='celebrate'>".$jubi_aar." års</span> medlemskab i
<span class='celebrate'>".$klan."</span>!</h2>
</div>";
}
} else { // ER DER EN MÅNEDSDAG, DER SKAL FEJRES?
// Hvis antallet af måneder er negativt, skal der lægges X år *
12 mdr til.
if($jubi_mdr < 0 && $jubi_aar > 0) {
$jubi_mdr = ($jubi_aar * 12) + $jubi_mdr;
}

// VARIABLE TIL KORREKT BENÆVNELSE
$mdrExt = ($jubi_mdr != 1) ? "måneders" : "måneds";

// TJEK OM ANTALLET AF MDR. ER EN AF DE DEFINEREDE FEJRINGER
if(in_array($jubi_mdr, $jubi)) {
// HVIS ANTAL MDR. = 18 UDSKRIVER VI 1½ ÅRS FREM FOR 18
MÅNEDERS
if($jubi_mdr == 18) {
$jubi_mdr = "1½";
$mdrExt = "års";
}
// UDSKRIV MÅNEDS-LYKØNSKNING
$msg .= "<div class='".$class." celebox'>
<h2><span class='celebrate'>T I L L Y K K E</span><br />
til <span class='celebrate'>".$spillerID."</span> med<br />
<span class='celebrate'>".$jubi_mdr." ".$mdrExt."</span>
medlemskab i <span class='celebrate'>".$klan."</span>!</h2>
</div>";
}
}
}

echo $msg;

$i++;
}
}

</CODE>

Det fungerer glimrende på selve dagen, som I kan se her -
http://1dpb.dk/?side=test - men jeg kan ikke gennemskue, hvordan jeg
får min "mission" til at lykkes...


Indmeldelsestidspunktet ($indmeldt) indsættes som timestamp ved hjælp
af strtotime() funktionen, hvis det er en hjælp.


Alle konstruktive indspark (også til evt. optimering af ovenstående
kode) modtages med taknemmelighed. :-)


--
Med venlig hilsen

Dennis Munding

Dennis Munding

unread,
Jan 13, 2018, 9:44:39 AM1/13/18
to
Ved ikke lige hvorfor dette indlæg ikke blev postet i PHP-gruppen også
- derfor FUT dertil...

Arne Vajhøj

unread,
Jan 13, 2018, 2:42:38 PM1/13/18
to
On 1/13/2018 8:54 AM, Dennis Munding wrote:
> Jeg er i gang med at lave en hjemmeside for nogle online-gamere og i
> den forbindelse, er jeg stødt på et "lille" problem.
>
> Ejeren af siden vil gerne have vist en fejring af "jubilæer" i klanen
> på siden. Ikke noget problem.
>
> Problemet består i, at han gerne vil have det vist på selve dagen og en
> uge frem.
> Det er "intervallet" af jubilæer, der knækker mig: 1, 3, 6, 9 og 18
> mdr. samt årligt.
> Havde det kun været årligt ville jeg nok selv kunne løse det, men jeg
> har fået stirret mig blind.
>
> Min php-kode til funktionen ser således ud:

> Det fungerer glimrende på selve dagen, som I kan se her -
> http://1dpb.dk/?side=test - men jeg kan ikke gennemskue, hvordan jeg
> får min "mission" til at lykkes...
>
> Indmeldelsestidspunktet ($indmeldt) indsættes som timestamp ved hjælp
> af strtotime() funktionen, hvis det er en hjælp.
>
> Alle konstruktive indspark (også til evt. optimering af ovenstående
> kode) modtages med taknemmelighed. :-)

Hvordan jeg ville angribe problemet:

<?php
class AnniversaryPolicyItem {
public $descrip;
public $interval;
public function __construct($descrip, $interval) {
$this->descrip = $descrip;
$this->interval = $interval;
}
}

class AnniversaryPolicy {
private $before;
private $after;
private $format;
private $annlist;
public function __construct($daysbefore, $daysafter, $format =
'd/m/Y') {
$this->before = new DateInterval('P' . $daysbefore . 'D');
$this->after = new DateInterval('P' . $daysafter . 'D');
$this->format = $format;
$this->annlist = array();
}
public function add($descrip, $interval) {
$this->annlist[] = new AnniversaryPolicyItem($descrip, new
DateInterval($interval));
}
public function getAnniversary($ts) {
$now = new DateTime();
$t1 = $now->sub($this->before);
$t1->setTime(0, 0, 0);
$now = new DateTime();
$t2 = $now->add($this->after);
$t2->setTime(23, 59, 59);
foreach($this->annlist as $annitem) {
$tsdt = new DateTime();
$tsdt->setTimestamp($ts);
$anntim = $tsdt->add($annitem->interval);
if($t1->getTimestamp() <= $anntim->getTimestamp() &&
$anntim->getTimestamp() <= $t2->getTimestamp()) {
return $annitem->descrip . ' ' .
$anntim->format($this->format);
}
}
return null;
}
}

function test($annpol, $ts) {
$ann = $annpol->getAnniversary($ts);
if($ann != null) {
echo "$ann\r\n";
} else {
echo "No anniversary\r\n";
}
}

$annpol = new AnniversaryPolicy(2, 2);
$annpol->add('1 year anniversay', 'P1Y');
$annpol->add('3 months anniversary', 'P3M');
$annpol->add('1 month anniversary', 'P1M');

test($annpol, time() - 28*24*60*60);
test($annpol, time() - 31*24*60*60);
test($annpol, time() - 34*24*60*60);
test($annpol, time() - 82*24*60*60);
test($annpol, time() - 92*24*60*60);
test($annpol, time() - 102*24*60*60);
test($annpol, time() - 255*24*60*60);
test($annpol, time() - 365*24*60*60);
test($annpol, time() - 375*24*60*60);

?>

Arne


Dennis Munding

unread,
Jan 15, 2018, 11:41:06 AM1/15/18
to
Arne Vajhøj wrote:

> On 1/13/2018 8:54 AM, Dennis Munding wrote:
> > Problemet består i, at han gerne vil have det vist på selve dagen
> > og en uge frem.
> > Det er "intervallet" af jubilæer, der knækker mig: 1, 3, 6, 9 og 18
> > mdr. samt årligt.

>
> Hvordan jeg ville angribe problemet:
>
> <?php
> class AnniversaryPolicyItem {
> public $descrip;
> public $interval;
> public function __construct($descrip, $interval) {
> $this->descrip = $descrip;
> $this->interval = $interval;
> }
> }

... [KODE-BLOKKE fjernet af hensyn til læsbarhed] ...

> ?>


Hej Arne,

Jeg glemte vist at nævne, at jeg stadig er en novice, når det kommer
til php - har aldrig arbejdet med class - men én gang skal jo være den
første. :-)

Giv mig lige nogle dage til at forstå dit forslag (hvis jeg kan), så
skal jeg nok vende tilbage.

Foreløbig tak for det detaljerede svar (omend jeg ikke helt ved,
hvordan jeg skal få det til at spille sammen med min egen kode. Men så
er det godt, at vejret er til aftener foran pc'en.) :-)

Arne Vajhøj

unread,
Jan 15, 2018, 11:52:57 AM1/15/18
to
On 1/15/2018 11:41 AM, Dennis Munding wrote:
> Arne Vajhøj wrote:
>> On 1/13/2018 8:54 AM, Dennis Munding wrote:
>>> Problemet består i, at han gerne vil have det vist på selve dagen
>>> og en uge frem.
>>> Det er "intervallet" af jubilæer, der knækker mig: 1, 3, 6, 9 og 18
>>> mdr. samt årligt.
>
>> Hvordan jeg ville angribe problemet:

> ... [KODE-BLOKKE fjernet af hensyn til læsbarhed] ...

> Jeg glemte vist at nævne, at jeg stadig er en novice, når det kommer
> til php - har aldrig arbejdet med class - men én gang skal jo være den
> første. :-)
>
> Giv mig lige nogle dage til at forstå dit forslag (hvis jeg kan), så
> skal jeg nok vende tilbage.
>
> Foreløbig tak for det detaljerede svar (omend jeg ikke helt ved,
> hvordan jeg skal få det til at spille sammen med min egen kode. Men så
> er det godt, at vejret er til aftener foran pc'en.) :-)

Nu er jeg heller ikke PHP guru. Onde tunger vil påstå at jeg
programmerer Java i PHP.

:-)

Jeg kunne godt indsætte nogle kommentarer i kodeb, hvis det
vil hælpe dig til at forstå den.

Arne


Dennis Munding

unread,
Jan 16, 2018, 4:27:42 PM1/16/18
to
Arne Vajhøj wrote:


> Nu er jeg heller ikke PHP guru. Onde tunger vil påstå at jeg
> programmerer Java i PHP.
>
> :-)
>
> Jeg kunne godt indsætte nogle kommentarer i kodeb, hvis det
> vil hælpe dig til at forstå den.


Det vil jeg da ikke takke nej til. :-)

Arne Vajhøj

unread,
Jan 16, 2018, 7:56:46 PM1/16/18
to
On 1/16/2018 4:27 PM, Dennis Munding wrote:
> Arne Vajhøj wrote:
>> Nu er jeg heller ikke PHP guru. Onde tunger vil påstå at jeg
>> programmerer Java i PHP.
>>
>> :-)
>>
>> Jeg kunne godt indsætte nogle kommentarer i kodeb, hvis det
>> vil hælpe dig til at forstå den.
>
>
> Det vil jeg da ikke takke nej til. :-)

<?php
/**
* Class AnniversaryPolicyItem hold information about a single
anniversary item:
* - textual description
* - interval that triggers anniversary
*/
class AnniversaryPolicyItem {
public $descrip;
public $interval;
/**
* Constrcut instance.
* @param string $descrip textual description
* @param DateInterval $interval interval that triggers anniversary
*/
public function __construct($descrip, $interval) {
$this->descrip = $descrip;
$this->interval = $interval;
}
}

/**
* Class AnniversaryPolicy holds multiple instances of
AnniversaryPolicyItem
* and can test if a given start date has any anniversaries.
* @author arne
*
*/
class AnniversaryPolicy {
private $before;
private $after;
private $format;
private $annlist;
/**
* Construct instance.
* @param integer $daysbefore number of days before actual
anniversary to start triggering
* @param integer $daysafter number of days after actual
anniversary to start triggering
* @param string $format dormat to use to displayt date
*/
public function __construct($daysbefore, $daysafter, $format =
'd/m/Y') {
$this->before = new DateInterval('P' . $daysbefore . 'D');
$this->after = new DateInterval('P' . $daysafter . 'D');
$this->format = $format;
$this->annlist = array();
}
/**
* Add interval that triggers anniversary.
* @param string $descrip textual description
* @param DateInterval $interval interval that triggers anniversary
*/
public function add($descrip, $interval) {
$this->annlist[] = new AnniversaryPolicyItem($descrip, new
DateInterval($interval));
}
/**
* Get any anniversary for the specified start date
* @param integer $ts start date as Unix timestamp (seconds since
1/1/1970)
* @return string|NULL anniversary information if any, null of no
anniversary
*/
public function getAnniversary($ts) {
// construct range $t1 .. $t2 where actual anniversay has to be
in to trigger anniversary display, basically:
// $t1 = now - before days, adjusted to start of day
// $t2 = now - after days, adjusted to end of day
$now = new DateTime();
$t1 = $now->sub($this->before);
$t1->setTime(0, 0, 0);
$now = new DateTime();
$t2 = $now->add($this->after);
$t2->setTime(23, 59, 59);
// loop through all anniversary items
foreach($this->annlist as $annitem) {
// calculate actual anniversary time
// $tsdt = start date + interval from anniversary item
$tsdt = new DateTime();
$tsdt->setTimestamp($ts);
$anntim = $tsdt->add($annitem->interval);
// test if $tsdt is in range $t1 .. $t2 and if so return
anniversary description and date
if($t1->getTimestamp() <= $anntim->getTimestamp() &&
$anntim->getTimestamp() <= $t2->getTimestamp()) {
return $annitem->descrip . ' ' .
$anntim->format($this->format);
}
}
// no anniversaries found so return null
return null;
}
}

// demo code:

Jan Hansen

unread,
Jan 16, 2018, 10:26:38 PM1/16/18
to
Jeg gætter på, at det TIMESTAMP er af formatet
'2017-12-16 00:00:00'
jeg ville lave det med den her "tjekjubi"-funktion:

<?php
// Medlemmer til testbrug:
$medlemmer = Array();
$medlemmer[] = Array('navn' => 'Arne', 'indmeldt' => '2017-10-11 23:59:59');
$medlemmer[] = Array('navn' => 'Børge', 'indmeldt' => '2017-12-16 00:00:00');
$medlemmer[] = Array('navn' => 'Carl', 'indmeldt' => '2016-01-14 23:59:59');
$medlemmer[] = Array('navn' => 'Dennis','indmeldt' => '2012-01-17 23:59:59');

// Løkke til brug med testmedlemmerne
foreach ($medlemmer as $aktuel) {
if ($jubi = tjekjubi($aktuel['indmeldt'])) {
if ($jubi%12==0) {
$jubi_mdr = $jubi/12; $mdrExt = "års";
} else {
$jubi_mdr = $jubi; $mdrExt = ($jubi == 1) ? "måneds" : "måneders";
}
echo $aktuel['navn'].' har '.$jubi_mdr.' '.$mdrExt.' jubilæum<br>';
} }

// Og så funktionen:
function tjekjubi($timestamp) {
$temp=explode("-",substr($timestamp,0,strpos($timestamp,' ')));
// hvis der er fejl i datoen, return false
if (count($temp)!=3) return false;
// navne, der er nemmere at overskue:
$aar = $temp[0]; $md = $temp[1]; $dag = $temp[2];
$idag = mktime(23,59,59);
// For 7 dage siden
$sidsteuge = $idag-(7*86400);
$aktueltaar = date("Y");
// Års-jubilæum
$temp = mktime(0,0,0,$md,$dag,$aktueltaar);
if ($temp > $sidsteuge && $temp <= $idag) return (12*($aktueltaar-$aar));
// Måneds jubi
$mdjubi=array(18, 9, 6, 3, 1);
foreach ($mdjubi as $jubi) {
$temp = mktime(0,0,0,$md+$jubi,$dag,$aar);
// Hvis tiden er udløbet, return false
if ($temp < $sidsteuge) return false;
// ...ellers er tiden > sidste uge, hvis <= idag return måneder
if ($temp <= $idag) return ($jubi);
} // videre til test af næste jubilæumsmåned
// Her må medlemskab være mindre end 1 måned, return false
return false;
}
?>



--
mvh Jan.
Help Microsoft stamp out piracy. Give
Linux to a friend today!

Jan Hansen

unread,
Jan 16, 2018, 11:32:27 PM1/16/18
to
Der var jeg et nummer for hurtig, det viste er år for meget, hvis et
medlem er indmeldt lige inden nytår, og vises på siden efter nytår.
Her er den lappede udgave:
// Træk et år fra aktuel, hvis indmeldelse er på den anden side af nytår
if ($md==12 && date("n")==1) $aktueltaar--;

Jan Hansen

unread,
Jan 16, 2018, 11:42:41 PM1/16/18
to
Det går godt på denne tid af dagen, det her virker også omkring nytår:
// Træk et år fra aktuel, hvis indmeldelse er på den anden side af nytår
if ($md==12 && date("n")==1) $aktueltaar--;

Dennis Munding

unread,
Jan 17, 2018, 5:15:50 AM1/17/18
to
Jan Hansen wrote:

> Jeg gætter på, at det TIMESTAMP er af formatet
> '2017-12-16 00:00:00'
> jeg ville lave det med den her "tjekjubi"-funktion:

[SNIP - KODE]

Beklager - du gættede forkert... ;-)

Det er lidt mere simpelt, da det indsættes i db således:
strtotime("dd-mm-åååå")

Tidspunktet på dagen er uvæsentligt for os. :-)

Men tak for indsparket - jeg kigger din ver.3 igennem og vender
tilbage, når jeg har testet det. :-)

Jan Hansen

unread,
Jan 17, 2018, 7:28:04 AM1/17/18
to
Dennis Munding skrev:

> Beklager - du gættede forkert... ;-)
>
> Det er lidt mere simpelt, da det indsættes i db således:
> strtotime("dd-mm-åååå")

Ja, det burde jeg have lagt mærke til i din kode,
$indArr = explode("-", date('j-n-Y', $indmeldt));

Jeg har rettet tjekjubi til det indput:

<?php
// Medlemmer til testbrug:
$medlemmer = Array();
$medlemmer[] = Array('navn' => 'Arne', 'indmeldt' => strtotime('2017-07-11 23:59:59'));
$medlemmer[] = Array('navn' => 'Børge', 'indmeldt' => strtotime('2017-12-17 00:00:00'));
$medlemmer[] = Array('navn' => 'Carl', 'indmeldt' => strtotime('2016-01-14 23:59:59'));
$medlemmer[] = Array('navn' => 'Dennis','indmeldt' => strtotime('2012-01-17 23:59:59'));

// Løkke til brug med testmedlemmerne
foreach ($medlemmer as $aktuel) {
if ($jubi = tjekjubi($aktuel['indmeldt'])) {
if ($jubi%12==0) {
$jubi_mdr = $jubi/12; $mdrExt = "års";
} else {
$jubi_mdr = $jubi; $mdrExt = ($jubi == 1) ? "måneds" : "måneders";
}
echo $aktuel['navn'].' har '.$jubi_mdr.' '.$mdrExt.' jubilæum<br>';
} }

// Og så funktionen:
function tjekjubi($indmeldt) {
list ($dag, $md, $aar) = explode("-", date("j-n-Y",$indmeldt) );
$idag = mktime(23,59,59);
// For 7 dage siden
$sidsteuge = $idag-(7*86400);
$aktueltaar = date("Y");
// Træk et år fra aktuel, hvis indmeldelse er på den anden side af nytår
if ($md==12 && date("n")==1) $aktueltaar--;
// Års-jubilæum
$temp = mktime(0,0,0,$md,$dag,$aktueltaar);
if ($temp > $sidsteuge && $temp <= $idag) return (12*($aktueltaar-$aar));
// Måneds jubi
$mdjubi=array(18, 9, 6, 3, 1); // jubilæumsmåneder

Dennis Munding

unread,
Jan 20, 2018, 9:27:32 AM1/20/18
to
Jan Hansen wrote:

> Dennis Munding skrev:
>
> > Beklager - du gættede forkert... ;-)
> >
> > Det er lidt mere simpelt, da det indsættes i db således:
> > strtotime("dd-mm-åååå")
>
> Ja, det burde jeg have lagt mærke til i din kode,
> $indArr = explode("-", date('j-n-Y', $indmeldt));
>
> Jeg har rettet tjekjubi til det indput:


[SNIP - KODE]
...
> $idag = mktime(23,59,59);
...
[SNIP - KODE]


Tusind tak Jan!

Dit forslag vandt i lodtrækningen (jeg er for grøn i php til at bruge
Arnes, som jeg dog vil gemme til læring. :-)).

Tog mig lidt tid at få det til at virke (igen fordi jeg er en "noob")
og så måtte jeg lige ændre en enkelt variable - $idag.

Den satte jeg = strtotime(date("j-n-Y")), da jeg ellers ikke ville få
alle de ønskede rækker med.
0 new messages