Time Zones

From Nutwiki
Revision as of 17:03, 27 October 2016 by Harald (Talk | contribs) (1 revision imported)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Test Environments

Hardware Comments Nut/OS
4.8.3
Nut/OS
4.8.7
Ethernut 1.3 H OK
Binaries
Compiler: AVR-GCC 4.3.2
OK
Binaries
Compiler: AVR-GCC 4.3.2
Ethernut 2.1 B OK
Binaries
Compiler: AVR-GCC 4.3.2
OK
Binaries
Compiler: AVR-GCC 4.3.2
Ethernut 3.0 E OK
Binaries
Compiler: ARM-GCC 4.3.3
OK
Binaries
Compiler: ARM-GCC 4.3.3

Overview

This example show how to build and update a simple world time clock with different timezones, daylight saving time and proper output formatting.

Source Code

<source lang="c">

  1. include <stdlib.h>
  2. include <stdio.h>
  3. include <io.h>
  4. include <time.h>
  1. include <dev/board.h>
  2. include <sys/timer.h>

/* total number of timezones used */

  1. define N_TZ 6

int main(void) {

   u_long baud = 115200;
   time_t cur_time = 0;
   tm *cur_dt = malloc(sizeof(tm));
   int i = 0;
   /* define names and timezones for the clock */
   char name[N_TZ][30] = { "Berlin", "New York", "Moscow", "Dubai", "Los Angeles", "Chicago" };
   int tz[N_TZ] = { +1, -5, +3, +4, -8, -6 };
   /* consider daylight saving time? 1 for yes, 0 for no */
   int dst[N_TZ] = { 1, 1, 1, 0, 1, 1 };


   NutRegisterDevice(&DEV_DEBUG, 0, 0);
   freopen(DEV_DEBUG_NAME, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   /* This time must be entered as UTC +0 */
   cur_dt->tm_hour = 14;
   cur_dt->tm_min = 8;
   cur_dt->tm_sec = 0;
   cur_dt->tm_mday = 17;
   cur_dt->tm_mon = 7;
   cur_dt->tm_year = 109;      /* years since 1900 */
   cur_dt->tm_isdst = 1;
   _daylight = 1;
   _timezone = 0;
   cur_time = mktime(cur_dt);
   stime(&cur_time);
   puts("Ethernut World Clock");
   for (;;) {
       puts("World time:\n");
       for (i = 0; i < N_TZ; i++) {
           _timezone = -tz[i] * 60 * 60;
           _daylight = dst[i];
           time(&cur_time);
           cur_dt = localtime(&cur_time);
           printf("%s:\n\t%02d:%02d:%02d   %02d-%02d-%04d\n", name[i], cur_dt->tm_hour, cur_dt->tm_min, cur_dt->tm_sec,
                  cur_dt->tm_mday, cur_dt->tm_mon, cur_dt->tm_year + 1900);
       }
       puts("\n");
       NutSleep(1000);
   }
   free(cur_dt);
   return 0;

} </source>

Details

<source lang="c"> /* define names and timezones for the clock */ char name[N_TZ][30] = { "Berlin", "New York", "Moscow", "Dubai", "Los Angeles", "Chicago" }; int tz[N_TZ] = { +1, -5, +3, +4, -8, -6 }; /* consider daylight saving time? 1 for yes, 0 for no */ int dst[N_TZ] = { 1, 1, 1, 0, 1, 1 }; </source>

We set up a list of timezone names, their actual timezone offsets and whether to consider daylight savings time for this particular timezone.

<source lang="c"> NutRegisterDevice(&DEV_DEBUG, 0, 0); freopen(DEV_DEBUG_NAME, "w", stdout); _ioctl(_fileno(stdout), UART_SETSPEED, &baud);

/* This time must be entered as UTC +0 */ cur_dt->tm_hour = 14; cur_dt->tm_min = 8; cur_dt->tm_sec = 0; cur_dt->tm_mday = 17; cur_dt->tm_mon = 7; cur_dt->tm_year = 109; /* years since 1900 */ cur_dt->tm_isdst = 1; </source>

Then we register our debug device as usual and fill the starting timestamp cur_dt with the current time. This time is hardcoded to keep the example simple, adjust it to the current time (UTC +0) before compiling. Normally we would get the time via NTP here or - if the board has an RTC - get the time from RTC.

<source lang="c"> _daylight = 1; _timezone = 0; cur_time = mktime(cur_dt); stime(&cur_time);

puts("Ethernut World Clock"); </source>

We enable DST, set the timezone to 0 (UTC +0, remember? We'll need that so we can calculate the time around the world in a moment.) Then we convert our timestamp into an integer value and use that to set the current time on the board. Our board now uses the time set in cur_dt. From here it's really easy to calculate the time in other timezones using Nut/OS.

<source lang="c"> for (i = 0; i < N_TZ; i++) {

   _timezone = -tz[i] * 60 * 60;
   _daylight = dst[i];
   time(&cur_time);
   cur_dt = localtime(&cur_time);
   printf("%s:\n\t%02d:%02d:%02d   %02d-%02d-%04d\n", name[i], cur_dt->tm_hour, cur_dt->tm_min, cur_dt->tm_sec,
          cur_dt->tm_mday, cur_dt->tm_mon, cur_dt->tm_year + 1900);

} puts("\n"); NutSleep(1000); </source>

Now that we have the time set and an array with timezones we want to use, we combine that data.

First we set the current timezone to the timezone we want to convert to. This does not have any immediate effects but it will affect all time conversions we do afterwards. They will use exactly this offset. Same goes for the daylight savings time setting. We grab it from the array and set it, but it doesn't have any immediate effects.

We then get the current time and store it in cur_time.

The next line <source lang="c"> cur_dt = localtime(&cur_time); </source> does the real work: It outputs our current time but modified by the timezone and daylight savings time settings. This way we can convert from one timezone (UTC +0 which we set earlier) to another timezone. The nice thing about this is that it fills out the cur_dt structure and we can now use that to output the time as easily as we filled out the time above.

So we do exactly that.

Output

<source lang="text"> Ethernut World Clock World time:

Berlin:

       15:08:00   17-07-2009

New York:

       09:08:00   17-07-2009

Moscow:

       17:08:00   17-07-2009

Dubai:

       17:08:00   17-07-2009

Los Angeles:

       06:08:00   17-07-2009

Chicago:

       08:08:00   17-07-2009

</source>

See also

Template:Languages