Calendario Eventi ricorrenti / ripetuti - Metodo di archiviazione ottimale


311

Sto creando un sistema di eventi personalizzato e se hai un evento ripetuto che assomiglia a questo:

L'evento A si ripete ogni 4 giorni a partire dal 3 marzo 2011

o

L'evento B si ripete ogni 2 settimane martedì a partire dal 1 marzo 2011

Come posso archiviarlo in un database in modo da rendere semplice la ricerca. Non desidero problemi di prestazioni se ci sono molti eventi e devo eseguire il rendering di ognuno di essi durante il rendering del calendario.


Puoi spiegare perché 1299132000 è codificato? Che cosa farà se devo ottenere le date dell'evento e l'utente per la data di fine indicata?
Murali Murugesan,

@Murali Boy questo è vecchio, ma sono abbastanza sicuro che 1299132000 dovrebbe essere la data corrente.
Brandon Wamboldt,

@BrandonWamboldt, ho provato la tua idea con SQL Server. stackoverflow.com/questions/20286332/display-next-event-date . Voglio trovare tutti i prossimi articoli come la versione c #
Billa,

Risposte:


211

Memorizzazione di ripetizioni "semplici"

Per il mio calendario basato su PHP / MySQL, volevo memorizzare le informazioni sugli eventi ricorrenti / ricorrenti nel modo più efficiente possibile. Non volevo avere un gran numero di righe e volevo facilmente cercare tutti gli eventi che avrebbero avuto luogo in una data specifica.

Il metodo seguente è ottimo per archiviare le informazioni ripetute che si verificano a intervalli regolari, come ogni giorno, ogni n giorni, ogni settimana, ogni mese ogni anno, ecc. Ecc. Questo include anche i modelli di tipo ogni martedì e giovedì, perché sono memorizzati separatamente come ogni settimana a partire da un martedì e ogni settimana a partire da un giovedì.

Supponendo che ho due tavoli, uno chiamato in eventsquesto modo:

ID    NAME
1     Sample Event
2     Another Event

E un tavolo chiamato events_metacosì:

ID    event_id      meta_key           meta_value
1     1             repeat_start       1299132000
2     1             repeat_interval_1  432000

Con repeat_start è una data senza ora come timestamp unix e repeat_interval un importo in secondi tra gli intervalli (432000 è 5 giorni).

repeat_interval_1 corrisponde a repeat_start dell'ID 1. Quindi se ho un evento che si ripete ogni martedì e ogni giovedì, repeat_interval sarebbe 604800 (7 giorni) e ci sarebbero 2 repeat_start e 2 repeat_intervals. La tabella sarebbe simile a questa:

ID    event_id      meta_key           meta_value
1     1             repeat_start       1298959200 -- This is for the Tuesday repeat
2     1             repeat_interval_1  604800
3     1             repeat_start       1299132000 -- This is for the Thursday repeat
4     1             repeat_interval_3  604800
5     2             repeat_start       1299132000
6     2             repeat_interval_5  1          -- Using 1 as a value gives us an event that only happens once

Quindi, se hai un calendario che scorre ogni giorno, afferrando gli eventi per il giorno in cui si trova, la query sarebbe simile a questa:

SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
RIGHT JOIN `events_meta` EM2 ON EM2.`meta_key` = CONCAT( 'repeat_interval_', EM1.`id` )
WHERE EM1.meta_key = 'repeat_start'
    AND (
        ( CASE ( 1299132000 - EM1.`meta_value` )
            WHEN 0
              THEN 1
            ELSE ( 1299132000 - EM1.`meta_value` )
          END
        ) / EM2.`meta_value`
    ) = 1
LIMIT 0 , 30

