C语言 如何计算欧盟的夏令时转换日期?

yv5phkfx  于 2022-12-11  发布在  其他
关注(0)|答案(2)|浏览(190)

给定一个UTC时间戳,我想确定DST在当时是否在欧盟处于活动状态。

qnzebej0

qnzebej01#

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:%02d:%02d on %d-%02d-%02d, 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:%02d:%02d on %d-%02d-%02d, 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:%02d:%02d on %d-%02d-%02d, 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.

yfwxisqw

yfwxisqw2#

夏令时从三月的最后一个星期日(02:00 CET)到十月的最后一个星期日(03:00 CEST)。(https://en.wikipedia.org/wiki/Summer_time_in_Europe)。要进行测试,请与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;
}

相关问题