Iso8601.cpp

/*

** Author: Samuel R. Blackburn   (http://www.codeproject.com/library/wfc.asp)

** Internet: wfc@pobox.com

**

** You can use it any way you like as long as you don't try to sell it.

**

** Any attempt to sell WFC in source code form must have the permission

** of the original author. You can produce commercial executables with

** WFC but you can't sell WFC.

**

** Copyright, 2000, Samuel R. Blackburn

**

** $Workfile: wfc_parse_iso_8601_string.cpp $

** $Revision: 7 $

** $Modtime: 1/24/00 6:11p $

** $Reuse Tracing Code: 1 $

*/

 

/****************************************************************************/

/**                                                                        **/

/** Modified 2005 by Diodia Software            (http://www.diodia.com/)   **/

/**                                                                        **/

/****************************************************************************/

#include "stdafx.h"

 

#include "RssHelpers.h"

 

static BOOL __parse_ymdhms( LPCTSTR time_string,

                            int&    year,

                            int&    month,

                            int&    day,

                            int&    hours,

                            int&    minutes,

                            int&    seconds,

                            TCHAR&  offset_character,

                            int&    offset_hours,

                            int&    offset_minutes )

{

   // Here's a sample ISO8601 date string

   //

   // 1969-07-20T22:56:15-04:00

 

   // Do a little idiot checking

 

   if ( time_string == NULL )

      return( FALSE );

 

   // Start with some believable defaults

 

   year             = 0;

   month            = 1;

   day              = 1;

   hours            = 0;

   minutes          = 0;

   seconds          = 0;

   offset_character = TEXT( 'Z' );

   offset_hours     = 0;

   offset_minutes   = 0;

 

   // We were passed a pointer, don't trust it

 

   try

   {

      if ( _tcslen( time_string ) < 4 )

      {

         // There ain't enough characters to even attempt to parse

         return( FALSE );

      }

 

      // OK, let's start parsing

 

      if ( _istdigit( time_string[ 0 ] ) == 0 )

      {

         // First character is not a digit

         return( FALSE );

      }

 

      if ( _istdigit( time_string[ 1 ] ) == 0 )

      {

         // Second character is not a digit

         return( FALSE );

      }

 

      if ( _istdigit( time_string[ 2 ] ) == 0 )

      {

         // Third character is not a digit"

         return( FALSE );

      }

 

      if ( _istdigit( time_string[ 3 ] ) == 0 )

      {

         // Fourth character is not a digit

         return( FALSE );

      }

 

      // If we get here, it means we've got 4 good digits

 

      TCHAR temp_string[ 5 ];

 

      temp_string[ 0 ] = time_string[ 0 ];

      temp_string[ 1 ] = time_string[ 1 ];

      temp_string[ 2 ] = time_string[ 2 ];

      temp_string[ 3 ] = time_string[ 3 ];

      temp_string[ 4 ] = 0x00;

 

      year = _ttoi( temp_string );

 

      DWORD index = 4;

 

      // index should be pointing here

      //     |

      //     v

      // 1969-07-20T22:56:15-04:00

 

      if ( time_string[ index ] == 0x00 )

      {

         // We're at the end of the string

 

         return( TRUE );

      }

 

      if ( time_string[ index ] != TEXT( '-' ) )

      {

         // The separator between year and month is not -

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //      |

      //      v

      // 1969-07-20T22:56:15-04:00

 

      if ( time_string[ index ] == 0x00 )

      {

         // We're at the end of the string

         return( TRUE );

      }

 

      if ( _istdigit( time_string[ index ] ) == 0 )

      {

         // First digit of month field isn't a digit at all

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //       |

      //       v

      // 1969-07-20T22:56:15-04:00

 

      // This test is safe because we could be sitting on a NULL

 

      if ( _istdigit( time_string[ index ] ) == 0 )

      {

         // Second digit of month field isn't a digit at all

         return( FALSE );

      }

 

      temp_string[ 0 ] = time_string[ index - 1 ];

      temp_string[ 1 ] = time_string[ index ];

      temp_string[ 2 ] = 0x00;

 

      month = _ttoi( temp_string );

 

      // Do a little idiot proofing

 

      if ( month < 1 || month > 12 )

      {

         // Funky month

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //        |

      //        v

      // 1969-07-20T22:56:15-04:00

 

      if ( time_string[ index ] == 0x00 )

      {

         return( TRUE );

      }

 

      if ( time_string[ index ] != TEXT( '-' ) )

      {

         // The separator between month and day fields is not -

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //         |

      //         v

      // 1969-07-20T22:56:15-04:00

 

      if ( time_string[ index ] == 0x00 )

      {

         // Odd, but not illegal

         return( TRUE );

      }

 

      if ( _istdigit( time_string[ index ] ) == 0 )

      {

         // First digit of day field isn't a digit at all

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //          |

      //          v

      // 1969-07-20T22:56:15-04:00

 

      // This test is safe because we could be sitting on a NULL

 

      if ( _istdigit( time_string[ index ] ) == 0 )

      {

         // Second digit of month field isn't a digit at all

         return( FALSE );

      }

 

      temp_string[ 0 ] = time_string[ index - 1 ];

      temp_string[ 1 ] = time_string[ index ];

 

      // We don't need to set temp_string[ 2 ] because we did that at line 158 above

 

      day = _ttoi( temp_string );

 

      // Do a very little bit of error checking

 

      if ( day < 1 || day > 31 )

      {

         // Funky day

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //           |

      //           v

      // 1969-07-20T22:56:15-04:00

 

      if ( time_string[ index ] == 0x00 )

      {

         // Odd, but not illegal

         return( TRUE );

      }

 

      if ( time_string[ index ] != TEXT( 'T' ) )

      {

         // Separator between date and time ain't T

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //            |

      //            v

      // 1969-07-20T22:56:15-04:00

 

      if ( time_string[ index ] == 0x00 )

      {

         // Odd, but not illegal

         return( TRUE );

      }

 

      if ( _istdigit( time_string[ index ] ) == 0 )

      {

         // First digit of hours field isn't a digit at all

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //             |

      //             v

      // 1969-07-20T22:56:15-04:00

 

      // This test is safe because we could be sitting on a NULL

 

      if ( _istdigit( time_string[ index ] ) == 0 )

      {

         // Second digit of month field isn't a digit at all

         return( FALSE );

      }

 

      temp_string[ 0 ] = time_string[ index - 1 ];

      temp_string[ 1 ] = time_string[ index ];

 

      // We don't need to set temp_string[ 2 ] because we did that at line 158 above

 

      hours = _ttoi( temp_string );

 

      index++;

 

      // index should be pointing here

      //              |

      //              v

      // 1969-07-20T22:56:15-04:00

 

      if ( time_string[ index ] == 0x00 )

      {

         // Odd, but not illegal

         return( TRUE );

      }

 

      if ( time_string[ index ] != TEXT( ':' ) )

      {

         // Separator between hours and minutes ain't :

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //               |

      //               v

      // 1969-07-20T22:56:15-04:00

 

      if ( time_string[ index ] == 0x00 )

      {

         // Odd, but not illegal

         return( TRUE );

      }

 

      if ( _istdigit( time_string[ index ] ) == 0 )

      {

         // First digit of time ain't no digit

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //                |

      //                v

      // 1969-07-20T22:56:15-04:00

 

      if ( _istdigit( time_string[ index ] ) == 0 )

      {

         // First digit of time ain't no digit

         return( FALSE );

      }

 

      temp_string[ 0 ] = time_string[ index - 1 ];

      temp_string[ 1 ] = time_string[ index ];

 

      minutes = _ttoi( temp_string );

 

      index++;

 

      // index should be pointing here

      //                 |

      //                 v

      // 1969-07-20T22:56:15-04:00

 

      if ( time_string[ index ] == 0x00 )

      {

         return( TRUE );

      }

 

      if ( time_string[ index ] != TEXT( ':' ) )

      {

         // Separator between minutes and seconds ain't :

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //                  |

      //                  v

      // 1969-07-20T22:56:15-04:00

 

      if ( time_string[ index ] == 0x00 )

      {

         // Odd, but not illegal

         return( TRUE );

      }

 

      if ( _istdigit( time_string[ index ] ) == 0 )

      {

         // First digit of seconds ain't no digit

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //                   |

      //                   v

      // 1969-07-20T22:56:15-04:00

 

      if ( _istdigit( time_string[ index ] ) == 0 )

      {

         // Second digit of seconds ain't no digit

         return( FALSE );

      }

 

      temp_string[ 0 ] = time_string[ index - 1 ];

      temp_string[ 1 ] = time_string[ index ];

 

      seconds = _ttoi( temp_string );

 

      index++;

 

      // index should be pointing here

      //                    |

      //                    v

      // 1969-07-20T22:56:15-04:00

 

      if ( time_string[ index ] == 0x00 ||

           time_string[ index ] == TEXT( 'Z' ) )

      {

         return( TRUE );

      }

 

      // OK, now is the time when parsing gets interesting

      // The current index may be sitting on a partial second.

      // Since CTime can't deal with partial seconds, we

      // will just skip that part entirely.

 

      if ( time_string[ index ] == TEXT( '.' ) )

      {

         index++;

 

         BOOL exit_loop = FALSE;

 

         while( exit_loop == FALSE )

         {

            if ( time_string[ index ] == 0x00 )

            {

               return( TRUE );

            }

 

            if ( _istdigit( time_string[ index ] ) == 0 )

            {

               exit_loop = TRUE;

            }

            else

            {

               index++;

            }

         }

      }

 

      // If we get here, we should be sitting on a Z, + or -

 

      if ( time_string[ index ] == TEXT( 'Z' ) )

      {

         return( TRUE );

      }

 

      if ( time_string[ index ] != TEXT( '+' ) &&

           time_string[ index ] != TEXT( '-' ) )

      {

         // Time zone designator ain't beginning with + or -

         return( FALSE );

      }

 

      offset_character = time_string[ index ];

 

      index++;

 

      // index should be pointing here

      //                     |

      //                     v

      // 1969-07-20T22:56:15-04:00

 

      if ( _istdigit( time_string[ index ] ) == 0 )

      {

         // first digit of hours offset ain't a digit

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //                      |

      //                      v

      // 1969-07-20T22:56:15-04:00

 

      if ( _istdigit( time_string[ index ] ) == 0 )

      {

         // second digit of hours offset ain't a digit

         return( FALSE );

      }

 

      temp_string[ 0 ] = time_string[ index - 1 ];

      temp_string[ 1 ] = time_string[ index ];

 

      offset_hours = _ttoi( temp_string );

 

      index++;

 

      // index should be pointing here

      //                       |

      //                       v

      // 1969-07-20T22:56:15-04:00

 

      if ( time_string[ index ] != TEXT( ':' ) )

      {

         // Separator between offset hours and minutes ain't a :

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //                        |

      //                        v

      // 1969-07-20T22:56:15-04:00

 

      if ( _istdigit( time_string[ index ] ) == 0 )

      {

         // First digit of minutes offset ain't a digit

         return( FALSE );

      }

 

      index++;

 

      // index should be pointing here

      //                        |

      //                        v

      // 1969-07-20T22:56:15-04:00

 

      if ( _istdigit( time_string[ index ] ) == 0 )

      {

         // Second digit of minutes offset ain't a digit

         return( FALSE );

      }

 

      temp_string[ 0 ] = time_string[ index - 1 ];

      temp_string[ 1 ] = time_string[ index ];

 

      offset_minutes = _ttoi( temp_string );

 

      return( TRUE );

   }

   catch( ... )

   {

      return( FALSE );

   }

}

 

BOOL wfc_parse_iso_8601_string( LPCTSTR time_string, FILETIME& the_time )

{

   the_time.dwHighDateTime = 0;

   the_time.dwLowDateTime = 0;

 

   SYSTEMTIME system_time;

 

   if ( wfc_parse_iso_8601_string( time_string, system_time ) == FALSE )

   {

      return( FALSE );

   }

 

   SystemTimeToFileTime(&system_time, &the_time);

 

   return( TRUE );

}

 

BOOL wfc_parse_iso_8601_string( LPCTSTR time_string, COleDateTime& the_time )

{

   the_time = COleDateTime( static_cast< time_t >( 0 ) );

 

   // Do a little idiot checking

 

   if ( time_string == NULL )

   {

      // time_string is NULL!

      return( FALSE );

   }

 

   int year    = 0;

   int month   = 0;

   int day     = 0;

   int hours   = 0;

   int minutes = 0;

   int seconds = 0;

 

   TCHAR offset_character = 0;

 

   int offset_hours   = 0;

   int offset_minutes = 0;

 

   if ( __parse_ymdhms( time_string, year, month, day, hours, minutes, seconds, offset_character, offset_hours, offset_minutes ) == FALSE )

   {

      // Can't parse string

      return( FALSE );

   }

 

   the_time = COleDateTime( year, month, day, hours, minutes, seconds );

 

   if ( offset_character != TEXT( 'Z' ) )

   {

      COleDateTimeSpan time_zone_offset( 0, offset_hours, offset_minutes, 0 );

 

      if ( offset_character == TEXT( '-' ) )

      {

         the_time += time_zone_offset;

      }

      else if ( offset_character == TEXT( '+' ) )

      {

         the_time -= time_zone_offset;

      }

   }

 

   return( TRUE );

}

 

BOOL wfc_parse_iso_8601_string( LPCTSTR time_string, SYSTEMTIME& the_time )

{

  

   the_time.wYear         = 0;

   the_time.wMonth        = 0;

   the_time.wDay          = 0;

   the_time.wDayOfWeek    = 0;

   the_time.wHour         = 0;

   the_time.wMinute       = 0;

   the_time.wSecond       = 0;

   the_time.wMilliseconds = 0;

 

   // Do a little idiot checking

 

   if ( time_string == NULL )

   {

      // time_string is NULL!

      return( FALSE );

   }

 

   int year    = 0;

   int month   = 0;

   int day     = 0;

   int hours   = 0;

   int minutes = 0;

   int seconds = 0;

 

   TCHAR offset_character = 0;

 

   int offset_hours   = 0;

   int offset_minutes = 0;

 

   if ( __parse_ymdhms( time_string, year, month, day, hours, minutes, seconds, offset_character, offset_hours, offset_minutes ) == FALSE )

   {

      // Can't parse string

      return( FALSE );

   }

 

   CTime ole_time = CTime( year, month, day, hours, minutes, seconds );

 

   if ( offset_character != TEXT( 'Z' ) )

   {

      CTimeSpan time_zone_offset( 0, offset_hours, offset_minutes, 0 );

 

      if ( offset_character == TEXT( '-' ) )