From a04403a3160bf80616f723d425f38b42f3969c23 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Wed, 25 Aug 2010 10:45:12 -0600 Subject: [PATCH] add GMT option to seconds->date --- collects/scribblings/reference/time.scrbl | 20 ++++++++-- src/racket/src/fun.c | 48 +++++++++++++++-------- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/collects/scribblings/reference/time.scrbl b/collects/scribblings/reference/time.scrbl index 4a405ca46a..00018d6930 100644 --- a/collects/scribblings/reference/time.scrbl +++ b/collects/scribblings/reference/time.scrbl @@ -15,13 +15,19 @@ The value of @racket[(current-seconds)] increases as time passes seconds can be compared with a time returned by @racket[file-or-directory-modify-seconds].} -@defproc[(seconds->date [secs-n exact-integer?]) date?]{ +@defproc[(seconds->date [secs-n exact-integer?] + [local-time? any/c #t]) + date?]{ Takes @racket[secs-n], a platform-specific time in seconds returned by @racket[current-seconds] or @racket[file-or-directory-modify-seconds], and returns an instance of the @racket[date] structure type. If @racket[secs-n] is too small or large, the @exnraise[exn:fail]. +The resulting @racket[date] reflects the time according to the local +time zone if @racket[local-time?] is @racket[#t], otherwise it +reflects a date in GMT. + The value returned by @racket[current-seconds] or @racket[file-or-directory-modify-seconds] is not portable among platforms. Convert a time in seconds using @racket[seconds->date] when @@ -44,9 +50,15 @@ Represents a date. For the @racket[second] field, values of leap-seconds. The @racket[year-day] field reaches @racket[365] only in leap years. -The @racket[time-zone-offset] field reports the number of seconds east -of GMT for the current time zone (e.g., Pacific Standard Time is -@racket[-28800]), an exact integer. +The @racket[dst?] field is @racket[#t] if the date reflects a +daylight-saving adjustment. The @racket[time-zone-offset] field +reports the number of seconds east of GMT for the current time zone +(e.g., Pacific Standard Time is @racket[-28800]), including any +daylight-saving adjustment (e.g., Pacific Daylight Time is +@racket[-25200]). When a @racket[date] record is generated by +@racket[seconds->date] with @racket[#f] as the second argument, then +the @racket[dst?] and @racket[time-zone-offset] fields are +@racket[#f] and @racket[0], respectively. The value produced for the @racket[time-zone-offset] field tends to be sensitive to the value of the @envvar{TZ} environment variable, diff --git a/src/racket/src/fun.c b/src/racket/src/fun.c index 3052129f49..b5f77e6ca1 100644 --- a/src/racket/src/fun.c +++ b/src/racket/src/fun.c @@ -470,7 +470,7 @@ scheme_init_fun (Scheme_Env *env) scheme_add_global_constant("seconds->date", scheme_make_prim_w_arity(seconds_to_date, "seconds->date", - 1, 1), + 1, 2), env); #endif @@ -8770,6 +8770,7 @@ static int month_offsets[12] = { 0, 31, 59, 90, static Scheme_Object *seconds_to_date(int argc, Scheme_Object **argv) { UNBUNDLE_TIME_TYPE lnow; + int get_gmt; int hour, min, sec, month, day, year, wday, yday, dst; long tzoffset; #ifdef USE_MACTIME @@ -8777,7 +8778,7 @@ static Scheme_Object *seconds_to_date(int argc, Scheme_Object **argv) DateTimeRec localTime; #else # ifdef USE_PALMTIME -# define CHECK_TIME_T UInt32 +# define CHECK_TIME_T UInt32 DateTimeType localTime; # else # define CHECK_TIME_T time_t @@ -8793,6 +8794,11 @@ static Scheme_Object *seconds_to_date(int argc, Scheme_Object **argv) scheme_wrong_type("seconds->date", "exact integer", 0, argc, argv); return NULL; } + + if (argc > 1) + get_gmt = SCHEME_FALSEP(argv[1]); + else + get_gmt = 0; if (scheme_get_time_val(secs, &lnow) && ((UNBUNDLE_TIME_TYPE)(now = (CHECK_TIME_T)lnow)) == lnow) { @@ -8805,7 +8811,10 @@ static Scheme_Object *seconds_to_date(int argc, Scheme_Object **argv) # ifdef USE_PALMTIME TimSecondsToDateTime(lnow, &localTime) ; # else - localTime = localtime(&now); + if (get_gmt) + localTime = gmtime(&now); + else + localTime = localtime(&now); success = !!localTime; # endif #endif @@ -8816,7 +8825,7 @@ static Scheme_Object *seconds_to_date(int argc, Scheme_Object **argv) # define mzDOW(localTime) localTime.dayOfWeek - 1 # else # define mzDOW(localTime) localTime.weekDay -#endif +# endif hour = localTime.hour; min = localTime.minute; @@ -8831,7 +8840,7 @@ static Scheme_Object *seconds_to_date(int argc, Scheme_Object **argv) yday = month_offsets[localTime.month - 1] + localTime.day - 1; /* If month > 2, is it a leap-year? */ if (localTime.month > 2) { -#ifdef USE_MACTIME +# ifdef USE_MACTIME unsigned long ttime; DateTimeRec tester; @@ -8845,11 +8854,11 @@ static Scheme_Object *seconds_to_date(int argc, Scheme_Object **argv) if (tester.month == 2) /* It is a leap-year */ yday++; -#else +# else /* PalmOS: */ if (DaysInMonth(2, year) > 28) yday++; -#endif +# endif } # ifdef USE_MACTIME @@ -8882,32 +8891,37 @@ static Scheme_Object *seconds_to_date(int argc, Scheme_Object **argv) wday = localTime->tm_wday; yday = localTime->tm_yday; - dst = localTime->tm_isdst; + if (get_gmt) + dst = 0; + else + dst = localTime->tm_isdst; tzoffset = 0; + if (!get_gmt) { # ifdef USE_TIMEZONE_VAR - tzoffset = -MSC_IZE(timezone); + tzoffset = -MSC_IZE(timezone); # endif # ifdef USE_TOD_FOR_TIMEZONE - { + { struct timezone xtz; struct timeval xtv; gettimeofday(&xtv, &xtz); tzoffset = -(xtz.tz_minuteswest * 60); - } + } # endif # ifdef USE_TIMEZONE_VAR_W_DLS - tzoffset = -(MSCBOR_IZE(timezone) - (dst ? 3600 : 0)); + tzoffset = -(MSCBOR_IZE(timezone) - (dst ? 3600 : 0)); # endif # ifdef USE_TIMEZONE_AND_ALTZONE_VAR - if (dst) - tzoffset = -altzone; - else - tzoffset = -timezone; + if (dst) + tzoffset = -altzone; + else + tzoffset = -timezone; # endif # ifdef USE_TM_GMTOFF_FIELD - tzoffset = localTime->tm_gmtoff; + tzoffset = localTime->tm_gmtoff; # endif + } #endif