gnuastro-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnuastro-commits] master 288dc17: Fits library: now returns sub-second


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 288dc17: Fits library: now returns sub-second string when a Z is present
Date: Mon, 24 Feb 2020 11:27:37 -0500 (EST)

branch: master
commit 288dc1767bb10dd6823ad46395741c5aec30f187
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    Fits library: now returns sub-second string when a Z is present
    
    Until now, when the time string ended with a `Z', and there were
    sub-seconds, the library couldn't interpret it.
    
    With this commit, the sub-second part is pulled out into another string,
    allowing the parsing of the date/time string even when there is a `Z' in
    the end.
---
 bin/fits/keywords.c |  7 +++++--
 doc/gnuastro.texi   | 56 ++++++++++++++++++-----------------------------------
 lib/fits.c          | 36 +++++++++++++++++++++++++---------
 3 files changed, 51 insertions(+), 48 deletions(-)

diff --git a/bin/fits/keywords.c b/bin/fits/keywords.c
index 7cbdc97..7458d0f 100644
--- a/bin/fits/keywords.c
+++ b/bin/fits/keywords.c
@@ -420,11 +420,14 @@ keywords_date_to_seconds(struct fitsparams *p, fitsfile 
*fptr)
       printf("%s (hdu %s), key `%s': %s\n", p->filename, p->cp.hdu,
              p->datetosec, fitsdate);
       printf("Seconds since 1970/01/01 (00:00:00): %zu%s\n\n", seconds,
-             subsecstr);
+             subsecstr?subsecstr:"");
       printf("(To suppress verbose output, run with `-q')\n");
     }
   else
-    printf("%zu%s\n", seconds, subsecstr);
+    printf("%zu%s\n", seconds, subsecstr?subsecstr:"");
+
+  /* Clean up. */
+  if(subsecstr) free(subsecstr);
 }
 
 
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 35c2900..aecf724 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -21155,48 +21155,30 @@ string.
 
 @deftypefun {char *} gal_fits_key_date_to_struct_tm (char @code{*fitsdate}, 
struct tm @code{*tp})
 @cindex Date: FITS format
-Parse @code{fitsdate} as a FITS date format string (most generally:
-@code{YYYY-MM-DDThh:mm:ss.ddd...}) into the C library's broken-down time
-structure, or @code{struct tm} (declared in @file{time.h}) and return a
-pointer to the remainder of the string (containing the optional sub-second
-portion of @code{fitsdate}, or the @code{.ddd...} of the format).
-
-The returned @code{char *} points to part of the @code{fitsdate} string, so
-it must not be freed. For example, if @code{fitsdate} contains no
-sub-second portion, then the returned @code{char *} will point to the
-NULL-character of @code{fitsdate}.
-
-Note that the FITS date format mentioned above is the most complete
-representation. The following two formats are also acceptable:
-@code{YYYY-MM-DDThh:mm:ss} and @code{YYYY-MM-DD}. This option can also
-interpret the older FITS date format where only two characters are given to
-the year and the date format is reversed
-(@code{DD/MM/YYThh:mm:ss.ddd...}). In this case (following the GNU C
-Library), this option will make the following assumption: values 68 to 99
-correspond to the years 1969 to 1999, and values 0 to 68 as the years 2000
-to 2068.
+Parse @code{fitsdate} as a FITS date format string (most generally: 
@code{YYYY-MM-DDThh:mm:ss.ddd...}) into the C library's broken-down time 
structure, or @code{struct tm} (declared in @file{time.h}) and return a pointer 
to a newly allocated array for the sub-second part of the format 
(@code{.ddd...}).
+Therefore it needs to be freed afterwards (if it isn't @code{NULL})
+When there is no sub-second portion, this pointer will be @code{NULL}.
+
+This is a relatively low-level function, an easier function to use is 
@code{gal_fits_key_date_to_seconds} which will return the subseconds as double 
precision floating point.
+
+Note that the FITS date format mentioned above is the most complete 
representation.
+The following two formats are also acceptable: @code{YYYY-MM-DDThh:mm:ss} and 
@code{YYYY-MM-DD}.
+This option can also interpret the older FITS date format where only two 
characters are given to the year and the date format is reversed 
(@code{DD/MM/YYThh:mm:ss.ddd...}).
+In this case (following the GNU C Library), this option will make the 
following assumption: values 68 to 99 correspond to the years 1969 to 1999, and 
values 0 to 68 as the years 2000 to 2068.
 @end deftypefun
 
 @deftypefun size_t gal_fits_key_date_to_seconds (char @code{*fitsdate}, char 
@code{**subsecstr}, double @code{*subsec})
 @cindex Unix epoch time
 @cindex Epoch time, Unix
-Return the Unix epoch time (number of seconds that have passed since
-00:00:00 Thursday, January 1st, 1970) corresponding to the FITS date format
-string @code{fitsdate} (see description of
-@code{gal_fits_key_date_to_struct_tm} above).
-
-The Unix epoch time is in units of seconds, but the FITS date format allows
-sub-second accuracy. The last two arguments are for the (optional)
-sub-second portion. If @code{fitsdate} contains sub-second accuracy, then
-the starting of the sub-second part is stored in the @code{char *} pointer
-that @code{subsecstr} points to, and @code{subsec} will the corresponding
-numerical value (between 0 and 1, in double precision floating point).
-
-This is a very useful function for operations on the FITS date values, for
-example sorting FITS files by their dates, or finding the time difference
-between two FITS files. The advantage of working with the Unix epoch time
-is that you don't have to worry about calendar details (for example the
-number of days in different months, or leap years, etc).
+Return the Unix epoch time (number of seconds that have passed since 00:00:00 
Thursday, January 1st, 1970) corresponding to the FITS date format string 
@code{fitsdate} (see description of @code{gal_fits_key_date_to_struct_tm} 
above).
+
+The Unix epoch time is in units of seconds, but the FITS date format allows 
sub-second accuracy.
+The last two arguments are for the (optional) sub-second portion.
+If @code{fitsdate} contains sub-second accuracy, then the starting of the 
sub-second part's string is stored in @code{subsecstr} (allocated separately), 
and @code{subsec} will be the corresponding numerical value (between 0 and 1, 
in double precision floating point).
+So to avoid leaking memory, when @code{subsecstr!=NULL}, it must be freed.
+
+This is a very useful function for operations on the FITS date values, for 
example sorting FITS files by their dates, or finding the time difference 
between two FITS files.
+The advantage of working with the Unix epoch time is that you don't have to 
worry about calendar details (for example the number of days in different 
months, or leap years, etc).
 @end deftypefun
 
 @deftypefun void gal_fits_key_read_from_ptr (fitsfile @code{*fptr}, gal_data_t 
@code{*keysll}, int @code{readcomment}, int @code{readunit})
diff --git a/lib/fits.c b/lib/fits.c
index 72604d4..2e65006 100644
--- a/lib/fits.c
+++ b/lib/fits.c
@@ -914,8 +914,8 @@ gal_fits_key_clean_str_value(char *string)
 char *
 gal_fits_key_date_to_struct_tm(char *fitsdate, struct tm *tp)
 {
-  char *c=NULL, *cf;
   int hasT=0, hassq=0, usesdash=0, usesslash=0, hasZ=0;
+  char *C, *cc, *c=NULL, *cf, *subsec=NULL, *nosubsec=fitsdate;
 
   /* Initialize the `tm' structure to all-zero elements. In particular, The
      FITS standard times are written in UTC, so, the time zone (`tm_zone'
@@ -938,6 +938,20 @@ gal_fits_key_date_to_struct_tm(char *fitsdate, struct tm 
*tp)
       case '\'': hassq=1;     break; /* Wholly Wrapped in a single-quote. */
       case 'Z':  hasZ=1;      break; /* When ends in `Z', means UTC. See  */
                                    /* https://www.w3.org/TR/NOTE-datetime */
+
+      /* In case we have sub-seconds in the string, we need to remove it
+         because `strptime' doesn't recognize sub-second resolution.*/
+      case '.':
+        /* Allocate space (by copying the remaining full string and adding
+           a `\0' where necessary. */
+        gal_checkset_allocate_copy(c, &subsec);
+        gal_checkset_allocate_copy(fitsdate, &nosubsec);
+
+        /* Parse the sub-second part and remove it from the copy. */
+        cc=nosubsec+(c-fitsdate);
+        for(C=subsec+1;*C!='\0';C++)
+          if(!isdigit(*C)) {*cc++=*C; *C='\0';}
+        *cc='\0';
       }
   while(++c<cf);
 
