This library takes the current time (which must be set to UTC, e.g. via an NTP call), and applies a timezone definition (loaded at startup) to calculate the local time. This includes the handling of daylight saving. See http://mbed.org/users/hlipka/notebook/time-zone-handling/ for more information (esp. how to get a time zone definition file).

Dependents:   CubiScan 000-FIN_youcef 005_ESSAI_youcef

Time.cpp

Committer:
hlipka
Date:
2011-02-18
Revision:
7:0c7207d674d3
Parent:
5:fde01b92a384

File content as of revision 7:0c7207d674d3:

/*
* TimeZone library
* Copyright (c) 2010 Hendrik Lipka
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include "Time.h"

#include "stdio.h"
#include "time.h"

using namespace std;

class TimeZoneEntry {
public:
    TimeStamp *_from;
    TimeStamp *_to;
    int _offset;
    TimeZoneEntry* next;
};

TimeZoneEntry* Time::_timeZoneEntries=NULL;

bool TimeStamp::isSame(TimeStamp* ts) {
    if (ts->getYear()!=getYear())
        return false;
    if (ts->getMonth()!=getMonth())
        return false;
    if (ts->getDay()!=getDay())
        return false;
    if (ts->getHour()!=getHour())
        return false;
    if (ts->getSecond()!=getSecond())
        return false;
    return true;
}
bool TimeStamp::isBefore(TimeStamp* ts) {
    if (getYear()<ts->getYear())
        return true;
    if (getYear()>ts->getYear())
        return false;

    if (getMonth()<ts->getMonth())
        return true;
    if (getMonth()>ts->getMonth())
        return false;

    if (getDay()<ts->getDay())
        return true;
    if (getDay()>ts->getDay())
        return false;

    if (getHour()<ts->getHour())
        return true;
    if (getHour()>ts->getHour())
        return false;

    if (getSecond()<ts->getSecond())
        return true;
    return false;
}
bool TimeStamp::isAfter(TimeStamp* ts) {
    return ts->isBefore(this);
}

Time::Time() {
//    printf("init time\n");
    if (NULL==Time::_timeZoneEntries) {
//        printf("reading time zones\n");
        readTimeZones();
    }
}

void Time::readTimeZones() {
    time_t rawtime;
    time ( &rawtime );
    TimeStamp *ts=new TimeStamp(rawtime);

    int currentYear=ts->getYear();
    delete ts;

    FILE *fp = fopen("/local/timezone.csv", "r");

    if (fp==NULL) {
        printf("error while reading timezone file [timezone.csv]\n");
        return;
    }

    TimeZoneEntry *current=NULL;


    char tmp[128]; // enough for a single line
    while (fgets(tmp,sizeof(tmp),fp)!=0) {
        if (tmp[0]!='#') {
            int fyear, fmon, fday, fhour, fmin, fsec;
            int tyear, tmon, tday, thour, tmin, tsec;
            int offset;
            int r=sscanf(tmp,"%4d-%2d-%2dT%2d:%2d:%2dZ,%4d-%2d-%2dT%2d:%2d:%2dZ,%d",
                         &fyear, &fmon, &fday, &fhour, &fmin, &fsec,
                         &tyear, &tmon, &tday, &thour, &tmin, &tsec,
                         &offset
                        );
            if (13!=r)
                continue;
            // when we have no current time, so the year is 1970 and we read everything
            // otherwise skip everything more than 4 years in advance to save memory
            if (currentYear!=1970 && (tyear<currentYear || fyear>currentYear+4)) {
                continue;
            }

            TimeStamp *from=new TimeStamp(fyear, fmon, fday, fhour, fmin, fsec,0);
            TimeStamp *to=new TimeStamp(tyear, tmon, tday, thour, tmin, tsec,0);
            TimeZoneEntry *tze=new TimeZoneEntry();
            tze->_from=from;
            tze->_to=to;
            tze->_offset=offset;
            tze->next=NULL;

            if (NULL==current) {
                current=tze;
                _timeZoneEntries=tze;
            } else {
                current->next=tze;
                current=tze;
            }
        }
    }
//    printf("closing time zone file\n");
    fclose(fp);
}

Time::~Time() {
}

int Time::getTimeOffset(TimeStamp* ts) {
    TimeZoneEntry *current=_timeZoneEntries;

    while (current!=NULL) {
        if (current->_from->isBefore(ts) && current->_to->isAfter(ts)) {
            return current->_offset;
        }
        current=current->next;
    }
    return 0;
}

TimeStamp* Time::getTime() {
    time_t rawtime;
    time ( &rawtime );
    TimeStamp *ts=new TimeStamp(rawtime);

    rawtime+=getTimeOffset(ts);
    ts->updateTime(rawtime);

    return ts;
}