datetime.cpp

来自「Shorthand是一个强大的脚本语言」· C++ 代码 · 共 826 行 · 第 1/2 页

CPP
826
字号
    m_time.wDay = atoi(day);
    m_time.wYear = atoi(year);
    m_time.wHour = atoi(hour);
    m_time.wMinute = atoi(min);
    m_time.wSecond = atoi(sec);
    m_time.wMilliseconds = 0;
    
    if (m_time.wYear < 1000) 
    {
        datetime now; 
        if (m_time.wYear < 100)
            m_time.wYear += (now.m_time.wYear/100)*100;
        else 
            m_time.wYear += (now.m_time.wYear/1000)*1000;
    }


    m_time.wMonth = 1 + month.index("jan\0feb\0mar\0apr\0may\0jun\0jul\0aug\0sep\0oct\0nov\0dec\0\0");
    if (m_time.wMonth == 0) return false;

#ifdef WIN32
    FILETIME filetime;
    if (!SystemTimeToFileTime(&m_time, &filetime)) return false;
#else
#endif

    zone.uppercase();
    char ch = zone.cstr()[0];
    if (isdigit(ch) || ch == '-' || ch == '+')
    {
        offset = atoi(zone);
    }
    else if (zone == "UT" || zone == "GMT") offset = 0;
    else if (zone == "EDT") offset = -400;
    else if (zone == "EST" || zone == "CDT") offset = -500;
    else if (zone == "CST" || zone == "MDT") offset = -600;
    else if (zone == "MST" || zone == "PDT") offset = -700;
    else if (zone == "PST") offset = -800;
    else if (zone == "Z") offset = 0;
    else if (zone.length() == 1)
    {
        // military zone
        if (ch >= 'A' && ch <= 'I') offset = - (ch-'A'+1)*100;
        else if (ch >= 'K' && ch <= 'M') offset = - (ch-'K'+10)*100;
        else if (ch >= 'N' && ch <= 'Y') offset = (ch-'N'+1)*100;
    }

    // portable zone offset, in minutes
    int local_bias = portable_zone_offset();

#ifdef WIN32
    // Windows:

    __int64 local_adjustment = - ((__int64) local_bias) * 600000000L;
    __int64 remote_adjustment = ( (__int64) ((offset/100*60) + offset%100)) * 600000000L;

    unsigned __int64 remote_time; memcpy(&remote_time, &filetime, 8);
    unsigned __int64 local_time = remote_time - remote_adjustment + local_adjustment;

    memcpy(&filetime, &local_time, 8);
    FileTimeToSystemTime(&filetime, &m_time);
#else
    // Unix:
    int local_adjustment = - local_bias * 60;
    int remote_adjustment = (offset/100*60 + offset/100)*60;
    add_seconds(local_adjustment - remote_adjustment);
#endif

    return true;
}


// nullifies date object making it invalid
void datetime::invalidate()
{
    memset(&m_time, 0, sizeof(m_time));
}


void datetime::add_days(int days)
{
    unsigned int j = jdn() + days;
    int y, m, d;
    julian2date_relaxed(j, &y, &m, &d);
    m_time.wYear = y;
    m_time.wMonth = m;
    m_time.wDay = d;
    
}


void datetime::add_seconds(int seconds)
{
    int j = jdn();
    int tod = m_time.wHour * 3600 + m_time.wMinute*60 + m_time.wSecond;
    
    int days_delta = seconds/86400;
    j    += days_delta;
    tod  += seconds%86400;
    if (tod > 86400)
    {
        j++;
        tod = tod%86400;
    }
    else if (tod < 0)
    {
        j--;
        tod = 86400 + tod;
    }
    unsigned int jdx[2];
    jdx[0] = j;
    jdx[1] = tod;
    import_jdx(jdx);
}



void datetime::export_rfc(string& result)
{
    // determine timezone
    //struct tm stm; time_t t = time(NULL);
    //memcpy(&stm, localtime(&t));

    // expires=Fri, 06 Sep 2002 00:07:35 GMT; path=/; 
    datetime ut = *this;
    int ut_offset = portable_zone_offset() * 60;
    ut.add_seconds(ut_offset);
    int wd = determine_weekday(m_time.wYear, m_time.wMonth, m_time.wDay)%7;

    result.printf("%s, %d-%s-%04d %02d:%02d:%02d GMT",
        weekday_names[wd], ut.m_time.wDay,
        month_names[abs(ut.m_time.wMonth-1)%12],
        ut.m_time.wYear,
        ut.m_time.wHour,
        ut.m_time.wMinute,
        ut.m_time.wSecond
    );
}


