util/src/script/utils/qscriptdate.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtScript module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL-ONLY$
       
    10 ** GNU Lesser General Public License Usage
       
    11 ** This file may be used under the terms of the GNU Lesser
       
    12 ** General Public License version 2.1 as published by the Free Software
       
    13 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    14 ** packaging of this file.  Please review the following information to
       
    15 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    16 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    17 **
       
    18 ** If you have questions regarding the use of this file, please contact
       
    19 ** Nokia at qt-info@nokia.com.
       
    20 ** $QT_END_LICENSE$
       
    21 **
       
    22 ****************************************************************************/
       
    23 
       
    24 #include "qscriptdate_p.h"
       
    25 
       
    26 #include <QtCore/qnumeric.h>
       
    27 #include <QtCore/qstringlist.h>
       
    28 
       
    29 #include <math.h>
       
    30 
       
    31 #ifndef Q_WS_WIN
       
    32 #   include <time.h>
       
    33 #   include <sys/time.h>
       
    34 #else
       
    35 #   include <windows.h>
       
    36 #endif
       
    37 
       
    38 QT_BEGIN_NAMESPACE
       
    39 
       
    40 namespace QScript {
       
    41 
       
    42 qsreal ToInteger(qsreal n);
       
    43 
       
    44 static const qsreal HoursPerDay = 24.0;
       
    45 static const qsreal MinutesPerHour = 60.0;
       
    46 static const qsreal SecondsPerMinute = 60.0;
       
    47 static const qsreal msPerSecond = 1000.0;
       
    48 static const qsreal msPerMinute = 60000.0;
       
    49 static const qsreal msPerHour = 3600000.0;
       
    50 static const qsreal msPerDay = 86400000.0;
       
    51 
       
    52 static qsreal LocalTZA = 0.0; // initialized at startup
       
    53 
       
    54 static inline qsreal TimeWithinDay(qsreal t)
       
    55 {
       
    56     qsreal r = ::fmod(t, msPerDay);
       
    57     return (r >= 0) ? r : r + msPerDay;
       
    58 }
       
    59 
       
    60 static inline int HourFromTime(qsreal t)
       
    61 {
       
    62     int r = int(::fmod(::floor(t / msPerHour), HoursPerDay));
       
    63     return (r >= 0) ? r : r + int(HoursPerDay);
       
    64 }
       
    65 
       
    66 static inline int MinFromTime(qsreal t)
       
    67 {
       
    68     int r = int(::fmod(::floor(t / msPerMinute), MinutesPerHour));
       
    69     return (r >= 0) ? r : r + int(MinutesPerHour);
       
    70 }
       
    71 
       
    72 static inline int SecFromTime(qsreal t)
       
    73 {
       
    74     int r = int(::fmod(::floor(t / msPerSecond), SecondsPerMinute));
       
    75     return (r >= 0) ? r : r + int(SecondsPerMinute);
       
    76 }
       
    77 
       
    78 static inline int msFromTime(qsreal t)
       
    79 {
       
    80     int r = int(::fmod(t, msPerSecond));
       
    81     return (r >= 0) ? r : r + int(msPerSecond);
       
    82 }
       
    83 
       
    84 static inline qsreal Day(qsreal t)
       
    85 {
       
    86     return ::floor(t / msPerDay);
       
    87 }
       
    88 
       
    89 static inline qsreal DaysInYear(qsreal y)
       
    90 {
       
    91     if (::fmod(y, 4))
       
    92         return 365;
       
    93 
       
    94     else if (::fmod(y, 100))
       
    95         return 366;
       
    96 
       
    97     else if (::fmod(y, 400))
       
    98         return 365;
       
    99 
       
   100     return 366;
       
   101 }
       
   102 
       
   103 static inline qsreal DayFromYear(qsreal y)
       
   104 {
       
   105     return 365 * (y - 1970)
       
   106         + ::floor((y - 1969) / 4)
       
   107         - ::floor((y - 1901) / 100)
       
   108         + ::floor((y - 1601) / 400);
       
   109 }
       
   110 
       
   111 static inline qsreal TimeFromYear(qsreal y)
       
   112 {
       
   113     return msPerDay * DayFromYear(y);
       
   114 }
       
   115 
       
   116 static inline qsreal YearFromTime(qsreal t)
       
   117 {
       
   118     int y = 1970;
       
   119     y += (int) ::floor(t / (msPerDay * 365.2425));
       
   120 
       
   121     qsreal t2 = TimeFromYear(y);
       
   122     return (t2 > t) ? y - 1 : ((t2 + msPerDay * DaysInYear(y)) <= t) ? y + 1 : y;
       
   123 }
       
   124 
       
   125 static inline bool InLeapYear(qsreal t)
       
   126 {
       
   127     qsreal x = DaysInYear(YearFromTime(t));
       
   128     if (x == 365)
       
   129         return 0;
       
   130 
       
   131     Q_ASSERT (x == 366);
       
   132     return 1;
       
   133 }
       
   134 
       
   135 static inline qsreal DayWithinYear(qsreal t)
       
   136 {
       
   137     return Day(t) - DayFromYear(YearFromTime(t));
       
   138 }
       
   139 
       
   140 static inline qsreal MonthFromTime(qsreal t)
       
   141 {
       
   142     qsreal d = DayWithinYear(t);
       
   143     qsreal l = InLeapYear(t);
       
   144 
       
   145     if (d < 31.0)
       
   146         return 0;
       
   147 
       
   148     else if (d < 59.0 + l)
       
   149         return 1;
       
   150 
       
   151     else if (d < 90.0 + l)
       
   152         return 2;
       
   153 
       
   154     else if (d < 120.0 + l)
       
   155         return 3;
       
   156 
       
   157     else if (d < 151.0 + l)
       
   158         return 4;
       
   159 
       
   160     else if (d < 181.0 + l)
       
   161         return 5;
       
   162 
       
   163     else if (d < 212.0 + l)
       
   164         return 6;
       
   165 
       
   166     else if (d < 243.0 + l)
       
   167         return 7;
       
   168 
       
   169     else if (d < 273.0 + l)
       
   170         return 8;
       
   171 
       
   172     else if (d < 304.0 + l)
       
   173         return 9;
       
   174 
       
   175     else if (d < 334.0 + l)
       
   176         return 10;
       
   177 
       
   178     else if (d < 365.0 + l)
       
   179         return 11;
       
   180 
       
   181     return qSNaN(); // ### assert?
       
   182 }
       
   183 
       
   184 static inline qsreal DateFromTime(qsreal t)
       
   185 {
       
   186     int m = (int) ToInteger(MonthFromTime(t));
       
   187     qsreal d = DayWithinYear(t);
       
   188     qsreal l = InLeapYear(t);
       
   189 
       
   190     switch (m) {
       
   191     case 0: return d + 1.0;
       
   192     case 1: return d - 30.0;
       
   193     case 2: return d - 58.0 - l;
       
   194     case 3: return d - 89.0 - l;
       
   195     case 4: return d - 119.0 - l;
       
   196     case 5: return d - 150.0 - l;
       
   197     case 6: return d - 180.0 - l;
       
   198     case 7: return d - 211.0 - l;
       
   199     case 8: return d - 242.0 - l;
       
   200     case 9: return d - 272.0 - l;
       
   201     case 10: return d - 303.0 - l;
       
   202     case 11: return d - 333.0 - l;
       
   203     }
       
   204 
       
   205     return qSNaN(); // ### assert
       
   206 }
       
   207 
       
   208 static inline qsreal WeekDay(qsreal t)
       
   209 {
       
   210     qsreal r = ::fmod (Day(t) + 4.0, 7.0);
       
   211     return (r >= 0) ? r : r + 7.0;
       
   212 }
       
   213 
       
   214 
       
   215 static inline qsreal MakeTime(qsreal hour, qsreal min, qsreal sec, qsreal ms)
       
   216 {
       
   217     return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms;
       
   218 }
       
   219 
       
   220 static inline qsreal DayFromMonth(qsreal month, qsreal leap)
       
   221 {
       
   222     switch ((int) month) {
       
   223     case 0: return 0;
       
   224     case 1: return 31.0;
       
   225     case 2: return 59.0 + leap;
       
   226     case 3: return 90.0 + leap;
       
   227     case 4: return 120.0 + leap;
       
   228     case 5: return 151.0 + leap;
       
   229     case 6: return 181.0 + leap;
       
   230     case 7: return 212.0 + leap;
       
   231     case 8: return 243.0 + leap;
       
   232     case 9: return 273.0 + leap;
       
   233     case 10: return 304.0 + leap;
       
   234     case 11: return 334.0 + leap;
       
   235     }
       
   236 
       
   237     return qSNaN(); // ### assert?
       
   238 }
       
   239 
       
   240 static qsreal MakeDay(qsreal year, qsreal month, qsreal day)
       
   241 {
       
   242     year += ::floor(month / 12.0);
       
   243 
       
   244     month = ::fmod(month, 12.0);
       
   245     if (month < 0)
       
   246         month += 12.0;
       
   247 
       
   248     qsreal t = TimeFromYear(year);
       
   249     qsreal leap = InLeapYear(t);
       
   250 
       
   251     day += ::floor(t / msPerDay);
       
   252     day += DayFromMonth(month, leap);
       
   253 
       
   254     return day - 1;
       
   255 }
       
   256 
       
   257 static inline qsreal MakeDate(qsreal day, qsreal time)
       
   258 {
       
   259     return day * msPerDay + time;
       
   260 }
       
   261 
       
   262 static inline qsreal DaylightSavingTA(double t)
       
   263 {
       
   264 #ifndef Q_WS_WIN
       
   265     long int tt = (long int)(t / msPerSecond);
       
   266     struct tm *tmtm = localtime((const time_t*)&tt);
       
   267     if (! tmtm)
       
   268         return 0;
       
   269     return (tmtm->tm_isdst > 0) ? msPerHour : 0;
       
   270 #else
       
   271     Q_UNUSED(t);
       
   272     /// ### implement me
       
   273     return 0;
       
   274 #endif
       
   275 }
       
   276 
       
   277 static inline qsreal LocalTime(qsreal t)
       
   278 {
       
   279     return t + LocalTZA + DaylightSavingTA(t);
       
   280 }
       
   281 
       
   282 static inline qsreal UTC(qsreal t)
       
   283 {
       
   284     return t - LocalTZA - DaylightSavingTA(t - LocalTZA);
       
   285 }
       
   286 
       
   287 static inline qsreal TimeClip(qsreal t)
       
   288 {
       
   289     if (! qIsFinite(t) || fabs(t) > 8.64e15)
       
   290         return qSNaN();
       
   291     return ToInteger(t);
       
   292 }
       
   293 
       
   294 static qsreal getLocalTZA()
       
   295 {
       
   296 #ifndef Q_WS_WIN
       
   297     struct tm* t;
       
   298     time_t curr;
       
   299     time(&curr);
       
   300     t = localtime(&curr);
       
   301     time_t locl = mktime(t);
       
   302     t = gmtime(&curr);
       
   303     time_t globl = mktime(t);
       
   304     return double(locl - globl) * 1000.0;
       
   305 #else
       
   306     TIME_ZONE_INFORMATION tzInfo;
       
   307     GetTimeZoneInformation(&tzInfo);
       
   308     return -tzInfo.Bias * 60.0 * 1000.0;
       
   309 #endif
       
   310 }
       
   311 
       
   312 /*!
       
   313   \internal
       
   314 
       
   315   Converts the QDateTime \a dt to an ECMA Date value (in UTC form).
       
   316 */
       
   317 qsreal FromDateTime(const QDateTime &dt)
       
   318 {
       
   319     if (!dt.isValid())
       
   320         return qSNaN();
       
   321     if (!LocalTZA) // ### move
       
   322         LocalTZA = getLocalTZA();
       
   323     QDate date = dt.date();
       
   324     QTime taim = dt.time();
       
   325     int year = date.year();
       
   326     int month = date.month() - 1;
       
   327     int day = date.day();
       
   328     int hours = taim.hour();
       
   329     int mins = taim.minute();
       
   330     int secs = taim.second();
       
   331     int ms = taim.msec();
       
   332     double t = MakeDate(MakeDay(year, month, day),
       
   333                         MakeTime(hours, mins, secs, ms));
       
   334     if (dt.timeSpec() == Qt::LocalTime)
       
   335         t = UTC(t);
       
   336     return TimeClip(t);
       
   337 }
       
   338 
       
   339 /*!
       
   340   \internal
       
   341 
       
   342   Converts the ECMA Date value \tt (in UTC form) to QDateTime
       
   343   according to \a spec.
       
   344 */
       
   345 QDateTime ToDateTime(qsreal t, Qt::TimeSpec spec)
       
   346 {
       
   347     if (qIsNaN(t))
       
   348         return QDateTime();
       
   349     if (!LocalTZA) // ### move
       
   350         LocalTZA = getLocalTZA();
       
   351     if (spec == Qt::LocalTime)
       
   352         t = LocalTime(t);
       
   353     int year = int(YearFromTime(t));
       
   354     int month = int(MonthFromTime(t) + 1);
       
   355     int day = int(DateFromTime(t));
       
   356     int hours = HourFromTime(t);
       
   357     int mins = MinFromTime(t);
       
   358     int secs = SecFromTime(t);
       
   359     int ms = msFromTime(t);
       
   360     return QDateTime(QDate(year, month, day), QTime(hours, mins, secs, ms), spec);
       
   361 }
       
   362 
       
   363 } // namespace QScript
       
   364 
       
   365 QT_END_NAMESPACE