LCOV - code coverage report
Current view: top level - src - date.h (source / functions) Hit Total Coverage
Test: app.info Lines: 43 43 100.0 %
Date: 2017-04-26 Functions: 8 9 88.9 %

          Line data    Source code
       1             : // Copyright 2012 the V8 project 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             : #ifndef V8_DATE_H_
       6             : #define V8_DATE_H_
       7             : 
       8             : #include "src/allocation.h"
       9             : #include "src/base/platform/platform.h"
      10             : #include "src/base/timezone-cache.h"
      11             : #include "src/globals.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : 
      16             : class DateCache {
      17             :  public:
      18             :   static const int kMsPerMin = 60 * 1000;
      19             :   static const int kSecPerDay = 24 * 60 * 60;
      20             :   static const int64_t kMsPerDay = kSecPerDay * 1000;
      21             :   static const int64_t kMsPerMonth = kMsPerDay * 30;
      22             : 
      23             :   // The largest time that can be passed to OS date-time library functions.
      24             :   static const int kMaxEpochTimeInSec = kMaxInt;
      25             :   static const int64_t kMaxEpochTimeInMs =
      26             :       static_cast<int64_t>(kMaxInt) * 1000;
      27             : 
      28             :   // The largest time that can be stored in JSDate.
      29             :   static const int64_t kMaxTimeInMs =
      30             :       static_cast<int64_t>(864000000) * 10000000;
      31             : 
      32             :   // Conservative upper bound on time that can be stored in JSDate
      33             :   // before UTC conversion.
      34             :   static const int64_t kMaxTimeBeforeUTCInMs = kMaxTimeInMs + kMsPerMonth;
      35             : 
      36             :   // Sentinel that denotes an invalid local offset.
      37             :   static const int kInvalidLocalOffsetInMs = kMaxInt;
      38             :   // Sentinel that denotes an invalid cache stamp.
      39             :   // It is an invariant of DateCache that cache stamp is non-negative.
      40             :   static const int kInvalidStamp = -1;
      41             : 
      42             :   DateCache();
      43             : 
      44       31860 :   virtual ~DateCache() {
      45       31860 :     delete tz_cache_;
      46       31860 :     tz_cache_ = NULL;
      47       31860 :   }
      48             : 
      49             : 
      50             :   // Clears cached timezone information and increments the cache stamp.
      51             :   void ResetDateCache();
      52             : 
      53             : 
      54             :   // Computes floor(time_ms / kMsPerDay).
      55             :   static int DaysFromTime(int64_t time_ms) {
      56      192827 :     if (time_ms < 0) time_ms -= (kMsPerDay - 1);
      57      192827 :     return static_cast<int>(time_ms / kMsPerDay);
      58             :   }
      59             : 
      60             : 
      61             :   // Computes modulo(time_ms, kMsPerDay) given that
      62             :   // days = floor(time_ms / kMsPerDay).
      63             :   static int TimeInDay(int64_t time_ms, int days) {
      64      107097 :     return static_cast<int>(time_ms - days * kMsPerDay);
      65             :   }
      66             : 
      67             : 
      68             :   // Given the number of days since the epoch, computes the weekday.
      69             :   // ECMA 262 - 15.9.1.6.
      70             :   int Weekday(int days) {
      71      175342 :     int result = (days + 4) % 7;
      72      175342 :     return result >= 0 ? result : result + 7;
      73             :   }
      74             : 
      75             : 
      76             :   bool IsLeap(int year) {
      77       85401 :     return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
      78             :   }
      79             : 
      80             : 
      81             :   // ECMA 262 - 15.9.1.7.
      82             :   int LocalOffsetInMs() {
      83      189855 :     if (local_offset_ms_ == kInvalidLocalOffsetInMs)  {
      84         220 :       local_offset_ms_ = GetLocalOffsetFromOS();
      85             :     }
      86      189855 :     return local_offset_ms_;
      87             :   }
      88             : 
      89             : 
      90       88770 :   const char* LocalTimezone(int64_t time_ms) {
      91       88770 :     if (time_ms < 0 || time_ms > kMaxEpochTimeInMs) {
      92       27990 :       time_ms = EquivalentTime(time_ms);
      93             :     }
      94       88770 :     bool is_dst = DaylightSavingsOffsetInMs(time_ms) != 0;
      95       88770 :     const char** name = is_dst ? &dst_tz_name_ : &tz_name_;
      96       88770 :     if (*name == nullptr) {
      97         167 :       *name = tz_cache_->LocalTimezone(static_cast<double>(time_ms));
      98             :     }
      99       88770 :     return *name;
     100             :   }
     101             : 
     102             :   // ECMA 262 - 15.9.5.26
     103             :   int TimezoneOffset(int64_t time_ms) {
     104       88799 :     int64_t local_ms = ToLocal(time_ms);
     105       88799 :     return static_cast<int>((time_ms - local_ms) / kMsPerMin);
     106             :   }
     107             : 
     108             :   // ECMA 262 - 15.9.1.9
     109             :   // LocalTime(t) = t + LocalTZA + DaylightSavingTA(t)
     110      187182 :   int64_t ToLocal(int64_t time_ms) {
     111      187182 :     return time_ms + LocalOffsetInMs() + DaylightSavingsOffsetInMs(time_ms);
     112             :   }
     113             : 
     114             :   // ECMA 262 - 15.9.1.9
     115             :   // UTC(t) = t - LocalTZA - DaylightSavingTA(t - LocalTZA)
     116        2673 :   int64_t ToUTC(int64_t time_ms) {
     117             :     // We need to compute UTC time that corresponds to the given local time.
     118             :     // Literally following spec here leads to incorrect time computation at
     119             :     // the points were we transition to and from DST.
     120             :     //
     121             :     // The following shows that using DST for (t - LocalTZA - hour) produces
     122             :     // correct conversion.
     123             :     //
     124             :     // Consider transition to DST at local time L1.
     125             :     // Let L0 = L1 - hour, L2 = L1 + hour,
     126             :     //     U1 = UTC time that corresponds to L1,
     127             :     //     U0 = U1 - hour.
     128             :     // Transitioning to DST moves local clock one hour forward L1 => L2, so
     129             :     // U0 = UTC time that corresponds to L0 = L0 - LocalTZA,
     130             :     // U1 = UTC time that corresponds to L1 = L1 - LocalTZA,
     131             :     // U1 = UTC time that corresponds to L2 = L2 - LocalTZA - hour.
     132             :     // Note that DST(U0 - hour) = 0, DST(U0) = 0, DST(U1) = 1.
     133             :     // U0 = L0 - LocalTZA - DST(L0 - LocalTZA - hour),
     134             :     // U1 = L1 - LocalTZA - DST(L1 - LocalTZA - hour),
     135             :     // U1 = L2 - LocalTZA - DST(L2 - LocalTZA - hour).
     136             :     //
     137             :     // Consider transition from DST at local time L1.
     138             :     // Let L0 = L1 - hour,
     139             :     //     U1 = UTC time that corresponds to L1,
     140             :     //     U0 = U1 - hour, U2 = U1 + hour.
     141             :     // Transitioning from DST moves local clock one hour back L1 => L0, so
     142             :     // U0 = UTC time that corresponds to L0 (before transition)
     143             :     //    = L0 - LocalTZA - hour.
     144             :     // U1 = UTC time that corresponds to L0 (after transition)
     145             :     //    = L0 - LocalTZA = L1 - LocalTZA - hour
     146             :     // U2 = UTC time that corresponds to L1 = L1 - LocalTZA.
     147             :     // Note that DST(U0) = 1, DST(U1) = 0, DST(U2) = 0.
     148             :     // U0 = L0 - LocalTZA - DST(L0 - LocalTZA - hour) = L0 - LocalTZA - DST(U0).
     149             :     // U2 = L1 - LocalTZA - DST(L1 - LocalTZA - hour) = L1 - LocalTZA - DST(U1).
     150             :     // It is impossible to get U1 from local time.
     151             : 
     152             :     const int kMsPerHour = 3600 * 1000;
     153        2673 :     time_ms -= LocalOffsetInMs();
     154        2673 :     return time_ms - DaylightSavingsOffsetInMs(time_ms - kMsPerHour);
     155             :   }
     156             : 
     157             : 
     158             :   // Computes a time equivalent to the given time according
     159             :   // to ECMA 262 - 15.9.1.9.
     160             :   // The issue here is that some library calls don't work right for dates
     161             :   // that cannot be represented using a non-negative signed 32 bit integer
     162             :   // (measured in whole seconds based on the 1970 epoch).
     163             :   // We solve this by mapping the time to a year with same leap-year-ness
     164             :   // and same starting day for the year. The ECMAscript specification says
     165             :   // we must do this, but for compatibility with other browsers, we use
     166             :   // the actual year if it is in the range 1970..2037
     167       85401 :   int64_t EquivalentTime(int64_t time_ms) {
     168             :     int days = DaysFromTime(time_ms);
     169       85401 :     int time_within_day_ms = static_cast<int>(time_ms - days * kMsPerDay);
     170             :     int year, month, day;
     171       85401 :     YearMonthDayFromDays(days, &year, &month, &day);
     172       85401 :     int new_days = DaysFromYearMonth(EquivalentYear(year), month) + day - 1;
     173       85401 :     return static_cast<int64_t>(new_days) * kMsPerDay + time_within_day_ms;
     174             :   }
     175             : 
     176             :   // Returns an equivalent year in the range [2008-2035] matching
     177             :   // - leap year,
     178             :   // - week day of first day.
     179             :   // ECMA 262 - 15.9.1.9.
     180       85401 :   int EquivalentYear(int year) {
     181       85401 :     int week_day = Weekday(DaysFromYearMonth(year, 0));
     182       85401 :     int recent_year = (IsLeap(year) ? 1956 : 1967) + (week_day * 12) % 28;
     183             :     // Find the year in the range 2008..2037 that is equivalent mod 28.
     184             :     // Add 3*28 to give a positive argument to the modulus operator.
     185       85401 :     return 2008 + (recent_year + 3 * 28 - 2008) % 28;
     186             :   }
     187             : 
     188             :   // Given the number of days since the epoch, computes
     189             :   // the corresponding year, month, and day.
     190             :   void YearMonthDayFromDays(int days, int* year, int* month, int* day);
     191             : 
     192             :   // Computes the number of days since the epoch for
     193             :   // the first day of the given month in the given year.
     194             :   int DaysFromYearMonth(int year, int month);
     195             : 
     196             :   // Breaks down the time value.
     197             :   void BreakDownTime(int64_t time_ms, int* year, int* month, int* day,
     198             :                      int* weekday, int* hour, int* min, int* sec, int* ms);
     199             : 
     200             :   // Cache stamp is used for invalidating caches in JSDate.
     201             :   // We increment the stamp each time when the timezone information changes.
     202             :   // JSDate objects perform stamp check and invalidate their caches if
     203             :   // their saved stamp is not equal to the current stamp.
     204             :   Smi* stamp() { return stamp_; }
     205             :   void* stamp_address() { return &stamp_; }
     206             : 
     207             :   // These functions are virtual so that we can override them when testing.
     208       32479 :   virtual int GetDaylightSavingsOffsetFromOS(int64_t time_sec) {
     209       32479 :     double time_ms = static_cast<double>(time_sec * 1000);
     210       32479 :     return static_cast<int>(tz_cache_->DaylightSavingsOffset(time_ms));
     211             :   }
     212             : 
     213         213 :   virtual int GetLocalOffsetFromOS() {
     214         213 :     double offset = tz_cache_->LocalTimeOffset();
     215             :     DCHECK(offset < kInvalidLocalOffsetInMs);
     216         213 :     return static_cast<int>(offset);
     217             :   }
     218             : 
     219             :  private:
     220             :   // The implementation relies on the fact that no time zones have
     221             :   // more than one daylight savings offset change per 19 days.
     222             :   // In Egypt in 2010 they decided to suspend DST during Ramadan. This
     223             :   // led to a short interval where DST is in effect from September 10 to
     224             :   // September 30.
     225             :   static const int kDefaultDSTDeltaInSec = 19 * kSecPerDay;
     226             : 
     227             :   // Size of the Daylight Savings Time cache.
     228             :   static const int kDSTSize = 32;
     229             : 
     230             :   // Daylight Savings Time segment stores a segment of time where
     231             :   // daylight savings offset does not change.
     232             :   struct DST {
     233             :     int start_sec;
     234             :     int end_sec;
     235             :     int offset_ms;
     236             :     int last_used;
     237             :   };
     238             : 
     239             :   // Computes the daylight savings offset for the given time.
     240             :   // ECMA 262 - 15.9.1.8
     241             :   int DaylightSavingsOffsetInMs(int64_t time_ms);
     242             : 
     243             :   // Sets the before_ and the after_ segments from the DST cache such that
     244             :   // the before_ segment starts earlier than the given time and
     245             :   // the after_ segment start later than the given time.
     246             :   // Both segments might be invalid.
     247             :   // The last_used counters of the before_ and after_ are updated.
     248             :   void ProbeDST(int time_sec);
     249             : 
     250             :   // Finds the least recently used segment from the DST cache that is not
     251             :   // equal to the given 'skip' segment.
     252             :   DST* LeastRecentlyUsedDST(DST* skip);
     253             : 
     254             :   // Extends the after_ segment with the given point or resets it
     255             :   // if it starts later than the given time + kDefaultDSTDeltaInSec.
     256             :   inline void ExtendTheAfterSegment(int time_sec, int offset_ms);
     257             : 
     258             :   // Makes the given segment invalid.
     259             :   inline void ClearSegment(DST* segment);
     260             : 
     261             :   bool InvalidSegment(DST* segment) {
     262             :     return segment->start_sec > segment->end_sec;
     263             :   }
     264             : 
     265             :   Smi* stamp_;
     266             : 
     267             :   // Daylight Saving Time cache.
     268             :   DST dst_[kDSTSize];
     269             :   int dst_usage_counter_;
     270             :   DST* before_;
     271             :   DST* after_;
     272             : 
     273             :   int local_offset_ms_;
     274             : 
     275             :   // Year/Month/Day cache.
     276             :   bool ymd_valid_;
     277             :   int ymd_days_;
     278             :   int ymd_year_;
     279             :   int ymd_month_;
     280             :   int ymd_day_;
     281             : 
     282             :   // Timezone name cache
     283             :   const char* tz_name_;
     284             :   const char* dst_tz_name_;
     285             : 
     286             :   base::TimezoneCache* tz_cache_;
     287             : };
     288             : 
     289             : }  // namespace internal
     290             : }  // namespace v8
     291             : 
     292             : #endif

Generated by: LCOV version 1.10