Sostituendo {current_timestamp}con il timestamp unix per la data corrente (meno l'ora, quindi i valori di ora, minuti e secondi sarebbero impostati su 0).

Spero che questo possa aiutare anche qualcun altro!


Memorizzazione di motivi ripetitivi "complessi"

Questo metodo è più adatto per la memorizzazione di modelli complessi come

Event A repeats every month on the 3rd of the month starting on March 3, 2011

o

Event A repeats Friday of the 2nd week of the month starting on March 11, 2011

Consiglierei di combinarlo con il sistema sopra per la massima flessibilità. Le tabelle per questo dovrebbero essere come:

ID    NAME
1     Sample Event
2     Another Event

E un tavolo chiamato events_metacosì:

ID    event_id      meta_key           meta_value
1     1             repeat_start       1299132000 -- March 3rd, 2011
2     1             repeat_year_1      *
3     1             repeat_month_1     *
4     1             repeat_week_im_1   2
5     1             repeat_weekday_1   6

repeat_week_imrappresenta la settimana del mese corrente, che potrebbe essere potenzialmente compresa tra 1 e 5. repeat_weekdaynel giorno della settimana, 1-7.

Ora supponendo che si stiano ripetendo i giorni / le settimane per creare una vista mensile nel calendario, è possibile comporre una query come questa:

SELECT EV . *
FROM `events` AS EV
JOIN `events_meta` EM1 ON EM1.event_id = EV.id
AND EM1.meta_key = 'repeat_start'
LEFT JOIN `events_meta` EM2 ON EM2.meta_key = CONCAT( 'repeat_year_', EM1.id )
LEFT JOIN `events_meta` EM3 ON EM3.meta_key = CONCAT( 'repeat_month_', EM1.id )
LEFT JOIN `events_meta` EM4 ON EM4.meta_key = CONCAT( 'repeat_week_im_', EM1.id )
LEFT JOIN `events_meta` EM5 ON EM5.meta_key = CONCAT( 'repeat_weekday_', EM1.id )
WHERE (
  EM2.meta_value =2011
  OR EM2.meta_value = '*'
)
AND (
  EM3.meta_value =4
  OR EM3.meta_value = '*'
)
AND (
  EM4.meta_value =2
  OR EM4.meta_value = '*'
)
AND (
  EM5.meta_value =6
  OR EM5.meta_value = '*'
)
AND EM1.meta_value >= {current_timestamp}
LIMIT 0 , 30

Questo combinato con il metodo sopra potrebbe essere combinato per coprire la maggior parte dei modelli di eventi ricorrenti / ricorrenti. Se ho perso qualcosa, per favore lascia un commento.


1
Sto provando i tuoi pattern ripetitivi "semplici" di memorizzazione. se devo ripeterlo ogni settimana martedì, devo modificare repeat_start o creare un nuovo record con l'ultima data. o c'è un modo per ripeterlo ogni settimana in base al primo repeat_start ???
gabinetto

1
La tua risposta è stata di grande aiuto @roguecoder ma non ha funzionato del tutto ... Ho trovato la mia risposta dopo questo post: stackoverflow.com/questions/10545869/…
Ben Sinclair,

1
In AND ( ( CASE ( 1299132000 - EM1.meta_value ) WHEN 0 THEN 1 ELSE ( 1299132000 - EM1.meta_value) END ) / EM2.meta_value ) = 1questo è / EM2.meta_valueposto in modo errato?
Murali Murugesan,

1
Questo è di grande aiuto. Come suggeriresti di accedere a questi come singoli record, ad esempio, se volessi avere commenti o check-in su singoli eventi?
johnrees,

26
Vale la pena notare che non si dovrebbero usare valori hardcoded per intervalli di ripetizione, cioè 86400secondi in un giorno, perché non tiene conto dell'ora legale. È più appropriato calcolare queste cose dinamicamente al volo e invece memorizzare interval = dailye interval_count = 1o interval = monthlye interval_count = 1.
Corey Ballou,

185

Mentre la risposta attualmente accettata mi è stata di grande aiuto, volevo condividere alcune utili modifiche che semplificano le query e aumentano anche le prestazioni.


Eventi semplici "ripetuti"

Per gestire eventi che si ripetono a intervalli regolari, come:

Repeat every other day 

o

Repeat every week on Tuesday 

Dovresti creare due tabelle, una chiamata in eventsquesto modo:

ID    NAME
1     Sample Event
2     Another Event

E un tavolo chiamato events_metacosì:

ID    event_id      repeat_start       repeat_interval
1     1             1369008000         604800            -- Repeats every Monday after May 20th 2013
1     1             1369008000         604800            -- Also repeats every Friday after May 20th 2013

Con repeat_startessendo una data timestamp unix senza tempo (1369008000 corrisponde al 20 maggio 2013), e repeat_intervaluna quantità in secondi tra intervalli (604800 è di 7 giorni).

Effettuando il ciclo ogni giorno del calendario puoi ottenere eventi di ripetizione usando questa semplice query:

SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
WHERE  (( 1299736800 - repeat_start) % repeat_interval = 0 )

È sufficiente sostituire il timestamp unix (1299736800) per ciascuna data del calendario.

Nota l'uso del modulo (segno%). Questo simbolo è come una divisione regolare, ma restituisce il '' resto '' invece del quoziente, e come tale è 0 ogni volta che la data corrente è un multiplo esatto dell'intervallo di ripetizione da repeat_start.

Confronto delle prestazioni

Questo è significativamente più veloce della risposta basata su "meta_keys" precedentemente suggerita, che era la seguente:

SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
RIGHT JOIN `events_meta` EM2 ON EM2.`meta_key` = CONCAT( 'repeat_interval_', EM1.`id` )
WHERE EM1.meta_key = 'repeat_start'
    AND (
        ( CASE ( 1299132000 - EM1.`meta_value` )
            WHEN 0
              THEN 1
            ELSE ( 1299132000 - EM1.`meta_value` )
          END
        ) / EM2.`meta_value`
    ) = 1

Se esegui EXPLAIN questa query, noterai che è richiesto l'uso di un buffer di join:

+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref              | rows | Extra                          |
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+
|  1 | SIMPLE      | EM1   | ALL    | NULL          | NULL    | NULL    | NULL             |    2 | Using where                    |
|  1 | SIMPLE      | EV    | eq_ref | PRIMARY       | PRIMARY | 4       | bcs.EM1.event_id |    1 |                                |
|  1 | SIMPLE      | EM2   | ALL    | NULL          | NULL    | NULL    | NULL             |    2 | Using where; Using join buffer |
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+--------------------------------+

La soluzione con 1 join sopra non richiede tale buffer.


Pattern "complessi"

È possibile aggiungere il supporto per tipi più complessi per supportare questi tipi di regole di ripetizione:

Event A repeats every month on the 3rd of the month starting on March 3, 2011

o

Event A repeats second Friday of the month starting on March 11, 2011

La tabella degli eventi può essere esattamente la stessa:

ID    NAME
1     Sample Event
2     Another Event

Quindi per aggiungere il supporto per queste regole complesse aggiungi le colonne in questo events_metamodo:

ID    event_id      repeat_start       repeat_interval    repeat_year    repeat_month    repeat_day    repeat_week    repeat_weekday
1     1             1369008000         604800             NULL           NULL            NULL          NULL           NULL             -- Repeats every Monday after May 20, 2013
1     1             1368144000         604800             NULL           NULL            NULL          NULL           NULL             -- Repeats every Friday after May 10, 2013
2     2             1369008000         NULL               2013           *               *             2              5                -- Repeats on Friday of the 2nd week in every month    

Si noti che è sufficiente specificare una repeat_interval o di un insieme di repeat_year, repeat_month, repeat_day, repeat_week, e repeat_weekdaydei dati.

Questo rende la selezione di entrambi i tipi contemporaneamente molto semplice. Basta scorrere ogni giorno e inserire i valori corretti (1370563200 per il 7 giugno 2013, quindi l'anno, il mese, il giorno, il numero della settimana e il giorno della settimana come segue):

SELECT EV.*
FROM `events` EV
RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
WHERE  (( 1370563200 - repeat_start) % repeat_interval = 0 )
  OR ( 
    (repeat_year = 2013 OR repeat_year = '*' )
    AND
    (repeat_month = 6 OR repeat_month = '*' )
    AND
    (repeat_day = 7 OR repeat_day = '*' )
    AND
    (repeat_week = 2 OR repeat_week = '*' )
    AND
    (repeat_weekday = 5 OR repeat_weekday = '*' )
    AND repeat_start <= 1370563200
  )

Ciò restituisce tutti gli eventi che si ripetono il venerdì della 2a settimana, nonché tutti gli eventi che si ripetono ogni venerdì, quindi restituisce sia l'ID evento 1 che 2:

ID    NAME
1     Sample Event
2     Another Event

* Sidenote nell'SQL sopra ho usato gli indici dei giorni feriali predefiniti di PHP Date , quindi "5" per venerdì


Spero che questo aiuti gli altri tanto quanto la risposta originale mi ha aiutato!


6
Questo è fantastico, grazie! Hai idea di come codificheresti "ogni 2 mesi il primo lunedì" o "ogni 3 mesi il primo lunedì", ecc.?
Jordan Lev,

6
Sono d'accordo che è fantastico. Mi sono imbattuto nello stesso dilemma di Jordan Lev, tuttavia. Il campo repeat_interval non è utile per ripetere mesi perché alcuni mesi sono più lunghi di altri. Inoltre, come limitare la durata di un evento ricorrente. Vale a dire, ogni 2 mesi il primo lunedì per 8 mesi. La tabella dovrebbe avere una sorta di data di fine.
Abinadi,

11
Questa è una risposta eccellente Ho lasciato repeat_interval e ho aggiunto repeat_end date, ma questa risposta mi ha aiutato enormemente.
Iain Collins,

3
Suggerimento: per motivi complessi, è possibile eliminare la repeat_intervalcolonna e rappresentarla nelle colonne successive (ad esempio repeat_year, ecc.) Per la prima riga, la situazione di ripetizione ogni lunedì dopo il 20 maggio 2013 può essere rappresentata inserendo un 1 nella repeat_weekdaye un *nelle altre colonne.
musubi,

3
@OlivierMATROT @milos L'idea è quella di impostare il campo che si desidera fissare esplicitamente e il resto al carattere jolly *. Pertanto, per "ogni mese il 3" è sufficiente impostare repeat_daysu 3, il resto dei repeatcampi su * (lasciare repeat_intervalnull) e impostare repeat_start sul codice temporale unix per il 3 marzo 2011 come data di ancoraggio.
ahoffner,

28

Miglioramento: sostituire il timestamp con la data

Come piccolo miglioramento della risposta accettata che è stata successivamente perfezionata da ahoffner, è possibile utilizzare un formato data anziché un timestamp. I vantaggi sono:

  1. date leggibili nel database
  2. nessun problema con gli anni> 2038 e il timestamp
  3. rimuove la necessità di fare attenzione ai timestamp che si basano su date destagionalizzate, ad esempio nel Regno Unito il 28 giugno inizia un'ora prima del 28 dicembre, quindi derivare un timestamp da una data può interrompere l'algoritmo di ricorsione.

per fare ciò, modificare il DB repeat_startda archiviare come tipo 'data' e repeat_intervalora contenere giorni anziché secondi. cioè 7 per una ripetizione di 7 giorni.

cambia la riga sql:

WHERE (( 1370563200 - repeat_start) % repeat_interval = 0 )

per:

WHERE ( DATEDIFF( '2013-6-7', repeat_start ) % repeat_interval = 0)

tutto il resto rimane lo stesso. Semplici!


E se volessi che il mio evento si ripetesse anno dopo anno? repeat_interval dovrebbe archiviare 365 giorni? E se l'anno avesse 366 giorni?
TGeorge,

3
@ George02 se l'evento è annuale lasci repeat_interval NULL e repeat_year è *, a seconda di quale ricorrenza è possibile impostare repeat_month e repeat_day, ad es. 11 marzo o repeat_month, repeat_week e repeat_weekday per impostare il 2 martedì di aprile.
jerrygarciuh,

25

Seguirei questa guida: https://github.com/bmoeskau/Extensible/blob/master/recurrence-overview.md

Assicurati anche di utilizzare il formato iCal in modo da non reinventare la ruota e ricorda la Regola # 0: NON memorizzare singole istanze di eventi ricorrenti come righe nel tuo database!


2
Come modelleresti un utente di tracciamento che ha partecipato a un'istanza specifica? Ha senso rompere dalla regola # 0 in questo caso?
Danny Sullivan,

2
@DannySullivan Dall'inizio della mia testa, avrei un'altra entità attendedEventcon baseInstanceIde instanceStartDate- Questo è ad esempio l'evento base da cui hai creato la vista del calendario delle regole ricorrenti e usa la data di inizio per specificare le informazioni su quell'istanza specifica Quindi questa entità potrebbe anche hanno qualcosa di simile attendedListIdche porta ad un altro tavolo di id,attendedUserId
Gal Bracha,

@DannySullivan So che è da un po 'che non mi chiedi. Ma al di fuori del commento precedente puoi sempre fare una ricerca inversa per vedere se quell'utente faceva parte del modello di ricorrenza dell'evento. Ciò ti direbbe se fossero almeno in programma per l'evento. Che abbiano effettivamente partecipato o meno è una storia diversa che sarebbe più simile al commento di DannySullivan.
BRogers

24

Per tutti coloro che sono interessati a questo, ora puoi semplicemente copiare e incollare per iniziare in pochi minuti. Ho preso il consiglio nei commenti e ho potuto. Fammi sapere se mi manca qualcosa.

"VERSIONE COMPLESSA":

eventi

+ ---------- + ---------------- +
| ID | NOME |
+ ---------- + ---------------- +
| 1 | Evento di esempio 1 |
| 2 | Secondo evento |
| 3 | Terzo evento |
+ ---------- + ---------------- +

events_meta

+ ---- + ---------- + -------------- + ------------------ + ------------- + -------------- + ------------ + ------- ------ + ---------------- +
| ID | event_id | repeat_start | repeat_interval | repeat_year | repeat_month | repeat_day | repeat_week | repeat_weekday |
+ ---- + ---------- + -------------- + ------------------ + ------------- + -------------- + ------------ + ------- ------ + ---------------- +
| 1 | 1 | 2014-07-04 | 7 | NULL | NULL | NULL | NULL | NULL |
| 2 | 2 | 26/06/2014 | NULL | 2014 | * | * | 2 | 5 |
| 3 | 3 | 2014-07-04 | NULL | * | * | * | * | 5 |
+ ---- + ---------- + -------------- + ------------------ + ------------- + -------------- + ------------ + ------- ------ + ---------------- +

Codice SQL:

CREATE TABLE IF NOT EXISTS `events` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `NAME` varchar(255) NOT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;

--
-- Dumping data for table `events`
--

INSERT INTO `events` (`ID`, `NAME`) VALUES
(1, 'Sample event'),
(2, 'Another event'),
(3, 'Third event...');

CREATE TABLE IF NOT EXISTS `events_meta` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `event_id` int(11) NOT NULL,
  `repeat_start` date NOT NULL,
  `repeat_interval` varchar(255) NOT NULL,
  `repeat_year` varchar(255) NOT NULL,
  `repeat_month` varchar(255) NOT NULL,
  `repeat_day` varchar(255) NOT NULL,
  `repeat_week` varchar(255) NOT NULL,
  `repeat_weekday` varchar(255) NOT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE KEY `ID` (`ID`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ;

--
-- Dumping data for table `events_meta`
--

INSERT INTO `events_meta` (`ID`, `event_id`, `repeat_start`, `repeat_interval`, `repeat_year`, `repeat_month`, `repeat_day`, `repeat_week`, `repeat_weekday`) VALUES
(1, 1, '2014-07-04', '7', 'NULL', 'NULL', 'NULL', 'NULL', 'NULL'),
(2, 2, '2014-06-26', 'NULL', '2014', '*', '*', '2', '5'),
(3, 3, '2014-07-04', 'NULL', '*', '*', '*', '*', '1');

disponibile anche come esportazione MySQL (per un facile accesso)

Esempio di codice PHP index.php:

<?php
    require 'connect.php';    

    $now = strtotime("yesterday");

    $pushToFirst = -11;
    for($i = $pushToFirst; $i < $pushToFirst+30; $i++)
    {
        $now = strtotime("+".$i." day");
        $year = date("Y", $now);
        $month = date("m", $now);
        $day = date("d", $now);
        $nowString = $year . "-" . $month . "-" . $day;
        $week = (int) ((date('d', $now) - 1) / 7) + 1;
        $weekday = date("N", $now);

        echo $nowString . "<br />";
        echo $week . " " . $weekday . "<br />";



        $sql = "SELECT EV.*
                FROM `events` EV
                RIGHT JOIN `events_meta` EM1 ON EM1.`event_id` = EV.`id`
                WHERE ( DATEDIFF( '$nowString', repeat_start ) % repeat_interval = 0 )
                OR ( 
                    (repeat_year = $year OR repeat_year = '*' )
                    AND
                    (repeat_month = $month OR repeat_month = '*' )
                    AND
                    (repeat_day = $day OR repeat_day = '*' )
                    AND
                    (repeat_week = $week OR repeat_week = '*' )
                    AND
                    (repeat_weekday = $weekday OR repeat_weekday = '*' )
                    AND repeat_start <= DATE('$nowString')
                )";
        foreach ($dbConnect->query($sql) as $row) {
            print $row['ID'] . "\t";
            print $row['NAME'] . "<br />";
        }

        echo "<br /><br /><br />";
    }
?>

Esempio di codice PHP connect.php:

<?
// ----------------------------------------------------------------------------------------------------
//                                       Connecting to database
// ----------------------------------------------------------------------------------------------------
// Database variables
$username = "";
$password = "";
$hostname = ""; 
$database = ""; 

// Try to connect to database and set charset to UTF8
try {
    $dbConnect = new PDO("mysql:host=$hostname;dbname=$database;charset=utf8", $username, $password);
    $dbConnect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

} catch(PDOException $e) {
    echo 'ERROR: ' . $e->getMessage();
}
// ----------------------------------------------------------------------------------------------------
//                                      / Connecting to database
// ----------------------------------------------------------------------------------------------------
?>

Anche il codice php è disponibile qui (per una migliore leggibilità):
index.php
e
connect.php
Ora l'impostazione di questo dovrebbe richiedere minuti. Non ore. :)


2
come posso fare una query per ottenere tutti gli eventi ripetuti all'interno di un intervallo di date ... ovvero ottenere tutti gli eventi ripetuti tra il 2014-10-01 e il 2014-12-30. grazie per il tuo post
Bene Wisher,

@Wellwisher - ripeti ... fino a quando la tabella temporanea stackoverflow.com/questions/34407833/…
Brad Kent il

1
@Alex Come posso eliminare un'occorrenza di istanza da un evento ripetuto.
Pugazhenthi,

1
So che questo è un vecchio thread, ma perché il tipo varchar sulle colonne repeat_ *? Non potresti usare un numero intero e un valore negativo invece di '*'?
Olivier MATROT

1
Grazie per il codice Devo tuttavia osservare che l'implementazione di db / query è un po 'inquietante e molto inefficiente. Ad esempio, perché usare varchar (255) per colonne così semplici (come menzionato @OlivierMATROT, è possibile utilizzare numeri interi e, in caso contrario, perché 255?). E se stai ripetendo la query 30 volte, perché non utilizzare istruzioni o procedure? Sto solo dicendo per amor se qualcuno sta per implementarlo.
Rony,

15

Mentre le soluzioni proposte funzionano, stavo cercando di implementare con il calendario completo e avrei richiesto oltre 90 chiamate al database per ogni vista (poiché carica il mese corrente, precedente e successivo), di cui non ero troppo elettrizzato.

Ho trovato una libreria di ricorsione https://github.com/tplaner/Quando si memorizzano semplicemente le regole nel database e una query per estrarre tutte le regole pertinenti.

Spero che questo possa aiutare qualcun altro, dato che ho trascorso così tante ore a cercare una buona soluzione.

Modifica: questa libreria è per PHP


Voglio anche usare fullcalendar. Come quando la biblioteca potrebbe aiutarmi? Come estrarre gli eventi propoer?
piernik,

@piernik - Vorrei impostare la libreria come nella documentazione e se si verificano problemi specifici, aprire una nuova domanda su StackOverflow con il codice che hai impostato e i problemi che stai riscontrando. Sono sicuro che se metterai così tanto impegno in alcuni membri ti aiuteranno.
Tim Ramsey,

Voglio dire che usando WhenDevi archiviare tutte le date di reccuring nel database o ottenere tutti gli eventi di reccuring e generare date in php no nel database. Ho ragione?
piernik,

@piernik Memorizzeresti la Data iniziale e le regole nel database e le utilizzeresti Whenper generare tutte le date - che sono popolate dalla data / regole iniziali memorizzate.
Tim Ramsey,

Non va bene neanche - Non puoi in un singolo comando mysql ottenere eventi corretti - Devi usare PHP per quello. Grazie comunque
piernik,

14

Perché non usare un meccanismo simile ai lavori cron di Apache? http://en.wikipedia.org/wiki/Cron

Per il calendario \ scheduling userei valori leggermente diversi per "bit" per adattarsi agli eventi standard di ricorrenza del calendario - anziché [giorno della settimana (0 - 7), mese (1 - 12), giorno del mese (1 - 31), ora (0 - 23), min (0 - 59)]

- Userei qualcosa come [Anno (ripetere ogni N anni), mese (1 - 12), giorno del mese (1 - 31), settimana del mese (1-5), giorno della settimana (0 - 7) ]

Spero che questo ti aiuti.


6
Penso che siano troppe opzioni per il giorno della settimana. 1-7 o 0-6 sembrano più precisi.
Abinadi,

2
È bene usare cron per memorizzare la ripetizione. ma il problema è che è molto difficile cercare.
Pietroso

@Vladimir come conservi, ogni due martedì (ogni due settimane martedì)
luglio

@julestruong sembra che questo sito abbia la risposta: coderwall.com/p/yzzu5a/running-a-cron-job-every-other-week
Ashton Wiersdorf

cron ha un'espressività limitata, poiché è apolide (si limita a confrontare la data / ora corrente / ipotermica con un modello), in quanto tale, non può rappresentare determinati modelli commerciali / umani comuni come "ogni terzo giorno" o "ogni 7 ore", che richiede di ricordare l'ultima occorrenza. Questo non è ovvio; potresti pensare di dire semplicemente giorno / 3 o ora / 7 in crontab, ma poi alla fine del mese / giorno, hai giorni / ore "rimanenti" che sono meno di 3 o 7; con possibili risultati catastrofici.
Jaime Guerrero,

5

Ho sviluppato un linguaggio di programmazione esoterico proprio per questo caso. La parte migliore è che è meno schema e indipendente dalla piattaforma. Devi solo scrivere un programma di selezione, per il tuo programma, la cui sintassi è vincolata dall'insieme di regole qui descritte -

https://github.com/tusharmath/sheql/wiki/Rules

Le regole sono estensibili e puoi aggiungere qualsiasi tipo di personalizzazione in base al tipo di logica di ripetizione che desideri eseguire, senza preoccuparti delle migrazioni di schemi ecc.

Questo è un approccio completamente diverso e potrebbe presentare alcuni svantaggi.


4

Assomiglia molto agli eventi MySQL che sono memorizzati nelle tabelle di sistema. Puoi guardare la struttura e capire quali colonne non sono necessarie:

   EVENT_CATALOG: NULL
    EVENT_SCHEMA: myschema
      EVENT_NAME: e_store_ts
         DEFINER: jon@ghidora
      EVENT_BODY: SQL
EVENT_DEFINITION: INSERT INTO myschema.mytable VALUES (UNIX_TIMESTAMP())
      EVENT_TYPE: RECURRING
      EXECUTE_AT: NULL
  INTERVAL_VALUE: 5
  INTERVAL_FIELD: SECOND
        SQL_MODE: NULL
          STARTS: 0000-00-00 00:00:00
            ENDS: 0000-00-00 00:00:00
          STATUS: ENABLED
   ON_COMPLETION: NOT PRESERVE
         CREATED: 2006-02-09 22:36:06
    LAST_ALTERED: 2006-02-09 22:36:06
   LAST_EXECUTED: NULL
   EVENT_COMMENT:


3

@Rogue Coder

Questo è fantastico!

Puoi semplicemente usare l'operazione modulo (MOD o% in mysql) per rendere semplice il tuo codice alla fine:

Invece di:

AND (
    ( CASE ( 1299132000 - EM1.`meta_value` )
        WHEN 0
          THEN 1
        ELSE ( 1299132000 - EM1.`meta_value` )
      END
    ) / EM2.`meta_value`
) = 1

Fare:

$current_timestamp = 1299132000 ;

AND ( ('$current_timestamp' - EM1.`meta_value` ) MOD EM2.`meta_value`) = 1")

Per andare oltre, si potrebbero includere eventi che non si ripetono per sempre.

È possibile aggiungere qualcosa come "repeat_interval_1_end" per indicare la data dell'ultimo "repeat_interval_1". Questo, tuttavia, rende la query più complicata e non riesco davvero a capire come farlo ...

Forse qualcuno potrebbe aiutare!


1

I due esempi che hai fornito sono molto semplici; possono essere rappresentati come un semplice intervallo (il primo è di quattro giorni, il secondo è di 14 giorni). Come modellerai questo dipenderà interamente dalla complessità delle tue ricorrenze. Se quello che hai sopra è davvero così semplice, quindi memorizzare una data di inizio e il numero di giorni nell'intervallo di ripetizione.

Se, tuttavia, è necessario supportare cose come

L'evento A si ripete ogni mese il 3 del mese a partire dal 3 marzo 2011

O

L'evento A si ripete il secondo venerdì del mese a partire dall'11 marzo 2011

Quindi questo è un modello molto più complesso.


1
Ho aggiunto le regole più complesse che hai appena affermato in un momento successivo, ma non per ora. Come modellerei la query SQL per ottenere eventi il ​​7 marzo 2011 in modo che ottenga il mio evento ricorrente?
Brandon Wamboldt,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.