// formats datetime using strftime()-compatible format
void datetime::format(const char* format, string& result) const
{
    struct tm stm;
    
    export_stm(&stm);
    //
    // populate weekday and year's day fields, because 
    // strftime() relies on what is set in the structure and may
    // even chokes on some systems when these fields are incorrect
    //
    stm.tm_wday  = determine_weekday(m_time.wYear, m_time.wMonth, m_time.wDay)%7;
    stm.tm_yday  = 1 + abs(jdn() - get_year_start(m_time.wYear))%366;
    stm.tm_isdst = daylight;
#if !defined(WIN32) && !defined(SOLARIS)
    stm.tm_gmtoff = 0;
    stm.tm_zone = tzname[daylight%2];
#endif

    char buf[512];
    if (strftime(buf, sizeof(buf), format, &stm) == 0)
    {
        throw new ShhObjectException(4107, "Date format is too long");
    }
    result = buf;
}



// exports value into "extended Julian" format which is 
// array of two integer number {JDN,seconds_since_midnight}
void datetime::export_jdx(unsigned int* jdx) const
{
    jdx[0] = jdn();
    jdx[1] = m_time.wHour * 3600 + m_time.wMinute*60 + m_time.wSecond;

}

void datetime::import_ydm(int year, int month, int day)
{
    m_time.wHour = 0;
    m_time.wMinute = 0;
    m_time.wSecond = 0;
    
    m_time.wYear = year;
    m_time.wMonth = month;
    m_time.wDay = day;
}


// imports JDN 
void datetime::import_jdn(int jdn)
{
    if (jdn < 0) 
        throw new ShhObjectException(4108, "Cannot convert number %d to date", jdn);
    else
    {
        m_time.wHour = 0;
        m_time.wMinute = 0;
        m_time.wSecond = 0;
        
        int y,d,m;
        julian2date_strict(jdn, &y, &m, &d);
    
        m_time.wYear = y;
        m_time.wMonth = m;
        m_time.wDay = d;
    }
}


// imports value from "extended Julian" format which is 
// array of two integer number {JDN,seconds_since_midnight}
void datetime::import_jdx(const unsigned int* jdx)
{
    int y,d,m;
    julian2date_relaxed(jdx[0], &y, &m, &d);
    
    m_time.wYear = y;
    m_time.wMonth = m;
    m_time.wDay = d;

    int secs = jdx[1];
    m_time.wHour   = secs/3600;   secs -= (m_time.wHour * 3600);
    m_time.wMinute = (secs/60); secs -= (m_time.wMinute * 60);
    m_time.wSecond = secs;
}

// returns JDN of the date
unsigned int datetime::jdn() const
{
    return date2julian_relaxed(m_time.wYear, m_time.wMonth, m_time.wDay);
}


// returns number of seconds since midnight on the specified date
unsigned int datetime::seconds_since_midnight() const
{
    return m_time.wHour*3600 + m_time.wMinute * 60 + m_time.wSecond;
}


const datetime& datetime::operator = (const datetime& other)
{
    memcpy(&m_time, &other.m_time, sizeof(SYSTEMTIME));
    return *this;
}


// converts month number to 3-letter abbreviation 
const char* datetime::month3(int month)
{
    switch(month)
    {
    case 1: return "Jan";
    case 2: return "Feb";
    case 3: return "Mar";
    case 4: return "Apr";
    case 5: return "May";
    case 6: return "Jun";
    case 7: return "Jul";
    case 8: return "Aug";
    case 9: return "Sep";
    case 10: return "Oct";
    case 11: return "Nov";
    case 12: return "Dec";
    default: return "";
    }
}


// prints datetime in "common" format: "22 Jul 2002, 6:17 AM"
void datetime::common_print(string& s) const
{
    const char* ampm = (m_time.wHour < 12) ? "AM" : "PM";
    int hour = m_time.wHour%12;
    if (hour == 0) hour = 12;
    
    s.printf("%d %s %d, %d:%02d %s", 
        m_time.wDay, month3(m_time.wMonth), m_time.wYear, hour, m_time.wMinute, ampm
    );
}

/** returns difference in days between two dates, disregarding time-of-day parts */
int day_difference(const datetime& one, const datetime& two)
{
    return one.jdn() - two.jdn();
}


