Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

215
Vistas
El resultado de agregar el segundo a la fecha es un minuto de descuento; solución alterna

Estoy agregando un segundo a una instancia de la fecha de la Fundación, pero el resultado tiene un error de un minuto completo.

 var calendar = Calendar(identifier: .iso8601) calendar.locale = Locale(identifier: "en") calendar.timeZone = TimeZone(identifier: "GMT")! let date1 = Date(timeIntervalSinceReferenceDate: -62544967141.9) let date2 = calendar.date(byAdding: DateComponents(second: 1), to: date1, wrappingComponents: true)! ISO8601DateFormatter().string(from: date1) // => 0019-01-11T22:00:58Z ISO8601DateFormatter().string(from: date2) // => 0019-01-11T21:59:59Z

Curiosamente, uno de los siguientes hace que el error desaparezca:

  • intervalo de tiempo redondo desde la fecha de referencia
  • no agregar zona horaria al calendario
  • establezca wrappingComponents en falso (aunque no debería ajustarse en este caso)

Realmente no necesito una precisión de menos de un segundo en mi código, así que creé esta extensión que me permite descartarla.

 extension Date { func roundedToSeconds() -> Date { return Date(timeIntervalSinceReferenceDate: round(timeIntervalSinceReferenceDate)) } }

quiero saber esto:

  • ¿Por qué ocurre este error?
  • ¿Estoy haciendo algo mal?
  • ¿Hay algún problema con mi solución alternativa?
over 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

¿Por qué ocurre este error?

Yo diría que esto es un error en Core Foundation (CF).

Calendar.date(byAdding:to:wrappingComponents:) llama a la función interna de Core Foundation _CFCalendarAddComponentsV , que a su vez usa la API de ICU Calendar C . ICU representa un tiempo como un número de coma flotante de milisegundos desde la época de Unix, mientras que CF usa un número de segundos de coma flotante desde la fecha de referencia de NeXT. Entonces CF tiene que convertir su representación a la representación de ICU antes de llamar a ICU, y volver a convertir para devolverle el resultado.

Así es como se convierte de una marca de tiempo CF a una marca de tiempo ICU:

 double startingInt; double startingFrac = modf(*atp, &startingInt); UDate udate = (startingInt + kCFAbsoluteTimeIntervalSince1970) * 1000.0;

La función modf divide un número de punto flotante en sus partes enteras y fraccionarias. Introduzcamos su fecha de ejemplo:

 var startingInt: Double = 0 var startingFrac: Double = modf(date1.timeIntervalSinceReferenceDate, &startingInt) print(startingInt, startingFrac) // Output: -62544967141.0 -0.9000015258789062

A continuación, CF llama a __CFCalendarAdd para agregar un segundo a -62544967141. Tenga en cuenta que -62544967141 se encuentra en el intervalo redondo de un minuto -62544967200 ..< -62544967140.0. Entonces, cuando CF agrega un segundo a -62544967141, obtiene -62544967140, que estaría en el intervalo de un minuto de la siguiente ronda. Dado que especificó componentes de ajuste, CF no puede cambiar la parte de los minutos de la fecha, por lo que vuelve al principio del intervalo de un minuto de la ronda original, -62544967200.

Finalmente, CF vuelve a convertir el tiempo de la UCI en un tiempo de CF, agregando la parte fraccionaria del tiempo original:

 *atp = (udate / 1000.0) - kCFAbsoluteTimeIntervalSince1970 + startingFrac + (nanosecond * 1.0e-9);

Entonces devuelve -62544967200 + -0.9000015258789062 = -62544967200.9, exactamente 59 segundos antes del tiempo de entrada.

¿Estoy haciendo algo mal?

No, el error está en CF, no en su código.

¿Hay algún problema con mi solución alternativa?

Si no necesita una precisión de menos de un segundo, su solución debería estar bien.

Puedo reproducirlo con fechas más recientes, pero hasta ahora solo con fechas de referencia negativas, por ejemplo, Date(timeIntervalSinceReferenceDate: -1008899941.9), que es 1969-01-11T22:00:58Z.

Cualquier timeIntervalSinceReferenceDate negativo en el último segundo de un intervalo de minutos debería causar el problema. El error hace que la primera ronda sea un minuto completo antes del tiempo 0 desde -60,999999999999999 hasta -1,0, pero debería abarcar desde -60,0 hasta -5e324. Todos los intervalos de minutos redondos más negativos se compensan de manera similar.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda