martes, 23 de enero de 2007

Un salto atrás

Este texto es una traducción del artículo A Leap Back, de Rob Weir (An antic disposition). Un enlace a este original se encuentra más contextualizado en su tinta en ECMA-376 no debe ser ISO 29500.
Para quien no siga estandaresabiertos.org: esto es una movida que viene de que Microsoft (que quiere decir... pues eso, software chiquitico) quiere que ISO estandarice un formato cerrado (e.d., que no cualquiera puede incluirlo en las aplicaciones que desarrolle) que compite directamente con un formato abierto (e.d., usable por CUALESQUIERA gentes all over the world) ya estandarizado.

Las primeras civilizaciones intentaron racionalizar el movimiento de los cuerpos celestes. El sol sale y se pone y a ese espacio de tiempo lo llamaron "día". La luna cambia de fase y a un ciclo completo lo llamaron "mes". Y el sol se mueve a través de los signos del zodiaco y a eso lo llamaron "año". Desafortunadamente, esos diversos periodos de tiempo no son bonitos múltiplos enteros los unos de los otros. Un mes lunar no son exactamente 30 días. Un año solar no son exactamente 12 meses lunares.

Para solventar estos problemas, se crearon los calendarios civiles - uno de los primeros estándares internacionales - para proporcionar un entendimiento común del cálculo de la fecha, sin el cuál el comercio, la justicia y la ciencia nunca se hubiesen desarrollado.

En el año 45 A.C., Julio César ordenó que un día extra fuese añadido a febrero cada cuatro años. (Curiosamente, este día extra no fue un 29 de febrero como hoy en día en los años bisiestos, sino que se hizo que el 24 de febrero durase dos días). Este sistema juliano estuvo en uso durante mucho tiempo, aunque presenta ligeros errores. Teniendo un año bisiesto cada cuatro años, teníamos 100 años bisiestos cada 400 años. Sin embargo, para mantener las estaciones alineadas debidamente con las festividades religiosas, etc., (¿quién quiere celebrar la Semana Santa en invierno?) era necesario tener sólo 97 años bisiestos cada 400 años.

Así, en 1582 el Papa Gregorio XIII promulgó una nueva forma de calcular los años bisiestos, diciendo que los años divisibles entre 100 serían bisiestos sólo si también eran divisibles entre 400. De esta manera, los años 1600 y 2000 serían bisiestos, pero no 1700, 1800 y 1900. El calendario gregoriano fue adoptado en principio por países católicos como España, Italia, Francia, etc. Los países protestantes como mucho lo habían adoptado para 1752, y los ortodoxos después, Rusia tras su revolución de 1918 y Grecia en 1923.

Entonces, para la mayoría del mundo, el calendario gregoriano ha sido ley durante 250-425 años. Es un estándar arraigado en las definiciones de cualquiera. ¿Quién lo ignoraría o se equivocaría en este punto?

Si has supuesto que "Microsoft" lo haría, avanza a la primera fila de la clase.

Las fechas en Excel se representan como un número de serie de fecha, donde las fechas se cuentan desde un origen, situado el 1 de enero de 1900. El problema es que desde las primeras implementaciones Excel se equivoca en esto. Excel piensa que 1900 es un año bisiesto, cuando no lo es según el calendario gregoriano, puesto que no es divisible entre 400. Este error hace que funciones de la hoja de cálculo como DIASEM() [WEEKDAY()] devuelvan valores incorrectos en algunos casos. Véase el artículo [en inglés, aquí en español] del soporte de Microsoft al respecto.

Ahora no tengo problemas con ese error que permanece en Excel por razones de compatibilidad histórica. Es un problema entre Microsoft y sus clientes y a mí no me concierne[1]. En cualquier caso, me apena bastante ver este error fomentado por un requerimiento en la especificación del Ecma Office Open XML (OOXML). Desde la parte 4 (Markup Language Reference -- ¡aviso: descarga de 34 MB!) sección 3.17.4.1 página 2522), "Date Representation" [Representación de Fechas]:
For legacy reasons, an implementation using the 1900 date base system shall treat 1900 as though it was a leap year. [Note: That is, serial value 59 corresponds to February 28, and serial value 61 corresponds to March 1, the next day, allowing the (nonexistent) date February 29 to have the serial value 60. end note] A consequence of this is that for dates between January 1 and February 28, WEEKDAY shall return a value for the day immediately prior to the correct day, so that the (nonexistent) date February 29 has a day-of-the-week that immediately follows that of February 28, and immediately precedes that of March 1.

