🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA Weekday y DatePart en Excel — extraer partes de una fecha, y por qué el lunes no es 1

|

VBA Weekday y DatePart en Excel — extraer partes de una fecha, y por qué el lunes no es 1

TL;DRYear(d), Month(d), Day(d), Hour(t), Minute(t), Second(t) devuelven cada uno un entero de una fecha — simple y sin ambigüedad. Weekday(d) es la trampa: devuelve de 1 a 7, pero la numeración depende de un segundo argumento que por defecto es vbSunday (1), así que por defecto el lunes es 2, no 1. Pasa vbMonday (o compara contra las constantes vb*) y la lógica de fin de semana deja de estar calladamente mal.

Sub PartsDemo()
    Dim d As Date: d = #2026-08-26#        ' un miercoles
    Debug.Print Year(d), Month(d), Day(d)  ' 2026  8  26
    Debug.Print Weekday(d)                 ' 4  - por defecto domingo=1, miercoles=4
    Debug.Print Weekday(d, vbMonday)       ' 3  - lunes=1, miercoles=3
    Debug.Print DatePart("ww", d)          ' 35 - numero de semana (sin funcion propia)
End Sub

Extraer partes es lo contrario de construir una fecha a partir de sus partes: tienes el Double y quieres el año, el mes, el día de la semana. La mayoría de las funciones son justo tan aburridas como deberían — Year, Month, Day se limitan a leer el número. Weekday es la que ha acabado con más macros de la cuenta, enteramente por culpa de un valor por defecto que nadie recuerda.

Lo que aprenderás

  • Los extractores simples — Year, Month, Day, Hour, Minute, Second — un entero cada uno
  • Por qué Weekday devuelve 2 para el lunes por defecto, y el único argumento que lo arregla
  • Cómo escribir pruebas de fin de semana y de días laborables que no estén mal en secreto
  • DatePart — el extractor general que alcanza el número de semana y el trimestre
  • Por qué los números de semana de DatePart("ww", …) pueden desviarse en uno en la frontera del año (ISO 8601)
  • WeekdayName y MonthName devuelven nombres localizados — para mostrar, no para parsear

Los extractores simples: un entero cada uno

Year, Month y Day descomponen una fecha en sus componentes de calendario; Hour, Minute y Second descomponen la fracción de hora. Cada uno devuelve un Integer normal y corriente, y no hay con qué tropezar:

Dim d As Date: d = Now                 ' 2026-08-26 14:30:07
Debug.Print Year(d)      ' 2026
Debug.Print Month(d)     ' 8   (un numero 1-12, no el nombre)
Debug.Print Day(d)       ' 26
Debug.Print Hour(d)      ' 14  (formato 24 horas)
Debug.Print Minute(d)    ' 30
Debug.Print Second(d)    ' 7

Month devuelve 8, no "August" — es un número. Estos son los ladrillos que vuelves a meter en DateSerial para construir fechas relacionadas (el primero del mes, el mismo día del año que viene, etc.). Ninguna sorpresa aquí — que es justo por lo que Weekday pilla a la gente desprevenida.

Por qué Weekday devuelve 2 para el lunes

Weekday(date, [firstDayOfWeek]) devuelve un número del 1 al 7 — pero qué día es el 1 lo fija el segundo argumento, y cuando lo omites VBA usa vbSunday, así que domingo = 1 y lunes = 2:

