Time Zones
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">
- include <stdlib.h>
- include <stdio.h>
- include <io.h>
- include <time.h>
- include <dev/board.h>
- include <sys/timer.h>
/* total number of timezones used */
- 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>