@@ -947,14 +961,14 @@ gal_fits_key_date_to_struct_tm(char *fitsdate, struct tm 
*tp)
         : ( usesdash
             ? ( hasT
                 ? ( hasZ
-                    ? strptime(fitsdate, hassq?"'%FT%TZ'":"%FT%TZ", tp)
-                    : strptime(fitsdate, hassq?"'%FT%T'":"%FT%T", tp) )
-                : strptime(fitsdate, hassq?"'%F'"   :"%F"   , tp))
+                    ? strptime(nosubsec, hassq?"'%FT%TZ'":"%FT%TZ", tp)
+                    : strptime(nosubsec, hassq?"'%FT%T'":"%FT%T", tp) )
+                : strptime(nosubsec, hassq?"'%F'"   :"%F"   , tp))
             : ( hasT
                 ? ( hasZ
-                    ? strptime(fitsdate, 
hassq?"'%d/%m/%yT%TZ'":"%d/%m/%yT%TZ", tp)
-                    : strptime(fitsdate, hassq?"'%d/%m/%yT%T'":"%d/%m/%yT%T", 
tp))
-                : strptime(fitsdate, hassq?"'%d/%m/%y'"   :"%d/%m/%y"   , tp)
+                    ? strptime(nosubsec, 
hassq?"'%d/%m/%yT%TZ'":"%d/%m/%yT%TZ", tp)
+                    : strptime(nosubsec, hassq?"'%d/%m/%yT%T'":"%d/%m/%yT%T", 
tp))
+                : strptime(nosubsec, hassq?"'%d/%m/%y'"   :"%d/%m/%y"   , tp)
                 )
             )
         );
@@ -977,8 +991,12 @@ gal_fits_key_date_to_struct_tm(char *fitsdate, struct tm 
*tp)
           "the years 1969 to 1999 and values 0 to 68 as the years 2000 to "
           "2068.", fitsdate);
 
+  /* If the subseconds were removed (and a new string was allocated), free
+     that extra new string. */
+  if(nosubsec!=fitsdate) free(nosubsec);
+
   /* Return the subsecond value. */
-  return c;
+  return subsec;
 }
 
 
@@ -1005,7 +1023,7 @@ gal_fits_key_date_to_seconds(char *fitsdate, char 
**subsecstr,
 
   /* If the user cared about the remainder (sub-second string), then set it
      and convert it to a double type. */
-  if(subsecstr)
+  if(subsecstr && tmp)
     {
       /* Set the output pointer. */
       *subsecstr=tmp;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]