format: Make fmt_date_template() human-friendly, respect field width.
authorBen Pfaff <blp@cs.stanford.edu>
Tue, 17 Jul 2012 06:36:30 +0000 (23:36 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Tue, 17 Jul 2012 14:09:57 +0000 (07:09 -0700)
The strings that fmt_date_template() returned were almost but not
quite the kind of strings that humans expect to see.  For one, they
always used "yy", even though the code uses 4-digit years ("yyyy")
when the field width is sufficient.  Similarly, they never included
seconds (i.e. omitted ":SS").  Finally, FMT_MOYR had an "X" where
one would expect a space.

This commit corrects all of the above issues.  Future commits will
make more use of fmt_date_template().

src/data/data-in.c
src/data/data-out.c
src/data/format.c
src/data/format.h

index e72d1b6ad4e1fd45ff5026f301bd3ee034e4b4b3..14a24fffe26d367497e9262fd9daa1a0709a68c0 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -1123,7 +1123,7 @@ parse_date (struct data_in *i)
   double time = 0, date = 0;
   enum time_sign time_sign = SIGN_NO_TIME;
 
-  const char *template = fmt_date_template (i->format);
+  const char *template = fmt_date_template (i->format, 0);
   size_t template_width = strlen (template);
   char *error;
 
@@ -1180,14 +1180,18 @@ parse_date (struct data_in *i)
         case '-':
         case '/':
         case '.':
-        case 'X':
           error = parse_date_delimiter (i);
           break;
         case ':':
           error = parse_time_delimiter (i);
         case ' ':
-          parse_spaces (i);
-          error = NULL;
+          if (i->format != FMT_MOYR)
+            {
+              parse_spaces (i);
+              error = NULL;
+            }
+          else
+            error = parse_date_delimiter (i);
           break;
         default:
           assert (count == 1);
index df447a6a12cac594c38937725030767c44d7999e..2a0dd0a19528bab246f1366963189ae82526c925 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2011, 2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -387,14 +387,11 @@ output_date (const union value *input, const struct fmt_spec *format,
   double number = input->f;
   int year, month, day, yday;
 
-  const char *template = fmt_date_template (format->type);
-  size_t template_width = strlen (template);
-  int excess_width = format->w - template_width;
+  const char *template = fmt_date_template (format->type, format->w);
 
   char tmp[64];
   char *p = tmp;
 
-  assert (format->w >= template_width);
   if (number == SYSMIS)
     goto missing;
 
@@ -411,6 +408,8 @@ output_date (const union value *input, const struct fmt_spec *format,
 
   while (*template != '\0')
     {
+      int excess_width;
+
       int ch = *template;
       int count = 1;
       while (template[count] == ch)
@@ -439,7 +438,7 @@ output_date (const union value *input, const struct fmt_spec *format,
             }
           break;
         case 'y':
-          if (count >= 4 || excess_width >= 2)
+          if (count >= 4)
             {
               if (year <= 9999)
                 p += sprintf (p, "%04d", year);
@@ -499,10 +498,7 @@ output_date (const union value *input, const struct fmt_spec *format,
                 }
               p += strlen (p);
             }
-          break;
-        case 'X':
-          *p++ = ' ';
-          break;
+          goto done;
         default:
           assert (count == 1);
           *p++ = ch;
@@ -510,6 +506,7 @@ output_date (const union value *input, const struct fmt_spec *format,
         }
     }
 
+ done:
   buf_copy_lpad (output, format->w, tmp, p - tmp, ' ');
   output[format->w] = '\0';
   return;
index dc546af84577e41917220635a20a3c3f8fd3438a..58e16d3075a4249080db940efcb1e7dd7285c938 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2010, 2011, 2012 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -881,38 +881,81 @@ fmt_usable_for_input (enum fmt_type type)
   return fmt_get_category (type) != FMT_CAT_CUSTOM;
 }
 
-/* For time and date formats, returns a template used for input
-   and output. */
+/* For time and date formats, returns a template used for input and output in a
+   field of the given WIDTH.
+
+   WIDTH only affects whether a 2-digit year or a 4-digit year is used, that
+   is, whether the returned string contains "yy" or "yyyy", and whether seconds
+   are include, that is, whether the returned string contains ":SS".  A caller
+   that doesn't care whether the returned string contains "yy" or "yyyy" or
+   ":SS" can just specify 0 to omit them. */
 const char *
-fmt_date_template (enum fmt_type type)
+fmt_date_template (enum fmt_type type, int width)
 {
+  const char *s1, *s2;
+
   switch (type)
     {
     case FMT_DATE:
-      return "dd-mmm-yy";
+      s1 = "dd-mmm-yy";
+      s2 = "dd-mmm-yyyy";
+      break;
+
     case FMT_ADATE:
-      return "mm/dd/yy";
+      s1 = "mm/dd/yy";
+      s2 = "mm/dd/yyyy";
+      break;
+
     case FMT_EDATE:
-      return "dd.mm.yy";
+      s1 = "dd.mm.yy";
+      s2 = "dd.mm.yyyy";
+      break;
+
     case FMT_JDATE:
-      return "yyddd";
+      s1 = "yyddd";
+      s2 = "yyyyddd";
+      break;
+
     case FMT_SDATE:
-      return "yy/mm/dd";
+      s1 = "yy/mm/dd";
+      s2 = "yyyy/mm/dd";
+      break;
+
     case FMT_QYR:
-      return "q Q yy";
+      s1 = "q Q yy";
+      s2 = "q Q yyyy";
+      break;
+
     case FMT_MOYR:
-      return "mmmXyy";
+      s1 = "mmm yy";
+      s2 = "mmm yyyy";
+      break;
+
     case FMT_WKYR:
-      return "ww WK yy";
+      s1 = "ww WK yy";
+      s2 = "ww WK yyyy";
+      break;
+
     case FMT_DATETIME:
-      return "dd-mmm-yyyy HH:MM";
+      s1 = "dd-mmm-yyyy HH:MM";
+      s2 = "dd-mmm-yyyy HH:MM:SS";
+      break;
+
     case FMT_TIME:
-      return "H:MM";
+      s1 = "H:MM";
+      s2 = "H:MM:SS";
+      break;
+
     case FMT_DTIME:
-      return "D HH:MM";
+      s1 = "D HH:MM";
+      s2 = "D HH:MM:SS";
+      break;
+
     default:
       NOT_REACHED ();
     }
+
+  return width >= strlen (s2) ? s2 : s1;
 }
 
 /* Returns a string representing the format TYPE for use in a GUI dialog. */
index 1744becccc68c91cb79881f269227a6923b1d179..def3cdc3f7a02eb3745f75bfe03c4a610d836f94 100644 (file)
@@ -134,7 +134,7 @@ bool fmt_usable_for_input (enum fmt_type) PURE_FUNCTION;
 int fmt_to_io (enum fmt_type) PURE_FUNCTION;
 bool fmt_from_io (int io, enum fmt_type *);
 
-const char *fmt_date_template (enum fmt_type) PURE_FUNCTION;
+const char *fmt_date_template (enum fmt_type, int width) PURE_FUNCTION;
 const char *fmt_gui_name (enum fmt_type);
 \f
 /* Format settings.