2012-11-17 8 views
12

La mia tabella ha dati di esempio e ho bisogno di calcolare ore di lavoro tra due timestamp in due colonne. Orario di lavoro: dalle 9:00 alle 17:00 e trascurato sabato e domenica, non sto considerando le festività pubbliche. Qualcuno può fornire alcune linee guida su come raggiungere questo obiettivo? Voglio output desiderato come indicato nella colonna 3, la data è in formato di: aaaa-mm-ggMysql: come calcolare le ore lavorative tra due timestamp e trascurare i fine settimana

Created date    Updated date   Business hrs 
    2012-03-05 9:00am 2012-03-05 3:00pm    6 
    2012-03-05 10:00am 2012-03-06 10:00am   9 
    2012-03-09 4:00pm 2012-03-19 10:00am   2 
+0

cosa hai provato? cosa non funziona ? – Yahia

+0

mi grattavo la logica e gli antipasti sarebbero buoni – yokoyoko

+0

per qualche punto di partenza vedi la mia risposta qui sotto ... – Yahia

risposta

3

Creare una tabella denominata BusinessHours, con una sola colonna chiamata ore che contiene una data ora. Crea l'ora come chiave primaria. Scrivi un processo per popolarlo con ogni ora lavorativa dell'anno (2012-01-02 00:90:00, 2012-01-02 00:10:00 ecc.). Questo non dovrebbe essere difficile in quanto le regole sono semplici. Sembra un sacco di dati, ma nel grande schema delle cose non lo è (ci sono solo 8760 ore in un anno - anche se la tua data impiega 8 byte ciascuna, si tratta di un enorme 60kB). Assicurati di pianificare un lavoro per mantenerlo popolato.

Poi:

Select 
    y.CreatedDate, 
    y.UpdatedDate, 
    Count(*) as BusinessHours 
From 
    YourTable y 
    Inner Join 
    BusinessHours h 
    On h.Hour >= y.CreatedDate And h.Hour < y.UpdatedDate 
Group By 
    y.CreatedDate, 
    y.UpdatedDate 

Questo dà anche un approccio abbastanza semplice se mai preso in considerazione nei giorni festivi - basta prendere le righe fuori dal tavolo BusinessHours.

0

provare

SELECT (FLOOR(DATEDIFF (UpdatedDate, CreatedDate)/7) * 5 + MOD (DATEDIFF (UpdatedDate, CreatedDate), 7)) * 8 + 
     TIMEDIFF (TIME (UpdatedDate), TIME(CreatedDate)) 
FROM YourTable 

È possibile che questo non è completa come solo "stime" il fine settimana ... ma dovrebbe iniziare ... un'altra opzione è quella di lavorare con una tabella di BusinessHours validi (ad dettagli vedi this answer from Laurence).

Per riferimento vedere MySQL documentation.

14

La domanda dice che le festività pubbliche non dovrebbero essere considerate, quindi questa risposta fa proprio questo: calcola l'orario di lavoro tenendo conto dei fine settimana, ignorando eventuali festività pubbliche.

Se è necessario tenere conto delle festività pubbliche, è necessario disporre di una tabella separata che elenchi le date per le festività pubbliche, che possono variare di anno in anno e da stato a stato o da paese a paese. La formula principale può rimanere la stessa, ma è necessario sottrarre dalle ore di risultato per le festività pubbliche che rientrano nell'intervallo di date date.

Creiamo una tabella con alcuni dati di esempio che copre vari casi:

CREATE TABLE T (CreatedDate datetime, UpdatedDate datetime); 

INSERT INTO T VALUES 
('2012-03-05 09:00:00', '2012-03-05 15:00:00'), -- simple part of the same day 
('2012-03-05 10:00:00', '2012-03-06 10:00:00'), -- full day across the midnight 
('2012-03-05 11:00:00', '2012-03-06 10:00:00'), -- less than a day across the midnight 
('2012-03-05 10:00:00', '2012-03-06 15:00:00'), -- more than a day across the midnight 
('2012-03-09 16:00:00', '2012-03-12 10:00:00'), -- over the weekend, less than 7 days 
('2012-03-06 16:00:00', '2012-03-15 10:00:00'), -- over the weekend, more than 7 days 
('2012-03-09 16:00:00', '2012-03-19 10:00:00'); -- over two weekends 