(Por razones de herencia, una implementación que usa el sistema base de fecha 1900 trata a 1900 como año bisiesto. [Nota: Esto es, el valor de número serie 59 corresponde al 28 de febrero, y el valor 61 al 1 de marzo, el día siguiente, permitiendo a la (inexistente) fecha 29 de febrero [de 1900] tener el valor serie 60. fin de la nota] Una consecuencia de esto es que para fechas entre el 1 de enero y el 28 de febrero, DIASEM [WEEKDAY] devuelve el valor del día inmediatamente anterior al correcto, de forma que la (inexistente) fecha de 29 de febrero tiene un dia-de-la-semana que sigue inmediatamente al del 28 de febrero y precede inmediatamente al del 1 de marzo.)
Entonces, ¿el nuevo estándar OOXML contradice ahora 400 años de uso del calendario civil, codifica una fecha inexistente y devuelve el valor incorrecto de DIASEM()? ¿Y este es el comportamiento normativo por obligación? ¿Es esto algún tipo de broma?

El argumento de las "razones de herencia" es completamente falaz. Microsoft podría fácilmente haber definido el formato XML para exigir fechas correctas, y controlar la compatibilidad en abrir/guardar archivos en Excel. Un formato de archivo no tiene por qué ser idéntico a la representación interna de una aplicación.

Así es como lo hubiese hecho yo: definir la especificación del OOXML para que codifique fechas usando números serie que respeten los cálculos de año bisiesto del calendario gregoriano usados por el 100%* de las naciones del planeta. Entonces, si Microsoft desea mantener este error en su producto, Excel tiene que añadir 1 o sustraer 1 a cada número de serie de fecha mayor o igual a 60 cuando se abra o se guarde, respectivamente, un archivo OOXML. Esto no es un trabajo de chinos[2]. En cualquier caso, lo que yo no haría es imponer el error para el resto de procesadores de OOXML. Y desde luego, no exigir a todo el mundo que quiera que el día de la semana sea correcto en 1900 que haga un cálculo extra.

Claro que esto exige que se añada código extra a Excel. Excel tiene un error. Por supuesto que exigirá código el reparar un error. Háganse cargo. Creo que la alternativa de forzar al resto del mundo a adoptar un nuevo sistema de calendario es tener más cojones que nadie[3]. La carga de un error debería recaer en el producto que tiene el error, y en nadie más.

Yendo más lejos, apuntaría que la sección 3.2.28 define un elemento workbookPr (Workbook Properties, Propiedades del Libro[4]) con varios atributos, entre los que se incluye el siguiente indicador[5]:
date1904 (Date 1904)
Specifies a boolean value that indicates whether the date systems used in the workbook starts in 1904.
A value of on, 1, or true indicates the date system starts in 1904.
A value of off, 0, or false indicates the workbook uses the 1900 date system, where 1/1/1900 is the first day in the system.
The default value for this attribute is false.

(fecha1904 (Fecha 1904)
Especifica un valor booleano que indica si los sistemas de fecha usados en el libro comienzan en 1904 o no.
Un valor de
on, 1, o verdadero indica que el sistema de fecha empieza en 1904.
Un valor de
off, 0, o falso indica que el libro usa el sistema de fecha de 1900, donde el 1/1/1900 es el primer día en el sistema.
El valor por defecto para este atributo es
falso.)
Se preguntarán qué tiene 1904 de particular. Este es otro problema hereditario de Excel, que las implementaciones de Excel para Mac, por razones que me son desconocidas, tenían una fecha origen interna del 1 de enero de 1904 en lugar del 1 de enero de 1900. Esto es malo para la Mac Business Unit de Microsoft y ha sido probablemente causa de frustración para ellos, teniendo que mantener estas dos fechas origen en su código interno.

