home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / powergui / data / str2date / str2date.cpp < prev   
Text File  |  1996-10-29  |  15KB  |  343 lines

  1. //************************************************************
  2. // Data Types - Creating Dates and Times from IStrings
  3. //
  4. // Copyright (C) 1994, Law, Leong, Love, Olson, Tsuji.
  5. // Copyright (c) 1997 John Wiley & Sons, Inc. 
  6. // All Rights Reserved.
  7. //                                                                              
  8. // DESCRIPTION:                                                                 
  9. //   This program implements the dateFrom function that performs the inverse  
  10. //   of IDate::asString.  You pass in the format specifiers and the formatted 
  11. //   date, and it figures the IDate that produced the formatted string.        
  12. //                                                                              
  13. //   Usage:      str2date formatteddate formatspecifier                         
  14. //                                                                              
  15. //
  16. //************************************************************
  17. #include <istring.hpp>
  18. #include <idate.hpp>
  19. #include <iostream.h>
  20.  
  21. IDate
  22.   dateFrom( const IString &dateString, const IString &formatString );
  23.  
  24. int main ( int argc, char *argv[] )
  25.   {
  26.   int
  27.     result = 0;
  28.  
  29.   /*----------------------------------------------------------------------------
  30.   | Get input and format strings.                                              |
  31.   ----------------------------------------------------------------------------*/
  32.   if ( argc < 2 )
  33.     {
  34.     cerr << "Input date string required.\a" << endl;
  35.     return 1;
  36.     }
  37.   IString
  38.     date  ( argv[1] ),
  39.     format( argv[2] );
  40.  
  41.   /*----------------------------------------------------------------------------
  42.   | Display date obtained from input.                                          |
  43.   ----------------------------------------------------------------------------*/
  44.   IDate
  45.     fromInput = dateFrom( date, format );
  46.   IString
  47.     check;
  48.   if ( argc == 2 )
  49.     check = fromInput.asString();
  50.   else
  51.     check = fromInput.asString( format );
  52.   if ( check != date )
  53.     cout << '\a';
  54.   cout << "Date appears to be: " << fromInput.asString( "%B %d %Y" ) << endl 
  55.        << "fromInput.asString( \"" << format << "\" ) -> \"" 
  56.        << check << "\"" << endl;
  57.  
  58.   return result;
  59.   }
  60.  
  61. IDate dateFrom ( const IString &dateString, const IString &formatString )
  62.   {
  63.   IDate
  64.     result;
  65.  
  66.   /*----------------------------------------------------------------------------
  67.   | Allocate arrays of strings to hold day and month names.                    |
  68.   ----------------------------------------------------------------------------*/
  69.   IString
  70.     dayNames[ 7 ],
  71.     dNames  [ 7 ],
  72.     monNames[ 12 ],
  73.     mNames  [ 12 ];
  74.  
  75.   /*----------------------------------------------------------------------------
  76.   | Allocte private format string for use by this function.                    |
  77.   ----------------------------------------------------------------------------*/
  78.   IString
  79.     fmtString( formatString );
  80.  
  81.   /*----------------------------------------------------------------------------
  82.   | If no format string is specified, use the default.  The default is the     |
  83.   | system-specified format.  We deduce it by formating some specified date    |
  84.   | and seeing how it is layed out.                                            |
  85.   ----------------------------------------------------------------------------*/
  86.   if ( fmtString.length() == 0 )
  87.     {
  88.     IString
  89.       test = IDate( IDate::November, 23, 1984 ).asString();
  90.     if ( test.indexOf( "11" ) == 1 )
  91.       fmtString = test.overlayWith( "%m", 1 ).overlayWith( "%d", 4 );
  92.     else
  93.       fmtString = test.overlayWith( "%m", 4 ).overlayWith( "%d", 1 );
  94.     fmtString.overlayWith( "%y", 7 );
  95.     }
  96.   else
  97.     /*--------------------------------------------------------------------------
  98.     | Format string might contain month/day name specifiers, so build arrays.  |
  99.     --------------------------------------------------------------------------*/
  100.     {
  101.     if ( fmtString.includes( "%a" ) || fmtString.includes( "%A" ) )
  102.       {
  103.       IDate
  104.         aDay( IDate::October, 4, 1985 );
  105.       for ( int i = 0; i < 7; i++ )
  106.         {
  107.         dNames[ i ] = (aDay+i).asString( "%a" );
  108.         dayNames[ i ] = (aDay+i).asString( "%A" );
  109.         }
  110.       }
  111.     if ( fmtString.includes( "%b" ) || fmtString.includes( "%B" ) )
  112.       {
  113.       IDate
  114.         aDay( IDate::January, 1, 1994 );
  115.       for ( int i = 0; i < 12; i++ )
  116.         {
  117.         mNames[ i ] = aDay.asString( "%b" );
  118.         monNames[ i ] = aDay.asString( "%B" );
  119.         aDay += IDate::daysInMonth( aDay.monthOfYear(), aDay.year() );
  120.         }
  121.       }
  122.     }
  123. cerr << "fmtString=" << fmtString << endl;
  124.   /*----------------------------------------------------------------------------
  125.   | Set indices into source and format strings.                                |
  126.   ----------------------------------------------------------------------------*/
  127.   unsigned
  128.     srcIndex = 1,
  129.     fmtIndex = 1;
  130.  
  131.   /*----------------------------------------------------------------------------
  132.   | Allocate placeholders for parsed month, day, year.                         |
  133.   ----------------------------------------------------------------------------*/
  134.   int
  135.     month = 0,
  136.     day   = 0,
  137.     year  = 0;
  138.  
  139.   /*----------------------------------------------------------------------------
  140.   | Parse out conversion specifiers in fmtString.                              |
  141.   ----------------------------------------------------------------------------*/
  142.   while ( fmtIndex <= fmtString.length() )
  143.     {
  144. cerr << IString( '|' ).rightJustify( fmtIndex ) << endl;
  145. cerr << fmtString << endl;
  146. cerr << IString( '|' ).rightJustify( srcIndex ) << endl;
  147. cerr << dateString << endl;
  148.     /*--------------------------------------------------------------------------
  149.     | Find the next conversion specifier.                                      |
  150.     --------------------------------------------------------------------------*/
  151.     unsigned
  152.       next = fmtString.indexOf( '%', fmtIndex );
  153.     if ( !next )
  154.       next = fmtString.length();
  155.  
  156.     /*--------------------------------------------------------------------------
  157.     | Skip over literal text in the source string.                             |
  158.     --------------------------------------------------------------------------*/
  159.     srcIndex += next - fmtIndex;
  160.  
  161.     /*--------------------------------------------------------------------------
  162.     | Switch on next conversion specifier (if there is one).                   |
  163.     --------------------------------------------------------------------------*/
  164.     if ( next < fmtString.length() )
  165.       {
  166.       IString
  167.         remainder = dateString.subString( srcIndex );
  168. cerr << "remainder=" << remainder << endl;
  169.       switch ( fmtString[ next+1 ] )
  170.         {
  171.         /*----------------------------------------------------------------------
  172.         | Source string contents will be something like Fri or Friday.         |
  173.         | Step through days of the week, looking for a match.                  |
  174.         ----------------------------------------------------------------------*/
  175.         case 'a': 
  176.           {
  177.           for ( unsigned i = 0; i < 7; i++ )
  178.             {
  179.             if ( dNames[ i ].isAbbreviationFor( remainder ) )
  180.               {
  181.               srcIndex += dNames[ i ].length();
  182.               break;
  183.               }
  184.             }
  185.           if ( i == 7 )
  186.             cerr << "Source string doesn't match format string.\a" << endl;
  187.           break;
  188.           }
  189.         case 'A':
  190.           {
  191.           for ( unsigned i = 0; i < 7; i++ )
  192.             {
  193.             if ( dayNames[ i ].isAbbreviationFor( remainder ) )
  194.               {
  195.               srcIndex += dayNames[ i ].length();
  196.               break;
  197.               }
  198.             }
  199.           if ( i == 7 )
  200.             cerr << "Source string doesn't match format string.\a" << endl;
  201.           break;
  202.           }
  203.         /*----------------------------------------------------------------------
  204.         | Source string contents will be something like Apr or April.          |
  205.         | Step through month names, looking for a match.  If one is found,     |
  206.         | then remember what month it was as this is useful information when   |
  207.         | it comes time to figure out what the IDate result should be.         |
  208.         ----------------------------------------------------------------------*/
  209.         case 'b':
  210.           {
  211.           for ( unsigned i = 0; i < 12; i++ )
  212.             {
  213.             if ( mNames[ i ].isAbbreviationFor( remainder ) )
  214.               {
  215.               month = i + (int)IDate::January;
  216.               srcIndex += mNames[ i ].length();
  217.               break;
  218.               }
  219.             }
  220.           if ( i == 12 )
  221.             cerr << "Source string doesn't match format string.\a" << endl;
  222.           break;
  223.           }
  224.         case 'B':
  225.           {
  226.           for ( unsigned i = 0; i < 12; i++ )
  227.             {
  228.             if ( monNames[ i ].isAbbreviationFor( remainder ) )
  229.               {
  230.               month = i + (int)IDate::January;
  231.               srcIndex += monNames[ i ].length();
  232.               break;
  233.               }
  234.             }
  235.           if ( i == 12 )
  236.             cerr << "Source string doesn't match format string.\a" << endl;
  237.           break;
  238.           }
  239.         case 'c':
  240.           /*--------------------------------------------------------------------
  241.           | Source string has the full-blown date in form 90/11/24.            |
  242.           --------------------------------------------------------------------*/
  243.           year = 1900 + remainder.asInt();
  244.           month = remainder.subString( 4 ).asInt() - 1 + (int)IDate::January;
  245.           day  = remainder.subString( 7 ).asInt();
  246.           next = fmtString.length();
  247.           break;
  248.         case 'd':
  249.           /*--------------------------------------------------------------------
  250.           | Source string has the day number as a two-digit value.             |
  251.           --------------------------------------------------------------------*/
  252.           day = remainder.subString( 1, 2 ).asInt();
  253.           srcIndex += 2;
  254.           break;
  255.         case 'j':
  256.           /*--------------------------------------------------------------------
  257.           | Source string has the day of the year as a 3 digit number.         |
  258.           --------------------------------------------------------------------*/
  259.           day = 0 - remainder.subString( 1, 3 ).asInt();
  260.           srcIndex += 3;
  261.           break;
  262.         case 'm':
  263.           /*--------------------------------------------------------------------
  264.           | Source string has month as a 2 digit number.                       |
  265.           --------------------------------------------------------------------*/
  266.           month = remainder.subString( 1, 2 ).asInt() - 1 + (int)IDate::January;
  267.           srcIndex += 2;
  268.           break;
  269.         case 'U':
  270.           /*--------------------------------------------------------------------
  271.           | Source string has week number as a two digit number.               |
  272.           --------------------------------------------------------------------*/
  273.           srcIndex += 2;
  274.           break;
  275.         case 'w':
  276.           /*--------------------------------------------------------------------
  277.           | Source string has day of the week as a one digit number.           |
  278.           --------------------------------------------------------------------*/
  279.           srcIndex += 1;
  280.           break;
  281.         case 'W':
  282.           /*--------------------------------------------------------------------
  283.           | Source string has week number as two digit number.                 |
  284.           --------------------------------------------------------------------*/
  285.           srcIndex += 2;
  286.           break;
  287.         case 'x':
  288.           /*--------------------------------------------------------------------
  289.           | Source string has date in form mm/dd/yy.                           |
  290.           --------------------------------------------------------------------*/
  291.           month = remainder.asInt() - 1 + (int)IDate::January;
  292.           day  = remainder.subString( 4 ).asInt();
  293.           year = 1900 + remainder.subString( 7 ).asInt();
  294.           next = fmtString.length();
  295.           break;
  296.         case 'y':
  297.           /*--------------------------------------------------------------------
  298.           | Source string has year (since 1900) as 2 digit string.             |
  299.           --------------------------------------------------------------------*/
  300.           year = 1900 + remainder.subString( 1, 2 ).asInt();
  301.           srcIndex += 2;
  302.           break;
  303.         case 'Y':
  304.           /*--------------------------------------------------------------------
  305.           | Source string has year (since 1900) as 2 digit string.             |
  306.           --------------------------------------------------------------------*/
  307.           year = remainder.subString( 1, 4 ).asInt();
  308.           srcIndex += 4;
  309.           break;
  310.         default:
  311.           /*--------------------------------------------------------------------
  312.           | Unknown specifier, ignore it.                                      |
  313.           --------------------------------------------------------------------*/
  314.           cerr << "Unknwn specifier %" << fmtString[ next+1 ] << endl;
  315.           srcIndex += 1;
  316.           break;
  317.         }
  318.       }
  319.  
  320.     /*--------------------------------------------------------------------------
  321.     | Advance fmtString index.                                                 |
  322.     --------------------------------------------------------------------------*/
  323.     fmtIndex = next + 2;
  324.     }
  325.  
  326. cerr << "month=" << month << endl;
  327. cerr << "day  =" << day   << endl;
  328. cerr << "year =" << year  << endl;
  329.  
  330.   if ( day < 0 )
  331.     /*--------------------------------------------------------------------------
  332.     | We got day as the day within the year.                                   |
  333.     --------------------------------------------------------------------------*/
  334.     result = IDate( year, -day );
  335.   else
  336.     /*--------------------------------------------------------------------------
  337.     | Construct result from month/day/year.                                    |
  338.     --------------------------------------------------------------------------*/
  339.     result = IDate( (IDate::Month)month, day, year );
  340.  
  341.   return result;
  342.   }
  343.