From 70f5dc8ff9fde80eec727671340943fa07db137d Mon Sep 17 00:00:00 2001 From: "mvl%exedo.nl" Date: Tue, 19 Sep 2006 20:39:30 +0000 Subject: [PATCH] bug 278236: don't use time_t, to prevent crashes for dates before 1970 or after 2038. r=ctalbert, dmose git-svn-id: svn://10.0.0.236/trunk@212015 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/calendar/base/src/calDateTime.cpp | 96 ++++++++++++++++++----- mozilla/calendar/base/src/calDateTime.h | 3 + 2 files changed, 79 insertions(+), 20 deletions(-) diff --git a/mozilla/calendar/base/src/calDateTime.cpp b/mozilla/calendar/base/src/calDateTime.cpp index 2c32baa1507..a5d37e30f61 100644 --- a/mozilla/calendar/base/src/calDateTime.cpp +++ b/mozilla/calendar/base/src/calDateTime.cpp @@ -284,10 +284,12 @@ calDateTime::SubtractDate(calIDateTime *aDate, calIDuration **aDuration) aDate->ToIcalTime(&itt2); // same as icaltime_subtract(), but minding timezones: - icaltimezone * utc = icaltimezone_get_utc_timezone(); - time_t t1t = icaltime_as_timet_with_zone(itt1, utc); - time_t t2t = icaltime_as_timet_with_zone(itt2, utc); - icaldurationtype idt = icaldurationtype_from_int((int)(t1t-t2t)); + PRTime t2t; + aDate->GetNativeTime(&t2t); + // for a duration, need to convert the difference in microseconds (prtime) + // to seconds (libical), so divide by one million. + icaldurationtype idt = + icaldurationtype_from_int(NS_STATIC_CAST(int, mNativeTime - t2t / PR_USEC_PER_SEC)); nsCOMPtr result(do_CreateInstance("@mozilla.org/calendar/duration;1")); if (!result) @@ -320,8 +322,6 @@ calDateTime::ToString(nsACString& aResult) NS_IMETHODIMP calDateTime::SetTimeInTimezone(PRTime aTime, const nsACString& aTimezone) { - struct icaltimetype icalt; - time_t tt; icaltimezone *tz = nsnull; if (aTimezone.IsEmpty()) @@ -330,16 +330,10 @@ calDateTime::SetTimeInTimezone(PRTime aTime, const nsACString& aTimezone) nsresult rv = GetIcalTZ(aTimezone, &tz); NS_ENSURE_SUCCESS(rv, rv); - PRInt64 temp, million; - LL_I2L(million, PR_USEC_PER_SEC); - LL_DIV(temp, aTime, million); - PRInt32 sectime; - LL_L2I(sectime, temp); + struct icaltimetype icalt = icaltime_null_time(); + PRTimeToIcaltime(aTime, PR_FALSE, tz, &icalt); - tt = sectime; - icalt = icaltime_from_timet_with_zone(tt, 0, tz); FromIcalTime(&icalt); - mIsValid = PR_TRUE; return NS_OK; @@ -567,12 +561,74 @@ calDateTime::FromIcalTime(icaltimetype *icalt) // mNativeTime: not moving the existing date to UTC, // but merely representing it a UTC-based way. t.is_date = 0; - time_t tt = icaltime_as_timet_with_zone(t, icaltimezone_get_utc_timezone()); - PRInt64 temp, million; - LL_I2L(million, PR_USEC_PER_SEC); - LL_I2L(temp, tt); - LL_MUL(temp, temp, million); - mNativeTime = temp; + mNativeTime = IcaltimeToPRTime(&t, icaltimezone_get_utc_timezone()); +} + +PRTime +calDateTime::IcaltimeToPRTime(const icaltimetype *const icalt, struct _icaltimezone *const tz) +{ + struct icaltimetype tt = *icalt; + struct PRExplodedTime et; + + /* If the time is the special null time, return 0. */ + if (icaltime_is_null_time(*icalt)) { + return 0; + } + + if (tz) { + // use libical for timezone conversion, as it can handle all ics + // timezones. having nspr do it is much harder. + tt = icaltime_convert_to_zone(*icalt, tz); + } + + /* Empty the destination */ + memset(&et, 0, sizeof(struct PRExplodedTime)); + + /* Fill the fields */ + if (icaltime_is_date(tt)) { + et.tm_sec = et.tm_min = et.tm_hour = 0; + } else { + et.tm_sec = tt.second; + et.tm_min = tt.minute; + et.tm_hour = tt.hour; + } + et.tm_mday = tt.day; + et.tm_month = tt.month-1; + et.tm_year = tt.year; + + return PR_ImplodeTime(&et); +} + +void +calDateTime::PRTimeToIcaltime(const PRTime time, const PRBool isdate, + struct _icaltimezone *const tz, + icaltimetype *icalt) +{ + icaltimezone *utc_zone; + + struct PRExplodedTime et; + PR_ExplodeTime(time, PR_GMTParameters, &et); + + icalt->year = et.tm_year; + icalt->month = et.tm_month + 1; + icalt->day = et.tm_mday; + + if (isdate) { + icalt->is_date = 1; + return; + } + + icalt->hour = et.tm_hour; + icalt->minute = et.tm_min; + icalt->second = et.tm_sec; + + /* Only do conversion when not in floating timezone */ + if (tz) { + utc_zone = icaltimezone_get_utc_timezone(); + icalt->is_utc = (tz == utc_zone) ? 1 : 0; + icalt->zone = tz; + } + return; } NS_IMETHODIMP diff --git a/mozilla/calendar/base/src/calDateTime.h b/mozilla/calendar/base/src/calDateTime.h index f768fe5badf..14959befa8b 100644 --- a/mozilla/calendar/base/src/calDateTime.h +++ b/mozilla/calendar/base/src/calDateTime.h @@ -88,6 +88,9 @@ protected: void FromIcalTime(icaltimetype *icalt); nsresult GetIcalTZ(const nsACString& tzid, struct _icaltimezone **tzp); + PRTime IcaltimeToPRTime(const icaltimetype *const icalt, struct _icaltimezone *const tz); + void PRTimeToIcaltime(const PRTime time, const PRBool isdate, struct _icaltimezone *const tz, icaltimetype *icalt); + PRTime mLastModified; };