📄 prtime.c
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape Portable Runtime (NSPR). * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//* * prtime.c -- * * NSPR date and time functions * */#include "prinit.h"#include "prtime.h"#include "prlock.h"#include "prprf.h"#include "prlog.h"#include <string.h>#include <ctype.h>#ifdef XP_MAC#include <time.h>#endif/* * Static variables used by functions in this file *//* * The following array contains the day of year for the last day of * each month, where index 1 is January, and day 0 is January 1. */static const int lastDayOfMonth[2][13] = { {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364}, {-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}};/* * The number of days in a month */static const PRInt8 nDays[2][12] = { {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};/* * Declarations for internal functions defined later in this file. */static void ComputeGMT(PRTime time, PRExplodedTime *gmt);static int IsLeapYear(PRInt16 year);static void ApplySecOffset(PRExplodedTime *time, PRInt32 secOffset);/* *------------------------------------------------------------------------ * * ComputeGMT -- * * Caveats: * - we ignore leap seconds * - our leap-year calculation is only correct for years 1901-2099 * *------------------------------------------------------------------------ */static voidComputeGMT(PRTime time, PRExplodedTime *gmt){ PRInt32 tmp, rem; PRInt32 numDays; PRInt64 numDays64, rem64; int isLeap; PRInt64 sec; PRInt64 usec; PRInt64 usecPerSec; PRInt64 secPerDay; /* * We first do the usec, sec, min, hour thing so that we do not * have to do LL arithmetic. */ LL_I2L(usecPerSec, 1000000L); LL_DIV(sec, time, usecPerSec); LL_MOD(usec, time, usecPerSec); LL_L2I(gmt->tm_usec, usec); /* Correct for weird mod semantics so the remainder is always positive */ if (gmt->tm_usec < 0) { PRInt64 one; LL_I2L(one, 1L); LL_SUB(sec, sec, one); gmt->tm_usec += 1000000L; } LL_I2L(secPerDay, 86400L); LL_DIV(numDays64, sec, secPerDay); LL_MOD(rem64, sec, secPerDay); /* We are sure both of these numbers can fit into PRInt32 */ LL_L2I(numDays, numDays64); LL_L2I(rem, rem64); if (rem < 0) { numDays--; rem += 86400L; } /* Compute day of week. Epoch started on a Thursday. */ gmt->tm_wday = (numDays + 4) % 7; if (gmt->tm_wday < 0) { gmt->tm_wday += 7; } /* Compute the time of day. */ gmt->tm_hour = rem / 3600; rem %= 3600; gmt->tm_min = rem / 60; gmt->tm_sec = rem % 60; /* Compute the four-year span containing the specified time */ tmp = numDays / (4 * 365 + 1); rem = numDays % (4 * 365 + 1); if (rem < 0) { tmp--; rem += (4 * 365 + 1); } /* * Compute the year after 1900 by taking the four-year span and * adjusting for the remainder. This works because 2000 is a * leap year, and 1900 and 2100 are out of the range. */ tmp = (tmp * 4) + 1970; isLeap = 0; /* * 1970 has 365 days * 1971 has 365 days * 1972 has 366 days (leap year) * 1973 has 365 days */ if (rem >= 365) { /* 1971, etc. */ tmp++; rem -= 365; if (rem >= 365) { /* 1972, etc. */ tmp++; rem -= 365; if (rem >= 366) { /* 1973, etc. */ tmp++; rem -= 366; } else { isLeap = 1; } } } gmt->tm_year = tmp; gmt->tm_yday = rem; /* Compute the month and day of month. */ for (tmp = 1; lastDayOfMonth[isLeap][tmp] < gmt->tm_yday; tmp++) { } gmt->tm_month = --tmp; gmt->tm_mday = gmt->tm_yday - lastDayOfMonth[isLeap][tmp]; gmt->tm_params.tp_gmt_offset = 0; gmt->tm_params.tp_dst_offset = 0;}/* *------------------------------------------------------------------------ * * PR_ExplodeTime -- * * Cf. struct tm *gmtime(const time_t *tp) and * struct tm *localtime(const time_t *tp) * *------------------------------------------------------------------------ */PR_IMPLEMENT(void)PR_ExplodeTime( PRTime usecs, PRTimeParamFn params, PRExplodedTime *exploded){ ComputeGMT(usecs, exploded); exploded->tm_params = params(exploded); ApplySecOffset(exploded, exploded->tm_params.tp_gmt_offset + exploded->tm_params.tp_dst_offset);}/* *------------------------------------------------------------------------ * * PR_ImplodeTime -- * * Cf. time_t mktime(struct tm *tp) * Note that 1 year has < 2^25 seconds. So an PRInt32 is large enough. * *------------------------------------------------------------------------ */#if defined(HAVE_WATCOM_BUG_2)PRTime __pascal __export __loadds#elsePR_IMPLEMENT(PRTime)#endifPR_ImplodeTime(const PRExplodedTime *exploded){ PRExplodedTime copy; PRTime retVal; PRInt64 secPerDay, usecPerSec; PRInt64 temp; PRInt64 numSecs64; PRInt32 fourYears; PRInt32 remainder; PRInt32 numDays; PRInt32 numSecs; /* Normalize first. Do this on our copy */ copy = *exploded; PR_NormalizeTime(©, PR_GMTParameters); fourYears = (copy.tm_year - 1970) / 4; remainder = (copy.tm_year - 1970) % 4; if (remainder < 0) { remainder += 4; fourYears--; } numDays = fourYears * (4 * 365 + 1); switch (remainder) { case 0: break; case 1: /* 1970 */ numDays += 365; break; case 2: /* 1970-1 */ numDays += 365 * 2; break; case 3: /* 1970-2 */ numDays += 365 * 3 + 1; break; } numSecs = copy.tm_yday * 86400 + copy.tm_hour * 3600 + copy.tm_min * 60 + copy.tm_sec; LL_I2L(temp, numDays); LL_I2L(secPerDay, 86400); LL_MUL(temp, temp, secPerDay); LL_I2L(numSecs64, numSecs); LL_ADD(numSecs64, numSecs64, temp); /* apply the GMT and DST offsets */ LL_I2L(temp, copy.tm_params.tp_gmt_offset); LL_SUB(numSecs64, numSecs64, temp); LL_I2L(temp, copy.tm_params.tp_dst_offset); LL_SUB(numSecs64, numSecs64, temp); LL_I2L(usecPerSec, 1000000L); LL_MUL(temp, numSecs64, usecPerSec); LL_I2L(retVal, copy.tm_usec); LL_ADD(retVal, retVal, temp); return retVal;}/* *------------------------------------------------------------------------- * * IsLeapYear -- * * Returns 1 if the year is a leap year, 0 otherwise. * *------------------------------------------------------------------------- */static int IsLeapYear(PRInt16 year){ if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) return 1; else return 0;}/* * 'secOffset' should be less than 86400 (i.e., a day). * 'time' should point to a normalized PRExplodedTime. */static voidApplySecOffset(PRExplodedTime *time, PRInt32 secOffset){ time->tm_sec += secOffset; /* Note that in this implementation we do not count leap seconds */ if (time->tm_sec < 0 || time->tm_sec >= 60) { time->tm_min += time->tm_sec / 60; time->tm_sec %= 60; if (time->tm_sec < 0) { time->tm_sec += 60; time->tm_min--; } } if (time->tm_min < 0 || time->tm_min >= 60) { time->tm_hour += time->tm_min / 60; time->tm_min %= 60; if (time->tm_min < 0) { time->tm_min += 60; time->tm_hour--; } } if (time->tm_hour < 0) { /* Decrement mday, yday, and wday */ time->tm_hour += 24; time->tm_mday--; time->tm_yday--; if (time->tm_mday < 1) { time->tm_month--; if (time->tm_month < 0) { time->tm_month = 11; time->tm_year--; if (IsLeapYear(time->tm_year)) time->tm_yday = 365; else time->tm_yday = 364;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -