Fix timezone handling near year boundaries
PR libfortran/98507 libgfortran/ChangeLog: * intrinsics/time_1.h: Prefer clock_gettime() over gettimeofday(). * intrinsics/date_and_time.c: Fix timezone wrapping. gcc/testsuite/ChangeLog: * gfortran.dg/date_and_time_1.f90: New file.
This commit is contained in:
parent
41cc28405c
commit
3f624a624a
3 changed files with 59 additions and 14 deletions
35
gcc/testsuite/gfortran.dg/date_and_time_1.f90
Normal file
35
gcc/testsuite/gfortran.dg/date_and_time_1.f90
Normal file
|
@ -0,0 +1,35 @@
|
|||
! PR libfortran/98507
|
||||
! { dg-do run }
|
||||
|
||||
program demo_time_and_date
|
||||
implicit none
|
||||
character(8) :: date
|
||||
character(10) :: time
|
||||
character(5) :: zone
|
||||
integer :: val(8)
|
||||
integer :: h, m
|
||||
|
||||
call date_and_time(values=val)
|
||||
|
||||
if (val(1) < 2000 .or. val(1) > 2100) stop 1
|
||||
if (val(2) < 1 .or. val(2) > 12) stop 2
|
||||
if (val(3) < 1 .or. val(3) > 31) stop 3
|
||||
|
||||
! Maximum offset is 14 hours (UTC+14)
|
||||
if (val(4) < -14*60 .or. val(4) > 14*60) stop 4
|
||||
|
||||
if (val(5) < 0 .or. val(5) > 23) stop 5
|
||||
if (val(6) < 0 .or. val(6) > 59) stop 6
|
||||
if (val(7) < 0 .or. val(7) > 60) stop 7
|
||||
if (val(8) < 0 .or. val(8) > 999) stop 8
|
||||
|
||||
call date_and_time(zone=zone)
|
||||
if (len(zone) /= 0) then
|
||||
! If ZONE is present, it should present the same information as
|
||||
! given in VALUES(4)
|
||||
if (len(zone) /= 5) stop 9
|
||||
read(zone(1:3),*) h
|
||||
read(zone(4:5),*) m
|
||||
if (val(4) /= 60*h+m) stop 10
|
||||
endif
|
||||
end
|
|
@ -113,9 +113,6 @@ gmtime_r (const time_t * timep, struct tm * result)
|
|||
VALUES for INTEGER(kind=4) and INTEGER(kind=8).
|
||||
|
||||
Based on libU77's date_time_.c.
|
||||
|
||||
TODO :
|
||||
- Check year boundaries.
|
||||
*/
|
||||
#define DATE_LEN 8
|
||||
#define TIME_LEN 10
|
||||
|
@ -131,7 +128,7 @@ date_and_time (char *__date, char *__time, char *__zone,
|
|||
gfc_array_i4 *__values, GFC_INTEGER_4 __date_len,
|
||||
GFC_INTEGER_4 __time_len, GFC_INTEGER_4 __zone_len)
|
||||
{
|
||||
int i;
|
||||
int i, delta_day;
|
||||
char date[DATE_LEN + 1];
|
||||
char timec[TIME_LEN + 1];
|
||||
char zone[ZONE_LEN + 1];
|
||||
|
@ -154,9 +151,22 @@ date_and_time (char *__date, char *__time, char *__zone,
|
|||
values[0] = 1900 + local_time.tm_year;
|
||||
values[1] = 1 + local_time.tm_mon;
|
||||
values[2] = local_time.tm_mday;
|
||||
values[3] = (local_time.tm_min - UTC_time.tm_min +
|
||||
60 * (local_time.tm_hour - UTC_time.tm_hour +
|
||||
24 * (local_time.tm_yday - UTC_time.tm_yday)));
|
||||
|
||||
/* Day difference with UTC should always be -1, 0 or +1.
|
||||
Near year boundaries, we may obtain a large positive (+364,
|
||||
or +365 on leap years) or negative (-364, or -365 on leap years)
|
||||
number, which we have to handle.
|
||||
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98507
|
||||
*/
|
||||
delta_day = local_time.tm_yday - UTC_time.tm_yday;
|
||||
if (delta_day < -1)
|
||||
delta_day = 1;
|
||||
else if (delta_day > 1)
|
||||
delta_day = -1;
|
||||
|
||||
values[3] = local_time.tm_min - UTC_time.tm_min
|
||||
+ 60 * (local_time.tm_hour - UTC_time.tm_hour + 24 * delta_day);
|
||||
|
||||
values[4] = local_time.tm_hour;
|
||||
values[5] = local_time.tm_min;
|
||||
values[6] = local_time.tm_sec;
|
||||
|
|
|
@ -213,19 +213,19 @@ gf_cputime (long *user_sec, long *user_usec, long *system_sec, long *system_usec
|
|||
static inline int
|
||||
gf_gettime (time_t * secs, long * usecs)
|
||||
{
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
struct timespec ts;
|
||||
int err = clock_gettime (CLOCK_REALTIME, &ts);
|
||||
*secs = ts.tv_sec;
|
||||
*usecs = ts.tv_nsec / 1000;
|
||||
return err;
|
||||
#elif defined(HAVE_GETTIMEOFDAY)
|
||||
struct timeval tv;
|
||||
int err;
|
||||
err = gettimeofday (&tv, NULL);
|
||||
*secs = tv.tv_sec;
|
||||
*usecs = tv.tv_usec;
|
||||
return err;
|
||||
#elif defined(HAVE_CLOCK_GETTIME)
|
||||
struct timespec ts;
|
||||
int err = clock_gettime (CLOCK_REALTIME, &ts);
|
||||
*secs = ts.tv_sec;
|
||||
*usecs = ts.tv_nsec / 1000;
|
||||
return err;
|
||||
#else
|
||||
time_t t = time (NULL);
|
||||
*secs = t;
|
||||
|
|
Loading…
Add table
Reference in a new issue