none
Hora transcurridas entre 2 fechas - RRS feed

  • Pregunta

  • Estimados muy buenas noches!.

    Quisiera plantear la siguiente duda con respecto al calculo de horas transcurridas entre 2 fechas del tipo DateTime.

    Tengo una tabla con los días y horario de entrada y salida como esta 

    ID Dia Entrada Salida
    1 Lunes 8:30 17:30
    2 Martes 8:30 17:30
    3 Miércoles 8:30 17:30
    4 Jueves 8:30 17:30
    5 Viernes 8:30 16:00

    La idea es poder calcular las horas transcurridas entre 2 fechas teniendo como excepción:

    Sábados y domingos que que la horas que vendrían por parámetro para las fechas de inicio y fin no salgan del intervalo que existen en la tabla "Horarios" (Tabla expuesta más arriba) .

    Por ejemplo : 

    Si como fecha de inicio paso 01-01-2020 05:00 (Antes de las 8:30 hrs) automáticamente considere como fecha de inicio el 01-01-2020 08:30 y para el caso en que la fecha de inicio coincida después del horario de salida por ejemplo 01-01-2020 18:00  se cambie a siguiente día hábil con hora de inicio 8:30 por ejemplo 02-01-2020 8:30 para finalmente hacer el calculo con la fecha de termino (Que por cierto debe calcular la hora de inicio 8:30 y la hora que viene definida en el parámetro de fecha fin)

    Se me había ocurrido generar una función que retorne las horas y minutos transcurrido entre 2 fechas, con parámetros de inicio y Fin, luego evaluar la fecha de inicio, para establecer el resultado de la regla de negocio escrita mas arriba para luego hacer un bucle entre las fechas, si es que la diferencia de días es mayor a 0 de tal manera recorrer día a día y sumar las horas y minutos, obviamente teniendo en consideración el numero de día representado por la tabla horario  y finalmente con la suma,  adicionar la ultima suma del ultimo día considerando la hora de inicio a las 8:30  vs la hora de termino del parámetro fin, para luego retornar el resultado. 

    La verdad que hoy me complica bastante este calculo. si pudiesen darme alguna sugerencias estaría bastante agradecido. 

    Comento que antes de postear busque en el foro, pero la mayoría de los casos hablan de horario laborales sin las variables de horario de inicio y termino para un determinado día. 

    Bendiciones a todos!.

    sábado, 6 de junio de 2020 3:04

Respuestas

  • Hola jcc2018: 

    Esas particularidades de fecha son complicadas de trabajar, por eso en los post no encuentras posts que encajen.

    Voy a darte un par de tips que te ayuden.

    Lo primero en cualquier escenario es concretar de que tipo de datos hablamos. 

    CREATE TABLE dbo.Horarios
    (
    id      tinyint
    , Dia     varchar(20)
    , Entrada time(0)
    , Salida  time(0)
     );
    GO
    INSERT INTO dbo.Horarios
    Values
    (1,     'Lunes',	'08:30','17:30'),
    (2,	'Martes',	'08:30','17:30'),
    (3,	'Miércoles',    '08:30','17:30'),
    (4,	'Jueves',	'08:30','17:30'),
    (5,	'Viernes',	'08:30','16:00');
    GO

    Con este escenario y a modo de pequeñas ayuditas que te puedan servir.

    declare @INICIO datetime = '20200601 18:00';
    
    declare @FIN datetime = '20200606';
    
    set datefirst 1;
    
    -- TIPS probablemente necesarios
    SELECT DATEDIFF(day, @INICIO, @FIN) as "Diferencia En Dias"
    	 , DATEPART(DW, @INICIO)		as "Dia Semana"
    	 , DATEPART(dw, @FIN)			as "dia Semana Fin"
    	 , DATEPART(wk, @INICIO)		as "Semana Actual Inicio"
    	 , DATEPART(wk, @FIN)			as "Semana Actual Fin";
    
    SELECT id, Dia, CASE WHEN TIMEFROMPARTS((DATEPART(HOUR,@INICIO)),(DATEPART(MINUTE,@INICIO)),0,0,0) < Entrada THEN Entrada
    					 ELSE TIMEFROMPARTS((DATEPART(HOUR,@INICIO)),(DATEPART(MINUTE,@INICIO)),0,0,0) END AS ENTRADA, SALIDA
    FROM dbo.Horarios D
    WHERE id = CASE WHEN TIMEFROMPARTS((DATEPART(HOUR,@INICIO)),(DATEPART(MINUTE,@INICIO)),0,0,0)< Salida THEN DATEPART(DW, @INICIO) 
    ELSE DATEPART(DW, @INICIO)+1 END

    Én la primera select tienes funciones útiles, para la diferencia de fechas. A priori, puedes controlar la semana en la que estás y la diferencia de dias. Si no estas en la misma semana y el dia en el que estás es menor 6, pues le restas 2, pero si estas en ..... finde.... 

    Luego en la segunda select, solo he expuesto el caso simple de la hora de entrada. (where) Si la hora de la entrada es menor que la salida entonces estoy en el mismo día, sino, estoy en el día siguiente. Y para devolver la hora de entrada puedes utilizar un case. Si es < que Entrada entonces, devolvemos entrada, sino la hora del parámetro.

    Con estos tips, yo creo que puedes montar una función que te lo calcule y así no tienes que hacer un bucle.

    sábado, 6 de junio de 2020 3:58
  •   

    ¿Alguna novedad sobre la consulta realizada? ¿Ha sido útil la respuesta proporcionada?  

     

    Gracias por usar los foros de MSDN.

    martes, 9 de junio de 2020 13:34
    Moderador

