Home > front end >  How to calculate daylight saving switchover dates for EU?
How to calculate daylight saving switchover dates for EU?

Time:12-11

Given a UTC timestamp, I'd like to determine if DST was active at that time in European Union.

CodePudding user response:

The usual way of answering this question makes use of the comprehensive tz database, which is built into most operating systems, with the exception of Windows, which uses its own, similar database.

A database like this is necessary in order for the C library localtime and mktime functions to work correctly.

If you already have a broken-down date and time (year/month/day, hour:minute:second), the function you want is mktime. Let's try two dates, July 8th and December 13th.

#include <stdio.h>
#include <time.h>

int main()
{
    struct tm tm1, tm2;
    /* July 8th */
    tm1.tm_year = 2022 - 1900;
    tm1.tm_mon = 7 - 1;
    tm1.tm_mday = 8;
    tm1.tm_hour = 12;
    tm1.tm_min = tm1.tm_sec = 0;
    tm1.tm_isdst = -1;
    mktime(&tm1);
    printf("at %d:d:d on %d-d-d, DST %s in effect\n",
        tm1.tm_hour, tm1.tm_min, tm1.tm_sec,
        tm1.tm_year 1900, tm1.tm_mon 1, tm1.tm_mday,
        tm1.tm_isdst ? "was" : "was not");

    /* December 13th */
    tm2.tm_year = 2022 - 1900;
    tm2.tm_mon = 12 - 1;
    tm2.tm_mday = 13;
    tm2.tm_hour = 12;
    tm2.tm_min = tm2.tm_sec = 0;
    tm2.tm_isdst = -1;
    mktime(&tm2);
    printf("at %d:d:d on %d-d-d, DST %s in effect\n",
        tm2.tm_hour, tm2.tm_min, tm2.tm_sec,
        tm2.tm_year 1900, tm2.tm_mon 1, tm2.tm_mday,
        tm2.tm_isdst ? "was" : "was not");
}

For me this prints

at 12:00:00 on 2022-07-08, DST was in effect
at 12:00:00 on 2022-12-13, DST was not in effect

When filling in struct tm, there are a couple of things to be careful of, as illustrated in the code above:

  • field tm_year is offset by 1900
  • field tm_mon is offset by 1 (it's 0-based)
  • field tm_isdst contains 1 if DST is in effect, 0 if its not, or -1 if we're not sure.

So the strategy is simply: fill in a struct tm with the desired date/time, set tm_isdst to -1 indicating that we don't know whether DST is in effect or not, and call mktime. Among other things, mktime figures out whether DST was in effect or not, and adjusts tm_isdst in the pointed-to struct tm accordingly.

If the "UTC timestamp" you said you had to start with is a Unix-style time_t value, you can answer your question using the localtime function, which starts with a time_t value and constructs a struct tm:

time_t t = 1670714400;
struct tm *tmp = localtime(&t);
printf("at %d:d:d on %d-d-d, DST %s in effect\n",
    tmp->tm_hour, tmp->tm_min, tmp->tm_sec,
    tmp->tm_year 1900, tmp->tm_mon 1, tmp->tm_mday,
    tmp->tm_isdst ? "was" : "was not");

On my machine this prints

at 18:20:00 on 2022-12-10, DST was not in effect

I've glossed over one important question, which is: how do localtime and mktime know which of the world's time zone and daylight savings rules to use? For Unix-like operating systems, at least, it's based on an environment variable, TZ. Normally it's set to match the part of the world where you are (where your computer is installed), although you can set it to anything you want. For example, if I wanted my program to use the rules for Central European time, I'd set TZ to Europe/Rome, the tz identifier for that zone.

The usual way of setting environment variables (again, under Unix) is from the shell, outside of your C program. For example, to run my program under a different time zone, I might type

TZ=Europe/Rome
export TZ
./myprogram

Or there's this shortcut:

TZ=Europe/Rome ./myprogram

Or, you can also set an environment variable from within a C program, like this:

setenv("TZ", "Europe/Rome", 1);
tzset();

setenv is a Posix function, not Standard C. After you change the TZ environment variable from within a C program like this, you have to call tzset to let the timezone-related functions like mktime know you've done so.

CodePudding user response:

Daylight saving time is observed from the last Sunday in March (02:00 CET) to the last Sunday in October (03:00 CEST). (https://en.wikipedia.org/wiki/Summer_time_in_Europe). To test, compare e.g. with https://www.timeanddate.com/time/change/germany?year=2022

#include <stdio.h>
#include <stdlib.h>

//included for reference only
int wd(int y, int m, int d)
{
    return (d  = m<3?y--:y-2, 23*m/9   d 4   y/4 - y/100   y/400) % 7;
    //https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week#Keith
}

#define GregorianAdpotion 1752
int main(int argc, char *argv[])
{
    int y = argc > 1 ? atoi(argv[1]) : 2022;
    if (y <= GregorianAdpotion)
        return 1;
    //https://rosettacode.org/wiki/Find_the_last_Sunday_of_each_month#FreeBASIC
    int x = 33 y   y/4 - y/100   y/400; //common part of Keith for Mar and Oct
    int last_Sun_March = 31 - x % 7;
    int last_Sun_Oct = 31 - (4   x) % 7;
    printf("DST from %d-03-%d 02:00 CET ", y, last_Sun_March);
    printf("to %d-10-%d 03:00 CEST\n", y, last_Sun_Oct);
    return 0;
}
  •  Tags:  
  • cdst
  • Related