Jump to content

pegones1

Members
  • Content Count

    768
  • Joined

  • Last visited

  • Days Won

    27

Posts posted by pegones1

  1. Hola Jabrajam, creo que te falta una referencia a Solver, como explica el enlace:

    En el editor de Visual Basic, con un módulo activo, haga clic en referencias en el menú herramientas y, a continuación, seleccione Solver en referencias disponibles. Si Solver no aparece en ** Referencias disponibles**, haga clic en Examinar y, a continuación, abra Solver.xlam en la subcarpeta \Archivos de programa\Microsoft Office\Office14\Library\SOLVER.

    https://docs.microsoft.com/es-es/office/vba/excel/concepts/functions/solverok-function

  2. Estudia el siguiente enlace para entender los códigos de formato de número personalizados:

    https://support.microsoft.com/es-es/office/códigos-de-formato-de-número-5026bbd6-04bc-48cd-bf33-80f18b4eae68

    Con el formato personalizado: #.##0;"" todos los números negativos se mostrarán como vacíos, pues se especifica el Imagen del botón Formato de los números negativos.

    Como he especificado dos secciones de código de formato, la primera sección de código se utiliza para números positivos y ceros y la segunda sección del código se usa para los números negativos.

    El formato de número no afecta al valor real de la celda que usa Excel para realizar los cálculos. El valor real se muestra en la barra de fórmulas.

    Espero haber contestado satisfactoriamente y hagas clic en el icono con un "Corazón".

  3. Hace 47 minutos , zelarra821 dijo:

    Vale. Casi.

    Te adjunto el fichero. Hay una opción que no has contemplado, y te he hecho un comentario al valor ¿?.

    ¡Gracias!

    Edad Certificado PW1.xlsm 20.15 kB · 0 descargas

    a) Formato de los números de celda para la edad mostrada como vacía: #.##0;""

    b) Opción contemplada en la función Edad si no se introduce la fecha de nacimiento:

        If sFechaNacimiento = "" Then
            ' Sin fecha de nacimiento
            Edad = -3
     

    Adjunto archivo con las evidencias:

    Edad Certificado PW2.xlsm

  4. Respuestas:

    1. Es conveniente mantener la función Edad como Long. Si sCertificado es "" entonces Edad=-1. Para los valores negativos devueltos como Edad se formatea el número de las celdas como: #.##0;"¿?" (valores negativos se muestran como: ¿?)
    2. Gracias por la observación, aunque no creo que la hay liado por eso. He sustituido el año de referencia por uno bisiesto: DateSerial(2000, 
    3. He incluido en la función Edad el chequeo de fechas numéricas además de fechas en formato texto. Considero que las celdas marcadas en color naranja no tienen sentido pues con Certificado = "-" no hace falta poner la fecha actual como fecha del certificado ni llamar a la función Edad con una función incrustada como HOY()...

    Prueba el adjunto.

    Edad Certificado PW1.xlsm

  5. Hace 1 hora, zelarra821 dijo:

    Estoy probando las dos funciones.

    Si utilizo ObtenerEdad, con las fechas 18-nov-1899 y 6-sep-1980, me da como edad 81, lo que es incorrecto.

    Si utilizo restarfechas, tengo que darle formato ("aa") para que me muestre los años. Con las dos fechas anteriores, sí que saca 80, que es el valor correcto. Eso, o cambiar el formato del DateDiff a "y".

    Esa función que has encontrado en la Web está pensada para fechas en formato americano: MM/DD/YYYY y no creo que te funcione para fechas con tu formato.

    Lo del formato de celda "aa" no te lo aconsejo, pues si el valor es mayor que 99 te dará un valor incorrecto.

    DateDiff a "y" es equivalente a "d" por lo que cuenta días y tampoco te servirá.

    Me acabo de enterar estudiando la función DateDiff que para años ("yyyy") devuelve 1 aunque solo haya transcurrido un día. ¡Y ese es el problema de contar un año de más!

    He modificado la función para corregir la edad (no es tan compleja como la que te bajaste de Internet):

    Function ObtenerEdad(sFecha1 As String, sFecha2 As String) As Long
    '
    ' Obtiene la diferencia en años entre dos fechas en formato Long
    ' Argumentos: sFecha1 y sFecha2 con las fechas a restar en formato String
    ' Rango de fechas desde el 1 de enero de 100 hasta el 31 de diciembre de 9999.
    '
    ' Funciones VBA: DateValue y DateDiff("yyyy",date1,date2) Functions
    '
        Dim dtFecha1 As Date
        Dim dtFecha2 As Date
        Dim dtMesDía1 As Date
        Dim dtMesDía2 As Date
        Dim lDías As Long
        Dim iCorregirAño As Integer
       
        dtFecha1 = DateValue(sFecha1)
        dtFecha2 = DateValue(sFecha2)
    
        '
        ' Al comparar el 31 de diciembre con el 1 de enero del año inmediatamente siguiente,
        ' DateDiff para el año ("yyyy") devuelve 1 aunque solo haya transcurrido un día.
        ' Por lo que se debe corregir restando un año en estos casos
        '
        If Year(dtFecha1) < Year(dtFecha2) Then
            dtMesDía1 = DateSerial(2001, Month(dtFecha1), Day(dtFecha1))
            dtMesDía2 = DateSerial(2001, Month(dtFecha2), Day(dtFecha2))
            If dtMesDía1 > dtMesDía2 Then
                iCorregirAño = 1
            End If
        End If
        
        ObtenerEdad = DateDiff("yyyy", dtFecha1, dtFecha2) - iCorregirAño
        
    End Function

    Ejemplo de edades calculadas:

    image.thumb.png.5f01537cf0c390111f19581fc4029af5.png

    En la última columna he incluido el resultado de tu función: CalculoEdad que creo que sólo funciona con fechas americanizadas... (como comprenderás, no he analizado esa función "AgeFunc" de Internet...)

  6. He preparado y probado un par de funciones:

    1. RestarFechas con la diferencia en días entre dos fechas.
    2. ObtenerEdad con la diferencia en años entre dos fechas.

    La segunda es la que te dará el resultado esperado como puedes ver en este ejemplo:

    image.png.e76c0332290266403dc57b65e01e25ab.png

    Este es el código de las dos funciones sugeridas:

    Option Explicit
    
    Function ObtenerEdad(sFecha1 As String, sFecha2 As String) As Long
    '
    ' Obtiene la diferencia en años entre dos fechas en formato Long
    ' Argumentos: sFecha1 y sFecha2 con las fechas a restar en formato String
    ' Rango de fechas desde el 1 de enero de 100 hasta el 31 de diciembre de 9999.
    '
    ' Funciones VBA: DateValue y DateDiff("yyyy",date1,date2) Functions
    '
        Dim dtFecha1 As Date
        Dim dtFecha2 As Date
       
        dtFecha1 = DateValue(sFecha1)
        dtFecha2 = DateValue(sFecha2)
    
        ObtenerEdad = DateDiff("yyyy", dtFecha1, dtFecha2)
        
    End Function
    
    Function RestarFechas(sFecha1 As String, sFecha2 As String) As Long
    '
    ' Obtiene la diferencia entre dos fechas en formato Long
    ' Argumentos: sFecha1 y sFecha2 con las fechas a restar en formato String
    ' Rango de fechas desde el 1 de enero de 100 hasta el 31 de diciembre de 9999.
    '
    ' Funciones VBA: DateValue y DateDiff("d",date1,date2) Functions
    '
        Dim dtFecha1 As Date
        Dim dtFecha2 As Date
       
        dtFecha1 = DateValue(sFecha1)
        dtFecha2 = DateValue(sFecha2)
    
        RestarFechas = DateDiff("d", dtFecha1, dtFecha2)
        
    End Function
    
    

    Como puedes comprobar, la única diferencia es el primer argumento de la función DateDiff que, para la edad en años debe ser "yyyy" y para la diferencia en días es "d". Esta función es muy potente para obtener diferencias de fechas como se puede estudiar en el siguiente enlace: DateDiff function

    Adjunto archivo de ejemplo en el que se deben habilitar las macros. Las nuevas funciones están en el módulo "ModRestarFechas".

    Incluye como un plus una hoja con un ejemplo del tema anterior para calcular el día de la semana.

    Años Menores que 1900 PW2.xlsm

  7. Hace 6 minutos , zelarra821 dijo:

    Me vale para darlo por solucionado, además de que es mucho más simple que de la forma en que lo hacía antes. Muchas gracias.

    Pues ya se puede dar por enterado algún Administrador de este foro.

    Lo único volver a resaltar que el formato establecido por la norma ISO 8601 es más conveniente cuando se introducen fechas en modo texto, como es el caso de fechas anteriores al año 1900. Siempre es mejor AAAA-MM-DD que todas las variantes de fechas que te he puesto como ejemplo en el comentario anterior.

    Hablaré de ésto en un próximo artículo de mi blog que espero que leas @zelarra821. Si no sabes cuál es, entra en mi perfil de este foro en "Formas de contacto" donde está mi dirección Web.

  8. Hace 12 horas, zelarra821 dijo:

    Aunque me contestes mañana, pero te digo lo que he probado.

    Para la fecha que coge tu módulo, he convertido la fecha así:

    
    Dim FechaFormateada As String
    FechaFormateada = Format(sDate, "d/m/yyyy")

    y me da error. Por eso te pedía que me dijeras cómo convertir la fecha en un formato que funcione con tus funciones. Además de cómo puedo aprovechar lo que has compartido para restar dos fechas, y obtener la edad.

    ¡Muchas gracias!

    @zelarra821, te da error porque el primer argumento de la función Format no puede ser un texto, sino un valor de fecha.

    Es mejor usar la función DateValue, cuyo argumento de fecha puede ser un texto que representa una fecha desde el 1 de enero de 100 hasta el 31 de diciembre de 9999. Sin embargo, la fecha también puede ser cualquier expresión que pueda representar una fecha, una hora o tanto una fecha como una hora, en ese rango.

    Por ejemplo, para obtener el número de serie (como Date) de la fecha textual (sDía como String):

    Function ObtieneNumSerieFecha(sDía As String) As Date
    '
    ' Obtiene el número de serie de una fecha en formato Date
    ' Argumentos: sDía con la fecha en formato String
    ' Funciones VBA: DateValue Function
    '
        ObtieneNumSerieFecha = DateValue(sDía)
    
    End Function
    

    La función que necesitas, para obtener el nombre del día de la semana, puede ser ésta:

    Function ObtieneNombreDíaSemana(sDía As String) As String
    '
    ' Obtiene el nombre del día de la semana en formato String
    ' Argumentos: sDía con la fecha en formato String
    ' Funciones VBA: DateValue, Weekday, WeekdayName Functions
    '
        Dim dtFecha As Date
        Dim iDíaSemana As Integer
       
        dtFecha = DateValue(sDía)
        
        iDíaSemana = Weekday(dtFecha, vbMonday)
        
        ObtieneNombreDíaSemana = WeekdayName(iDíaSemana, False, vbMonday)
    
    End Function

    Estas 2 funciones dan siempre el mismo número de serie y el mismo nombre del día de la semana para un día en distintos formatos, como se demuestra en el siguiente ejemplo:

    image.thumb.png.23218c42d76b239076fc486661468b5a.png

    Ya me dirás si te vale para dar por solucionado y cerrar este tema.

     

    Lo de restar dos fechas para obtener la edad de personas que nacieron antes de 1900 da para un nuevo comentario. Mejor, abres otro tema que puedes titular así:

    "Cómo restar dos fechas si alguna es anterior al año 1900"

    Aprovecho para saludar a @Antoni y para preguntarle por qué se rió de mi primer comentario, si no es mucho pedir. 😜

  9. @zelarra821,

    1. Para sacar el nombre del día de la semana, tengo que utilizar la función WeekdayName(), ¿verdad? SI. Mira el archivo que adjunté donde se usa esa función.
    2.  
    3. Para exportar esto a otra hoja de cálculo, ¿basta con copiar el módulo? ¿o tengo que hacer algo más? Para usarlo en otra hoja del mismo libro ya existe el módulo. Para usarlo en otro libro de trabajo debes exportar ese módulo e importarlo en el nuevo libro.

    El resto de preguntas te las contesto mañana que hoy ya tengo que dejarlo.

    Si no puedes esperar, pregunta a los demás participantes de este bendito foro que tanto he consultado desde hace 100 años.

  10. Hace 16 minutos , zelarra821 dijo:

    No, ese es perfecto. Yo esto solo no necesito a modo informativo. He sacado el árbol genealógico de mi familia, y quería calcular la edad y el día de la semana en que nacieron, se casaron o murieron. Para no tener que hacerlo a mano, porque Excel no permite fechas anteriores a 1900, busqué la manera de hacerlo por VBA, pero no encontraba nada en Internet, de ahí que viniese aquí a preguntar.

    Así que se agradece mucho tu aportación.

    Un saludo.

    Solo te falta darle al corazón de abajo a la derecha en el primer mensaje que respondí en este hilo con mi aportación. Gracias anticipadas por hacer clic en ese corazón...

  11. Hace 2 minutos , zelarra821 dijo:

    Muchas gracias, @pegones1, ¡qué pasada, y qué curro! Un saludo.

    Desde que me dedico en serio a los cálculos me ha apasionado la conversión de fechas. Excel es una herramienta única para tratarlas, sobre todo siendo que VBA permite números de serie negativos para fechas anteriores al año 1900.

    Este "curro" han sido 3 horas que ya están bien pagadas al recibir tu pronta respuesta, además de servirme para añadir un nuevo artículo a mi blog que titularé:

    "Cómo calcular fechas anteriores a 1900 en Excel"

    @zelarra821, ¿se te ocurre un título mejor?

  12. En 5/10/2020 at 21:34 , Cristian 1985 dijo:

    No, no la afecta, solo confirma que los resultados son correctos.

    Lo que me encantaría es que el gran Antoni nos deleite con una de sus maravilosas macros a las que nos tiene acostumbrados 👍👍👍👍👍

     

    Como @Antoni debe estar muy ocupado, adjunto un archivo con 3 macros para obtener el día de la semana desde el 0100-01-01 (aaaa-mm-dd), en formato ISO 8601, que es el primer día admitido por VBA.

    La función GetWeekDayName() devuelve el día de la semana si se le pasa una cadena de texto en formato ISO 8601, llamando a las otras dos macros. Es fácil convertir una string con una fecha en formato de texto al formato estándar ISO.

    Option Explicit
    
    Function GetWeekDayName(sDate As String) As String
    '
    ' VBA WeekdayName Function
    '
        Dim iWeekDay As Integer
        
        iWeekDay = GetWeekDay(sDate)
        
        GetWeekDayName = WeekdayName(iWeekDay, False, vbMonday)
    
    End Function
    
    Function GetWeekDay(sDate As String) As Integer
    '
    ' VBA WeekDay Function
    '
        Dim dtDate As Date
        
        dtDate = GetSerialDate(sDate)
        
        GetWeekDay = Weekday(dtDate, vbMonday)
    
    End Function
    
    Function GetSerialDate(sDate As String) As Double
    '
    ' VBA DateSerial Function
    '
        Dim iYear As Integer
        Dim iMonth As Integer
        Dim iDay As Integer
        
        iYear = Left$(sDate, 4)
        iMonth = Mid$(sDate, 6, 2)
        iDay = Right$(sDate, 2)
        
        GetSerialDate = DateSerial(iYear, iMonth, iDay)
    
    End Function
    

    En el fichero adjunto he incluido las fechas especiales que:

    1. Fechas incorrectas en Excel inferiores al 1900-03-01
    2. Fecha errónea en Excel y en VBA: 1900-02-29, ya que el año 1900 no es bisiesto.
    3. Primera fecha correcta en VBA: 0100-01-01
    4. Fechas que no han existido en el Calendario Gregoriano, anteriores al 1582-10-15
    5. Último día correcto en Excel y en VBA: 9999-12-31

     @zelarra821 , @isidrod , espero que sea de ayuda y ayude a comprender el mundo pasado, presente y futuro.

    Años Menores que 1900 PW1.xlsm

  13. Es un placer volver a contactar con amigos como tú @Gerson Pineda y @Sergio en estos días tan atípicos para todos y deseo que sigáis bien en situaciones difíciles para todos.

    He editado un nuevo aporte que espero le hagáis algo de caso pues me ha supuesto bastante esfuerzo y es el primero después de varios años:

    A ver si hacéis algún comentario a este aporte que me sirva de acicate para seguir publicando este verano.

  14. Buenas Matías, una alternativa a la función avanzada MIN.SI.CONJUNTO() es usar una fórmula matricial que se introduce con:

    Ctrl + Mayús + Intro (Excel automáticamente encierra la fórmula entre llaves para indicar que es una fórmula matricial)

    Fórmula para versiones superiores de Excel:

    =MIN.SI.CONJUNTO($C$2:$C$31;$B$2:$B$31;$G$2;$E$2:$E$31;$H$2)

    Fórmula matricial alternativa para versiones de Excel que no soportan la función MIN.SI.CONJUNTO():

    =MIN(SI(($B$2:$B$31=$G$2)*($E$2:$E$31=$H$2);$C$2:$C$31))

    Seleccionar los valores en los desplegables de estas dos celdas:

    $G$2  el DiaProd

    $H$2 el Mes

    Adjunto archivo de ejemplo con las dos fórmulas.

    Consulta_MIN.SI.CONJUNTO_PW1.xlsx

  15. He publicado en mi blog cómo se hace la

    Al final de este vídeo se ven las manecillas de todos los relojes moviéndose al unísono:

    Sólo lo he probado en Excel 2010 y los amigos me dicen que en Excel 2007 el proceso es muy lento y en un segundo no le da tiempo a refrescar los relojes y se emplean funciones que no soporta Excel 2003.

    Son muy gratificantes las 1000 visitas que ha tenido este tema en un mes.

  16. Se me ocurre Gerson que puede servir para no tener que escribir los prefijos para las llamadas internacionales.

    Target = "+34 976 " & Target[/CODE]

    y así poder tener una base de datos con los números telefónicos de mis amigos de Zaragoza.

  17. karlmay, siempre he pensado que lo mejor de Excel son sus fórmulas y funciones propias a las que hay que sacar todo el partido. :mad:

    Los problemas que se solucionan con macros VBA ayudan a entender más aplicaciones que incorporan Visual Basic for Applications, pero todo lo que se pueda hacer sin código en Excel es más instructivo y próximo al cálculo puro y duro. :P

    verzulsan, pensaba que no te sorprendería con ésto y me alegra que sigas sorprendiéndote con las pequeñas maravillas de Excel. :rolleyes:

    El sermón de los políticos es que nuestra juventud es la que más abandona los estudios y no se tiene futuro si no se estudia, así que ¡a ser aplicado y a estudiar con ganas! que sé positivamente que lo estás haciendo. :)

  18. Para conocer el estado de los proyectos o anteproyectos se necesita una Hoja de Firmas que indique quién y cuándo ha firmado cada uno de los hitos.

    Adjunto Hoja de Firmas, sin macros ni VBA, con la siguiente fórmula iterativa en la celda C8:

    =SI(C9="";"";SI(Y(B8<>"";C8="";C9<>"");AHORA();C8))[/CODE]

    Para que funcionen estas fórmulas, con cálculo circular, en [b]Opciones de Excel[/b], en la ficha de [b]Fórmulas[/b] marca la casilla [b]Habilitar calculo iterativo[/b] y en [b]Iteraciones máximas[/b] pon al menos un 1.

    Esta hoja puede servir de ejemplo para guardar las fechas de cambio de estado de cualquier evento, mediante una marca, que en este caso es la firma.

    HojaFirmasAnteproyectos.zip

  19. Mucas gracia por tu interes Ioyama!!

    Preguntare a pegones1 a ver si tenemos suerte!

    Saludos

    Hola MIARROW, como te ha dicho ioyama para que no salga el mensaje de error se debe hacer la llamada con macros, valiéndose de On Error Resume Next. Prueba ésto:

    Option Explicit

    Public ArrancaPara As Boolean
    Private datHora As Date

    Sub ArrancaParaReloj()
    ArrancaPara = Not ArrancaPara
    If ArrancaPara Then
    RefrescaConsultaWeb
    Else
    StopTemporizador
    End If
    End Sub

    Sub StartTemporizador() 'arranca el temporizador
    datHora = Now + TimeSerial(0, 1, 0)
    Application.OnTime Earliesttime:=datHora, Procedure:="RefrescaConsultaWeb", Schedule:=True
    End Sub

    Sub StopTemporizador() 'para el temporizador
    Application.OnTime Earliesttime:=datHora, Procedure:="RefrescaConsultaWeb", Schedule:=False
    End Sub

    Sub RefrescaConsultaWeb()
    On Error Resume Next
    Err.Clear

    [COLOR="blue"]Sheets(1).QueryTables(1).Refresh BackgroundQuery:=False[/COLOR]

    If Err.Number <> 0 Then
    Debug.Print Now & " Error: " & Err.Number & " " & Err.Description
    End If

    StartTemporizador
    End Sub[/CODE]

    Cambia el número de la hoja 1 por el que uses y el número de consulta en la llamada a [color=blue]Refresh (en azul)[/color].

    Al ejecutar ArrancaParaReloj() se ejecuta cada minuto RefrescaConsultaWeb() y cuando falla no sale la ventana del mensaje de error pero se escribe en la ventana de Inmediato la fecha y hora, el error y su descripción con Debug.Print para saber cuándo y cuántas veces ha pasado.

    [b]IMPORTANTE:[/b] En la ventana de propiedades de la conexión [b]NO MARQUES Actualizar cada 1 minutos[/b]. Esto ya lo hace el temporizador en código con: TimeSerial(0, 1, 0)

    Para dar las gracias, click en la mano abajo a la izquierda de este mensaje con la palabra [b]Gracias[/b].

  20. Gerson, no pienso que nos hayamos salido para nada del tema principal ya que nos hallamos convirtiendo divisas y lo principal es saber cómo se representan los decimales para que sea exacto el cambio de monedas.

    neverdelimon1 y verzulsan, la interpretación que da el fabricante de

    MED = Micro$oft te Extrae tus Datos

    A todos, he subido una nueva versión al Post #1 sin importar si el separador decimal es el punto o la coma.

×
×
  • Create New...

Important Information

Privacy Policy