Weekday(#2026-08-24#)             ' 2  - ese lunes, porque domingo=1 por defecto
Weekday(#2026-08-24#, vbMonday)   ' 1  - ahora lunes=1 ... domingo=7

Este es el bug estrella de toda la familia. Código como If Weekday(d) = 1 Then ' Monday está mal — 1 es domingo en una llamada por defecto — y código como If Weekday(d) = 6 Or Weekday(d) = 7 Then ' weekend depende por completo de una suposición sobre el primer día que es invisible en el punto de llamada. Hay dos arreglos robustos, y ambos eliminan la adivinanza:

' Arreglo 1 - fija el primer dia explicitamente, y el lunes es de verdad 1:
If Weekday(d, vbMonday) >= 6 Then MsgBox "weekend"   ' 6 = sab, 7 = dom

' Arreglo 2 - compara contra las constantes con nombre, nunca numeros magicos:
If Weekday(d) = vbSaturday Or Weekday(d) = vbSunday Then MsgBox "weekend"

Las constantes vb* (vbSunday, vbMonday, … vbSaturday) son correctas independientemente del argumento de primer día, y por eso compararse contra ellas es el hábito más seguro. La regla: nunca escribas un número pelado para un día de la semana — o pasas vbMonday para que la numeración sea la que esperas, o comparas con una constante vb*.

DatePart: el extractor general

DatePart(interval, date, [firstDayOfWeek], [firstWeekOfYear]) es la versión navaja suiza: toma los mismos códigos de intervalo que DateAdd y DateDiff y extrae esa unidad. Para el año, el mes, el día y la hora duplica las funciones dedicadas — pero es la única forma integrada de alcanzar un par de partes que no tienen función propia:

DatePart("q", d)     ' trimestre del ano (1-4) - no existe la funcion Quarter()
DatePart("ww", d)    ' numero de semana (1-53)
DatePart("y", d)     ' dia del ano (1-366) - la "y" que significa dia del ano
DatePart("m", d)     ' 8 - igual que Month(d)

Echa mano de DatePart cuando necesites el trimestre o el número de semana, y usa las funciones Year / Month / Day a secas para las partes de cada día porque se leen con más claridad. Fíjate en la misma trampa de códigos de DateAdd: "y" es día del año y "ww" es semana — dilos en voz alta una vez.

La trampa del número de semana en la frontera del año

DatePart("ww", …) tiene su propio valor por defecto que sorprende a la gente: tanto la primera semana del año como el primer día de la semana son por defecto una regla al estilo estadounidense (vbSunday, vbFirstJan1), que no es ISO 8601 — el estándar que usan la mayor parte de Europa y casi todos los calendarios de empresa. Así que los últimos días de diciembre y los primeros de enero pueden caer en un número de semana que no esperabas:

DatePart("ww", #2026-12-31#)                          ' 53  (regla US por defecto)
DatePart("ww", #2026-12-31#, vbMonday, vbFirstFourDays) ' la respuesta al estilo ISO

Si tus números de semana importan — semanas de nómina, números de sprint, cualquier cosa que deba coincidir con un calendario de la pared — pasa vbMonday como primer día de la semana y vbFirstFourDays como regla de primera semana para cumplir ISO 8601. El clásico bug de «mis números de semana se desvían en uno cerca de Año Nuevo» son siempre estos dos valores por defecto.

WeekdayName y MonthName están localizadas

Para convertir un número de día de la semana o de mes en un nombre, usa WeekdayName y MonthName. Ambas devuelven el nombre en el idioma de la máquina, lo que las hace ideales para mostrar y un error para cualquier cosa que vayas a volver a parsear:

WeekdayName(2)              ' "Monday" en una maquina inglesa, "Montag" en una alemana
MonthName(8)               ' "August" / "August" / "aout" segun la configuracion regional
WeekdayName(2, True)       ' abreviado: "Mon"

Como la salida sigue la configuración regional del usuario, nunca la compares con una cadena inglesa fija ni la escribas en un archivo que leerá otro sistema — eso es un bug de localización esperando a suceder. Para una etiqueta estable que tú controlas, formatea la fecha en su lugar: Format(d, "dddd") da el nombre completo del día de la semana y Format(d, "mmmm") el del mes, todavía sensibles a la configuración regional pero explícitos, vía Format. Usa WeekdayName / MonthName para mostrar en pantalla; usa números (Weekday, Month) para la lógica.

El veredicto honesto: las partes son fáciles, los valores por defecto no

Sacar partes de una fecha es lo menos misterioso de las fechas en VBA — con un asterisco que provoca una parte desproporcionada de los bugs:

  • Partes simples, funciones simplesYear, Month, Day, Hour, Minute, Second. Cada una devuelve un entero; Month es un número, no un nombre.
  • Weekday tiene un valor por defecto oculto → es vbSunday, así que el lunes es 2. Pasa vbMonday, o compara con vbSaturday / vbSunday — nunca un número pelado.
  • DatePart para lo que no tiene función → el trimestre ("q") y el número de semana ("ww"); haz que las semanas cumplan ISO con vbMonday + vbFirstFourDays.
  • Los nombres están localizadosWeekdayName / MonthName siguen el idioma de la máquina; úsalas para mostrar, nunca para parsear.

El único hábito que previene más bugs: un número de día de la semana nunca debería ser un literal. Di qué día es el primero, o nombra el día que quieres decir.

Cómo ayuda ExcelMaster

Los bugs de extracción de partes son sutiles porque el código parece obviamente correcto: un filtro de fin de semana que comprueba Weekday = 1, una columna de número de semana que no coincide con el calendario de nóminas cada enero, un informe que escribe WeekdayName en un archivo que un sistema en otro idioma luego no consigue leer. Cada uno es un valor por defecto que nadie recordó.

ExcelMaster escribe la extracción que sale bien a la primera. Describe la regla — «salta los fines de semana», «agrupa las filas por trimestre», «etiqueta cada fila con su semana ISO» — y usa Weekday(d, vbMonday) o las constantes vb* para la lógica de día de la semana, DatePart con los argumentos ISO para los números de semana, y mantiene los nombres de visualización separados de los números sobre los que ramificas. Tú describes la regla del calendario; él escribe la extracción de partes que no depende de un valor por defecto oculto.

Preguntas frecuentes

¿Por qué Weekday devuelve el número de día equivocado en VBA?

Porque Weekday numera la semana desde su segundo argumento, que por defecto es vbSunday — así que el domingo es 1 y el lunes es 2. Si supusiste que el lunes es 1, cada resultado se desvía en uno. Pasa el primer día explícitamente, Weekday(d, vbMonday), para que vaya del lunes como 1 al domingo como 7, o compara el resultado con las constantes con nombre vbSaturday y vbSunday en lugar de números codificados a fuego.

¿Cómo compruebo si una fecha es fin de semana en VBA?

Usa las constantes para que el valor por defecto del primer día no pueda morderte: If Weekday(d) = vbSaturday Or Weekday(d) = vbSunday Then …. Las constantes vb* son correctas sin importar qué argumento de primer día de la semana esté en juego. Como alternativa, Weekday(d, vbMonday) >= 6 trata el 6 (sábado) y el 7 (domingo) como el fin de semana — solo asegúrate de haber pasado vbMonday.

¿Cómo obtengo el trimestre o el número de semana de una fecha en VBA?

Usa DatePart, porque no hay una función Quarter ni Week dedicada. DatePart("q", d) devuelve el trimestre del 1 al 4, y DatePart("ww", d) devuelve el número de semana. Para números de semana ISO 8601, pasa los argumentos extra: DatePart("ww", d, vbMonday, vbFirstFourDays), o la semana en torno a Año Nuevo puede desviarse en uno.

¿Cuál es la diferencia entre Month y MonthName en VBA?

Month(d) devuelve el mes como un número (1–12) para usar en la lógica; MonthName(n) convierte un número de mes en su nombre como texto (MonthName(8) da "August"). MonthName sigue el idioma de la máquina, así que úsala solo para mostrar — para ramificar o comparar usa el número de Month.

¿WeekdayName devuelve nombres en inglés en VBA?

Solo en una máquina en inglés. WeekdayName y MonthName devuelven nombres en la configuración regional del sistema, así que el mismo código produce "Monday" o "Montag" o "lundi" en máquinas distintas. Nunca compares su salida con una cadena inglesa fija; para una etiqueta controlada usa Format(d, "dddd"), y para la lógica usa el Weekday numérico.

Probado en

Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 26/08/2026.

Guías relacionadas: VBA DateAdd y DateDiff · VBA Now, Date y Time · VBA Format · VBA CStr, CDate y Val · Bucle For en VBA