In MS SQL Server Io uso la seguente formula:

SELECT 
    CreatedDate, 
    UpdatedDate, 
    DATEDIFF(minute, CreatedDate, UpdatedDate)/60.0 - 
    DATEDIFF(day, CreatedDate, UpdatedDate)*16 - 
    DATEDIFF(week, CreatedDate, UpdatedDate)*16 AS BusinessHours 
FROM T 

che produce il seguente risultato:

+-------------------------+-------------------------+---------------+ 
|  CreatedDate  |  UpdatedDate  | BusinessHours | 
+-------------------------+-------------------------+---------------+ 
| 2012-03-05 09:00:00  | 2012-03-05 15:00:00  | 6    | 
| 2012-03-05 10:00:00  | 2012-03-06 10:00:00  | 8    | 
| 2012-03-05 11:00:00  | 2012-03-06 10:00:00  | 7    | 
| 2012-03-05 10:00:00  | 2012-03-06 15:00:00  | 13   | 
| 2012-03-09 16:00:00  | 2012-03-12 10:00:00  | 2    | 
| 2012-03-06 16:00:00  | 2012-03-15 10:00:00  | 50   | 
| 2012-03-09 16:00:00  | 2012-03-19 10:00:00  | 42   | 
+-------------------------+-------------------------+---------------+ 

Funziona, perché in SQL Server DATEDIFF restituisce il conteggio del specificato datapart i confini attraversati tra lo punto di arrivo.

Ogni giorno ha 8 ore di lavoro. Calcolo il numero totale di ore tra due date, quindi sottraggo il numero dei midnights moltiplicato per 16 ore non lavorative al giorno, quindi sottraggo il numero di fine settimana moltiplicato per 16 (8 + 8 ore lavorative per Sat + Sun).

Si presuppone inoltre che la data e l'ora di inizio e di fine indicate siano durante l'orario di ufficio.

In MySQL l'equivalente più vicino è TIMESTAMPDIFF, ma funziona in modo diverso. Calcola effettivamente la differenza in secondi e divide (scartando la parte frazionaria) per il numero di secondi nell'unità scelta.

Quindi, per ottenere i risultati di cui abbiamo bisogno è possibile calcolare la TIMESTAMPDIFF tra alcuni datetime ancora e CreatedDate e UpdatedDate invece di calcolare la differenza tra CreatedDate e UpdatedDate direttamente.

Ho scelto 2000-01-03 00:00:00, che è un lunedì. È possibile scegliere qualsiasi altro lunedì (o domenica, se la settimana inizia domenica) a mezzanotte per la data di ancoraggio.

La query MySQL diventa (vedi SQL Fiddle):

SELECT 
    CreatedDate, 
    UpdatedDate, 

    TIMESTAMPDIFF(MINUTE, CreatedDate, UpdatedDate)/60.0 - 

    16*(
     TIMESTAMPDIFF(DAY, '2000-01-03',UpdatedDate)- 
     TIMESTAMPDIFF(DAY, '2000-01-03',CreatedDate) 
    ) - 

    16*(
     TIMESTAMPDIFF(WEEK, '2000-01-03',UpdatedDate)- 
     TIMESTAMPDIFF(WEEK, '2000-01-03',CreatedDate) 
    ) AS BusinessHours 

FROM T 
+0

Questo sembrerebbe funzionare per potenziali ore lavorative, ma l'orario lavorativo attuale con le vacanze che cambiano di anno in anno richiederebbe una definizione esplicita da qualche parte , probabilmente in una tabella. – JRD

+0

@ JRD, hai ragione. La domanda afferma chiaramente che le festività pubbliche dovrebbero essere ignorate e non l'ho ripetuta nella risposta. Immagino, farei meglio a farlo ... –

+2

Una soluzione molto intelligente, comunque. – JRD

0

Usa datediff per calcolare la diff tra l'inizio e l'ora di fine e quindi sottrarre (DATE_ADD con ore negativi) le ore di riposo: 24 per i giorni del fine settimana, 16 per i giorni lavorativi prevedono la fine e il giorno di inizio che richiede un calcolo aggiuntivo. Se un giorno è giorno del fine settimana o no, può essere specificato con il metodo dayofweek.

Problemi correlati