Home | History | Annotate | Download | only in fpdfsdk
      1 // Copyright 2016 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "fpdfsdk/cpdfsdk_datetime.h"
      8 
      9 #include "core/fxcrt/fx_extension.h"
     10 
     11 namespace {
     12 
     13 int GetTimeZoneInSeconds(int8_t tzhour, uint8_t tzminute) {
     14   return (int)tzhour * 3600 + (int)tzminute * (tzhour >= 0 ? 60 : -60);
     15 }
     16 
     17 bool IsLeapYear(int16_t year) {
     18   return ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0)));
     19 }
     20 
     21 uint16_t GetYearDays(int16_t year) {
     22   return (IsLeapYear(year) ? 366 : 365);
     23 }
     24 
     25 uint8_t GetMonthDays(int16_t year, uint8_t month) {
     26   uint8_t mDays;
     27   switch (month) {
     28     case 1:
     29     case 3:
     30     case 5:
     31     case 7:
     32     case 8:
     33     case 10:
     34     case 12:
     35       mDays = 31;
     36       break;
     37 
     38     case 4:
     39     case 6:
     40     case 9:
     41     case 11:
     42       mDays = 30;
     43       break;
     44 
     45     case 2:
     46       if (IsLeapYear(year))
     47         mDays = 29;
     48       else
     49         mDays = 28;
     50       break;
     51 
     52     default:
     53       mDays = 0;
     54       break;
     55   }
     56 
     57   return mDays;
     58 }
     59 
     60 }  // namespace
     61 
     62 CPDFSDK_DateTime::CPDFSDK_DateTime() {
     63   ResetDateTime();
     64 }
     65 
     66 CPDFSDK_DateTime::CPDFSDK_DateTime(const ByteString& dtStr) {
     67   ResetDateTime();
     68   FromPDFDateTimeString(dtStr);
     69 }
     70 
     71 CPDFSDK_DateTime::CPDFSDK_DateTime(const CPDFSDK_DateTime& that)
     72     : m_year(that.m_year),
     73       m_month(that.m_month),
     74       m_day(that.m_day),
     75       m_hour(that.m_hour),
     76       m_minute(that.m_minute),
     77       m_second(that.m_second),
     78       m_tzHour(that.m_tzHour),
     79       m_tzMinute(that.m_tzMinute) {}
     80 
     81 CPDFSDK_DateTime::CPDFSDK_DateTime(const FX_SYSTEMTIME& st) {
     82   tzset();
     83 
     84   m_year = static_cast<int16_t>(st.wYear);
     85   m_month = static_cast<uint8_t>(st.wMonth);
     86   m_day = static_cast<uint8_t>(st.wDay);
     87   m_hour = static_cast<uint8_t>(st.wHour);
     88   m_minute = static_cast<uint8_t>(st.wMinute);
     89   m_second = static_cast<uint8_t>(st.wSecond);
     90 }
     91 
     92 void CPDFSDK_DateTime::ResetDateTime() {
     93   tzset();
     94 
     95   time_t curTime;
     96   time(&curTime);
     97 
     98   struct tm* newtime = localtime(&curTime);
     99   m_year = newtime->tm_year + 1900;
    100   m_month = newtime->tm_mon + 1;
    101   m_day = newtime->tm_mday;
    102   m_hour = newtime->tm_hour;
    103   m_minute = newtime->tm_min;
    104   m_second = newtime->tm_sec;
    105 }
    106 
    107 bool CPDFSDK_DateTime::operator==(const CPDFSDK_DateTime& that) const {
    108   return m_year == that.m_year && m_month == that.m_month &&
    109          m_day == that.m_day && m_hour == that.m_hour &&
    110          m_minute == that.m_minute && m_second == that.m_second &&
    111          m_tzHour == that.m_tzHour && m_tzMinute == that.m_tzMinute;
    112 }
    113 
    114 bool CPDFSDK_DateTime::operator!=(const CPDFSDK_DateTime& datetime) const {
    115   return !(*this == datetime);
    116 }
    117 
    118 time_t CPDFSDK_DateTime::ToTime_t() const {
    119   struct tm newtime;
    120 
    121   newtime.tm_year = m_year - 1900;
    122   newtime.tm_mon = m_month - 1;
    123   newtime.tm_mday = m_day;
    124   newtime.tm_hour = m_hour;
    125   newtime.tm_min = m_minute;
    126   newtime.tm_sec = m_second;
    127 
    128   return mktime(&newtime);
    129 }
    130 
    131 CPDFSDK_DateTime& CPDFSDK_DateTime::FromPDFDateTimeString(
    132     const ByteString& dtStr) {
    133   int strLength = dtStr.GetLength();
    134   if (strLength <= 0)
    135     return *this;
    136 
    137   int i = 0;
    138   while (i < strLength && !std::isdigit(dtStr[i]))
    139     ++i;
    140 
    141   if (i >= strLength)
    142     return *this;
    143 
    144   int j = 0;
    145   int k = 0;
    146   char ch;
    147   while (i < strLength && j < 4) {
    148     ch = dtStr[i];
    149     k = k * 10 + FXSYS_DecimalCharToInt(ch);
    150     j++;
    151     if (!std::isdigit(ch))
    152       break;
    153     i++;
    154   }
    155   m_year = static_cast<int16_t>(k);
    156   if (i >= strLength || j < 4)
    157     return *this;
    158 
    159   j = 0;
    160   k = 0;
    161   while (i < strLength && j < 2) {
    162     ch = dtStr[i];
    163     k = k * 10 + FXSYS_DecimalCharToInt(ch);
    164     j++;
    165     if (!std::isdigit(ch))
    166       break;
    167     i++;
    168   }
    169   m_month = static_cast<uint8_t>(k);
    170   if (i >= strLength || j < 2)
    171     return *this;
    172 
    173   j = 0;
    174   k = 0;
    175   while (i < strLength && j < 2) {
    176     ch = dtStr[i];
    177     k = k * 10 + FXSYS_DecimalCharToInt(ch);
    178     j++;
    179     if (!std::isdigit(ch))
    180       break;
    181     i++;
    182   }
    183   m_day = static_cast<uint8_t>(k);
    184   if (i >= strLength || j < 2)
    185     return *this;
    186 
    187   j = 0;
    188   k = 0;
    189   while (i < strLength && j < 2) {
    190     ch = dtStr[i];
    191     k = k * 10 + FXSYS_DecimalCharToInt(ch);
    192     j++;
    193     if (!std::isdigit(ch))
    194       break;
    195     i++;
    196   }
    197   m_hour = static_cast<uint8_t>(k);
    198   if (i >= strLength || j < 2)
    199     return *this;
    200 
    201   j = 0;
    202   k = 0;
    203   while (i < strLength && j < 2) {
    204     ch = dtStr[i];
    205     k = k * 10 + FXSYS_DecimalCharToInt(ch);
    206     j++;
    207     if (!std::isdigit(ch))
    208       break;
    209     i++;
    210   }
    211   m_minute = static_cast<uint8_t>(k);
    212   if (i >= strLength || j < 2)
    213     return *this;
    214 
    215   j = 0;
    216   k = 0;
    217   while (i < strLength && j < 2) {
    218     ch = dtStr[i];
    219     k = k * 10 + FXSYS_DecimalCharToInt(ch);
    220     j++;
    221     if (!std::isdigit(ch))
    222       break;
    223     i++;
    224   }
    225   m_second = static_cast<uint8_t>(k);
    226   if (i >= strLength || j < 2)
    227     return *this;
    228 
    229   ch = dtStr[i++];
    230   if (ch != '-' && ch != '+')
    231     return *this;
    232   if (ch == '-')
    233     m_tzHour = -1;
    234   else
    235     m_tzHour = 1;
    236   j = 0;
    237   k = 0;
    238   while (i < strLength && j < 2) {
    239     ch = dtStr[i];
    240     k = k * 10 + FXSYS_DecimalCharToInt(ch);
    241     j++;
    242     if (!std::isdigit(ch))
    243       break;
    244     i++;
    245   }
    246   m_tzHour *= static_cast<int8_t>(k);
    247   if (i >= strLength || j < 2)
    248     return *this;
    249 
    250   if (dtStr[i++] != '\'')
    251     return *this;
    252   j = 0;
    253   k = 0;
    254   while (i < strLength && j < 2) {
    255     ch = dtStr[i];
    256     k = k * 10 + FXSYS_DecimalCharToInt(ch);
    257     j++;
    258     if (!std::isdigit(ch))
    259       break;
    260     i++;
    261   }
    262   m_tzMinute = static_cast<uint8_t>(k);
    263   return *this;
    264 }
    265 
    266 ByteString CPDFSDK_DateTime::ToCommonDateTimeString() {
    267   return ByteString::Format("%04d-%02u-%02u %02u:%02u:%02u ", m_year, m_month,
    268                             m_day, m_hour, m_minute, m_second) +
    269          (m_tzHour < 0 ? "-" : "+") +
    270          ByteString::Format("%02d:%02u", std::abs(static_cast<int>(m_tzHour)),
    271                             m_tzMinute);
    272 }
    273 
    274 ByteString CPDFSDK_DateTime::ToPDFDateTimeString() {
    275   ByteString dtStr;
    276   char tempStr[32];
    277   memset(tempStr, 0, sizeof(tempStr));
    278   FXSYS_snprintf(tempStr, sizeof(tempStr) - 1, "D:%04d%02u%02u%02u%02u%02u",
    279                  m_year, m_month, m_day, m_hour, m_minute, m_second);
    280   dtStr = ByteString(tempStr);
    281   if (m_tzHour < 0)
    282     dtStr += ByteString("-");
    283   else
    284     dtStr += ByteString("+");
    285   memset(tempStr, 0, sizeof(tempStr));
    286   FXSYS_snprintf(tempStr, sizeof(tempStr) - 1, "%02d'%02u'",
    287                  std::abs(static_cast<int>(m_tzHour)), m_tzMinute);
    288   dtStr += ByteString(tempStr);
    289   return dtStr;
    290 }
    291 
    292 void CPDFSDK_DateTime::ToSystemTime(FX_SYSTEMTIME& st) {
    293   time_t t = this->ToTime_t();
    294   struct tm* pTime = localtime(&t);
    295 
    296   if (!pTime)
    297     return;
    298 
    299   st.wYear = static_cast<uint16_t>(pTime->tm_year) + 1900;
    300   st.wMonth = static_cast<uint16_t>(pTime->tm_mon) + 1;
    301   st.wDay = static_cast<uint16_t>(pTime->tm_mday);
    302   st.wDayOfWeek = static_cast<uint16_t>(pTime->tm_wday);
    303   st.wHour = static_cast<uint16_t>(pTime->tm_hour);
    304   st.wMinute = static_cast<uint16_t>(pTime->tm_min);
    305   st.wSecond = static_cast<uint16_t>(pTime->tm_sec);
    306   st.wMilliseconds = 0;
    307 }
    308 
    309 CPDFSDK_DateTime CPDFSDK_DateTime::ToGMT() const {
    310   CPDFSDK_DateTime new_dt = *this;
    311   new_dt.AddSeconds(-GetTimeZoneInSeconds(new_dt.m_tzHour, new_dt.m_tzMinute));
    312   new_dt.m_tzHour = 0;
    313   new_dt.m_tzMinute = 0;
    314   return new_dt;
    315 }
    316 
    317 CPDFSDK_DateTime& CPDFSDK_DateTime::AddDays(short days) {
    318   if (days == 0)
    319     return *this;
    320 
    321   int16_t y = m_year;
    322   uint8_t m = m_month;
    323   uint8_t d = m_day;
    324 
    325   int ldays = days;
    326   if (ldays > 0) {
    327     int16_t yy = y;
    328     if ((static_cast<uint16_t>(m) * 100 + d) > 300)
    329       yy++;
    330     int ydays = GetYearDays(yy);
    331     int mdays;
    332     while (ldays >= ydays) {
    333       y++;
    334       ldays -= ydays;
    335       yy++;
    336       mdays = GetMonthDays(y, m);
    337       if (d > mdays) {
    338         m++;
    339         d -= mdays;
    340       }
    341       ydays = GetYearDays(yy);
    342     }
    343     mdays = GetMonthDays(y, m) - d + 1;
    344     while (ldays >= mdays) {
    345       ldays -= mdays;
    346       m++;
    347       d = 1;
    348       mdays = GetMonthDays(y, m);
    349     }
    350     d += ldays;
    351   } else {
    352     ldays *= -1;
    353     int16_t yy = y;
    354     if ((static_cast<uint16_t>(m) * 100 + d) < 300)
    355       yy--;
    356     int ydays = GetYearDays(yy);
    357     while (ldays >= ydays) {
    358       y--;
    359       ldays -= ydays;
    360       yy--;
    361       int mdays = GetMonthDays(y, m);
    362       if (d > mdays) {
    363         m++;
    364         d -= mdays;
    365       }
    366       ydays = GetYearDays(yy);
    367     }
    368     while (ldays >= d) {
    369       ldays -= d;
    370       m--;
    371       d = GetMonthDays(y, m);
    372     }
    373     d -= ldays;
    374   }
    375 
    376   m_year = y;
    377   m_month = m;
    378   m_day = d;
    379 
    380   return *this;
    381 }
    382 
    383 CPDFSDK_DateTime& CPDFSDK_DateTime::AddSeconds(int seconds) {
    384   if (seconds == 0)
    385     return *this;
    386 
    387   int n;
    388   int days;
    389 
    390   n = m_hour * 3600 + m_minute * 60 + m_second + seconds;
    391   if (n < 0) {
    392     days = (n - 86399) / 86400;
    393     n -= days * 86400;
    394   } else {
    395     days = n / 86400;
    396     n %= 86400;
    397   }
    398   m_hour = static_cast<uint8_t>(n / 3600);
    399   m_hour %= 24;
    400   n %= 3600;
    401   m_minute = static_cast<uint8_t>(n / 60);
    402   m_second = static_cast<uint8_t>(n % 60);
    403   if (days != 0)
    404     AddDays(days);
    405 
    406   return *this;
    407 }
    408