Get current timezone using Google Time API


#1

Hi, I saw there were a few questions about getting timezone corrected time from the internet, so I thought I’d make a writeup, corrections and comments are of course welcome! :slight_smile:

I’ll not cover how to get your location as you may be using GPS hardware, or if you’re using WiFi-based location this is covered in the guide in the docs using deviceLocator.

To make this work you will need an API key for Googles Time Zone API, this can be had at: https://developers.google.com/maps/documentation/timezone/get-api-key

You will have to create a webhook integration for it in the developer console with the following settings:

Event Name: getTimeZone (Can be whatever you like)
URL: https://maps.googleapis.com/maps/api/timezone/json
Request type: GET
Request format: Query parameters
Query parameters (Under advanced settings):

{
  "key": <Your Google Time Zone API key>,
  "timestamp": "{{timestamp}}",
  "location": "{{loc}}"
}

Response template: {{dstOffset}}:{{rawOffset}}:{{status}}:{{timeZoneId}}:{{timeZoneName}}

As for your code, it should look something like this:

bool tzUpdated = 0;
float currentLatitude = <device latitude>;
float currentLongitude = <device longitude>;

void tzHandler(const char *event, const char *data) {
    char charBuf[100];
    String command = data;
    command.toCharArray(charBuf, 100);
    const int value_count = 20;     // the maximum number of values
    String values[value_count];     // store the values here

    char string[20];
    strcpy(string, charBuf);        // the string to split
    int idx = 0;
    for (char* pt=strtok(string, ":"); pt && idx<value_count; pt=strtok(NULL, ":")) {
        values[idx++] = pt;
    }
    
    if(values[2] == "OK") {  // Check if the webhook returned successfully
        dstOffset = atof(values[0]) / 3600;  // Convert DST offset to hours
        timeZone = atof(values[1]) / 3600;  // Convert timezone offset to hours
        Serial.println(command + ":" + String(dstOffset, 1) + ":" + String(timeZone, 1));  // Print received data
        Time.setDSTOffset(dstOffset);  // Sets the offset for when DST is applied
        if(atoi(values[0]) > 0) {  // If there is a DST offset applied
            Time.beginDST();  // Enable DST
        } else {
            Time.endDST();  // Otherwise disable DST
        }
        Time.zone(timeZone);  // Update timezone
    }
}

setup() {
    Particle.subscribe(System.deviceID() + "/hook-response/getTimeZone/", tzHandler, MY_DEVICES);  // Subscribe to webhook
}

loop() {
    if(!tzUpdated) {  // Check if timezone needs update
        String data = "{ \"loc\": \"" + String(currentLatitude) + "," + String(currentLongitude) + "\", \"timestamp\": \"" + Time.now() + "\" }";  // Create a request string
        if(Particle.connected()) {  // Check that we have a cloud connection
            Particle.publish("getTimeZone", data, PRIVATE);  // Then hit webhook
            tzUpdated = 1;  // Set the updated flag to prevent hammering the webhook
        }
    }
}

You should set your currentLatitude and currentLongitude variables by geolocation or manually before calling the timezone update. It can be rerun by setting tzUpdated to false.

As a closing comment, the Google Time Zone API is a billed service if you have too much usage, so your code should use the update function sparingly to avoid this.

Hope this is helpful to someone!


New (BETA) library to configure local time settings