• mktime 夏令时


            我们的最终目的是把字符串格式的时间转换为内部使用的“日历时间”,即到UTC 1970年1月1日零时的秒数。这里就存在夏令时的问题。比如俄罗斯时间2008年10月26日2:30由于夏令时的跳变会经过两次,这两次所代表的“日历时间”明显不同。如果仍按照上面的程序,由mktime()函数来决定这个时间是否处于夏令时(它会根据当前时区自动判断,在没有发生时间重叠的情况下处理是正确的)就会有问题。这时我们不能使用ttm.tm_isdst = -1了,而是明确使用ttm_tm_isdst = 1来告知mktime()现在处于夏令时,明确使用ttm.tm_isdst = 0来告知未处于夏令时。
    结论:使用字符串时间表示时一定要有标记表示这个时间是否处于夏令时,推荐在时间字符串后面添加DST或者加上时区。否则,无法正确处理夏令时情况。如果时间字符串表示的是UTC时间,则无需上述处理过程。

    mktime各种情况测试一下

        在支持不支持夏令时时区,夏令时区间,非夏令时区间,切入夏令时丢失小时时,切出夏令时重复小时时。。tm_isdst 的不同作用

        mktime是用于生成指定的本地时刻的,多数情况下我们都会把tm_isdst设置为-1,这样子可以把指定时刻是否为夏令时交由系统判断.不过实际应用中发现,对于切出夏令时时出现的重复小时,一个小时处于夏令时,一个小时不处于夏令时,因为我们没有指定是否处于夏令时,这时得到的结果便不稳定,可能是处于夏令时的小时,也可能是处于非夏令时的小时.

        下面是测试结果:
        tm中tm_isdst分别为0,1,-1对mktime结果影响.
        tm_isdst = -1(由系统判断)
        对于切入夏令时丢失的小时前的小时,生成时间为指定时间.
        对于切入夏令时丢失的小时,生成时间为指定小时后面一个小时(不受前面mk结果影响)
        对于切入夏令时丢失的小时后的小时,生成时间为指定时间.

        对于切出夏令时重复的小时前的小时,生成时间为指定时间.
        对于切出夏令时重复的小时,生成时间受前面mk结果影响,倘若前次mk时间结果处于夏令时,则结果为处于夏令时的那个小时;倘若前次mk时间结果不处于夏令时,则结果为不处于夏令时的那个小时;
        对于切出夏令时重复的小时后的小时,生成时间为指定时间.

        tm_isdst = 0(指定为非夏令时)
        对于切入夏令时丢失的小时前的小时,生成时间为指定时间.
        对于切入夏令时丢失的小时,生成时间为指定小时后面一个小时(不受前面mk结果影响)
        对于切入夏令时丢失的小时后的小时,生成时间为指定时间后面一个小时.

        对于切出夏令时重复的小时前的小时,生成时间为指定时间后面一个小时.
        对于切出夏令时重复的小时,生成时间为不处于夏令时的那个小时;
        对于切出夏令时重复的小时后的小时,生成时间为指定时间.

        tm_isdst = 1(指定为夏令时)
        对于切入夏令时丢失的小时前的小时,生成时间为指定时间前面一个小时.
        对于切入夏令时丢失的小时,生成时间为指定小时后面一个小时(不受前面mk结果影响)
        对于切入夏令时丢失的小时后的小时,生成时间为指定时间.

        对于切出夏令时重复的小时前的小时,生成时间为指定时间.
        对于切出夏令时重复的小时,生成时间为处于夏令时的那个小时;
    对于切出夏令时重复的小时后的小时,生成时间为指定时间前面一个小时.

        倘若mktime传入时间因为夏令时存在两个,那mktime会认为该时间可能处于夏令时也可能处于非夏令时。是否处于夏令时由mktime生成的上一个时间决定,倘若上一个时间处于夏令时则生成的该重复时间是处于夏令时的,否则生成的该重复时间是处于非夏令时的。程序内部的原因是它在mktime中用一个静态变量保存夏令时状态,下次生成时间是优先以保存的状态来生成时间。

        倘若mktime一个不存在的夏令时(出现夏令时切换时丢失的那个小时)会直接生成丢失小时的下一个小时。这个结果是确定的稳定的。

    暂时解决问题的一个方案:

        

    #include <iostream>
    #include <time.h>
    #include <arpa/inet.h>
    using namespace std;
    time_t MakeTime(int iYear, int iMonth, int iMonthDay,
    int iHour, int iMinute, int iSecond, int iIsdst)
    {
    struct tm dTm;
    dTm.tm_mon = iMonth - 1;
    dTm.tm_mday = iMonthDay ;
    dTm.tm_year = iYear - 1900;
    dTm.tm_hour = iHour;
    dTm.tm_min = iMinute;
    dTm.tm_sec = iSecond;
    dTm.tm_isdst = iIsdst;

    time_t ret = mktime(&dTm);

    // 判断生成的是不是夏令时中的,倘若系统一直不是夏令时,可以省一些性能
    if(1 == dTm.tm_isdst)

    {
    // 调整为非夏令时
    dTm.tm_isdst = 0;

    time_t tmpRet = mktime(&dTm);
    if(iHour == dTm.tm_hour)
    {
    // 确定为重复时间
    ret = tmpRet;

    }
    }
    return ret;

    }

    string ToString(time_t tTime)
    {
    struct tm Tm;
    struct tm* pTm;
    pTm = localtime_r(&tTime, &Tm);
    if(NULL == pTm)
    {
    }
    int iSecond = pTm->tm_sec;
    int iMinute = pTm->tm_min;
    int iHour = pTm->tm_hour;
    int iMonthDay = pTm->tm_mday;
    int iMonth = pTm->tm_mon + 1;
    int iYear = pTm->tm_year + 1900;
    #define MAX_DATETIME_STRING_FORMAT "%04d-%02d-%02d %02d:%02d:%02d %s"
    static const int MaxDateTimeStringLength = 23;
    char temp[MaxDateTimeStringLength + 1];
    snprintf(temp, MaxDateTimeStringLength + 1, MAX_DATETIME_STRING_FORMAT, iYear, iMonth, iMonthDay, iHour, iMinute, iSecond, pTm->tm_zone);
    return temp;
    }

    int main()
    {
        setenv("TZ","Europe/Moscow",1);
      tzset();
        time_t tt = MakeTime(2011,10,30, 2, 30, 00, -1);

    string tstring = ToString(tt);
    cout<<tstring<<endl;
    cout<<"Moscow exit UTC time(duplicate hour 2011-10-30 02:30:00):"<<ToString(MakeTime(2011, 10, 30, 2, 30, 00, -1))<<endl;

    cout<<"Isdst = -1"<<endl;
    cout<<"Moscow enter UTC time(before miss hour 2011-03-27 01:30:00):"<<ToString(MakeTime(2011, 3, 27, 1, 30, 00, -1))<<endl;
    cout<<"Moscow exit UTC time(duplicate hour 2011-10-30 02:30:00):"<<ToString(MakeTime(2011, 10, 30, 2, 30, 00, -1))<<endl;
    cout<<"Moscow enter UTC time(miss hour 2011-03-27 02:30:00):"<<ToString(MakeTime(2011, 3, 27, 2, 30, 00, -1))<<endl;
    cout<<"Moscow enter UTC time(miss hour 2011-03-27 03:30:00):"<<ToString(MakeTime(2011, 3, 27, 3, 30, 00, -1))<<endl;
    cout<<"Moscow exit UTC time(before duplicate hour 2011-10-30 01:30:00):"<<ToString(MakeTime(2011, 10, 30, 1, 30, 00, -1))<<endl;
    cout<<"Moscow exit UTC time(duplicate hour 2011-10-30 02:30:00):"<<ToString(MakeTime(2011, 10, 30, 2, 30, 00, -1))<<endl;
    cout<<"Moscow exit UTC time(after duplicate hour 2011-10-30 03:30:00):"<<ToString(MakeTime(2011, 10 ,30, 3, 30, 00, -1))<<endl;
    cout<<"Moscow enter UTC time(before miss hour 2011-03-27 01:30:00):"<<ToString(MakeTime(2011, 3, 27, 1, 30, 00, -1))<<endl;
    cout<<"Moscow exit UTC time(duplicate hour 2011-10-30 02:30:00):"<<ToString(MakeTime(2011, 10, 30, 2, 30, 00, -1))<<endl;

    cout<<"Current time :"<<ToString(time(0))<<endl;
    cout<<"Isdst = -1"<<endl;
    cout<<"Moscow enter UTC time(before miss hour 2011-03-27 01:30:00):"<<ToString(MakeTime(2011, 3, 27, 1, 30, 00, -1))<<endl;
    cout<<"Moscow enter UTC time(miss hour 2011-03-27 02:30:00):"<<ToString(MakeTime(2011, 3, 27, 2, 30, 00, -1))<<endl;
    cout<<"Moscow enter UTC time(miss hour 2011-03-27 03:30:00):"<<ToString(MakeTime(2011, 3, 27, 3, 30, 00, -1))<<endl;
    cout<<"Moscow exit UTC time(before duplicate hour 2011-10-30 01:30:00):"<<ToString(MakeTime(2011, 10, 30, 1, 30, 00, -1))<<endl;
    cout<<"Moscow exit UTC time(duplicate hour 2011-10-30 02:30:00):"<<ToString(MakeTime(2011, 10, 30, 2, 30, 00, -1))<<endl;
    cout<<"Moscow exit UTC time(after duplicate hour 2011-10-30 03:30:00):"<<ToString(MakeTime(2011, 10 ,30, 3, 30, 00, -1))<<endl;

    cout<<"Isdst = 1"<<endl;
    cout<<"Moscow enter UTC time(before miss hour 2011-03-27 01:30:00):"<<ToString(MakeTime(2011, 3, 27, 1, 30, 00, 1))<<endl;
    cout<<"Moscow enter UTC time(miss hour 2011-03-27 02:30:00):"<<ToString(MakeTime(2011, 3, 27, 2, 30, 00, 1))<<endl;
    cout<<"Moscow enter UTC time(miss hour 2011-03-27 03:30:00):"<<ToString(MakeTime(2011, 3, 27, 3, 30, 00, 1))<<endl;
    cout<<"Moscow exit UTC time(before duplicate hour 2011-10-30 01:30:00):"<<ToString(MakeTime(2011, 10, 30, 1, 30, 00, 1))<<endl;
    cout<<"Moscow exit UTC time(duplicate hour 2011-10-30 02:30:00):"<<ToString(MakeTime(2011, 10, 30, 2, 30, 00, 1))<<endl;
    cout<<"Moscow exit UTC time(after duplicate hour 2011-10-30 03:30:00):"<<ToString(MakeTime(2011, 10 ,30, 3, 30, 00, 1))<<endl;

    cout<<"Isdst = 0"<<endl;
    cout<<"Moscow enter UTC time(before miss hour 2011-03-27 01:30:00):"<<ToString(MakeTime(2011, 3, 27, 1, 30, 00, 0))<<endl;
    cout<<"Moscow enter UTC time(miss hour 2011-03-27 02:30:00):"<<ToString(MakeTime(2011, 3, 27, 2, 30, 00, 0))<<endl;
    cout<<"Moscow enter UTC time(miss hour 2011-03-27 03:30:00):"<<ToString(MakeTime(2011, 3, 27, 3, 30, 00, 0))<<endl;
    cout<<"Moscow exit UTC time(before duplicate hour 2011-10-30 01:30:00):"<<ToString(MakeTime(2011, 10, 30, 1, 30, 00, 0))<<endl;
    cout<<"Moscow exit UTC time(duplicate hour 2011-10-30 02:30:00):"<<ToString(MakeTime(2011, 10, 30, 2, 30, 00, 0))<<endl;
    cout<<"Moscow exit UTC time(after duplicate hour 2011-10-30 03:30:00):"<<ToString(MakeTime(2011, 10 ,30, 3, 30, 00, 0))<<endl;
    }

     MakeTime的测试代码

    setenv("TZ","Europe/Moscow",1);
    tzset();
    // DST = -1

    // 切入夏令时丢失的小时前的小时
    assert("2011-03-27 01:30:00 MSK" == ToString(MakeTime(2011, 3, 27, 1, 30, 00, -1)));
    // 切入夏令时丢失的小时
    assert("2011-03-27 03:30:00 MSD" == ToString(MakeTime(2011, 3, 27, 2, 30, 00, -1)));
    // 切入夏令时丢失的小时后的小时
    assert("2011-03-27 03:30:00 MSD" == ToString(MakeTime(2011, 3, 27, 3, 30, 00, -1)));
    // 切入夏令时丢失的小时
    assert("2011-03-27 03:30:00 MSD" == ToString(MakeTime(2011, 3, 27, 2, 30, 00, -1)));

    // 切出夏令时重复的小时前的小时
    assert("2011-10-30 01:30:00 MSD" == ToString(MakeTime(2011, 10, 30, 1, 30, 00, -1)));
    // 切出夏令时重复的小时
    assert("2011-10-30 02:30:00 MSD" == ToString(MakeTime(2011, 10, 30, 2, 30, 00, -1)));
    // 切出夏令时重复的小时后的小时
    assert("2011-10-30 03:30:00 MSK" == ToString(MakeTime(2011, 10 ,30, 3, 30, 00, -1)));
    // 切出夏令时重复的小时
    assert("2011-10-30 02:30:00 MSK" == ToString(MakeTime(2011, 10, 30, 2, 30, 00, -1)));

    // DST = 0

    // 切入夏令时丢失的小时前的小时
    assert("2011-03-27 01:30:00 MSK" == ToString(MakeTime(2011, 3, 27, 1, 30, 00, 0)));
    // 切入夏令时丢失的小时
    assert("2011-03-27 03:30:00 MSD" == ToString(MakeTime(2011, 3, 27, 2, 30, 00, 0)));
    // 切入夏令时丢失的小时后的小时
    assert("2011-03-27 04:30:00 MSD" == ToString(MakeTime(2011, 3, 27, 3, 30, 00, 0)));
    // 切入夏令时丢失的小时
    assert("2011-03-27 03:30:00 MSD" == ToString(MakeTime(2011, 3, 27, 2, 30, 00, 0)));

    // 切出夏令时重复的小时前的小时
    assert("2011-10-30 02:30:00 MSD" == ToString(MakeTime(2011, 10, 30, 1, 30, 00, 0)));
    // 切出夏令时重复的小时
    assert("2011-10-30 02:30:00 MSK" == ToString(MakeTime(2011, 10, 30, 2, 30, 00, 0)));
    // 切出夏令时重复的小时后的小时
    assert("2011-10-30 03:30:00 MSK" == ToString(MakeTime(2011, 10 ,30, 3, 30, 00, 0)));
    // 切出夏令时重复的小时
    assert("2011-10-30 02:30:00 MSK" == ToString(MakeTime(2011, 10, 30, 2, 30, 00, 0)));


    // DST = 1

    // 切入夏令时丢失的小时前的小时
    assert("2011-03-27 00:30:00 MSK" == ToString(MakeTime(2011, 3, 27, 1, 30, 00, 1)));
    // 切入夏令时丢失的小时
    assert("2011-03-27 01:30:00 MSK" == ToString(MakeTime(2011, 3, 27, 2, 30, 00, 1)));
    // 切入夏令时丢失的小时后的小时
    assert("2011-03-27 03:30:00 MSD" == ToString(MakeTime(2011, 3, 27, 3, 30, 00, 1)));
    // 切入夏令时丢失的小时
    assert("2011-03-27 01:30:00 MSK" == ToString(MakeTime(2011, 3, 27, 2, 30, 00, 1)));

    // 切出夏令时重复的小时前的小时
    assert("2011-10-30 01:30:00 MSD" == ToString(MakeTime(2011, 10, 30, 1, 30, 00, 1)));
    // 切出夏令时重复的小时
    assert("2011-10-30 02:30:00 MSD" == ToString(MakeTime(2011, 10, 30, 2, 30, 00, 1)));
    // 切出夏令时重复的小时后的小时
    assert("2011-10-30 02:30:00 MSK" == ToString(MakeTime(2011, 10 ,30, 3, 30, 00, 1)));
    // 切出夏令时重复的小时
    assert("2011-10-30 02:30:00 MSD" == ToString(MakeTime(2011, 10, 30, 2, 30, 00, 1)));



  • 相关阅读:
    python制作一个塔防射箭游戏
    有两个链表a和b,设结点中包含学号、姓名。从a链表中删去与b链表中有相同 学号的那些结点。
    python实现一个简单的21点游戏
    C语音,函数padd的功能是调整pa指向的链表中结点的位置,使得所有x值为偶数的结点出现在链表的前半部,所有x值为奇数的结点出现在链表的后半部。
    scratch绘制特殊图形1
    验证哥德巴赫猜想,输出6-100之间的偶数等于两个质数之和
    写一函数check检测字符串中的左右括号数是否匹配
    C语言文件操作题,将整数1-10及其算术平方根存入文件,再读取出来显示在屏幕上
    湖南2020对口计算机32题第1、2、3小题
    基础
  • 原文地址:https://www.cnblogs.com/dongzhiquan/p/2237075.html
Copyright © 2020-2023  润新知