Converting local time from CTS to UTC time

Hi,

I'm currently reading the local time from a client via the CTS over BLE, but need to convert that in my nRF52832 to UTC time.  Is there some API's available that do this?  I can't seem to find any, and was thinking "surely, someone has done this before?"

Cheers,

Mike

Parents Reply Children
  • OK, ended up sorting this out for myself.  Below is my code.  I'm sure someone could make this more efficient, but I'm a hardware guy so just happy it works! Haha.

    At the moment I'm just hard coding the values for .timeZone and .dst into my bt_cts_local_time structure, as I've not yet been able to extract this from the CTS.  Plus it made it easier for me to test all the various scenarios.

    #define DAYS_IN_WEEK 7
    #define MONTHS_IN_YEAR 12
    #define MINS_IN_HOUR 60
    #define HOURS_IN_DAY 24
    #define JANUARY 1
    #define FEBRUARY 2
    #define MARCH 3
    #define DECEMBER 12
    
    /**
     * @brief CTS Local Time structure
     *
     * @param timeZone Offset from UTC in hours
     * @param dst Daylight Savings Time: 1 = active, 0 = inactive
     */
    struct bt_cts_local_time
    {
        int8_t timeZone;           /**< Current Time Zone */
        uint8_t dst;               /**< Daylight Saving Time value */
    } ;
    
    struct bt_cts_current_time local_time, utc_time;
    struct bt_cts_local_time local_time_info;
    
    uint8_t daysInMonth[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    
    // Convert time from Current Time Service to UTC time
    // cts_current_time = time from CTS
    // cts_local_time = local time info (time zone and DST) from CTS
    // utc_time = time converted to UTC
    void convert_to_utc_time (struct bt_cts_current_time *cts_current_time, struct bt_cts_local_time *cts_local_time, struct bt_cts_current_time *utc_time)
    {
        int8_t  minOffset = 0,
                hourOffset = 0,
                dayOffset = 0,
                monthOffset = 0,
                yearOffset = 0,
                days_in_current_month = 0,
                days_in_previous_month = 0;
        uint8_t week_day,
                day,
                month,
                hour,
                min;
        uint16_t year;
        bool isLeapYear;
    
        week_day = cts_current_time->exact_time_256.day_of_week;
        day = cts_current_time->exact_time_256.day;
        month = cts_current_time->exact_time_256.month;
        hour = cts_current_time->exact_time_256.hours;
        min = cts_current_time->exact_time_256.minutes;
        year = cts_current_time->exact_time_256.year;
        
        /* Calculate time offset due to local time zone and daylight savings */
        // .timeZone and .dst are expressed in multiples of 15 minutes
        // Negative offset means local time is behind UTC, positive offset means local time is ahead of UTC
        hourOffset = (int8_t)((cts_local_time->timeZone/4) + (cts_local_time->dst/4));
        minOffset = (int8_t)((cts_local_time->timeZone%4) + (cts_local_time->dst%4))*15;
        
        if (year%4 == 0) {
            isLeapYear = true;
            if (month == FEBRUARY) {
                days_in_current_month = daysInMonth[FEBRUARY]+1;
            }
            else {
                days_in_current_month = daysInMonth[month];
            }
            if (month == MARCH) {
                days_in_previous_month = daysInMonth[FEBRUARY]+1;
            }
            else if (month == JANUARY) {
                days_in_previous_month = daysInMonth[DECEMBER];
            }
            else {
                days_in_previous_month = daysInMonth[month-1];
            }
        }
        else {
            isLeapYear = false;
            if (month == JANUARY) {
                days_in_previous_month = daysInMonth[DECEMBER];
            }
            else {
                days_in_previous_month = daysInMonth[month-1];
            }
            days_in_current_month = daysInMonth[month];
        }
    
        /* Update mintues */
        if (minOffset < 0) { 
            //Local behind UTC - increase minutes  
            if ((min + abs(minOffset)) > MINS_IN_HOUR) {
                ++hourOffset;
                min = (min + abs(minOffset)) - MINS_IN_HOUR;
            }
            else {
                min = (min + abs(minOffset));
            }
        }
        else if (minOffset >= 0) {
            //Local ahead of UTC - reduce minutes  
            if (min < minOffset) {
                --hourOffset;
                min = MINS_IN_HOUR + min - minOffset;
            }
            else {
                min = min - minOffset;
            }
        }
    
        /* Update hours */
        if (hourOffset < 0) {
            //Local behind UTC - increase hours 
                if ((hour + abs(hourOffset)) > HOURS_IN_DAY) {
                ++dayOffset;
                hour = (hour + abs(hourOffset)) - HOURS_IN_DAY;
            }
            else {
                hour = (hour + abs(hourOffset));
            }
        }
        else if (hourOffset >= 0) {
            //Local ahead of UTC - reduce hours
            if (hour < hourOffset) {
                --dayOffset;
                hour = HOURS_IN_DAY + hour - hourOffset;
            }
            else {
                hour = hour - hourOffset;
            }
        }
        
    
        /* Update day of month */
        if (dayOffset >= 0) {
            if ((day + dayOffset) > days_in_current_month) {
            ++monthOffset;
            day = (day + dayOffset) - days_in_current_month;
        }
        else {
            day = day + dayOffset;
        }
        }
        else if (dayOffset < 0) {
            if (day <= abs(dayOffset)) {
                --monthOffset;
                day = days_in_previous_month + day + dayOffset;
            }
            else {
                day = day + dayOffset;
            }
        }
    
        /* Update month */
        if (monthOffset >= 0) {
            if ((month + monthOffset) > MONTHS_IN_YEAR) {
            ++yearOffset;
            month = (month + monthOffset) - MONTHS_IN_YEAR;
        }
        else {
            month = month + monthOffset;
        }
        }
        else if (monthOffset < 0) {
            if (month <= abs(monthOffset)) {
                --yearOffset;
                month = MONTHS_IN_YEAR + month + monthOffset;
            }
            else {
                month = month + monthOffset;
            }
        }
        
        /* Update day of week */
        if (dayOffset >= 0) {
            if ((week_day + dayOffset) > DAYS_IN_WEEK) {
                week_day = (week_day + dayOffset) - DAYS_IN_WEEK;
            }
            else {
                week_day = week_day + dayOffset;
            }
        }
        else if (dayOffset < 0) {
            if (week_day <= abs(dayOffset)) {
                week_day = DAYS_IN_WEEK + week_day + dayOffset;
            }
            else {
                week_day = week_day + dayOffset;
            }
        }
     
        /* Set UTC time */
        utc_time->exact_time_256.seconds = cts_current_time->exact_time_256.seconds;
        utc_time->exact_time_256.minutes = min;
        utc_time->exact_time_256.hours = hour;
        utc_time->exact_time_256.day_of_week = week_day;
        utc_time->exact_time_256.day = day;
        utc_time->exact_time_256.month = month;
        utc_time->exact_time_256.year = year + yearOffset;
    
    }

    Cheers,

    Mike

  • There you go. I'm glad you found a solution that works for you.

    Best regards,

    Simon

Related