8- Fechas
Autor: César de Miguel - Aloa Informática S.L. - cesar@aloa.info
Todo lo que querías saber sobre las Fechas y No te atrevías a preguntar
Parte 1ª: Fechas
(Tempus fugit: Así pasan los días)
En esta parte sólo hablaremos de fechas. Posteriormente hablaremos de horas (junto con las fechas).
Para empezar, entendamos algo que es básico.
Si alguien no lo entiende, que se lo crea. ¡Es una orden para seguir el curso!
Una fecha (un día concreto) en Access es un nº entero.
Una fecha en Access No es una combinación de palabras, letras, números y separadores, ni de palabras ni de formatos.
Insisto. Un día cualquiera es un número entero, y Hoy (el día en que esto escribo es) = 37940.
Hoy, día 15 de Noviembre del Año de Gracia de 2003, sábado es, para Access, el día 37940 (y así se almacena).
Lo pongas en el formato que quieras (un montón de posibles combinaciones), internamente es el 37940.
Ayer fue el 37939 y mañana será 37941. Y dentro de mil días será el 38940.
Ahora bien, para enseñarlo o hablar de hoy no decimos el día 37940, porque sería un rollo, sino que decimos o ponemos, entre otros formatos:
15 de Noviembre del Año de Gracia de 2003, sábado, ó
15-11-03, ó
15/11/2003, ó
15/XI/2003, ó
11/15/2003, ó
2003/15/11, ó
15 nov 2003, ó
15/2003/11/, ó
Simplemente hoy ó... (más de tropecientas combinaciones sin contar las versiones del calendario musulmán, ni judío, ni chino, ni japonés tradicional).
Todos hablamos del mismo hecho, día, pero lo expresamos de distinta forma.
Así que, ¿son iguales todas ellas?. En expresión, no; pero en contenido, sí.
Lo podemos probar diciéndole a cualquiera que esto es una fecha (y aquí le das cualquiera de las versiones) y, por muy enrevesada que esté expresada, sabrá que se refiere al día de hoy. Es decir al 37940.
La idea es buena y simple: almacenamos el número y lo narramos como nos convenga.
El problema viene de que ciertos 'mensajes' son equívocos.
Por ejemplo, la fecha 2003/12/25, seguro que, incluso para el estadounidense medio de la América más profunda, será el Christmas que del año 2003, aunque le choque un poco porque no es esa su forma acostumbrada de expresarlo.
Pero si le dices 7/4/2004 no tendrá dudas de que es su fiesta nacional del año 2004, su cuatro de julio, mientras que para el menda, o sea César, es el día en que tengo que preparar el semillero de calabazas, porque ya es el siete de abril. ¿Veis lo equívoco del continente o formato del mensaje?
Así pues, al meter fechas en la base de datos no importa cómo la introduzcas, siempre que y cuando no sea equívoca. (De aquí sale un consejo: si lo metes en forma de número entero no habrá equivocaciones, o como aconseja Frank Rivera en OSI: aaaa/mm/dd).
Por lo tanto las fechas no se meten en la base de datos en formato de fecha corta, larga, semilarga, fusa o semifusa: las fechas se meten en formato fecha (entendiendo por ello cualquiera que entienda el sistema) siempre que no sea confusa.
Para que se entienda mejor, el hecho de variar el color de la fecha y ponerla en color rojo no afecta al valor de la fecha.
Es lo mismo 23/11/2006 que 23/11/2006 que 23/11/2006 que 23/11/2006 que ... ¿o es que se almacena de distinta forma?
Pues también es lo mismo 23/11/2006 que 11/23/2006, ó que 23/2006/11, ó que 2006/23/11, ó que .........Lo que sí sucede es que se presenta en cada circunstancia en el formato que convenga: rojo, letra bastardilla (con perdón), Times, 12 pt, aa/mmm/dddd, ...
Cuándo es equívoca (cuidado con la configuración regional y con la diferencia entre el ámbito español del Access -consultas, formularios, informes- y al ámbito inglés -VBA y SQL-) es cuando vienen los líos, y eso es lo que hay que evitar.
Fin de esta parte.
Preguntas a esta parte :
1.- ¿Se puede acceder a ese número interno de fecha?. ¿Cómo?.
Variable = clng(MiFecha)
Ej. ?clng(date()) nos devuelve 37942
Respuesta sólo válida para el día en que hoy
(devuelto por la función date())era el
37942.
2.- ¿Se puede, una vez conocido ese número, pasarlo al formato que queramos?. ¡Siempre!. ¿Cómo?.
Por fuera, ámbito español: NúmeroVistoComoFecha = CDate(Número;"dd/mm/aaaa"). Usado en ámbito español, es decir en tablas, consultas, formularios e informes
Por dentro, ámbito inglés: NúmeroVistoComoFecha = CDate(Número,"mm/dd/yyyy"). En ámbito inglés, es decir en SQL y VBA .
3.- ¿Existe alguna manera de crear una fecha en access que diga exactamente" 3 de febrero de 2005"; y no como me sale con la fecha larga:"jueves, 3 de febrero de 2005"?
Crear lo que se dice crear, NO si quieres que sea un campo de tipo Fecha/hora, pero si le puedes dar el formato que pides:
Format(Date,"dd"" de ""mmmm"" de ""yyyy"), si es en Visual Basic
ó con
dd" de "mmmm" de "aaaa, si es consulta, formulario, ...
4.- ¿Sucede lo mismo en otras Bases de Datos?
En Access, en Oracle, en SQL Server y en la inmensa mayoría de las BD actuales (no conozco ninguna excepción) un campo de tipo Date, ó DateTime, ó (como se llame en cada sitio) ..., es internamente una cifra entera.
Cada Sistema de Gestión de Base de Datos (SGBD) lleva un calendario continuo, un día tras otro, desde el origen que han querido poner. Tan simple y claro, como que hoy es ayer + 1, y pasado mañana será mañana + 1 ú hoy + 2 ó ayer + 3, ..., y no importa que en medio se cambie de año, mes, semana, siglo ó milenio.
Del formato, que si juliano, que si gregoriano, que si ISO, que si OSI, que si EuroDate, que si DateBush (o que te den igual mejor), que si FoxFate, que si ..., son formas externas de ese nº. Son máscaras, por decirlo así, de presentación del mismo hecho.
Eso sí, cada SGBD ha tenido libertad para fijar su propio origen, y así como nuestro calendario occidental contemporáneo difiere en el origen del chino, del musulmán, judío, romano antiguo, el de Access también puede diferir de los otros sistemas, y teniendo en cuenta los ajustes provocados voluntariamente a cada calendario (¿Sabes, p. ej., que Stª Teresa murió un 4 de octubre y fue enterrada al día siguiente, 15 de octubre?. Pues, sí, le pilló una reforma de calendario.)
Parte 2ª: Consolidación del concepto de fechas en Access
Resumen/repaso de lo publicado (explícita o implícitamente):
En Access, una fecha (un día concreto) es un nº entero.
No importa el formato (tamaño, color, tipo de letra, d-m-aa, dd-mmm) en que se exprese.
El lío viene al introducirla en la base de datos, ya que varios de los formatos anteriores -valóralo tu mismo- no sirven para, de forma clara e inequívoca, decirle al ordenador/computadora a qué fecha nos referimos.
El problema más habitual es el del cambio de mes por el día y viceversa, porque 7/4/2003 no es la mismo para un americano de Los Estardos Unidos de Norteamérica, que para un hispano. (Por cierto, no sé si nuestras amigos mexicanos usan el formato mm/dd/aaaa, como estándar) Como sabéis, para uno es el 4 de julio y para el otro el 7 de abril.
Y este lío lo lleva Access, con no muy buen semblante, porque por fuera quiere ser hispano y por dentro americano. Y habla Espánglish ó Inglisñol a su manera. Entonces dependiendo de qué ambiente uses, Access te entenderá lo uno o lo otro y te armará líos a poco que te descuides.
Si trabajas en el ámbito externo, es decir, tablas, consultas, formularios, macros e informes lo entiende como siete de abril. Este ámbito se caracteriza por el hecho de que si usas inglés/americano para expresar conceptos, Access lo traduce. (Ej.: Escribes Not null, y, entonces, va Access y pone la turbadora traducción de Negado Nulo).
En cambio si estás en el ámbito más interno del producto, SQL y Visual Basic, allí el idioma de trabajo y el ámbito cultural es el inglés. Allí no puedes decir 35,24 euros, porque la coma no es el separador decimal (aunque hace esfuerzos a veces por traducirlo lo cual complica más las cosas) y si dices cdate("7/4/2004") te entenderá que es la fiesta nacional de E.E.U.U. de Norteamérica.
Y es de aquí de donde viene el embrollo, al cual yo no os voy a dar ninguna solución porque tampoco tengo una vía infalible (aunque tengo claro que si pusiéramos un sólo número entero nunca habría problemas). Pero creo que cada uno se buscará la más adecuada.
No obstante una cosa sabida de las manías de Access, es que si la fecha se la das en formato aaaammdd nunca confundirá el día con el mes, ni viceversa. En cuanto detecta que ese es el formato, no importa el ambiente hispano o anglo, ¡lo entiende bien!. P. ej. 20030407, es sin duda el siete de abril del año 2003.
Consecuencias:
Averiguar cuántos días han transcurrido
entre dos fechas es, nada más fácil,
restarlas:
Clng(date()-MiFcNacimiento) -y a mí me sale la
barbaridad de 20939
(Ejercicio: ¿cuándo nació esta criatura?)
¿Qué día se cumplen los 10000 días de mi vida?: CDate(FcNacimiento + 10000)
Os paso un montón de ensayos aprovechando
las posibilidades de ayuda, en depuración o
en inmediato, de Access:
?FcNacimiento 28/05/1975 (que no es la mía)
?clng(FcNacimiento) 27542
?cdate(FcNacimiento) 28/05/1975
?cdate(clng(FcNacimiento)) 28/05/1975
?cdate(clng(FcNacimiento)+10000) 13/10/2002
?cdate(clng(FcNacimiento+10000)) 13/10/2002
?isdate(fcnacimiento) Verdadero
?isdate(27542) Falso
?#28/5/1975# 28/05/1975
?28/05/1975 2,835443E-03
?"28/05/1975" 28/05/1975
?isdate(28/05/1975) Falso
?isdate("28/05/1975") Verdadero
?clng(fcnacimiento)-date() 04/07/1871
?clng(date()-fcnacimiento) 10406
?clng(fcnacimiento-date()) -10406
Temas de la ayuda de Access.
Consejo: consultar los siguientes temas -especialmente los que están en negrita- y practicarlos
Obtener la fecha o la hora actuales. Date,
Now, Time
Realizar cálculos de fechas. DateAdd,
DateDiff, DatePart
Devolver una fecha. DateSerial, DateValue
Devolver una hora. TimeSerial, TimeValue
Establecer la fecha o la hora. Date,
Time
Medir el tiempo de un proceso. Timer
Convertir entre tipos de datos. CBool, CByte,
CCur, CDate, CDbl, CDec, CInt, CLng,
CSng, CStr, CVar, CVErr, Fix, Int
Establecer tipos de datos intrínsecos.
Boolean, Byte, Currency, Date, Double,
Integer, Long, Object, Single, String,
Variant (predeterminado)
Comprobar los tipos de datos. IsArray,
IsDate, IsEmpty, IsError, IsMissing,
IsNull, IsNumeric, IsObject
Funciones Day, Month, Year, WeekDay,
Format(expresión[, formato[, primerdíadesemana[, primerdíadeaño]]])
expresión Obligatorio. Cualquier expresión
válida.
formato Opcional. Una expresión de formato
definida por el usuario o con nombre válida.
primerdíadesemana Opcional. Una constante
que especifica el primer día de la semana.
primerdíadeñao Opcional. Una constante que
especifica la primera semana del año.
Ejercicios:
¿En que fecha comienza el calendario de Access?. ¿Cuál es día 1?
¿Tiene sentido una fecha negativa?
¿Cuál es la diferencia entre "25/12/2003", 25/12/2003 y #25/12/2003#
Para responder, probemos (en la depuración del Access 97 que es el que más a mano tenía. ¡Ojo que es ambiente americano!):
?cdate(1): 31/12/1899
?cdate(-1): 29/12/1899 Veamos que lo considera algo más que un número, si lo incluyes con intención de que sea una fecha.
Así por ejemplo, el día del descubrimiento
de América se puede averiguar, al derecho y
al revés:
?clng(cdate("12/10/1492")) -148732 (Observar el
signo menos)
?clng(#10/12/1492#) -148732 . (Aquí se nota que
hay que poner mm/dd/aaaa, como ya se había
advertido).
"25/12/2003", es un texto. Efectivamente. Y lo usaremos para expresar una fecha cuando la función nos pide una cadena (string) de caracteres o para convertirlo en fecha mediante Cdate("25/12/2003").
25/12/2003, así al desnudo, tiene pinta de expresión aritmética con dos divisiones. Por ejemplo ?25/12/2003 nos da 0,001040107 (1,040107 E-03, en coma flotante)
#25/12/2003#. Es formato fecha y el sistema intenta interpretarlo como tal. Pero ¡cuidado! que depende del ambiente americano o hispano. Aquí, como no existe el mes 'veinticinco-embre', pues no existen dudas, como ha sucedido arriba, con #10/12/1492#..
Parte 3ª: Hablemos de horas.
¿Y que pasa con las fracciones de día: el mediodía, la media tarde, la medianoche, el amaiketako, las cinco de la tarde, las tres y media después de almorzar, las doce y cuarto, media hora después de empezar el partido, un cuarto hora de antes de la hora de salida, tres minutos más tarde, ... ?
Resumen de lo publicado (explícita o
implicitamente):
En Access, un día concreto es un
nº entero,
que se puede tratar como eso:
un nº al que se pueden sumar o restar días para trasladarnos
en el tiempo ó
hacer semisumas para averiguar el momento equidistante entre
dos fechas, ó ...
Pues primera confesión: Os he mentido un poquito. Debo precisar algo más.
En realidad un día concreto es la parte entera de un número decimal, guardado como double-doble en Access.
Así que no es de extrañar que el mediodía del mencionado 15-11-2003, día que internamente es el 37940, sea 37940,5 (En americano 37940.5 -obsérvese el punto-).
Dicho de otra forma 37940,5 es en realidad 15-11-2003 12 h
Y con precisión de ferrocarril (al minuto), 37940 es 15-11-2003 00:00 y 37940,5 es 15-11-2003 12:00
Si se ha entendido esto, ya habéis entendido todo el rollo de las horas, los minutos y los segundos.
Recordad aquellos problemas de secundaria de convertir grados sexagesimales a centesimales y viceversa y horas, o bien minutos y segundos a fracciones de día y tendréis una aproximación muy clarita a lo que aquí se cuece. Veámoslo haciendo unos ejercicios:
Ejercicios:
Si Jaimito entra al despacho de la directora a las once menos cuarto y sale veinte minutos más tarde, ¿a qué hora ha salido?
Pues, hagamos trabajar a la ventana de depuración (Access 97) o a la inmediato (2000 y sucesivas):
?#10:45# + #00:20#, nos da 11:05:00
o bien dado que veinte minutos expresados en
fracción de día es 20/60/24 días
(20 minutos/60 que tiene la hora/24 horas
que tiene el día):
?#10:45# + 20/60/24, pues también nos da lo mismo: 11:05:00
(Nota: 20/60/24 tiene formato de día. Si se me permite el chiste, podría decir que es el día 20 de sexagesimiembre de 2024 o quizá 1924?-. Esto nos hace reflexionar sobre el por qué, habitualemente para Access, 12/04/2007 no es lo mismo que #12/04/2007#. La primera expresión es una división y la segunda una fecha.)
Otro problema:
El padre de Jaimito trabaja en turno de noche en la fábrica de colchones ColcheX y entró a las 10 y media de la noche del 14/7/2003. El turno es de 7 horas y 33 minutos. ¿A qué hora salió?
Hago lo mismo:
?#14/7/2003 22:30# + #7:33#, lo que nos da como respuesta 15/07/2003 6:03:00 , totalmente correcta.
Hubiera sido lo mismo plantearlo como
"A la hora de entrada le sumo la fracción de
d��a que suponen las 7h con 33m"
y nos debe dar lo mismo.Dado que dicha
fracción puede representarse como
7m 33s = 7/24 + 33/60/24 = 0,3145833 (en americano 0.3145833), no es de extrañar que
?#14/7/2003 22:30# + 0.3145833, también nos dé 15/07/2003 6:03:00
ó que
?#14/7/2003 22:30# + 7/24 (minutos reducidos a días) + 33/60/24 (segundos reducidos a días),
ó que
obtenga el mismo resultado 15/07/2003
6:03:00
ó que
?#14/7/2003 22:30# + ((7 + 33) / 60) / 24, pues lo mismo.
Otro problema:
El padre de Jaimito trabaja en turno de noche en la fábrica de fibra de vidrio "La Coronita" y entra todas las noches a las 10 y media. El turno es de 7 horas y 33 minutos. ¿A qué hora sale?
¡Esto está chupado!, nos decimos. Ponemos
?#22:30# + #7:33#,
y nos da la sorprendente (si lo esperábamos
ya no es sorpresa) respuesta de
31/12/1899 6:03:00
En la que observo que la hora de salida es correcta, pero la fecha, ¿qué pasa con la fecha?
Pues nada; que al no poner día nos considera las diez y media de la noche del día cero.
Recordemos que dicho día (el cero):
?format(cdate(0),"dd/mm/yyyy, ddd") es el 30/12/1899, sáb
Y como detrás del treinta viene el treinta y uno, pues no es de extrañar que el día siguiente sea el día de San Silvestre (Año Viejo) de 1899.
Pues no lo hagáis caso. En realidad yo solo quería saber a qué hora salía, luego pido sólo la hora.
(No necesito el día: ya me se que es del día siguiente)
¿Como?.
Pues con el Format correspondiente (solo horas y minutos).
?format(#22:30# + #7:33#, "hh:nn" ), obteniendo lo que cabía esperar: 06:03
Y otro:
¿Cual es el día que está entre el 30 de diciembre de 2003 y el 1 de Enero de 2004?
Pues la semisuma:
?format((#30/12/2003# + #1/1/2004#)/2, "d-m-yyyy")
= 31-12-2003
Si no pongo format: ?(#30/12/2003# + #1/1/2004#)/2 = 37986
Lo que es lo mismo, ya que ?format(37986, "d-m-yyyy") = 31-12-2003
Otro más , un pelín paradójico, porque pide una respuesta, digamos, rara:
¿Cual es el día que está entre el 30 de diciembre de 2003 y el San Silvestre de tal año o sea el 31de diciembre de 2003?
?format((#30/12/2003# + #31/12/2003#)/2, "d-m-yyyy") = 30-12-2003
¿Se ha confundido? No. Porque ha buscado el punto medio del día 30 (cuando empieza) y el del 31 (en su comienzo). ¿Dónde está dicho punto?. Pues en el mediodía del 30.
Veámoslo de otras formas:
(#30/12/2003# + #31/12/2003#) / 2 = 37985,5 (día 30 y medio, podíamos decir).
Más claro:
?format((#30/12/2003# + #31/12/2003#)/2, "d-m-yyyy h:n") = 30-12-2003 12:0, ó
?format((#30/12/2003# + #31/12/2003#)/2, "d-m-yyyy h:nn") = 30-12-2003 12:00, ó
?format((#30/12/2003# + #31/12/2003#)/2, "d-m-yyyy h:nn:ss") = 30-12-2003 12:00:00,
donde segundos y minutos no son significativos, porque no existen, pero si dan idea de una mayor precisión.
Otro:
Quisiera sumar un minuto a la hora actual.
Respuesta:
Now() + (1/1440).
Ó Now() + (1 / 60 / 24)
En ambos casos la expresión entre paréntesis convierte el minuto en una fracción de día. Pues el día es la unidad en que se trabaja en esto de las fechas/horas
Más:
Dada una hora en un campo tipo date, llamado LaHora, ¿cómo redondear al cuarto de hora siguiente?
Respuesta:
cdate(clng ((LaHora * 24 + 0.2499) * 4) / 4 / 24)
(El truco está en trasladar el momento a –casi- un cuarto de hora más tarde y despreciar la fracción que sobre del cuarto de hora).
Y otro:
Dada una hora en LaHora, un campo tipo date, ¿cómo redondear al cuarto de hora más cercano?
Respuesta:
cdate(clng ((LaHora * 24 + 0.1249) * 4) / 4 / 24)
(En la misma línea que el anterior pero ahora traslado a la mitad del cuarto de hora más tarde)
Convertir una hora en una fracción de día, es un problema que admite varios enfoques en función de los datos que tengas y cómo los tengas.
Casos habituales.
Tienes separados o puedes separarlos los componentes del tiempo: horas, minutos y, quizá, segundos
Su fracción es:
(horas / 24 + minutos / (24 * 60) +
segundos) / (24 * 60 * 60)
ó su equivalente
((horas * 60 + minutos) * 60 + segundos) /
(24 * 60 * 60)
En el caso de la 8 y media, 8:30, 8,5 (que
todos son lo mismo):
8 / 24 + 30 /(24 * 60) =
0.354166
La hora, los minutos y los segundo forman
parte de un campo de tipo fecha ó date:
Sabes que Access expresa un momento en el
tiempo, como un número con parte entera y
parte decimal:
día , fracción_del_día
¿Como verlo de esta forma?.
Tomemos el momento actual ó ahora: now(),
que mi caso me da: now() =22/07/2004 8:04:11
(Si fuera un campo llamado momento, sería
sustituir now() por momento)
Pues, para ver sus partes, puede ser así:
cdbl(now()), lo que me da en este
momento: 38190,3374537037 (Hoy es el día
38190. Ahora es la fracción 0,3374537037 de
hoy)
Con lo que queda claro que la fracción del
día en la que estamos es su parte decimal:
0,3374537037
Si la quiero tener separadita, pues le quito
la parte entera.
¿Cómo?. Pues
Si quiero verlo en forma de h:m:s:
cdbl(now()) - int(now()) = 8:04:11
Y si lo quiero ver en decimal
cdbl(cdbl(now()) - int(now())) = 0,3374537037
Anexos:
De Leonardo Henrnández Ferreiro
Función para calcular el Domingo de Pascua:
Function DomingoPascua(Año As Integer)
As Date
' Esta función ha
sido desarrollada por Leonardo
Henrnández Ferreiro lhf@coiim.es
' Particularmente para los usuarios de
la lista soloaccess. Puede utilizarse
libremente
' cuantas veces se desee manteneniendo
el origen de la misma
Dim R1 As Integer, R2 As Integer, R3 As
Integer, TFECHA As Date
R1 = (19 * (Año - Int(Año / 19) * 19) +
24) - Int((19 * (Año - Int(Año / 19) *
19) + 24) / 30) * 30
R2 = (2 * (Año - Int(Año / 4) * 4) + 4 *
(Año - Int(Año / 7) * 7) + 6 * R1 + 5) -
Int((2 * (Año - Int(Año / 4) * 4) + 4 *
(Año - Int(Año / 7) * 7) + 6 * R1 + 5) /
7) * 7
R3 = R1 + R2
If R3 >= 10 Then TFECHA = (R3 - 9) &
"/04/" & Año Else TFECHA = (R3 + 22) &
"/03/" & Año
DomingoPascua = TFECHA
End Function
'Sabiendo el Domingo de Pascua, ya podemos saber más datos, en forma de diferencia de días:
'Miércoles de Ceniza (Inicio cuaresma) 46 días antes del domingo de Pascua
'Domingo de Ramos 7 días antes del domingo de Pascua
'Domingo de Ascensión (antes jueves) 42 días después del domingo de Pascua.
'Domingo de Pascua de Pentecostés 49 días después del domingo de Pascua
'Domingo de Corpus Christi (antes jueves) 63 días después del domingo de Pascua
De Francisco Rivera:
' Trabajando con días laborables en VBA
' Author: Ken Getz
' Traducción y Adap: Francisco Rivera (fzombie)
VBA y Access no proveen ningún soporte para trabajar con los típocos días laborables el "VBA Developers Handbook" contiene varias funciones que proveen información sobre los días siguientes y los previos, y para encontrar el primero y el último día laborable en un mes. Para trabajar con vacaciones, la función original SkipHolidays acepta una referencia a un recordset que contenga todas las fechas que quieres brincarte. Para incrementar la flexibilidad y facilidad de uso, las funciones originales han sido re-escritas para aceptar una array de vacaciones, como la función en Excel.
' ********* Inicio del Código **************
Public Function AñadeDiasLab(lngDias As
Long, Optional FechaIn As Date = 0,
Optional ArrVacaciones As Variant) As
Date
' Añade el número especificado de día
laborables a la fecha indicada
' Entrada:
' lngDias: Número de días laborables que
añadiremos a la fecha inicial
' FechaIn: Fecha en la cual comenzamos a
buscar. Se usa la fecha actual no se
especifica una
' ArrVacaciones (Opcional): Array que
contiene las fechas de vacaciones.
Puedes ser un solo valor
' Salida:
' Valor de Retorno : La fecha de los
días trabajados tomando en cuenta fines
de semana y vacaciones
' Ejemplo:
' AñadeDiasLab(10, #2/9/2000#, Array(#2/16/2000#,
#2/17/2000#))
' nos regresa #2/25/2000#, el cual es la
fecha más 10 días laborables
Dim lngConteo As Long
Dim dtmTemp As Date
If FechaIn = 0 Then FechaIn = Date
dtmTemp = FechaIn
For lngConteo = 1 To lngDias
dtmTemp = SigDiaLab(dtmTemp,
ArrVacaciones)
Next lngConteo
AñadeDiasLab = dtmTemp
End Function
Public Function SigDiaLab(Optional
FechaIn As Date = 0, Optional
ArrVacaciones As Variant = Empty) As
Date
' Obtiene el siguiente día laborable
después de la fecha especificada.
' Requiere:
' SaltarVacaciones
' EsFindeSemana
' Entrada:
' FechaIn: Fecha en la cual comenzamos a
buscar. Se usa la fecha actual no se
especifica una.
' ArrVacaciones (Opcional): Array que
contiene las fechas de vacaciones.
Puedes ser un solo valor
' Salida:
' Valor de Retorno: La fecha del
siguiente día laborable tomando en
cuenta fines de semana y vacaciones
' Ejemplo:
' FechaIn = SigDiaLab(#5/23/1997#,
#5/26/97#)
If FechaIn = 0 Then FechaIn = Date
SigDiaLab = SaltarVacaciones(ArrVacaciones,
FechaIn + 1, 1)
End Function
Public Function AntDiaLab(Optional
FechaIn As Date = 0, Optional
ArrVacaciones As Variant = Empty) As
Date
' Obtiene el anterior día laboral antes
dela fecha especificada.
' Requiere:
' SaltarVacaciones
' EsFindeSemana
' Entrada:
' FechaIn: Fecha en la cual comenzamos a
buscar. Se usa la fecha actual no se
especifica una.
' ArrVacaciones (Optional): Array que
contiene las fechas de vacaciones.
Puedes ser un solo valor
' Salida:
' Valor de Retorno: La fecha del
anterior día laborable tomando en cuenta
vacaciones y fines de semana
' Ejemplo:
' FechaIn = AntDiaLab(#1/1/2000#, Array(#12/31/1999#,
#1/1/2000#))
If FechaIn = 0 Then FechaIn = Date
AntDiaLab = SaltarVacaciones(ArrVacaciones,
FechaIn - 1, -1)
End Function
Public Function PrimerDiaLabMes(Optional
FechaIn As Date = 0, Optional
ArrVacaciones As Variant = Empty) As
Date
' Obtiene el primero día laborable del
mes especificado
' Requiere:
' SaltarVacaciones
' EsFindeSemana
' Entrada:
' FechaIn: Fecha del mes que nos
interesa. Usa la actual si no
especificamos una
' ArrVacaciones (Opcional): Array que
contiene las fechas de vacaciones.
Puedes ser un solo valor
' Salida:
' Valor de Retorno: La fecha del primer
día laborable en el mes, tomando en
cuenta vacaciones y fines de semana
' Ejamplo:
' FechaIn = PrimerDiaLabMes(#1/1/1999#,
#1/1/1999#)
Dim dtmTemp As Date
If FechaIn = 0 Then FechaIn = Date
dtmTemp = DateSerial(Year(FechaIn),
Month(FechaIn), 1)
PrimerDiaLabMes = SaltarVacaciones(ArrVacaciones,
dtmTemp, 1)
End Function
Public Function UltimoDiaLabMes(Optional
FechaIn As Date = 0, Optional
ArrVacaciones As Variant = Empty) As
Date
' Obtiene el último día laboral en el
mes especificado.
' Requiere:
' SaltarVacaciones
' EsFindeSemana
' Entrada:
' FechaIn: Fecha del mes que nos
interesa
' ArrVacaciones (Opcional): Array que
contiene las fechas de vacaciones.
Puedes ser un solo valor
' Salida:
' Valor de Retorno: La fecha del ultimo
día laborable en el mes, tomando en
cuenta vacaciones y fines de semana
' Ejamplo:
' FechaIn = UltimoDiaLabMes(#12/1/1999#,
#12/31/1999#)
Dim dtmTemp As Date
If FechaIn = 0 Then FechaIn = Date
dtmTemp = DateSerial(Year(FechaIn),
Month(FechaIn) + 1, 0)
UltimoDiaLabMes = SaltarVacaciones(ArrVacaciones,
dtmTemp, -1)
End Function
Public Function ContarDiasLab(ByVal
dtmInicio As Date, ByVal dtmFin As Date,
Optional ArrVacaciones As Variant =
Empty) As Integer
' Cuenta los días laborables (sin fines
de semana ni vacaciones en una rango de
fechas )
' Requiere:
' SaltarVacaciones
' CountHolidays
' EsFindeSemana
' Entrada:
' dtmInicio: Fecha que especifica el
inicio del rango
' dtmFin: Fecha que especifica el fin
del rango
' ArrVacaciones (Opcional): Array que
contiene las fechas de vacaciones.
Puedes ser un solo valor
' Salida:
' Valor de Retorno: Número de días
laborables, sin contar fines de semana y
opcionalmente vacaciones
' Ejamplo:
' ContarDiasLab(#7/2/2000#, #7/5/2000#,
)
Dim intDias As Integer, dtmTemp As Date,
intExtrae As Integer
If dtmFin < dtmInicio Then
dtmTemp = dtmInicio
dtmInicio = dtmFin
dtmFin = dtmTemp
End If
dtmInicio = SaltarVacaciones(ArrVacaciones,
dtmInicio, 1)
dtmFin = SaltarVacaciones(ArrVacaciones,
dtmFin, -1)
If dtmInicio > dtmFin Then
ContarDiasLab = 0
Else
intDias = dtmFin - dtmInicio + 1
intExtrae = (DateDiff("ww", dtmInicio,
dtmFin) * 2)
intExtrae = intExtrae +
ContarVacacionesA(ArrVacaciones,
dtmInicio, dtmFin)
ContarDiasLab = intDias - intExtrae
End If
End Function
Private Function ContarVacacionesA(ArrVacaciones
As Variant, dtmInicio As Date, dtmFin As
Date) As Long
' Contamos las vacaciones entre dos
fechas finales.
' Requerida por:
' ContarDiasLaborables
' Requiere:
' EsFindeSemana
Dim lngItem As Long
Dim lngConteo As Long
Dim blnEncontrado As Long
Dim dtmTemp As Date
On Error GoTo ManejoError
lngConteo = 0
Select Case VarType(ArrVacaciones)
Case vbArray + vbDate, vbArray +
vbVariant
For lngItem = LBound(ArrVacaciones) To
UBound(ArrVacaciones)
dtmTemp = ArrVacaciones(lngItem)
If dtmTemp >= dtmInicio And dtmTemp <=
dtmFin Then
If Not EsFinDeSemana(dtmTemp) Then
lngConteo = lngConteo + 1
End If
End If
Next lngItem
Case vbDate
If ArrVacaciones >= dtmInicio And
ArrVacaciones <= dtmFin Then
If Not EsFinDeSemana(ArrVacaciones) Then
lngConteo = 1
End If
End If
End Select
ExitHere:
ContarVacacionesA = lngConteo
Exit Function
ManejoError:
Resume ExitHere
End Function
Private Function FindItemInArray(varItemToFind
As Variant, avarItemsToSearch As Variant)
As Boolean
Dim lngItem As Long
On Error GoTo ManejoError
For lngItem = LBound(avarItemsToSearch)
To UBound(avarItemsToSearch)
If avarItemsToSearch(lngItem) =
varItemToFind Then
FindItemInArray = True
GoTo ExitHere
End If
Next lngItem
ExitHere:
Exit Function
ManejoError:
Resume ExitHere
End Function
Private Function EsFinDeSemana(dtmTemp
As Variant) As Boolean
' Si tus fines de semana no son Sábado (día7)
ó Domingo (Día 1) cambiamos la rutina
para devolver
' True para cualquier días que uses como
tus fines de semana
' Requerida por:
' SaltarVacaciones
' PrimerDiaLabMes
' UltimoDiaLabMes
' SigDiaLab
' AntDiaLab
' ContarDiasLab
If VarType(dtmTemp) = vbDate Then
Select Case EsFinDeSemana(dtmTemp)
Case vbSaturday, vbSunday
EsFinDeSemana = True
Case Else
EsFinDeSemana = False
End Select
End If
End Function
Private Function SaltarVacaciones(ArrVacaciones
As Variant, dtmTemp As Date,
intIncrement As Integer) As Date
'
Nos saltamos los fines de semana y
vacaciones en un arreglo referido como
by ArrVacaciones.
' Requerida por:
' PrimerDiaLabMes
' UltDiaLabMes
' SigDiaLab
' AntDiaLab
' ContarDiasLab
' Requiere:
' EsFindeSemana
Dim strCriterio As String
Dim strNomCampo As String
Dim lngItem As Long
Dim blnEncontrado As Boolean
On Error GoTo ManejoError
Do
Do While EsFinDeSemana(dtmTemp)
dtmTemp = dtmTemp + intIncrement
Loop
Select Case VarType(ArrVacaciones)
Case vbArray + vbDate, vbArray +
vbVariant
Do
blnEncontrado = FindItemInArray(dtmTemp,
ArrVacaciones)
If blnEncontrado Then
dtmTemp = dtmTemp + intIncrement
End If
Loop Until Not blnEncontrado
Case vbDate
If dtmTemp = ArrVacaciones Then
dtmTemp = dtmTemp + intIncrement
End If
End Select
Loop Until Not EsFinDeSemana(dtmTemp)
ExitHere:
SaltarVacaciones = dtmTemp
Exit Function
ManejoError:
Resume ExitHere
End Function
' ********* Fin del Código **************
' Tiempo, añadir y quitar, y hojas de tiempo.
' Author: Robin Stoddart-Stones
' Traducción y Adap: Francisco Rivera (fzombie)
Ha habido un reciente debate sobre como "Añadir tiempo", "Convertir horas en minutos", y "Trabajar sobre las 24 horas", y existen métodos interesantes Access 97/2000 tienes el campo Fecha/Hora que tiene algunas propiedades interesantes.
Preparando el campo Fecha/Hora
Si especificamos el campo Fecha como Fecha/Hora, toma la fecha y hora actual del sistema. Esto nos da un simple formato de fecha pata aplicaciones de tiempo.
Vamos a usar la ventana Inmediato para probar esto (suponiendo que saben manejar la ventana Inmediato)
Usar un botón para almacenar la Fecha y Hora en un campo Fecha (o una variable de Fecha)
Esto sería:
Dim lsdt as Date (en el módulo) y en la ventana Inmediato (ó ventana de depuración)
lsdt=Date + Time
? lsdt= "17/02/99 17:10:49" (correcto al momento de escribir)
Un campo fecha puede ser extraido de otro y el resultado sería la fracción del día
Esto sería:
lsdt=#16:00#-#15:45#
?lsdt
1.04166666666666E-02
? (24*60)*1.04166666666666E-02
14.9999999999999 (aproximadamente 15 minutos para n/1000ths de un segundo)
En otras palabras, extraer un tiempo de otro para obtener una respuesta aritmética. Añadimos varias de esas fracciones juntas y obtenemos el tiempo total.
?1.04166666666666E-02 +1.04166666666666E-02
2.08333333333332E-02
?(24*60)*2.08333333333332E-02
29.9999999999998 (Lo suficientemente cerca a 30 minutos)
Si el resultado está debajo de las 24 horas podemos mostrar el total de manera muy simple sin usas matemáticas, usando format (x, "Short Timer")
Esto sería:
?format(2.08333333333332E-02,"short time")
00:30
Lo cual es muy útil.
Por ejemplo si tus cobros son 11.50 por hora entonces tu promedio diario es = 24*11.50 y el cargo para 30 minutos de trabajo sería:
?24*11.50 * 2.08333333333332E-02
5.74999999999996
Así, en un campo fecha tienes almacenados el numero de las horas trabajadas, y una opción de formato nos dice a los usuarios de ese tiempo en un cálculo simple y podemos obtener el costo aun debajo de 24 horas totales de trabajo
Pero que pasa si hemos trabajado más de 24 horas ?? Simple, si añadimos incrementos pequeños. Veamos una demostración de 47 medias horas a 49 medias horas
?47*2.08333333333332E-02
0.97916666666666
?24* 0.97916666666666
23.4999999999998 (47 medias horas son 23.5 horas)
?48*2.08333333333332E-02
0.999999999999994
?24*0.999999999999994
23.9999999999999 (24 horas)
?49*2.08333333333332E-02
1.02083333333333
?24*1.02083333333333
24.4999999999999 (24.5 Horas)
Ahora, si calculamos la duración podemos añadir esta duración de 24.5 horas a una fecha y encontrar la fecha final
lsdt=#01-dic-99#
?lsdt
01/12/99
lsdt=lsdt+1.02083333333333
?lsdt
02/12/99 00:30:00
En otras palabras, la medianoche entre el 30/Nov/99 y el 1/Dic/99 + 24.5 horas es pasada la medianoche del 2 de Diciembre. El único problema es que aqui no tenemos un formato rápido para decir que número de días y horas tenemos si hemos ido más allá de las 24.
?format(1.02083333333333,"short Time")
00:30
Pero no nos tomará mucho probar si el valor el mayor que uno ó calcular la fracción de las 24 horas que restan
lsdt=1.020833333333
dias=Int(lsdt)
?dias
1
Horas=24*(lsdt-dias)
?horas
0.499999999991999
minutos=(horas-int(horas))*60
?minutos
29.99999999952
Y si trabajamos sobre la medianoche, entonces:
?#02-dic-99 00:30# - #01-dic-99 00:00#
1.02083333333576
Lo cual está lo suficientemente cerca para mi en este momento (La diferencia es la precisión de la máquina cuando multiplica 49 veces)(y 49 medias horas se convierte en 1.0208333333)
Haciendo el proceso al revés:
Si estás trabajanod hojas de tiempo en dónde se escriben las horas y los minutos en lugar de Tiempos, entonces:
minutos =mins/(24*60)
Horas=hrs/24
Tiempo=horas + minutos
?#07:30#-#00:00#
0.3125
minutos=30/(24*60)
horas=7/24
?horas+minutos
0.3125
Yo suelo tener definidas unas constates públicas que me lo tienen preparado.
Const hora As Single = 1 / 24
Const minuto As Single = 1 / 24 / 60
Const segundo As Single = 1 / 24 / 60 / 60
Así que cuando quiero restar n minutos de un campo Fecha/hora llamado, p.ej. instante,
resultado = instante - n * minuto
' Cuantos domingos hay entre dos fechas
' Author: Michel Walsh
' Traducción y Adap: Francisco Rivera (fzombie)
Por una observación inicial hecha por Lyle Fairfield, aqui hay una solución para obtener el número de, digamos, miércoles entre dos fechas indicadas:
Public Function CuantosD(FechaIni As
Date, FechaFin As Date, WD As Long)
' Puedes usar el manejo de errores como
quieras.
CuantosD = DateDiff("ww", FechaIni,
FechaFin, WD) - Int(WD = Weekday(FechaIni))
End Function
De la misma forma, alguien puede fácilmente obtener el número de días de la semana (excluyendo fines de semana) simplemente quitando el número de sábados y domingos:
Public Function CuantosDSem(FechaIni As
Date, FechaFin As Date, Optional
FechaFinesIncluida As Boolean = True)
CuantosDSem = DateDiff("d", FechaIni,
FechaFin) - FechaFinesIncluida -
CuantosD(FechaIni, FechaFin, vbSunday) -
CuantosD(FechaIni, FechaFin, vbSaturday)
End Function
FUNCION DIAS LABORABLES
Function Dias_Lab(FechaIni As Variant,
FechaFin As Variant) As Integer
' Esta función no trabaja con vacaciones
Dim Semanas As Variant
Dim DateCnt As Variant
Dim DiasFin As Integer
FechaIni = DateValue(FechaIni)
FechaFin = DateValue(FechaFin)
Semanas = DateDiff("w", FechaIni,
FechaFin)
DateCnt = DateAdd("ww", Semanas,
FechaIni)
DiasFin = 0
Do While DateCnt < FechaFin
If Format(DateCnt, "ddd") <> "Sun" And
Format(DateCnt, "ddd") <> "Sat" Then
DiasFin = DiasFin + 1
End If
DateCnt = DateAdd("d", 1, DateCnt)
Loop
Dias_Lab = Semanas * 5 + DiasFin
End Function
' Como manejar la medianoche en los cálculos de tiempo
' Author: Robin Stoddard-Stones
' Traducción: Francisco Rivera (fzombie)
Si quieres incluir a la medianoche en tus cálculos de tiepo, una manera sencilla
es incluir el operador de medianoche (1)
Sería: #23.45# -1 = 00:15:00
Si necesitas ir más allá de la medianoche entonces necesitas incluir el operador
(y formatear el resultador para poder entenderlo)
#23:45# - 1-#00.15# = -2.08333333333333E-02
pero
format(#23:45#-1-#00:15#,"short time") = 00:30
y
format(-2.08333333333333E-02, "short time")= 00:30"
FUNCIONES VARIAS PARA EL MANEJO DE FECHAS
'*************************** Inicio de Código *******************************
Function PrimeroMes(LaFecha
As Date)
' Este
código fué originalmente escrito por
Lewis Moseley.
' Eres libre de usarlo en tus
aplicaciones, ' siempre y cuando se
quede este copyright.
' Adaptado por Francisco Rivera (fzombie)
' Código cortesía de Lewis Moseley
' Obtiene la fecha que es el primer dia
del mes de la fecha indicada
Dim D As Integer, M As Integer, Y As
Integer
If IsNull(LaFecha) Then
PrimeroMes = Null
Else
D = Day(LaFecha)
M = Month(LaFecha)
Y = Year(LaFecha)
PrimeroMes = DateSerial(Y, M, 1)
End If
End Function
Function UltimoMes(LaFecha As Date)
' Obtiene la
fecha que es el último día del mes, de
la fecha indicada
Dim D As Integer, M As Integer, Y As
Integer
If IsNull(LaFecha) Then
UltimoMes = Null
Else
D = Day(LaFecha)
M = Month(LaFecha)
Y = Year(LaFecha)
' Encontramos el primer día del
siguiente mes y regresamos un día
UltimoMes = DateAdd("m", 1, DateSerial(Y,
M, 1)) - 1
End If
End Function
Function MesSig(LaFecha As Date)
' Obtiene
una fecha con un mes más adelantado a
partir de la fecha indicada
MesSig = DateAdd("m", 1, LaFecha)
End Function
Function MesPas(LaFecha As Date)
' Obtiene
una fecha con un mes de retraso a partir
de la fecha indicada
MesPas = DateAdd("m", -1, LaFecha)
End Function
Function DiadelMes(LaFecha As Date,
DiaEsp As Integer)
' Obtiene la
fecha que es el día especificado del mes
y año indicado
Dim M As Integer, Y As Integer
If IsNull(LaFecha) Then
DiadelMes = Null
Else
M = Month(LaFecha)
Y = Year(LaFecha)
DiadelMes = DateSerial(Y, M, DiaEsp)
End If
End Function
'*************************** Fin Código *******************************
‘ Obtener una fecha en el futuro con una fecha determinada
‘ Author: Dev Ashish
‘ Traducción y Adap: Francisco Rivera (fzombie)
(P) ¿ Como puedo tomar una fecha y obtener la misma fecha con una año de adelanto ?
tmpFecha = #1/Ene/97#
NuevaFecha= DateSerial(year(tmpFecha)+1, month(tmpFecha), day(tmpFecha))
Deberíamos obtener un valor de 1/Ene/98para la variable NuevaFecha.
También podemos usar la función function forde esta manera:
NuevaFecha = DateAdd( 1, "yyyy", tmpFecha)
‘Calcular la edad de una persona
‘Author: Dev Ashish, Michel Walsh & Tim Walters
‘ Traducción y Adap: Francisco Rivera (fzombie)
(P) Como puedo calcular la edad de una persona conociendo su fecha de nacimiento?
Asumimos que el campo de la fecha de nacimiento se llama [FechaNac] y es del tipo Fecha, podemos usar el siguiente cálculo:
Edad=DateDiff("yyyy", [FechaNac], Now())+Int( Format(now(), "mmdd") < Format( [FechaNac], "mmdd") )
Alternativa: Puedes usar esta función para calcular la edad
Function Edad(FechaIni, FechaHoy) As
Integer
If Month(FechaHoy) < Month(FechaIni) Or
(Month(FechaHoy) = Month(FechaIni) And
Day(FechaHoy) < Day(FechaIni)) Then
Edad = Year(FechaHoy) - Year(FechaIni) -
1
Else
Edad = Year(FechaHoy) - Year(FechaIni)
End If
End Function
Esta es otra función para edad, más detallada
Public Sub
CalcEdad(vFecha1 As Date,
vFecha2 As Date, ByRef vYears As Integer,
ByRef vMeses As Integer, ByRef vDias As
Integer)
' Calcula la edad en Años, Meses y Días
vMeses = DateDiff("m", vFecha1, vFecha2)
vDias = DateDiff("d", DateAdd("m",
vMeses, vFecha1), vFecha2)
If vDias < 0 Then
vMeses = vMeses - 1
vDias = DateDiff("d", DateAdd("m",
vMeses, vFecha1), vFecha2)
End If
vYears = vMeses \ 12
vMeses = vMeses Mod 12
End Sub
P.- ¿Qué formato aplicar al 1/1/2004 para que salga como “1 de Enero de 2004”?
R.- Prueba con el siguiente formato: d" de "mmmm" de "aaaa
P. Necesito saber cómo generar el día juliano mediante una fecha, ya sea con una consulta o en un campo calculado en un formulario.
R. No sé qué entiendes por día juliano.
En mis tiempos de Cobol (¡qué tiempos aquellos!) significaba el nº de día consecutivo a partir del 1 de enero de ese año.
Si es así, la cosa es una simple resta de fechas.
DíaJuliano = Fecha - cdate("1/1/" & year(Fecha)) + 1, donde Fecha es aquella para la que quieres el día juliano.
Nosotros llamábamos Fecha Juliana, en contraposición a la Fecha Gregoriana, a la que se de daba en formato
aajjj ó aaaajjj,
donde a es el año en dos o cuatro cifras y jjj el día juliano anteriormente definido.
FechaJuliana = format(Fecha, "yy") & format(DíaJuliano,"000") ó format(Fecha, "yyyy") & format(DíaJuliano,"000") , si es en ámbito interno ó
FechaJuliana = format(Fecha;"aa") & format(DíaJuliano;"000") ó format(Fecha; "aaaa") & format(DíaJuliano;"000") , si lo es en el externo
P. Quiero pasar un numérico a un tipo fecha/hora. Por
ejemplo pasar 120 minutos a un formato hora, es decir, 2:00 horas para luego almacenar esas 2:00 horas en campo fecha/hora.
R. Access almacena un determinado momento del tiempo como un nº, el cual
en su parte entera nos habla del día
(es un nº consecutivo desde el 1, referido
al día (cdate(1)=) 31/12/1899, en que
comienza el calendario de Access), y
en su parte decimal de la fracción del día que corresponda.
Así, por ejemplo, el instante señalado como
el segundo nº 14 del minuto 30 de las 3 de la tarde del 17 de Mayo del año de gracia de 2002, es para Access el nº
37393,6459953704
El que lo veamos como 17/5/2002 15:30:14 es puro maquillaje. Eso lo hace el formato que se aplica.
Si pides, port ejemplo,
cdate(37393.6459953704) (entre otras formas), tienes la respuesta en tu formato regional para fechas y horas. Yo obtengo: 17/05/2002 15:30:14
Así pues, para transformar cualquier concepto de tiempo al formato Fecha/Hora debes convertirlo en días.
Si tu número entero habla de minutos, tendrás que dividirlo entre (24 X 60 =) 1440 minutos que tiene el día y así lo tendrás con el valor justo.
Ej. tiempo = minutos / 1440
(donde tiempo es un campo Fecha/hora y minutos es el campo numérico que comentabas)
segundos, habría que dividirlo entre 86400 (24 X 60 X 60)
milisegundos, entre 8640000 que es el resultado de 24 X 60 X 60 X 1000 horas, 24 semanas, habría que multiplicarlo por 7 y así sucesivamente.
P- Averiguar el nº de días de la semana escogido que hay entre dos fechas dadas.
Function Pasados(Inicio As Date, Fin As Date, DíaSemana As Byte) As Integer
' Calcula el número de días de la semana prefijados (lunes, martes, ...)
' pasados entre dos fechas puras, inclusive ambas
' Es decir, de un lunes al siguiente lunes, devolvería 2
' DíaSemana: 1 si es Domingo, 2 si Lunes, ... (El estándar de que el Domingo sea 1, puede cambiarse en el programa)
Dim Semanas As Integer, Quedan As Byte, OtroMás As Byte, ElInicioEs As Integer, ElÚltimoEs As Byte
If Int(Fin) < Int(Inicio) Then MsgBox "Las fechas deben estar en orden. Sin embargo " & Inicio & " es posterior a " & Fin: Exit Function
If DíaSemana < 1 Or DíaSemana > 7 Then MsgBox "El dia de la semana ha de estar entre 1 y 7": Exit Function
Semanas = Int((Fin - Inicio) / 7): Quedan = (Int(Fin) - Int(Inicio)) - (7 * Semanas)
ElInicioEs = Weekday(Inicio): ElÚltimoEs = Weekday(DateAdd("D", Quedan, Inicio))
If ElÚltimoEs < ElInicioEs Then
OtroMás = Abs(DíaSemana >= ElInicioEs) + Abs(DíaSemana <= ElÚltimoEs)
Else
OtroMás = Abs(DíaSemana >= ElInicioEs And DíaSemana <= ElÚltimoEs)
End If
Pasados = Semanas + OtroMás
End Function
Calcular en minutos el retraso de entrada de una persona
Como no tengo tu modelo de datos, cosa que cuando se pide ayuda es muy interesante incluir, vamos a ver como calcularía el retraso en minutos de un señor que teniendo que entrar a las 7:55 entra a la hora que indica su ficha de Marcaje.
Llamo MarcaEntrada al now() del marcaje de la ficha en un día determinado.
Supongo, pues, que este marcaje incluye el día y la hora.
No me voy a fijar en el día (supongo por muy retrasado que entre los hará en el mismo día. Si fuera turno de noche que empieza a las 23:55 y el empleado entra a las 00:17, estaríamos en otro caso).
HoraDeEntrar = 7/24 + 55/24/60 '<<No hacemos caso del día
HoraDeEntrada = MarcaEntrada - int(MarcaEntrada) '<<No hacemos caso del día, y nos quedamos con su fracción
if HoraDeEntrar < HoraDeEntrada then
RetrasoEnFracciónDeDía = (HoraDeEntrada -HoraDeEntrar) 'días
RetrasoEnFracciónDeHora = (HoraDeEntrada -HoraDeEntrar) * 24 'horas
RetrasoEnFracciónDeMinuto = (HoraDeEntrada -HoraDeEntrar) * 24 * 60 'minutos
RetrasoEnFracciónDeSegundoo = (HoraDeEntrada -HoraDeEntrar) * 24 * 60 * 60 'segundos
Else
'No hay retraso
End if
Si acumulas el tiempo retrasado tendrás el retraso total (en la unidad de tiempo que hayas escogido). Si no ha sido en minutos, lo puedes transformar de forma fácil, según hemos hecho.
FIN !!