{"id":1070,"date":"2012-01-29T14:48:10","date_gmt":"2012-01-29T13:48:10","guid":{"rendered":"http:\/\/www.stenyak.com\/?p=1070"},"modified":"2012-01-29T14:48:10","modified_gmt":"2012-01-29T13:48:10","slug":"zonas-horarias-dst-desplazamientos-y-otras-zarandajas","status":"publish","type":"post","link":"https:\/\/www.stenyak.com\/?p=1070","title":{"rendered":"Zonas horarias, DST, Desplazamientos y otras zarandajas"},"content":{"rendered":"<p>[\u00a0<a class=\"vt-p\" href=\"http:\/\/www.stenyak.com\/archives\/1004\/sobre-la-hora-universal-y-los-relojes-atomicos-o-que-tienen-en-comun-el-tomtom-y-unos-trigales\/\"><strong>Ir a la parte 1 de 2<\/strong>: &#8220;Sobre la Hora Universal y los relojes at\u00f3micos (o qu\u00e9 tienen en com\u00fan el TomTom y unos trigales)&#8221;<\/a>\u00a0]<\/p>\n<p>Continuamos desentra\u00f1ando el misterio de las horas, orientando la explicaci\u00f3n principalmente a programadores.<\/p>\n<p>Hemos establecido qu\u00e9 sistemas de medici\u00f3n de la hora existen. Tambi\u00e9n hemos visto que el estandard de facto es UTC, y por buenas razones.<\/p>\n<p>Y ahora vamos a ver como se pueden representar esas horas en una aplicaci\u00f3n.<\/p>\n<blockquote><p>A efectos pr\u00e1cticos, en este art\u00edculo voy a llamar &#8220;<em><strong>hora<\/strong><\/em>&#8221; al conjunto de &#8220;<em><strong>fecha+hora<\/strong><\/em>&#8220;.<\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<h1>Conceptos b\u00e1sicos<\/h1>\n<h2>Repaso de UTC<\/h2>\n<p>Quedabamos en que UTC es una hora universal, que trata de indicar <strong>la hora del planeta<\/strong>\u00a0Tierra en general. No est\u00e1 ligado a ning\u00fan pa\u00eds en concreto, ni a ning\u00fan continente, sino al planeta entero: Espa\u00f1a no tiene horas UTC. Argentina no tiene horas UTC. El planeta Tierra s\u00ed que tiene horas UTC.<\/p>\n<p>Si en una hora UTC particular es pleno d\u00eda en Espa\u00f1a, entonces en esa misma hora UTC ser\u00e1 noche cerrada en sus ant\u00edpodas; y ser\u00e1 el amanecer o el anochecer si nos quedamos a medio camino entre ambos puntos.<\/p>\n<p><strong>UTC no sufre saltos<\/strong> [*], sino que avanza siempre a una velocidad constante. Porque el planeta Tierra tampoco sufre saltos ni rotaciones bruscas en ning\u00fan momento (menos mal :-D).<br \/>\n<span style=\"color: #808080;\">[*] <span style=\"color: #808080;\"><a href=\"http:\/\/www.stenyak.com\/archives\/1004\/sobre-la-hora-universal-y-los-relojes-atomicos-o-que-tienen-en-comun-el-tomtom-y-unos-trigales\/\">T\u00e9cnicamente s\u00ed (tiene saltos por debajo del segundo)<\/a><\/span>, pero se puede ignorar perfectamente para este art\u00edculo.<\/span><\/p>\n<p>&nbsp;<\/p>\n<h2>Hora Local (Local Time)<\/h2>\n<p>Los habitantes de este planeta estamos acostumbrados a hablar en t\u00e9rminos locales. Yo, como habitante de Madrid, puedo decir &#8220;Me levanto a trabajar a las 07:00&#8221;. Un japon\u00e9s, a su vez, puede decir &#8220;Yo tambi\u00e9n me levanto a trabajar a las 07:00&#8221;. Pero obviamente no hablamos de la misma hora UTC, sino de una hora &#8220;local&#8221;.<\/p>\n<p>Trabajar con horas locales <strong>puede ser complicado<\/strong>, por ejemplo cuando el locutor se desplaza de sitio. Si despegas de Madrid a las 10:00 (hora local madrile\u00f1a), vuelas 10 horas, y aterrizas en Miami, la hora local de Miami no ser\u00e1n las 20:00, sino otra, que hay que calcular <strong>en base a unos cuantos factores<\/strong>.<\/p>\n<p>En cambio, si despegas a las 10:00 UTC, <strong>s\u00ed<\/strong> que aterrizas a las 20:00 UTC.<\/p>\n<p style=\"text-align: center;\"><a class=\"vt-p\" href=\"http:\/\/www.stenyak.com\/wp-content\/uploads\/2012\/01\/clock.jpg\"><img loading=\"lazy\" class=\"aligncenter size-medium wp-image-1097\" title=\"\" src=\"http:\/\/www.stenyak.com\/wp-content\/uploads\/2012\/01\/clock-300x230.jpg\" alt=\"\" width=\"300\" height=\"230\" align=\"center\" \/><\/a><\/p>\n<h2>Desplazamiento (Offset)<\/h2>\n<p>El offset es, literalmente, la siguiente resta matem\u00e1tica: <strong>hora local<\/strong> &#8211; <strong>hora UTC<\/strong>.<\/p>\n<p><strong>Por ejemplo<\/strong>: La hora local actual en Madrid es finales de Enero a las 20:00. La hora UTC actual en el planeta es finales de Enero a las 19:00 UTC. Por tanto, 20:00 &#8211; 19:00 = 01:00 de offset.<\/p>\n<blockquote><p><strong>Inciso sobre el Horario de Verano:<\/strong><\/p>\n<p>El Horario de Verano, como sabeis, tiene como objetivo reducir el consumo el\u00e9ctrico, tener m\u00e1s luz durante las horas laborales, etc (al margen de que se consigan o no dichos prop\u00f3sitos :-P).<\/p>\n<p>Consiste en mover las manecillas de los relojes locales de un pa\u00eds, para atrasar o adelantar la hora local durante unos meses determinados, cada a\u00f1o.<\/p>\n<ul>\n<li>Lo t\u00edpico es atrasar o adelantarlo 1h, pero en algunos paises es 30 minutos.<\/li>\n<li>Cada pa\u00eds lo puede aplicar durante unos meses diferentes: de marzo a octubre, de abril a septiembre&#8230; Los d\u00edas exactos tambi\u00e9n pueden variar.<\/li>\n<li>En muchos pa\u00edses ni siquiera se aplica el Horario de Verano.<\/li>\n<\/ul>\n<p>En cualquier caso, el offset\u00a0<strong>ya<\/strong>\u00a0lleva inclu\u00eddo el horario de verano cuando se usa, puesto que el offset se obtiene restando la hora local (que ya lleva aplicado el cambio horario) y la hora UTC.<\/p><\/blockquote>\n<p><strong>Otro ejemplo<\/strong>: En Agosto de este a\u00f1o se habr\u00e1 aplicado el horario de verano en Madrid, por lo que el offset no ser\u00e1 01:00h sino 02:00h.<\/p>\n<p>El offset de una localizaci\u00f3n geogr\u00e1fica puede variar tanto a lo largo de un mismo a\u00f1o, como hemos visto, pero tambi\u00e9n <strong>a lo largo de varios a\u00f1os<\/strong>. Por ejemplo:<\/p>\n<ul>\n<li>Antes del 1901, cada provincia espa\u00f1ola ten\u00eda su propia hora local, en base a su meridiano concreto. Ahora ya no.<\/li>\n<li>En el 1918, en Espa\u00f1a se decide <strong>empezar a aplicar el horario de verano<\/strong>, que nunca antes se hab\u00eda utilizado. El offset ya no es el mismo todo el a\u00f1o, sino que aumenta 1h en verano (como en el presente).<\/li>\n<li>El 16 de Marzo de 1940, Espa\u00f1a decide incrementar todos sus relojes en una hora: el offset pasa de 0h a 1h en invierno, y de 1h a 2h en verano. (se <strong>ha cambiado la zona horaria<\/strong>, que explico m\u00e1s abajo)<\/li>\n<li>Si varios paises con diferentes horas locales <strong>eliminan sus fronteras pol\u00edticas<\/strong> para unirse en un solo pa\u00eds, seguramente modifiquen sus horas locales para coincidir en todo el territorio (variando por tanto el offset).<\/li>\n<\/ul>\n<p>Por tanto, es perfectamente posible que dos pa\u00edses tengan el mismo offset durante algunos meses del a\u00f1o, pero difieran durante otros.<\/p>\n<p>Dicho de otra forma: <em><strong>a partir de un offset, no se puede deducir en qu\u00e9 localizaci\u00f3n te encuentras, ni por tanto qu\u00e9 otros offsets existir\u00e1n en otros momentos del a\u00f1o<\/strong><\/em>.<\/p>\n<p><strong>Por ejemplo<\/strong>: Si no sabes si tu +01:00h actual es de Madrid o del Congo, no puedes saber si en Agosto ser\u00e1 un +02:00h (caso de Madrid), o se mantendr\u00e1 en +01:00h (caso de Congo, sin horario de verano).<\/p>\n<p>&nbsp;<\/p>\n<h2>Zona horaria (Time Zone, o TZ)<\/h2>\n<p>Se dice que varias poblaciones est\u00e1n en una misma Zona Horaria, cuando desde el a\u00f1o <strong>1970<\/strong> han compartido <strong>siempre<\/strong>\u00a0la misma<strong> hora local<\/strong>. La nomenclatura es &#8220;Area\/Localizaci\u00f3n&#8221;.<\/p>\n<div id=\"attachment_1098\" style=\"width: 360px\" class=\"wp-caption aligncenter\"><a class=\"vt-p\" href=\"http:\/\/en.wikipedia.org\/wiki\/List_of_tz_database_time_zones\"><img aria-describedby=\"caption-attachment-1098\" loading=\"lazy\" class=\"size-full wp-image-1098\" style=\"border-width: 4px; border-color: black; border-style: solid;\" title=\"Time Zones Map\" src=\"http:\/\/www.stenyak.com\/wp-content\/uploads\/2012\/01\/tzdb.png\" alt=\"\" width=\"350\" height=\"178\" \/><\/a><p id=\"caption-attachment-1098\" class=\"wp-caption-text\">Mapa de todos los TimeZones<\/p><\/div>\n<p>No hay que confundir con los husos horarios, meridianos ni offsets. Son conceptos diferentes: &#8220;UTC+02:00&#8221; no es realmente una Zona Horaria, es un Offset respecto de UTC.<\/p>\n<p>Por ejemplo: En Espa\u00f1a, desde el 1970 hasta ahora, han existido tres regiones que <strong>no siempre<\/strong> han compartido completamente las horas locales en todo momento. Las tres zonas horarias (o TZs) son:<\/p>\n<ul>\n<li><strong>Europe\/Madrid<\/strong>: para la pen\u00ednsula y baleares principalmente.<\/li>\n<li><strong>Atlantic\/Canary<\/strong>: para el archipi\u00e9lago canario.<\/li>\n<li><strong>Africa\/Ceuta<\/strong>: para Ceuta y Melilla.<\/li>\n<\/ul>\n<p>Actualmente, esas 3 timezones usan horario de verano, por lo que actualmente sus offsets respectivos de invierno son 1h, 0h y 1h; y los de verano 2h, 1h y 2h.<\/p>\n<p>Cada TZ ha tenido un pasado diferente: algunos aplicaron el horario de verano durante 20 a\u00f1os, otros no lo aplicaron; unos tenian un offset de 5h, otros de 10h, etc.<\/p>\n<p>Toda esa informaci\u00f3n se almacena en lo que se llama <strong><a class=\"vt-p\" href=\"http:\/\/en.wikipedia.org\/wiki\/Tz_database\">tz database<\/a><\/strong>\u00a0(en castellano, base de datos de zonas horarias).<\/p>\n<p>La <strong>tz database<\/strong>\u00a0debe ser actualizada constantemente, reflejando los cambios horarios que se pueden producir a lo largo de los a\u00f1os.<\/p>\n<p>&nbsp;<\/p>\n<h1>Empieza el meollo de la cuesti\u00f3n<\/h1>\n<p><img loading=\"lazy\" class=\"size-medium wp-image-1101 alignright\" style=\"border-width: 4px; border-color: black; border-style: solid;\" src=\"http:\/\/www.stenyak.com\/wp-content\/uploads\/2012\/01\/flights-300x199.jpg\" alt=\"\" width=\"300\" height=\"199\" \/><br \/>\nUna vez que conocemos los conceptos b\u00e1sicos, podemos pasar a la acci\u00f3n:<\/p>\n<p><em>\u00bfEn qu\u00e9 me influye todo eso a la hora de dise\u00f1ar mi software?<\/em><\/p>\n<p><em>\u00bfC\u00f3mo gestiono las horas correctamente?<br \/>\n\u00bfY si mi usuario vuela de Espa\u00f1a a la India y cambia el reloj de su portatil?<br \/>\n\u00bfY si mi usuario quiere introducir la hora local de despegue y la hora local de aterrizaje en mi software de calendario?<br \/>\n\u00bfY si mi software tiene varios usuarios simult\u00e1neos en diferentes zonas del mundo?<\/em><\/p>\n<p>Una pol\u00edtica habitual en el mundo de la programaci\u00f3n es:<\/p>\n<blockquote><p>&#8220;<strong><em>Almacena y procesa globlamente, muestra localmente<\/em><\/strong>&#8220;.<\/p><\/blockquote>\n<p>Dicho de otra forma: elige un formato <strong>neutro<\/strong>\u00a0para almacenar y operar sobre los datos, y preoc\u00fapate de las particularidades culturales cuando debas mostrar o recoger los datos de un usuario final.<\/p>\n<blockquote><p>Recordemos que en este post se usa la palabra &#8220;<em>hora<\/em>&#8221; como abreviaci\u00f3n de &#8220;<em>fecha+hora<\/em>&#8220;.<\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<h2>&#8220;Almacena y procesa globalmente&#8221;<\/h2>\n<p>Empecemos con un ejemplo sencillote:<\/p>\n<blockquote>\n<div>Tenemos una variable tipo <em>entero<\/em>, cuyo\u00a0valor es 7 millones.<\/div>\n<div>\n<ul>\n<li>El ordenador <strong>almacena y opera<\/strong> <strong>globalmente<\/strong>. Concretamente, usa el binario:\u00a0<strong>00000000011010101100111111000000<\/strong>.<\/li>\n<li>En cambio al <strong>mostrarlo<\/strong> en una hoja de c\u00e1lculo, nos puede mostrar\u00a0&#8220;<strong>7.000.000<\/strong>&#8220;, o bien &#8220;<strong>7,000,000<\/strong>&#8220;, o tal vez &#8220;<strong>7e6<\/strong>&#8220;, o incluso &#8220;<strong>######<\/strong>&#8220;, seg\u00fan el contexto <strong>local<\/strong> (d\u00f3nde vivimos, tama\u00f1o de la celda, formato del n\u00famero&#8230;).<\/li>\n<\/ul>\n<\/div>\n<\/blockquote>\n<div>De igual forma, la pr\u00e1ctica apropiada suele ser <strong>almacenar y operar<\/strong>\u00a0en Hora UTC, y <strong>mostrar<\/strong>\u00a0en Hora Local.<\/div>\n<div><\/div>\n<div>Y no es porque sea <strong>conveniente<\/strong>, sino que muchas veces adem\u00e1s es <strong>necesario<\/strong>. Por ejemplo:<\/div>\n<blockquote><p>Tenemos una Hora Local, las 15:00 de un d\u00eda de Enero. Se le quiere sumar casi medio a\u00f1o (24h*180d\u00edas=4320h) a esa hora. \u00bfCu\u00e1l ser\u00e1 la Hora Local resultante?:<\/p>\n<ol>\n<li>Las 15:00 hora local, como en la hora de partida.<\/li>\n<li>Las 16:00 hora local, porque hay que aplicar el Horario de Verano.<\/li>\n<li>Ninguna de las 2 anteriores.<\/li>\n<li>Cualquiera de las 3 anteriores.<\/li>\n<\/ol>\n<p>Y la soluci\u00f3n es <em>4) Cualquiera de las tres anteriores<\/em>, puesto que depende de la zona horaria:<\/p>\n<ul>\n<li>En el Mosc\u00fa actual o el Madrid del a\u00f1o 1910, no hay horario de verano, luego ser\u00eda <em>1) Las 15:00<\/em>.<\/li>\n<li>En el Madrid actual hay horario de verano, luego ser\u00eda <em>2) Las 16:00<\/em>.<\/li>\n<li>En la Isla de Lord Howe hay horario de verano de 30m, en vez de la hora t\u00edpica, luego ser\u00eda <em>3) Las 15:30<\/em>.<\/li>\n<\/ul>\n<\/blockquote>\n<p>Queda claro entonces\u00a0que la \u00fanica forma de operar correctamente con horas es pasarlas a UTC, operar sobre ellas y finalmente (si hace falta), convertirlas a la Hora Local de nuestra elecci\u00f3n para mostr\u00e1rselo al usuario final.<\/p>\n<p>&nbsp;<\/p>\n<h2>&#8220;Muestra localmente&#8221;<\/h2>\n<p>Hemos establecido que, para la interfaz con el usuario final, necesitamos conversiones de UTC a Hora Local (al renderizar en pantalla) y viceversa (al aceptar datos del usuario)<\/p>\n<p>Si hab\u00e9is entendido perfectamente todo lo explicado hasta hora, se pueden deducir cu\u00e1les son las posibles conversiones <strong>inequ\u00edvocas<\/strong> que podemos hacer:<\/p>\n<p>[table id=3 \/]<\/p>\n<div>Dos aspectos a destacar son:<\/div>\n<h3>a) Almacenar el offset no vale para mucho<\/h3>\n<div>Un offset solamente es v\u00e1lido para una hora concreta del a\u00f1o, en un lugar concreto del planeta.<\/div>\n<div><\/div>\n<div>Tal y como se explic\u00f3 antes, en la <em>secci\u00f3n de Offset<\/em>: si solamente conocemos el Offset para una Hora Local, no podemos averiguar m\u00e1gicamente a qu\u00e9 lugar (TimeZone) pertenece esa Hora Local.<\/div>\n<div><\/div>\n<div>Y por tanto, tampoco podemos calcular autom\u00e1gicamente el offset que habr\u00e1 en otros momentos del a\u00f1o (o lo que es lo mismo, la Hora Local en otros momentos del a\u00f1o). Para ello <strong>necesitamos<\/strong>\u00a0el TZ; no queda otra opci\u00f3n posible.<\/div>\n<div><\/div>\n<div>As\u00ed que en vez de almacenar, Hora Local + Offset, bien podr\u00edamos almacenar \u00fanicamente el UTC a secas.<\/div>\n<h3>b) El usuario deber\u00eda poder especificar el offset al introducir una hora<\/h3>\n<div>Como veis en la tabla, la unica forma <strong>inequ\u00edvoca<\/strong> de que el usuario introduzca una hora, es indicar tambi\u00e9n el offset <strong>de alguna forma<\/strong>.<\/div>\n<div><\/div>\n<div>Por ejemplo: si el usuario introduce la Hora Local &#8220;02:30&#8221;, necesitamos saber a <strong>cu\u00e1l de las dos posibles &#8220;02:30&#8221;<\/strong> existentes se refiere (en caso de existir horario de verano en ese lugar).<\/div>\n<div><\/div>\n<div>Existen muchas formas de hacerlo:<\/div>\n<div>\n<ul>\n<li>Un checkbox con el que marcar si la fecha va con DST o no.<\/li>\n<li>Una dropdown con 25 o 23 elementos (horas), en vez de los 24 habituales.<\/li>\n<li>Una mensaje de pregunta que \u00fanicamente saltar\u00e1 cuando se d\u00e9 el caso de una hora ambigua.<\/li>\n<li>Etc.<\/li>\n<\/ul>\n<\/div>\n<div>Por ejemplo, esta es una forma que aconseja Microsoft si se utiliza su framework de .NET: \u00a0<a class=\"vt-p\" title=\"How to: Let Users Resolve Ambiguous Times\" href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb397782.aspx\">MSDN &#8211; How to let users resolve ambiguous times<\/a><\/div>\n<p>&nbsp;<\/p>\n<div>Si <strong>no<\/strong> se da esa opci\u00f3n al usuario, <strong>el sistema inform\u00e1tico deber\u00e1 resolver la ambig\u00fcedad de forma arbitraria<\/strong>.\u00a0Que en funci\u00f3n del caso concreto, puede ser algo perfectamente aceptable (aunque siempre mejorable).<\/div>\n<h1>Ult\u00edlogo<\/h1>\n<div>Con esto terminamos la segunda y \u00faltima parte del temario.<br \/>\nEspero que hayais conseguido leer y entender hasta este punto, y no est\u00e9is aqu\u00ed unicamente porque os haya llamado la atenci\u00f3n eso de &#8220;<em>ult\u00edlogo<\/em>&#8221; ;-).<br \/>\nCon suerte el art\u00edculo ha sido de ayuda y os evitar\u00e1 bugs y quebraderos de cabeza en un futuro.<\/div>\n<p>&nbsp;<\/p>\n<div><strong>Happy coding!<\/strong><\/div>\n<p>[\u00a0<a class=\"vt-p\" href=\"http:\/\/www.stenyak.com\/archives\/1004\/sobre-la-hora-universal-y-los-relojes-atomicos-o-que-tienen-en-comun-el-tomtom-y-unos-trigales\/\"><strong>Ir a la parte 1 de 2<\/strong>: &#8220;Sobre la Hora Universal y los relojes at\u00f3micos (o qu\u00e9 tienen en com\u00fan el TomTom y unos trigales)&#8221;<\/a>\u00a0]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>[\u00a0Ir a la parte 1 de 2: &#8220;Sobre la Hora Universal y los relojes at\u00f3micos (o qu\u00e9 tienen en com\u00fan el TomTom y unos trigales)&#8221;\u00a0] Continuamos desentra\u00f1ando el misterio de las horas, orientando la explicaci\u00f3n principalmente a programadores. Hemos establecido qu\u00e9 sistemas de medici\u00f3n de la hora existen. Tambi\u00e9n hemos visto que el estandard de [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[4],"tags":[13,23],"_links":{"self":[{"href":"https:\/\/www.stenyak.com\/index.php?rest_route=\/wp\/v2\/posts\/1070"}],"collection":[{"href":"https:\/\/www.stenyak.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.stenyak.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.stenyak.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.stenyak.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1070"}],"version-history":[{"count":0,"href":"https:\/\/www.stenyak.com\/index.php?rest_route=\/wp\/v2\/posts\/1070\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.stenyak.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1070"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.stenyak.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1070"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.stenyak.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1070"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}