Todas las respuestas

  • Hola jcc2018: 

    Esas particularidades de fecha son complicadas de trabajar, por eso en los post no encuentras posts que encajen.

    Voy a darte un par de tips que te ayuden.

    Lo primero en cualquier escenario es concretar de que tipo de datos hablamos. 

    CREATE TABLE dbo.Horarios
    (
    id      tinyint
    , Dia     varchar(20)
    , Entrada time(0)
    , Salida  time(0)
     );
    GO
    INSERT INTO dbo.Horarios
    Values
    (1,     'Lunes',	'08:30','17:30'),
    (2,	'Martes',	'08:30','17:30'),
    (3,	'Miércoles',    '08:30','17:30'),
    (4,	'Jueves',	'08:30','17:30'),
    (5,	'Viernes',	'08:30','16:00');
    GO

    Con este escenario y a modo de pequeñas ayuditas que te puedan servir.

    declare @INICIO datetime = '20200601 18:00';
    
    declare @FIN datetime = '20200606';
    
    set datefirst 1;
    
    -- TIPS probablemente necesarios
    SELECT DATEDIFF(day, @INICIO, @FIN) as "Diferencia En Dias"
    	 , DATEPART(DW, @INICIO)		as "Dia Semana"
    	 , DATEPART(dw, @FIN)			as "dia Semana Fin"
    	 , DATEPART(wk, @INICIO)		as "Semana Actual Inicio"
    	 , DATEPART(wk, @FIN)			as "Semana Actual Fin";
    
    SELECT id, Dia, CASE WHEN TIMEFROMPARTS((DATEPART(HOUR,@INICIO)),(DATEPART(MINUTE,@INICIO)),0,0,0) < Entrada THEN Entrada
    					 ELSE TIMEFROMPARTS((DATEPART(HOUR,@INICIO)),(DATEPART(MINUTE,@INICIO)),0,0,0) END AS ENTRADA, SALIDA
    FROM dbo.Horarios D
    WHERE id = CASE WHEN TIMEFROMPARTS((DATEPART(HOUR,@INICIO)),(DATEPART(MINUTE,@INICIO)),0,0,0)< Salida THEN DATEPART(DW, @INICIO) 
    ELSE DATEPART(DW, @INICIO)+1 END

    Én la primera select tienes funciones útiles, para la diferencia de fechas. A priori, puedes controlar la semana en la que estás y la diferencia de dias. Si no estas en la misma semana y el dia en el que estás es menor 6, pues le restas 2, pero si estas en ..... finde.... 

    Luego en la segunda select, solo he expuesto el caso simple de la hora de entrada. (where) Si la hora de la entrada es menor que la salida entonces estoy en el mismo día, sino, estoy en el día siguiente. Y para devolver la hora de entrada puedes utilizar un case. Si es < que Entrada entonces, devolvemos entrada, sino la hora del parámetro.

    Con estos tips, yo creo que puedes montar una función que te lo calcule y así no tienes que hacer un bucle.

    sábado, 6 de junio de 2020 3:58
  •   

    ¿Alguna novedad sobre la consulta realizada? ¿Ha sido útil la respuesta proporcionada?  

     

    Gracias por usar los foros de MSDN.

    martes, 9 de junio de 2020 13:34
    Moderador