PageRenderTime 14ms CodeModel.GetById 8ms app.highlight 3ms RepoModel.GetById 1ms app.codeStats 0ms

/js/src/prmjtime.h

http://github.com/zpao/v8monkey
C Header | 166 lines | 54 code | 22 blank | 90 comment | 2 complexity | 8bdec022689a0e623cb681891737d922 MD5 | raw file
  1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2 *
  3 * ***** BEGIN LICENSE BLOCK *****
  4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  5 *
  6 * The contents of this file are subject to the Mozilla Public License Version
  7 * 1.1 (the "License"); you may not use this file except in compliance with
  8 * the License. You may obtain a copy of the License at
  9 * http://www.mozilla.org/MPL/
 10 *
 11 * Software distributed under the License is distributed on an "AS IS" basis,
 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 13 * for the specific language governing rights and limitations under the
 14 * License.
 15 *
 16 * The Original Code is Mozilla Communicator client code, released
 17 * March 31, 1998.
 18 *
 19 * The Initial Developer of the Original Code is
 20 * Netscape Communications Corporation.
 21 * Portions created by the Initial Developer are Copyright (C) 1998
 22 * the Initial Developer. All Rights Reserved.
 23 *
 24 * Contributor(s):
 25 *
 26 * Alternatively, the contents of this file may be used under the terms of
 27 * either of the GNU General Public License Version 2 or later (the "GPL"),
 28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 29 * in which case the provisions of the GPL or the LGPL are applicable instead
 30 * of those above. If you wish to allow use of your version of this file only
 31 * under the terms of either the GPL or the LGPL, and not to allow others to
 32 * use your version of this file under the terms of the MPL, indicate your
 33 * decision by deleting the provisions above and replace them with the notice
 34 * and other provisions required by the GPL or the LGPL. If you do not delete
 35 * the provisions above, a recipient may use your version of this file under
 36 * the terms of any one of the MPL, the GPL or the LGPL.
 37 *
 38 * ***** END LICENSE BLOCK ***** */
 39
 40#ifndef prmjtime_h___
 41#define prmjtime_h___
 42
 43#include <time.h>
 44
 45struct JSContext;
 46
 47/*
 48 * Implements a small cache for daylight saving time offset computation.
 49 *
 50 * The basic idea is premised upon this fact: the DST offset never changes more
 51 * than once in any thirty-day period.  If we know the offset at t_0 is o_0,
 52 * the offset at [t_1, t_2] is also o_0, where t_1 + 3_0 days == t_2,
 53 * t_1 <= t_0, and t0 <= t2.  (In other words, t_0 is always somewhere within a
 54 * thirty-day range where the DST offset is constant: DST changes never occur
 55 * more than once in any thirty-day period.)  Therefore, if we intelligently
 56 * retain knowledge of the offset for a range of dates (which may vary over
 57 * time), and if requests are usually for dates within that range, we can often
 58 * provide a response without repeated offset calculation.
 59 *
 60 * Our caching strategy is as follows: on the first request at date t_0 compute
 61 * the requested offset o_0.  Save { start: t_0, end: t_0, offset: o_0 } as the
 62 * cache's state.  Subsequent requests within that range are straightforwardly
 63 * handled.  If a request for t_i is far outside the range (more than thirty
 64 * days), compute o_i = dstOffset(t_i) and save { start: t_i, end: t_i,
 65 * offset: t_i }.  Otherwise attempt to *overextend* the range to either
 66 * [start - 30d, end] or [start, end + 30d] as appropriate to encompass
 67 * t_i.  If the offset o_i30 is the same as the cached offset, extend the
 68 * range.  Otherwise the over-guess crossed a DST change -- compute
 69 * o_i = dstOffset(t_i) and either extend the original range (if o_i == offset)
 70 * or start a new one beneath/above the current one with o_i30 as the offset.
 71 *
 72 * This cache strategy results in 0 to 2 DST offset computations.  The naive
 73 * always-compute strategy is 1 computation, and since cache maintenance is a
 74 * handful of integer arithmetic instructions the speed difference between
 75 * always-1 and 1-with-cache is negligible.  Caching loses if two computations
 76 * happen: when the date is within 30 days of the cached range and when that
 77 * 30-day range crosses a DST change.  This is relatively uncommon.  Further,
 78 * instances of such are often dominated by in-range hits, so caching is an
 79 * overall slight win.
 80 *
 81 * Why 30 days?  For correctness the duration must be smaller than any possible
 82 * duration between DST changes.  Past that, note that 1) a large duration
 83 * increases the likelihood of crossing a DST change while reducing the number
 84 * of cache misses, and 2) a small duration decreases the size of the cached
 85 * range while producing more misses.  Using a month as the interval change is
 86 * a balance between these two that tries to optimize for the calendar month at
 87 * a time that a site might display.  (One could imagine an adaptive duration
 88 * that accommodates near-DST-change dates better; we don't believe the
 89 * potential win from better caching offsets the loss from extra complexity.)
 90 */
 91class DSTOffsetCache {
 92  public:
 93    inline DSTOffsetCache();
 94    int64_t getDSTOffsetMilliseconds(int64_t localTimeMilliseconds, JSContext *cx);
 95
 96    inline void purge();
 97
 98  private:
 99    int64_t computeDSTOffsetMilliseconds(int64_t localTimeSeconds);
100
101    int64_t offsetMilliseconds;
102    int64_t rangeStartSeconds, rangeEndSeconds;
103
104    int64_t oldOffsetMilliseconds;
105    int64_t oldRangeStartSeconds, oldRangeEndSeconds;
106
107    static const int64_t MAX_UNIX_TIMET = 2145859200; /* time_t 12/31/2037 */
108    static const int64_t MILLISECONDS_PER_SECOND = 1000;
109    static const int64_t SECONDS_PER_MINUTE = 60;
110    static const int64_t SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE;
111    static const int64_t SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR;
112
113    static const int64_t RANGE_EXPANSION_AMOUNT = 30 * SECONDS_PER_DAY;
114
115  private:
116    void sanityCheck();
117};
118
119JS_BEGIN_EXTERN_C
120
121typedef struct PRMJTime       PRMJTime;
122
123/*
124 * Broken down form of 64 bit time value.
125 */
126struct PRMJTime {
127    int32_t tm_usec;            /* microseconds of second (0-999999) */
128    int8_t tm_sec;              /* seconds of minute (0-59) */
129    int8_t tm_min;              /* minutes of hour (0-59) */
130    int8_t tm_hour;             /* hour of day (0-23) */
131    int8_t tm_mday;             /* day of month (1-31) */
132    int8_t tm_mon;              /* month of year (0-11) */
133    int8_t tm_wday;             /* 0=sunday, 1=monday, ... */
134    int32_t tm_year;            /* absolute year, AD */
135    int16_t tm_yday;            /* day of year (0 to 365) */
136    int8_t tm_isdst;            /* non-zero if DST in effect */
137};
138
139/* Some handy constants */
140#define PRMJ_USEC_PER_SEC       1000000L
141#define PRMJ_USEC_PER_MSEC      1000L
142
143/* Return the current local time in micro-seconds */
144extern int64_t
145PRMJ_Now(void);
146
147/* Release the resources associated with PRMJ_Now; don't call PRMJ_Now again */
148#if defined(JS_THREADSAFE) && (defined(HAVE_GETSYSTEMTIMEASFILETIME) || defined(HAVE_SYSTEMTIMETOFILETIME))
149extern void
150PRMJ_NowShutdown(void);
151#else
152#define PRMJ_NowShutdown()
153#endif
154
155/* get the difference between this time zone and  gmt timezone in seconds */
156extern int32_t
157PRMJ_LocalGMTDifference(void);
158
159/* Format a time value into a buffer. Same semantics as strftime() */
160extern size_t
161PRMJ_FormatTime(char *buf, int buflen, const char *fmt, PRMJTime *tm);
162
163JS_END_EXTERN_C
164
165#endif /* prmjtime_h___ */
166