Pero, ¿por qué este problema? ¿Por qué debería un formato XML estándar tener en cuenta lo que Excel hace en un Mac? ¿Por qué debería tener en cuenta las peculiaridades de cualquier proveedor? Si RobOffice (un ejemplo ficticio) quiere usar internamente como fecha origen el 15 de marzo de 1903 no es mi problema. En mi implementación puedo hacer lo que me dé la gana. Pero cuando se trata de escribir un formato de archivo estándar, los caprichos de mi implementación no deberían convertirse en un requisito para el resto de usuarios del formato de archivo. Es más, si no puedo decidirme por una sola fecha origen, mis indecisiones no deberían provocar que otras implementaciones requieran código extra, todo por culpa de mi indecisión.

Ahí está, pues. Dos formas en que Microsoft ha creado un formato innecesariamente complicado, y ha hecho tu vida más dificil si pretendes trabajar con él, todo debido a la exclusiva ventaja de su implementación. Me gustaría poder asegurar que esto es un ejemplo aislado en esta aproximación al OOXML. Pero tristemente, es la regla, no la excepción.

NT's:
[1]^ Probablemente, el autor usa OpenOffice en lugar de Microsoft Office, al igual que el traductor.
[2]^ Rocket science en el original.
[3]^ The ultimate in chutzpah en el original.
[4]^ En las versiones en español de Excel, se traduce workbook como libro, si bien la traducción literal es cuaderno de ejercicios.
[5]^ Traducción libre de flag, término empleado en estructuras de datos para definir un indicador (generalmente con un valor de verdadero/falso) codificado en la implementación de un tipo de dato.

*^
Apunte-estrellica del traductor:
Lo más notorio no es que el 100% de las naciones usa el calendario gregoriano, si no que el porcentaje de naciones que usan el calendario 'exceliano' es el 0%

Esto es la primera traducción más o menos seria que hago en mi vida, probablemente tendrá fallos de ortografía y/o de traducción. No soy profesional, si quien lo lea y coteje con el original encuentra que algo debe ser de otra manera, que deje un comentario y un equipo de formados chimpacés mecanógrafos solucionará el problema a la mínima de cambio.

7 comentarios:

Mu dijo...

No sé cómo será en países más islamistas, pero en Marruecos, donde viví, el calendario musulmán se usa para cuestiones religiosas y tradicionales. Para cuestiones profesionales y financieras el calendario es el mismo que en el resto del mundo.

Trylobytero dijo...

Lo corrijo.

Juan Manuel de Prada dijo...

Los matamoros son unos hijos de puta, y el terrorismo islámico es lo mejor que nos ha dado dios.

Coto a la cárcel.

vtapia dijo...

Excelente traducción.
Coincido con que MS debe resolver su problema con el calendario gregoriano, pero ¿cómo hacemos para que otras herramientas ofimática abran documentos "legacy" de MS e interpreten bien las fechas?. ¿También deberían resolverlo internamente?.

Trylobytero dijo...

Los documentos "legacy" de MS pueden ser importados. Si se dispusiera de una biblioteca de importación de documentos MS-legacy (desconozco si existe) todas las herramientas lo tendrían más fácil.

Por cierto, gracias por el comentario. A este blog le están saliendo telarañas.

Anónimo dijo...

Estimados:

cabe aclara que en el calendario gregoriano la regla para determinar si un año es bisiesto está compuesta de dos partes:

a) las dos últimas cifras deben ser divisibles por 4, siempre y cuando estas dos pultimas cifras no sean 00.

b) si las dos últimas cifras del año en cuestión llegasen a ser 00, entonces debe tomarse las 4 cifras del número del año y dividirlas por 400.


Aún así, en el año 3226 y cada 3226 años el calendario gregoriano tiene un error de 1 día.

Saludos.

Pablo

Trylobytero dijo...

No es lo que se discute en el artículo, pero buen apunte.