/** 
 * returns -1, 0, or +1 depending on whether date one is less, equals, or
 * greater than date two.
 * all components are considered, up to seconds.
 */
int compare_dates(const datetime& one, const datetime& two)
{
    int daydiff = one.jdn() - two.jdn();
    if (daydiff != 0) return daydiff > 0 ? 1 : -1;

    int secdiff = one.seconds_since_midnight() - two.seconds_since_midnight();
    if (secdiff == 0) return 0;
    else if (secdiff < 0) return -1;
    else return 1;
}





// imports value from variety of string formats by trying 
// to guess fields automatically
bool datetime::import_any(const char* s)
{
    return false; // not implemented yet
}

#define DX(x) ((int)((x)-'0'))
#define DX2(x) DX(x[0])*10 + DX(x[1])



/**
 * imports date/time from any of formats returned by MySQL
 * (DATE,TIME,DATETIME or any TIMESTAMP)
 */
bool datetime::import_mysql(const char* input)
{
   // date+time specification with optional time 
   RX datetime_rx(
    "([0-9]{1,4})[^0-9]+([0-9]{1,2})[^0-9]+([0-9]{1,2})( +([0-9]{1,2})[^0-9]+([0-9]{1,2})[^0-9]+([0-9]{1,2}))?",
        RXX_NO_BK_PARENS|RXX_NO_BK_VBAR|RXX_INTERVALS|RXX_NO_BK_BRACES
   );
   
   // time-only specification
   RX time_rx(
    "([0-9]{1,2})[^0-9]+([0-9]{1,2})([^0-9]+([0-9]{1,2}))?",
     RXX_NO_BK_PARENS|RXX_NO_BK_VBAR|RXX_INTERVALS|RXX_NO_BK_BRACES
   );

   memset(&m_time, 0, sizeof(m_time)); 
   local();
   m_time.wMilliseconds = 0;

   if (time_rx.match(input))
   {
       string s;
       time_rx.submatch(1, s); m_time.wHour   = atoi(s);
       time_rx.submatch(2, s); m_time.wMinute = atoi(s);
       time_rx.submatch(3, s); m_time.wSecond = atoi(s);
       return true;
   }
   else if (datetime_rx.match(input))
   {
       string s;
       datetime_rx.submatch(1, s); m_time.wYear   = atoi(s);
       datetime_rx.submatch(2, s); m_time.wMonth  = atoi(s);
       datetime_rx.submatch(3, s); m_time.wDay    = atoi(s);
       datetime_rx.submatch(5, s); m_time.wHour   = atoi(s);
       datetime_rx.submatch(6, s); m_time.wMinute = atoi(s);
       datetime_rx.submatch(7, s); m_time.wSecond = atoi(s);
       return true;
   }
   else
   {
       bool only_digits = true;
       int n = strlen(input);

       // timstampes returned by SQL must have even number of characters
       if (n%2 != 0 || n == 0 || n > 14) return false;

       for(int i=0; i<n; i++)
       {
           if (!isdigit(input[i])) { only_digits = false; break; }
       }
       if (!only_digits) return false /* sorry */;

       // import format depends on the length
       // 14: YYYYMMDDHHMMSS
       // 12: YYMMDDHHMMSS
       // 10: YYMMDDHHMM
       // 8:  YYYYMMDD
       // 6:  YYMMDD
       // 4:  YYMM
       // 2:  YY
       
       const char* p = input;
       if (n == 8 || n == 14)
       {
           m_time.wYear = DX(p[0])*1000 + DX(p[1])*100 + DX(p[2])*10 + DX(p[3]);
           p += 4;
       }
       else 
       {
           m_time.wYear = (m_time.wYear/100)*100 + DX2(p);
           p += 2;
       }
       
       if (n >= 4)  { m_time.wMonth  = DX2(p); p+= 2;} else m_time.wMonth = 1;
       if (n >= 6)  { m_time.wDay    = DX2(p); p+= 2;} else m_time.wDay = 1;
       if (n >= 10) { m_time.wHour   = DX2(p); p+= 2;} else m_time.wHour = 0;
       if (n >= 10) { m_time.wMinute = DX2(p); p+= 2;} else m_time.wMinute = 0;
       if (n >= 12) { m_time.wSecond = DX2(p); p+= 2;} else m_time.wSecond = 0;
       m_time.wMilliseconds = 0;

       return true;
   }

}



⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?