?? RIGHT := 110 ??
?? NEWTITLE := 'NOS/VE SCL : Conversions between the "binary" and string forms for dates and times.' ??
MODULE clm$date_time_conversion;

{
{ PURPOSE:
{   This module contains the requests CLP$CONVERT_DATE_TIME_TO_STRING,
{   CLP$CONVERT_STRING_TO_DATE_TIME, etc.  These requests handle the
{   transformation between the myriad formats for date and time data.
{

?? NEWTITLE := 'Global declarations', EJECT ??
?? PUSH (LISTEXT := ON) ??
*copyc cle$ecc_date_time_format
*copyc clt$date_or_time
*copyc clt$date_time
*copyc clt$date_time_form_string
*copyc clt$day_and_month_names
*copyc clt$name
*copyc ose$message_gen_exceptions
*copyc oss$job_paged_literal
*copyc ost$date
*copyc ost$day_of_week
*copyc ost$name
*copyc ost$status
*copyc ost$string
*copyc ost$time
*copyc ost$time_zone
*copyc pmt$time_increment
?? POP ??
*copyc clp$convert_integer_to_string
*copyc clp$evaluate_unsigned_decimal
*IF NOT $true(osv$unix)
*copyc clp$find_help_module
*IFEND
*copyc clp$find_day_and_month_names
*copyc clp$get_day_and_month_names
*copyc clp$initialize_parse_state
*copyc clp$scan_lexical_unit
*copyc clp$trimmed_string_size
*copyc clp$validate_name
*copyc clv$day_and_month_names_list
*copyc clv$english_day_and_month_names
*copyc clv$non_decimal_digit
*copyc clv$non_space
*IF NOT $true(osv$unix)
*copyc osp$find_natural_language
*copyc osp$find_parameter_prompt
*copyc osp$generate_log_message
*ELSE
*copyc clt$parameter_name
*copyc ost$natural_language
*IFEND
*copyc osp$set_status_abnormal
*copyc osv$lower_to_upper
*copyc pmp$compute_day_of_week
*copyc pmp$get_compact_date_time
*copyc pmp$get_default_date_time_form
*copyc pmp$get_time_zone
*IF NOT $true(osv$unix)
*copyc pmp$log
*IFEND
*copyc pmp$this_is_a_leap_year
?? EJECT ??

  TYPE
    clt$large_dt_form_string = string ( * <= clc$max_date_time_form_string + 3);

  CONST
    clc$max_day_name = 9,
    clc$max_month_name = 9;


  VAR
    clv$last_day_of_month: [STATIC, READ, oss$job_paged_literal] array [1 .. 12] of
          28 .. 31 := [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

  VAR
    clv$cumulative_days: [STATIC, READ, oss$job_paged_literal] array [0 .. 12] of
          0 .. 365 := [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365];

  VAR
    clv$cumulative_leap_days: [STATIC, READ, oss$job_paged_literal] array [0 .. 12] of
          0 .. 366 := [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366];

  VAR
    clv$right_paren: [STATIC, READ, oss$job_paged_literal] packed array [char] of boolean := [
          {---} REP 41 of FALSE, { ) } TRUE, {---} REP 214 of FALSE];

  VAR
    clv$non_international_letter: [STATIC, READ, oss$job_paged_literal] packed array [char] of boolean := [
          {---} REP 65 of TRUE, {A..Z} REP 26 of FALSE, { [ } FALSE, { \ } FALSE, { ] } FALSE, { ^ } FALSE,
    {---}
    REP 2 of TRUE, {a..z} REP 26 of FALSE, { { } FALSE, { | } FALSE, { } FALSE, { ~ } FALSE,
          {---} REP 129 of TRUE];

  VAR
    clv$non_date_time_separator: [STATIC, READ, oss$job_paged_literal] packed array [char] of boolean := [
          {---} REP 32 of TRUE, {   } FALSE, {---} REP 11 of TRUE, { , } FALSE, { - } FALSE, { . } FALSE,
    { / }
    FALSE, {---} REP 10 of TRUE, { : } FALSE, {---} REP 36 of TRUE, { _ } FALSE, {---} REP 160 of TRUE];

  TYPE
    clt$date_time_pieces = (clc$undefined, clc$mn_lang, clc$mn, clc$ma_lang, clc$ma, clc$m2, clc$dn_lang,
          clc$dn, clc$da_lang, clc$da, clc$d2, clc$y2, clc$y4, clc$year, clc$j3, clc$dot, clc$hyphen,
          clc$comma, clc$colon, clc$space, clc$slash, clc$date_name, clc$date_number, clc$h24, clc$h12,
          clc$mm, clc$ss, clc$s10, clc$s100, clc$s1000, clc$month, clc$mdy, clc$dmy, clc$isod, clc$ordinal,
          clc$amorpm, clc$millisecond, clc$tz, clc$tz_lang, clc$tza, clc$tza_lang),

    clt$date_time_set = set of clt$date_time_pieces;

  TYPE
    clt$ampm_specification = (clc$no_ampm, clc$am, clc$pm);

  TYPE
    clt$hours_specification = (clc$hours_12, clc$hours_24);

  CONST
    dst_string = 'DAYLIGHT_SAVING_TIME',
    dst_string_length = 20,
    st_string = 'STANDARD_TIME',
    st_string_length = 13,
    clc$max_time_string = 12,
    clc$max_date_string = 18,
    clc$time_substring = 8,
    clc$max_date_or_time_pieces = 7,
    clc$max_total_date_time_pieces = (clc$max_date_or_time_pieces * 2) + 1 + 10,
    {+ 10 for extraneous separators that a user might decide to throw in.}
    clc$max_built_in_formats = 15;

  TYPE
    clt$input_format = record
      piece: array [1 .. clc$max_total_date_time_pieces] of clt$date_time_pieces,
      size: array [1 .. clc$max_total_date_time_pieces] of 0 .. 31,
      index: array [1 .. clc$max_total_date_time_pieces] of 0 .. 255,
    recend;

  TYPE
    clt$format_types = record
      num_of_elements: 1 .. clc$max_date_or_time_pieces,
      date_or_time: clt$date_or_time,
      elements: array [1 .. clc$max_date_or_time_pieces] of clt$date_time_pieces,
      format: array [1 .. clc$max_date_or_time_pieces] of clt$date_time_pieces,
    recend;

?? FMT (FORMAT := OFF) ??

  VAR
    built_in_formats: [STATIC, READ, oss$job_paged_literal] array [1 .. clc$max_built_in_formats] of
      clt$format_types := [
         [7, clc$time,
         [clc$date_number, clc$colon, clc$date_number, clc$colon, clc$date_number, clc$dot,
          clc$date_number],
         [clc$h24, clc$colon, clc$mm, clc$colon, clc$ss, clc$dot, clc$s1000]],
         [7, clc$time,
         [clc$date_number, clc$dot, clc$date_number, clc$dot, clc$date_number, clc$comma, clc$date_number],
         [clc$h24, clc$dot, clc$mm, clc$dot, clc$ss, clc$comma, clc$s100]],
         [5, clc$time,
         [clc$date_number, clc$colon, clc$date_number, clc$space, clc$date_name, clc$undefined,
          clc$undefined],
         [clc$h12, clc$colon, clc$mm, clc$space, clc$amorpm, clc$undefined, clc$undefined]],
         [5, clc$time,
         [clc$date_number, clc$colon, clc$date_number, clc$colon, clc$date_number, clc$undefined,
          clc$undefined],
         [clc$h24, clc$colon, clc$mm, clc$colon, clc$ss, clc$undefined, clc$undefined]],
         [5, clc$date,
         [clc$date_name, clc$space, clc$date_number, clc$comma, clc$date_number, clc$undefined,
          clc$undefined],
         [clc$mn, clc$space, clc$d2, clc$comma, clc$year, clc$undefined, clc$undefined]],
         [5, clc$date,
         [clc$date_number, clc$space, clc$date_name, clc$space, clc$date_number, clc$undefined,
          clc$undefined],
         [clc$d2, clc$space, clc$mn, clc$space, clc$year, clc$undefined, clc$undefined]],
         [5, clc$date,
         [clc$date_number, clc$hyphen, clc$date_name, clc$hyphen, clc$date_number, clc$undefined,
          clc$undefined],
         [clc$d2, clc$hyphen, clc$mn, clc$hyphen, clc$year, clc$undefined, clc$undefined]],
         [5, clc$date,
         [clc$date_number, clc$slash, clc$date_number, clc$slash, clc$date_number, clc$undefined,
          clc$undefined],
         [clc$m2, clc$slash, clc$d2, clc$slash, clc$year, clc$undefined, clc$undefined]],
         [5, clc$date,
         [clc$date_number, clc$hyphen, clc$date_number, clc$hyphen, clc$date_number, clc$undefined,
          clc$undefined],
         [clc$year, clc$hyphen, clc$m2, clc$hyphen, clc$d2, clc$undefined, clc$undefined]],
         [5, clc$date,
         [clc$date_number, clc$dot, clc$date_number, clc$dot, clc$date_number, clc$undefined,
          clc$undefined],
         [clc$d2, clc$dot, clc$m2, clc$dot, clc$year, clc$undefined, clc$undefined]],
         [3, clc$date,
         [clc$date_number, clc$date_name, clc$date_number, clc$undefined, clc$undefined, clc$undefined,
          clc$undefined],
         [clc$d2, clc$mn, clc$year, clc$undefined, clc$undefined, clc$undefined, clc$undefined]],
         [3, clc$date,
         [clc$date_number, clc$date_number, clc$date_number, clc$undefined, clc$undefined, clc$undefined,
          clc$undefined],
         [clc$year, clc$m2, clc$d2, clc$undefined, clc$undefined, clc$undefined, clc$undefined]],
         [3, clc$date,
         [clc$date_number, clc$hyphen, clc$date_number, clc$undefined, clc$undefined, clc$undefined,
          clc$undefined],
         [clc$year, clc$hyphen, clc$j3, clc$undefined, clc$undefined, clc$undefined, clc$undefined]],
         [1, clc$date,
         [clc$date_number, clc$undefined, clc$undefined, clc$undefined, clc$undefined, clc$undefined,
          clc$undefined],
         [clc$undefined, clc$undefined, clc$undefined, clc$undefined, clc$undefined, clc$undefined,
          clc$undefined]],
         [1, clc$date,
         [clc$date_name, clc$undefined, clc$undefined, clc$undefined, clc$undefined, clc$undefined,
          clc$undefined],
         [clc$undefined, clc$undefined, clc$undefined, clc$undefined, clc$undefined, clc$undefined,
          clc$undefined]]];

?? FMT (FORMAT := ON) ??
?? TITLE := 'interpret_language', EJECT ??

  PROCEDURE [INLINE] interpret_language
    (    format_string: clt$large_dt_form_string;
         start_index: 0 .. clc$max_date_time_form_string;
     VAR language_size: 0 .. 31;
     VAR status: ost$status);

    VAR
      name_ok: boolean,
      separator_index: integer,
      separator_found: boolean,
      valid_language: ost$natural_language;


    status.normal := TRUE;

    name_ok := FALSE;
    separator_index := 0;
    separator_found := FALSE;
    valid_language := '';

    #SCAN (clv$right_paren, format_string (start_index, * ), separator_index, separator_found);
    IF NOT separator_found THEN
      osp$set_status_abnormal ('CL', cle$language_delimiter_missing, '', status);
      RETURN;
    IFEND;
    language_size := separator_index - 1;
    clp$validate_name (format_string (start_index, language_size), valid_language, name_ok);
    IF NOT name_ok THEN
      osp$set_status_abnormal ('CL', ose$bad_natural_language, format_string (start_index, language_size),
            status);
    IFEND;

  PROCEND interpret_language;
?? TITLE := 'convert_integer_to_rj_string', EJECT ??

  CONST
    max_digits_to_convert_to_string = 4;

?? SKIP := 3 ??

  PROCEDURE [INLINE] convert_integer_to_rj_string
    (    intger: integer;
         fill_character: char;
     VAR strng: string ( * <= max_digits_to_convert_to_string));

    VAR
      int: integer,
      length: 0 .. max_digits_to_convert_to_string,
      i: integer;


    int := intger;
    length := STRLENGTH (strng);

    REPEAT
      strng (length) := $CHAR ((int MOD 10) + $INTEGER ('0'));
      length := length - 1;
      int := int DIV 10;
    UNTIL (int = 0);

    FOR i := 1 TO length DO
      strng (i) := fill_character;
    FOREND;

  PROCEND convert_integer_to_rj_string;
?? TITLE := 'read_format_string', EJECT ??

  PROCEDURE read_format_string
    (    format_string: clt$date_time_form_string;
     VAR format_data: clt$input_format;
     VAR array_index: integer;
     VAR leading_zeroes: boolean;
     VAR need_preferred_language: boolean;
     VAR status: ost$status);

    VAR
      char_found: boolean,
      char_position: integer,
      date_format: string (clc$max_date_time_form_string + 3),
      {Make sure there is room in the date_format to look past end.}
      format_length: integer,
      ignore_status: ost$status,
      language: ost$natural_language,
      language_start: integer,
      log_status: ost$status;


    status.normal := TRUE;

    char_found := FALSE;
    char_position := 0;
    date_format := '';
    format_length := clp$trimmed_string_size (format_string);
    language_start := 0;
    leading_zeroes := TRUE;
    need_preferred_language := FALSE;

    #TRANSLATE (osv$lower_to_upper, format_string, date_format);

    #SCAN (clv$non_space, date_format, char_position, char_found);
    IF NOT char_found THEN
      osp$set_status_abnormal ('CL', cle$date_time_format_null, format_string, status);
    IFEND;

{ Step through format string to see what version of the date and time is
{wanted.}

    array_index := 0;
    REPEAT
      array_index := array_index + 1;

      IF date_format (char_position, 2) = 'MS' THEN
        format_data.piece [array_index] := clc$h24;
        format_data.piece [array_index + 1] := clc$colon;
        format_data.piece [array_index + 2] := clc$mm;
        format_data.piece [array_index + 3] := clc$colon;
        format_data.piece [array_index + 4] := clc$ss;
        format_data.piece [array_index + 5] := clc$dot;
        format_data.piece [array_index + 6] := clc$s1000;
        array_index := array_index + 6;
        char_position := char_position + 2;

      ELSEIF date_format (char_position, 11) = 'MILLISECOND' THEN
        format_data.piece [array_index] := clc$h24;
        format_data.piece [array_index + 1] := clc$colon;
        format_data.piece [array_index + 2] := clc$mm;
        format_data.piece [array_index + 3] := clc$colon;
        format_data.piece [array_index + 4] := clc$ss;
        format_data.piece [array_index + 5] := clc$dot;
        format_data.piece [array_index + 6] := clc$s1000;
        array_index := array_index + 6;
        char_position := char_position + 11;

      ELSEIF date_format (char_position, 3) = 'HMS' THEN
        format_data.piece [array_index] := clc$h24;
        format_data.piece [array_index + 1] := clc$colon;
        format_data.piece [array_index + 2] := clc$mm;
        format_data.piece [array_index + 3] := clc$colon;
        format_data.piece [array_index + 4] := clc$ss;
        array_index := array_index + 4;
        char_position := char_position + 3;

      ELSEIF date_format (char_position, 4) = 'AMPM' THEN
        format_data.piece [array_index] := clc$h12;
        format_data.piece [array_index + 1] := clc$colon;
        format_data.piece [array_index + 2] := clc$mm;
        format_data.piece [array_index + 3] := clc$space;
        format_data.piece [array_index + 4] := clc$amorpm;
        array_index := array_index + 4;
        char_position := char_position + 4;

      ELSEIF date_format (char_position, 6) = 'AMORPM' THEN
        format_data.piece [array_index] := clc$amorpm;
        char_position := char_position + 6;

      ELSEIF date_format (char_position, 4) = 'ISOT' THEN
        format_data.piece [array_index] := clc$h24;
        format_data.piece [array_index + 1] := clc$dot;
        format_data.piece [array_index + 2] := clc$mm;
        format_data.piece [array_index + 3] := clc$dot;
        format_data.piece [array_index + 4] := clc$ss;
        format_data.piece [array_index + 5] := clc$comma;
        format_data.piece [array_index + 6] := clc$s100;
        array_index := array_index + 6;
        char_position := char_position + 4;

      ELSEIF date_format (char_position, 4) = 'ISOD' THEN
        format_data.piece [array_index] := clc$y4;
        format_data.piece [array_index + 1] := clc$hyphen;
        format_data.piece [array_index + 2] := clc$m2;
        format_data.piece [array_index + 3] := clc$hyphen;
        format_data.piece [array_index + 4] := clc$d2;
        array_index := array_index + 4;
        char_position := char_position + 4;

      ELSEIF date_format (char_position, 7) = 'ORDINAL' THEN
        format_data.piece [array_index] := clc$y4;
        format_data.piece [array_index + 1] := clc$j3;
        array_index := array_index + 1;
        char_position := char_position + 7;

      ELSEIF date_format (char_position) = 'D' THEN
        char_position := char_position + 1;

        IF date_format (char_position) = '2' THEN
          format_data.piece [array_index] := clc$d2;
          char_position := char_position + 1;

        ELSEIF date_format (char_position) = 'N' THEN
          IF date_format (char_position + 1) = '(' THEN
            format_data.index [array_index] := char_position + 2; {Beginning of language string.}
            interpret_language (date_format, format_data.index [array_index], format_data.size [array_index],
                  status);
            IF NOT status.normal THEN
              RETURN;
            IFEND;
            char_position := format_data.index [array_index] + format_data.size [array_index] + 1;
            format_data.piece [array_index] := clc$dn_lang;

          ELSE
            need_preferred_language := TRUE;
            format_data.piece [array_index] := clc$dn;
            char_position := char_position + 1;
          IFEND;

        ELSEIF date_format (char_position) = 'A' THEN
          IF date_format (char_position + 1) = '(' THEN
            format_data.index [array_index] := char_position + 2; {Beginning of language string.}
            interpret_language (date_format, format_data.index [array_index], format_data.size [array_index],
                  status);
            IF NOT status.normal THEN
              RETURN;
            IFEND;
            char_position := format_data.index [array_index] + format_data.size [array_index] + 1;
            format_data.piece [array_index] := clc$da_lang;

          ELSE
            need_preferred_language := TRUE;
            format_data.piece [array_index] := clc$da;
            char_position := char_position + 1;
          IFEND

        ELSEIF date_format (char_position, 2) = 'MY' THEN
{Format is DMY}
          format_data.piece [array_index] := clc$d2;
          format_data.piece [array_index + 1] := clc$dot;
          format_data.piece [array_index + 2] := clc$m2;
          format_data.piece [array_index + 3] := clc$dot;
          format_data.piece [array_index + 4] := clc$y2;
          array_index := array_index + 4;
          char_position := char_position + 2;

        ELSE
          osp$set_status_abnormal ('CL', cle$unexpected_dt_format_char, date_format (char_position - 1, 2),
                status);
          RETURN;
        IFEND;

      ELSEIF date_format (char_position) = 'M' THEN
        char_position := char_position + 1;

        IF date_format (char_position) = '2' THEN
          format_data.piece [array_index] := clc$m2;
          char_position := char_position + 1;

        ELSEIF date_format (char_position) = 'N' THEN
          IF date_format (char_position + 1) = '(' THEN
            format_data.index [array_index] := char_position + 2; {Beginning of language string.}
            interpret_language (date_format, format_data.index [array_index], format_data.size [array_index],
                  status);
            IF NOT status.normal THEN
              RETURN;
            IFEND;
            char_position := format_data.index [array_index] + format_data.size [array_index] + 1;
            format_data.piece [array_index] := clc$mn_lang;

          ELSE
            need_preferred_language := TRUE;
            format_data.piece [array_index] := clc$mn;
            char_position := char_position + 1;
          IFEND;

          IF (date_format (char_position) = ' ') OR (date_format (char_position) = '-') THEN
            leading_zeroes := FALSE;
          IFEND;

        ELSEIF date_format (char_position) = 'A' THEN
          IF date_format (char_position + 1) = '(' THEN
            format_data.index [array_index] := char_position + 2; {Beginning of language string.}
            interpret_language (date_format, format_data.index [array_index], format_data.size [array_index],
                  status);
            IF NOT status.normal THEN
              RETURN;
            IFEND;
            char_position := format_data.index [array_index] + format_data.size [array_index] + 1;
            format_data.piece [array_index] := clc$ma_lang;

          ELSE
            need_preferred_language := TRUE;
            format_data.piece [array_index] := clc$ma;
            char_position := char_position + 1;
          IFEND;

          IF (date_format (char_position) = ' ') OR (date_format (char_position) = '-') THEN
            leading_zeroes := FALSE;
          IFEND;

        ELSEIF date_format (char_position, 2) = 'DY' THEN
{Format is MDY}
          format_data.piece [array_index] := clc$m2;
          format_data.piece [array_index + 1] := clc$slash;
          format_data.piece [array_index + 2] := clc$d2;
          format_data.piece [array_index + 3] := clc$slash;
          format_data.piece [array_index + 4] := clc$y2;
          array_index := array_index + 4;
          char_position := char_position + 2;

        ELSEIF date_format (char_position, 4) = 'ONTH' THEN
{Format is MONTH}
          format_data.piece [array_index] := clc$mn;
          format_data.piece [array_index + 1] := clc$space;
          format_data.piece [array_index + 2] := clc$d2;
          format_data.piece [array_index + 3] := clc$comma;
          format_data.piece [array_index + 4] := clc$y4;
          array_index := array_index + 4;
          char_position := char_position + 4;
          need_preferred_language := TRUE;
          leading_zeroes := FALSE;

        ELSEIF date_format (char_position) = 'M' THEN
          format_data.piece [array_index] := clc$mm;
          char_position := char_position + 1;

        ELSE
          osp$set_status_abnormal ('CL', cle$unexpected_dt_format_char, date_format (char_position - 1, 2),
                status);
          RETURN;
        IFEND;

      ELSEIF date_format (char_position) = 'T' THEN
        char_position := char_position + 1;

        IF date_format (char_position) = 'Z' THEN
          IF date_format (char_position + 1) = 'A' THEN
            IF date_format (char_position + 2) = '(' THEN
              format_data.index [array_index] := char_position + 3; {Beginning of language string.}
              interpret_language (date_format, format_data.index [array_index],
                    format_data.size [array_index], status);
              IF NOT status.normal THEN
                RETURN;
              IFEND;
              char_position := format_data.index [array_index] + format_data.size [array_index] + 1;
              format_data.piece [array_index] := clc$tza_lang;

            ELSE
              need_preferred_language := TRUE;
              format_data.piece [array_index] := clc$tza;
              char_position := char_position + 2;
            IFEND;

          ELSEIF date_format (char_position + 1) = '(' THEN
            format_data.index [array_index] := char_position + 2; {Beginning of language string.}
            interpret_language (date_format, format_data.index [array_index], format_data.size [array_index],
                  status);
            IF NOT status.normal THEN
              RETURN;
            IFEND;
            char_position := format_data.index [array_index] + format_data.size [array_index] + 1;
            format_data.piece [array_index] := clc$tz_lang;

          ELSE
            need_preferred_language := TRUE;
            format_data.piece [array_index] := clc$tz;
            char_position := char_position + 1;
          IFEND;

        ELSE
          osp$set_status_abnormal ('CL', cle$unexpected_dt_format_char, date_format (char_position - 1, 2),
                status);
          RETURN;
        IFEND;

      ELSEIF date_format (char_position) = 'H' THEN
        char_position := char_position + 1;

        IF date_format (char_position, 2) = '12' THEN
          format_data.piece [array_index] := clc$h12;
          char_position := char_position + 2;

        ELSEIF date_format (char_position, 2) = '24' THEN
          format_data.piece [array_index] := clc$h24;
          char_position := char_position + 2;

        ELSE
          osp$set_status_abnormal ('CL', cle$unexpected_dt_format_char, date_format (char_position - 1, 2),
                status);
          RETURN;
        IFEND;

      ELSEIF date_format (char_position) = 'Y' THEN
        char_position := char_position + 1;

        IF date_format (char_position) = '2' THEN
          format_data.piece [array_index] := clc$y2;
          char_position := char_position + 1;

        ELSEIF date_format (char_position) = '4' THEN
          format_data.piece [array_index] := clc$y4;
          char_position := char_position + 1;

        ELSE
          osp$set_status_abnormal ('CL', cle$unexpected_dt_format_char, date_format (char_position - 1, 2),
                status);
          RETURN;
        IFEND;

      ELSEIF date_format (char_position) = 'S' THEN
        char_position := char_position + 1;

        IF date_format (char_position) = 'S' THEN
          format_data.piece [array_index] := clc$ss;
          char_position := char_position + 1;

        ELSEIF date_format (char_position) = '1' THEN
          IF date_format (char_position + 3) = '0' THEN
            format_data.piece [array_index] := clc$s1000;
            char_position := char_position + 3;

          ELSEIF date_format (char_position + 2) = '0' THEN
            format_data.piece [array_index] := clc$s100;
            char_position := char_position + 2;

          ELSEIF date_format (char_position + 1) = '0' THEN
            format_data.piece [array_index] := clc$s10;
            char_position := char_position + 1;
          IFEND;

        ELSE
          osp$set_status_abnormal ('CL', cle$unexpected_dt_format_char, date_format (char_position - 1, 2),
                status);
          RETURN;
        IFEND;

      ELSEIF date_format (char_position, 2) = 'J3' THEN
        format_data.piece [array_index] := clc$j3;
        char_position := char_position + 2;

      ELSEIF date_format (char_position) = '-' THEN
        format_data.piece [array_index] := clc$hyphen;
        char_position := char_position + 1;

      ELSEIF date_format (char_position) = ' ' THEN
        format_data.piece [array_index] := clc$space;
        WHILE (date_format (char_position) = ' ') AND (char_position < format_length) DO
          char_position := char_position + 1;
        WHILEND;

      ELSEIF date_format (char_position) = '/' THEN
        format_data.piece [array_index] := clc$slash;
        char_position := char_position + 1;

      ELSEIF date_format (char_position) = ':' THEN
        format_data.piece [array_index] := clc$colon;
        char_position := char_position + 1;

      ELSEIF date_format (char_position) = '.' THEN
        format_data.piece [array_index] := clc$dot;
        char_position := char_position + 1;

      ELSEIF date_format (char_position) = ',' THEN
        IF (array_index > 1) AND (format_data.piece [array_index - 1] = clc$space) THEN
          array_index := array_index - 1;
        IFEND;
        format_data.piece [array_index] := clc$comma;
        char_position := char_position + 1;
        WHILE (date_format (char_position) = ' ') AND (char_position < format_length) DO
          char_position := char_position + 1;
        WHILEND;

      ELSE
        osp$set_status_abnormal ('CL', cle$unexpected_dt_format_char, date_format (char_position), status);
        RETURN;
      IFEND;
    UNTIL (char_position >= format_length);

    IF format_data.piece [array_index] = clc$space THEN
      array_index := array_index - 1;
    IFEND;

  PROCEND read_format_string;
?? TITLE := 'compare_format_arrays', EJECT ??

  PROCEDURE [INLINE] compare_format_arrays
    (    input_format: clt$input_format;
     VAR piece_index: 1 .. clc$max_total_date_time_pieces;
     VAR matching_index: 1 .. clc$max_built_in_formats;
     VAR status: ost$status);

    VAR
      index: 1 .. clc$max_date_or_time_pieces + 1,
      temp_matching_index: 1 .. clc$max_built_in_formats + 1,
      temp_piece: 1 .. clc$max_total_date_time_pieces;


    status.normal := TRUE;
    matching_index := 1;
    temp_matching_index := 1;
    index := 1;

    IF piece_index > clc$max_total_date_time_pieces THEN
      osp$set_status_abnormal ('CL', cle$unknown_date_time_format, '', status);
      RETURN;
    IFEND;

    WHILE temp_matching_index <= clc$max_built_in_formats DO
      temp_piece := piece_index;

    /check_formats/
      WHILE TRUE DO
        IF index > built_in_formats [temp_matching_index].num_of_elements THEN
          piece_index := piece_index + built_in_formats [temp_matching_index].num_of_elements;
          matching_index := temp_matching_index;
          RETURN;
        ELSEIF input_format.piece [temp_piece] <> built_in_formats [temp_matching_index].elements [index] THEN
          EXIT /check_formats/;
        ELSE
          temp_piece := temp_piece + 1;
          index := index + 1;
        IFEND;
      WHILEND /check_formats/;

      index := 1;
      temp_matching_index := temp_matching_index + 1;
    WHILEND;

    osp$set_status_abnormal ('CL', cle$unknown_date_time_format, '', status);

  PROCEND compare_format_arrays;
?? TITLE := 'clp$convert_string_to_date_time', EJECT ??
*copyc clh$convert_string_to_date_time

  PROCEDURE [XDCL, #GATE] clp$convert_string_to_date_time
    (    str: string ( * );
         format: clt$date_time_form_string;
     VAR date_time: clt$date_time;
     VAR status: ost$status);

    VAR
      am_pm: string (2),
      ampm_spec: clt$ampm_specification,
      char_position: integer,
      date_name: string (clc$max_date_string),
      language: ost$natural_language,
      end_index: integer,
      fill_match: integer, {fill_match holds position in format_data array}
      format_index: integer,
      found: boolean,
      hours_spec: clt$hours_specification,
      temp_data: integer,
      i: integer,
      count: integer,
      j3: integer,
      j3_specified: boolean,
      leading_zeroes: boolean,
      log_status: ost$status,
      format_data: clt$input_format,
      {} {holds date_time format extracted from built_in_formats}
            matching_index: 1 .. clc$max_built_in_formats,
      {} {matching_index indicates matching format in built_in_formats}
            need_preferred_language: boolean,
      piece_index: 1 .. clc$max_total_date_time_pieces,
      {} {piece_index keeps track of location in str_format}
            preferred_language: ost$natural_language,
      selected_language: ^ost$natural_language,
      str_format: clt$input_format,
      str_length: integer,
      today: ost$date_time;

?? NEWTITLE := 'interpret_input_string', EJECT ??

    PROCEDURE interpret_input_string
      (VAR status: ost$status);

?? NEWTITLE := 'shift_str_format_array', EJECT ??

      PROCEDURE [INLINE] shift_str_format_array
        (    size: integer);


{Shift everything in the array over one position to the right.}
        FOR i := clc$max_total_date_time_pieces DOWNTO piece_index + 1 + 1 DO
          str_format.piece [i] := str_format.piece [i - 1];
          str_format.size [i] := str_format.size [i - 1];
          str_format.index [i] := str_format.index [i - 1];
        FOREND;

        str_format.piece [piece_index + 1] := clc$date_number;
        str_format.size [piece_index + 1] := str_format.size [piece_index] - size;
        str_format.index [piece_index + 1] := str_format.index [piece_index] + size;

        str_format.size [piece_index] := size;
        {Index and type of piece for first piece is OK}

      PROCEND shift_str_format_array;
?? OLDTITLE, EJECT ??

      piece_index := 1;
      FOR format_index := 1 TO count DO
        CASE format_data.piece [format_index] OF

        = clc$h12 =
          clp$evaluate_unsigned_decimal (str (str_format.index [piece_index], str_format.size [piece_index]),
                temp_data, status);
          IF NOT status.normal THEN
            RETURN;
          ELSEIF (temp_data < 1) OR (temp_data > 12) OR (date_time.time_specified) THEN
            osp$set_status_abnormal ('CL', cle$impossible_date_or_time, str, status);
            RETURN;
          IFEND;
          hours_spec := clc$hours_12;
          date_time.time_specified := TRUE;
          date_time.value.hour := temp_data;
          piece_index := piece_index + 1;

        = clc$h24 =
          IF (format_index + 1 <= count) AND (str_format.size [piece_index] > 2) THEN
            shift_str_format_array (2);
          IFEND;
          clp$evaluate_unsigned_decimal (str (str_format.index [piece_index], str_format.size [piece_index]),
                temp_data, status);
          IF NOT status.normal THEN
            RETURN;
          ELSEIF (temp_data < 0) OR (temp_data > 23) OR (date_time.time_specified) THEN
            osp$set_status_abnormal ('CL', cle$impossible_date_or_time, str, status);
            RETURN;
          IFEND;
          hours_spec := clc$hours_24;
          date_time.time_specified := TRUE;
          date_time.value.hour := temp_data;
          piece_index := piece_index + 1;

        = clc$s10 =
          clp$evaluate_unsigned_decimal (str (str_format.index [piece_index], str_format.size [piece_index]),
                temp_data, status);
          IF NOT status.normal THEN
            RETURN;
          ELSEIF (temp_data < 0) OR (temp_data > 9) THEN
            osp$set_status_abnormal ('CL', cle$impossible_date_or_time, str, status);
            RETURN;
          IFEND;
          date_time.time_specified := TRUE;
          date_time.value.millisecond := temp_data * 100;
          piece_index := piece_index + 1;

        = clc$s100 =
          clp$evaluate_unsigned_decimal (str (str_format.index [piece_index], str_format.size [piece_index]),
                temp_data, status);
          IF NOT status.normal THEN
            RETURN;
          ELSEIF (temp_data < 0) OR (temp_data > 99) THEN
            osp$set_status_abnormal ('CL', cle$impossible_date_or_time, str, status);
            RETURN;
          IFEND;
          date_time.time_specified := TRUE;
          date_time.value.millisecond := temp_data * 10;
          piece_index := piece_index + 1;

        = clc$s1000 =
          clp$evaluate_unsigned_decimal (str (str_format.index [piece_index], str_format.size [piece_index]),
                temp_data, status);
          IF NOT status.normal THEN
            RETURN;
          ELSEIF (temp_data < 0) OR (temp_data > 999) THEN
            osp$set_status_abnormal ('CL', cle$impossible_date_or_time, str, status);
            RETURN;
          IFEND;
          date_time.time_specified := TRUE;
          date_time.value.millisecond := temp_data;
          piece_index := piece_index + 1;

        = clc$mm =
          IF (format_index + 1 <= count) AND (str_format.size [piece_index] > 2) THEN
            shift_str_format_array (2);
          IFEND;
          clp$evaluate_unsigned_decimal (str (str_format.index [piece_index], str_format.size [piece_index]),
                temp_data, status);
          IF NOT status.normal THEN
            RETURN;
          ELSEIF (temp_data < 0) OR (temp_data > 59) THEN
            osp$set_status_abnormal ('CL', cle$impossible_date_or_time, str, status);
            RETURN;
          IFEND;
          date_time.time_specified := TRUE;
          date_time.value.minute := temp_data;
          piece_index := piece_index + 1;

        = clc$ss =
          IF (format_index + 1 <= count) AND (str_format.size [piece_index] > 2) THEN
            shift_str_format_array (2);
          IFEND;
          clp$evaluate_unsigned_decimal (str (str_format.index [piece_index], str_format.size [piece_index]),
                temp_data, status);
          IF NOT status.normal THEN
            RETURN;
          ELSEIF (temp_data < 0) OR (temp_data > 59) THEN
            osp$set_status_abnormal ('CL', cle$impossible_date_or_time, str, status);
            RETURN;
          IFEND;
          date_time.time_specified := TRUE;
          date_time.value.second := temp_data;
          piece_index := piece_index + 1;

        = clc$d2 =
          IF str_format.piece [piece_index] <> clc$date_number THEN
            osp$set_status_abnormal ('CL', cle$unknown_date_time_format, str, status);
            RETURN;
          IFEND;

          IF (format_index + 1 <= count) AND (str_format.size [piece_index] > 2) THEN
            shift_str_format_array (2);
          IFEND;

          clp$evaluate_unsigned_decimal (str (str_format.index [piece_index], str_format.size [piece_index]),
                temp_data, status);
          IF NOT status.normal THEN
            RETURN;
          ELSEIF (temp_data < 1) OR (temp_data > 31) THEN
            osp$set_status_abnormal ('CL', cle$impossible_date_or_time, str, status);
            RETURN;
          IFEND;
          date_time.value.day := temp_data;
          piece_index := piece_index + 1;

        = clc$dn, clc$da, clc$dn_lang, clc$da_lang =
{When converting a string to a date time, the day of the week is irrelevant information.
{No processing needs to take place except for some checking.
          IF (str_format.piece [piece_index] <> clc$date_name) THEN
            osp$set_status_abnormal ('CL', cle$unknown_date_time_format, str, status);
            RETURN;
          IFEND;
          piece_index := piece_index + 1;

        = clc$mn, clc$ma =
          IF str_format.piece [piece_index] <> clc$date_name THEN
            osp$set_status_abnormal ('CL', cle$unknown_date_time_format, str, status);
            RETURN;
          IFEND;
          #TRANSLATE (osv$lower_to_upper, str (str_format.index [piece_index], str_format.size [piece_index]),
                date_name);
          get_month_number (preferred_language, status);
          IF NOT status.normal THEN
            RETURN;
          IFEND;
          piece_index := piece_index + 1;

        = clc$ma_lang, clc$mn_lang =
          IF str_format.piece [piece_index] <> clc$date_name THEN
            osp$set_status_abnormal ('CL', cle$unknown_date_time_format, str, status);
            RETURN;
          IFEND;
          #TRANSLATE (osv$lower_to_upper, str (str_format.index [piece_index], str_format.size [piece_index]),
                date_name);
          language := format (format_data.index [format_index], format_data.size [format_index]);
          get_month_number (language, status);
          IF NOT status.normal THEN
            RETURN;
          IFEND;
          piece_index := piece_index + 1;

        = clc$m2 =
          IF str_format.piece [piece_index] <> clc$date_number THEN
            osp$set_status_abnormal ('CL', cle$unknown_date_time_format, str, status);
            RETURN;
          IFEND;

          IF (format_index + 1 <= count) AND (str_format.size [piece_index] > 2) THEN
            shift_str_format_array (2);
          IFEND;

          clp$evaluate_unsigned_decimal (str (str_format.index [piece_index], str_format.size [piece_index]),
                temp_data, status);
          IF NOT status.normal THEN
            RETURN;
          ELSEIF (temp_data < 1) OR (temp_data > 12) THEN
            osp$set_status_abnormal ('CL', cle$impossible_date_or_time, str, status);
            RETURN;
          IFEND;
          date_time.value.month := temp_data;
          piece_index := piece_index + 1;

        = clc$y2, clc$y4, clc$year =
          IF (str_format.piece [piece_index] <> clc$date_number) OR (date_time.date_specified) THEN
            osp$set_status_abnormal ('CL', cle$unknown_date_time_format, str, status);
            RETURN;
          IFEND;

          {Check to see if one of the 'all number' formats has been given.}
          IF format_index + 1 <= count THEN
            IF (format_data.piece [format_index] = clc$y4) AND (str_format.size [piece_index] > 4) THEN
              shift_str_format_array (4);
            ELSEIF (format_data.piece [format_index] = clc$y2) AND (str_format.size [piece_index] > 6) THEN
{Assume that the format is the MAIL/VE required format of Y2M2D2H24MMSS.}
              shift_str_format_array (2);
            ELSEIF (format_data.piece [format_index] = clc$y2) AND (str_format.size [piece_index] > 2) THEN
              shift_str_format_array (2);
            ELSEIF format_data.piece [format_index] = clc$year THEN {One of the built_in formats.}
              CASE str_format.size [piece_index] OF
              = 5, 6 =
                shift_str_format_array (2);

              = 7, 8 =
                shift_str_format_array (4);

              ELSE
                ;
              CASEND;
            IFEND;
          IFEND;

          clp$evaluate_unsigned_decimal (str (str_format.index [piece_index], str_format.size [piece_index]),
                temp_data, status);
          IF NOT status.normal THEN
            RETURN;
          ELSEIF (temp_data >= 0) AND (temp_data <= 99) THEN
            date_time.value.year := temp_data;

{ This code allows NOS/VE to work until the year 2079.  It is neccessary because
{ otherwise the year value will be off by 100 years.

            IF (temp_data < 80) THEN
              date_time.value.year := date_time.value.year + 100;
            IFEND;
          ELSEIF (temp_data >= 1900) AND (temp_data <= 2155) THEN
            date_time.value.year := temp_data - 1900;
          ELSE
            osp$set_status_abnormal ('CL', cle$impossible_date_or_time, str, status);
            RETURN;
          IFEND;
          date_time.date_specified := TRUE;
          piece_index := piece_index + 1;

        = clc$j3 =
          IF str_format.piece [piece_index] <> clc$date_number THEN
            osp$set_status_abnormal ('CL', cle$unknown_date_time_format, str, status);
            RETURN;
          IFEND;

          IF (format_index + 1 <= count) AND (str_format.size [piece_index] > 3) THEN
            shift_str_format_array (3);
          IFEND;

          j3_specified := TRUE;
          j3 := piece_index;
          piece_index := piece_index + 1;

        = clc$amorpm =
          #TRANSLATE (osv$lower_to_upper, str (str_format.index [piece_index], 2), am_pm);
          IF am_pm = 'AM' THEN
            ampm_spec := clc$am;
          ELSEIF am_pm = 'PM' THEN
            ampm_spec := clc$pm;
          ELSE
            osp$set_status_abnormal ('CL', cle$impossible_date_or_time, str, status);
            RETURN;
          IFEND;
          piece_index := piece_index + 1;

        = clc$tz, clc$tz_lang, clc$tza, clc$tza_lang =
{If a time zone is present in the string, the date_time is not modified.}
          piece_index := piece_index + 1;

        = clc$slash, clc$dot, clc$hyphen, clc$colon, clc$comma, clc$space =
          piece_index := piece_index + 1;
          {don't need to do anything

        ELSE
          osp$set_status_abnormal ('CL', cle$unknown_date_time_format, '', status);
          RETURN;
        CASEND;
      FOREND;

    PROCEND interpret_input_string;
?? TITLE := 'get_month_number', EJECT ??

    PROCEDURE [INLINE] get_month_number
      (    language: ost$natural_language;
       VAR status: ost$status);

      VAR
        ignore_status: ost$status,
        days_and_months_ptr: ^clt$day_and_month_names,
        month: string (clc$max_date_string),
        using_english: boolean;


      days_and_months_ptr := NIL;
      month := '';
      using_english := FALSE;

      clp$find_day_and_month_names (language, days_and_months_ptr);
      IF days_and_months_ptr = NIL THEN
        clp$get_day_and_month_names (language, days_and_months_ptr, status);
        IF NOT status.normal THEN
*IF NOT $true(osv$unix)
          osp$generate_log_message ($pmt$ascii_logset [pmc$job_log, pmc$system_log], status, ignore_status);
*IFEND
          status.normal := TRUE;
          IF preferred_language = '' THEN
*IF NOT $true(osv$unix)
            osp$find_natural_language (selected_language);
            preferred_language := selected_language^;
*ELSE
            preferred_language := osc$english;
*IFEND
          IFEND;
          IF preferred_language <> language THEN
            clp$get_day_and_month_names (preferred_language, days_and_months_ptr, status);
            IF NOT status.normal THEN
*IF NOT $true(osv$unix)
              osp$generate_log_message ($pmt$ascii_logset [pmc$job_log, pmc$system_log], status,
                    ignore_status);
*IFEND
              status.normal := TRUE;
              days_and_months_ptr := ^clv$english_day_and_month_names;
              using_english := TRUE;
            IFEND;
          ELSE
            days_and_months_ptr := ^clv$english_day_and_month_names;
            using_english := TRUE;
          IFEND;
        IFEND;
      IFEND;

    /find_month/
      WHILE TRUE DO
        FOR i := 1 TO 12 DO
          #TRANSLATE (osv$lower_to_upper, days_and_months_ptr^.months [i].value, month);
          IF date_name = month THEN
            date_time.value.month := i;
            RETURN;
          ELSE
            #TRANSLATE (osv$lower_to_upper, days_and_months_ptr^.months_abbrev [i].value, month);
            IF date_name = month THEN
              date_time.value.month := i;
              RETURN;
            IFEND;
          IFEND;
        FOREND;
        IF using_english THEN
{ English is what we just looked at - give up.}
          EXIT /find_month/;
        IFEND;
        days_and_months_ptr := ^clv$english_day_and_month_names;
        using_english := TRUE;
      WHILEND /find_month/;

      osp$set_status_abnormal ('CL', cle$name_not_month_or_day, date_name, status);

    PROCEND get_month_number;
?? OLDTITLE, EJECT ??

    status.normal := TRUE;

    am_pm := '';
    ampm_spec := clc$no_ampm;
    char_position := 0;
    count := 0;
    date_name := '';
    language := '';
    end_index := 0;
    found := FALSE;
    hours_spec := clc$hours_12;
    j3 := 0;
    j3_specified := FALSE;
    leading_zeroes := TRUE;
    matching_index := 1;
    need_preferred_language := FALSE;
    piece_index := 1;
    preferred_language := '';
    str_length := STRLENGTH (str);
    temp_data := 0;

    {Initialize date_time variable.}
    date_time.value.year := 0;
    date_time.value.month := 1;
    date_time.value.day := 1;
    date_time.value.hour := 0;
    date_time.value.minute := 0;
    date_time.value.second := 0;
    date_time.value.millisecond := 0;
    date_time.date_specified := FALSE;
    date_time.time_specified := FALSE;

    {Initialize str_format variable.}
    FOR i := 1 TO clc$max_total_date_time_pieces DO
      str_format.piece [i] := clc$undefined;
      str_format.size [i] := 0;
      str_format.index [i] := 0;
    FOREND;

    {Initialize format_data variable.}
    FOR i := 1 TO clc$max_total_date_time_pieces DO
      format_data.piece [i] := clc$undefined;
      format_data.size [i] := 0;
      format_data.index [i] := 0;
    FOREND;

{Read input string to get data on date pieces.}

    #SCAN (clv$non_space, str, char_position, found);
    IF NOT found THEN
      osp$set_status_abnormal ('CL', cle$impossible_date_or_time, '"NULL STRING"', status);
      RETURN;
    IFEND;

    REPEAT
      count := count + 1;
      IF count > clc$max_total_date_time_pieces THEN
        osp$set_status_abnormal ('CL', cle$date_time_string_too_long, str, status);
        RETURN;
      IFEND;

      CASE str (char_position) OF
      = 'A' .. 'Z', 'a' .. 'z' =
        #SCAN (clv$non_international_letter, str (char_position, * ), end_index, found);
        str_format.size [count] := end_index - 1;
        str_format.index [count] := char_position;
        str_format.piece [count] := clc$date_name;
        char_position := char_position + end_index - 1;
      = '0' .. '9' =
        #SCAN (clv$non_decimal_digit, str (char_position, * ), end_index, found);
        str_format.piece [count] := clc$date_number;
        str_format.size [count] := end_index - 1;
        str_format.index [count] := char_position;
        char_position := char_position + end_index - 1;
      = ' ' =
        #SCAN (clv$non_space, str (char_position, * ), end_index, found);
        str_format.piece [count] := clc$space;
        str_format.size [count] := end_index - 1;
        str_format.index [count] := char_position;
        char_position := char_position + end_index - 1;
      = '/' =
        str_format.piece [count] := clc$slash;
        str_format.size [count] := 1;
        str_format.index [count] := char_position;
        char_position := char_position + 1;
      = ':' =
        str_format.piece [count] := clc$colon;
        str_format.size [count] := 1;
        str_format.index [count] := char_position;
        char_position := char_position + 1;
      = '.' =
        str_format.piece [count] := clc$dot;
        str_format.size [count] := 1;
        str_format.index [count] := char_position;
        char_position := char_position + 1;
      = ',' =
        IF (count > 1) AND (str_format.piece [count - 1] = clc$space) THEN
          #SCAN (clv$non_space, str (char_position + 1, * ), end_index, found);
          str_format.piece [count - 1] := clc$comma;
          str_format.size [count - 1] := end_index;
          str_format.index [count - 1] := char_position;
          char_position := char_position + end_index;
          count := count - 1;
        ELSE
          #SCAN (clv$non_space, str (char_position + 1, * ), end_index, found);
          str_format.piece [count] := clc$comma;
          str_format.size [count] := end_index;
          str_format.index [count] := char_position;
          char_position := char_position + end_index;
        IFEND;
      = '-' =
        str_format.piece [count] := clc$hyphen;
        str_format.size [count] := 1;
        str_format.index [count] := char_position;
        char_position := char_position + 1;
      ELSE
        osp$set_status_abnormal ('CL', cle$unexpected_dt_format_char, str (char_position), status);
        RETURN;
      CASEND;

    UNTIL (char_position > str_length);

    count := 0;
    fill_match := 1;
    piece_index := 1;

    IF format = '' THEN
      {If no format is supplied check data gathered above to determine}
      {format of input string.}
      need_preferred_language := TRUE;
      WHILE (piece_index <= clc$max_total_date_time_pieces) AND
            (str_format.piece [piece_index] <> clc$undefined) DO
        WHILE str_format.piece [piece_index] IN $clt$date_time_set
              [clc$space, clc$comma, clc$dot, clc$colon, clc$hyphen, clc$slash] DO
          piece_index := piece_index + 1;
          format_data.piece [fill_match] := clc$space;
          fill_match := fill_match + 1;
          count := count + 1;
        WHILEND;
        compare_format_arrays (str_format, piece_index, matching_index, status);
        IF NOT status.normal THEN
          RETURN;
        ELSEIF (built_in_formats [matching_index].elements [1] = clc$date_number) AND
              (built_in_formats [matching_index].format [1] = clc$undefined) THEN
          CASE str_format.size [piece_index - 1] OF
          = 5 =
            format_data.piece [fill_match] := clc$y2;
            format_data.piece [fill_match + 1] := clc$j3;
            fill_match := fill_match + 2;
            count := count + 2;
          = 6 =
            format_data.piece [fill_match] := clc$y2;
            format_data.piece [fill_match + 1] := clc$m2;
            format_data.piece [fill_match + 2] := clc$d2;
            fill_match := fill_match + 3;
            count := count + 3;
          = 7 =
            format_data.piece [fill_match] := clc$y4;
            format_data.piece [fill_match + 1] := clc$j3;
            fill_match := fill_match + 2;
            count := count + 2;
          = 8 =
            format_data.piece [fill_match] := clc$y4;
            format_data.piece [fill_match + 1] := clc$m2;
            format_data.piece [fill_match + 2] := clc$d2;
            fill_match := fill_match + 3;
            count := count + 3;
          ELSE
            ;
          CASEND;
        ELSEIF (built_in_formats [matching_index].elements [1] = clc$date_name) AND
              (built_in_formats [matching_index].format [1] = clc$undefined) THEN
          format_data.piece [fill_match] := clc$dn;
          fill_match := fill_match + 1;
          count := count + 1;
        ELSE
          i := 1;
          WHILE (i <= clc$max_date_or_time_pieces) AND (built_in_formats [matching_index].format [i] <>
                clc$undefined) DO
            format_data.piece [fill_match] := built_in_formats [matching_index].format [i];
            i := i + 1;
            fill_match := fill_match + 1;
            count := count + 1;
          WHILEND;
        IFEND;
      WHILEND;
    ELSE
      {If format is supplied call routine that interprets it.}
      read_format_string (format, format_data, count, leading_zeroes, need_preferred_language, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
    IFEND;

    FOR i := 1 TO piece_index - 1 DO
      IF format_data.piece [i] = clc$undefined THEN
        osp$set_status_abnormal ('CL', cle$unknown_date_time_format, format, status);
        RETURN;
      IFEND;
    FOREND;

    IF need_preferred_language THEN
*IF NOT $true(osv$unix)
      osp$find_natural_language (selected_language);
      preferred_language := selected_language^;
*ELSE
      preferred_language := osc$english;
*IFEND
    IFEND;

    {Read input string and determine contents based on format}
    {that was either deduced or supplied.}

    interpret_input_string (status);

    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF (hours_spec = clc$hours_12) THEN
      IF (ampm_spec = clc$pm) THEN
        IF date_time.value.hour <> 12 THEN
          date_time.value.hour := date_time.value.hour + 12;
        IFEND;
      ELSEIF ampm_spec = clc$am THEN
        IF date_time.value.hour = 12 THEN
          date_time.value.hour := 0;
        IFEND;
      IFEND;
    IFEND;

    IF j3_specified THEN
      i := 1;
      clp$evaluate_unsigned_decimal (str (str_format.index [j3], str_format.size [j3]), temp_data, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      IF NOT (pmp$this_is_a_leap_year (date_time.value.year + 1900)) THEN
        WHILE (i <= UPPERBOUND (clv$cumulative_days)) AND (temp_data > clv$cumulative_days [i]) DO
          i := i + 1;
        WHILEND;
        temp_data := temp_data - clv$cumulative_days [i - 1];
      ELSE
        WHILE (i <= UPPERBOUND (clv$cumulative_leap_days)) AND (temp_data > clv$cumulative_leap_days [i]) DO
          i := i + 1;
        WHILEND;
        temp_data := temp_data - clv$cumulative_leap_days [i - 1];
      IFEND;
      date_time.value.month := i;
      date_time.value.day := temp_data;

    IFEND;

    clp$validate_date_time (date_time, str, status);

  PROCEND clp$convert_string_to_date_time;
?? TITLE := 'clp$convert_date_time_to_string', EJECT ??
*copyc clh$convert_date_time_to_string

  PROCEDURE [XDCL, #GATE] clp$convert_date_time_to_string
    (    date_time: clt$date_time;
         format: clt$date_time_form_string;
     VAR str: ost$string;
     VAR status: ost$status);

    VAR
      adjust: integer,
      count: integer,
      char_position: integer,
      day_name: clt$name,
      date_str: ost$string,
      default_date_format: ost$default_date_format,
      default_date_format_size: integer,
      default_time_format: ost$default_time_format,
      default_time_format_size: integer,
      default_format_string: string (clc$max_date_time_form_string),
      format_data: clt$input_format,
      format_index: integer,
      format_length: integer,
      format_string: ^clt$date_time_form_string,
      found: boolean,
      hour: integer,
      identifier: ost$string,
      language: ost$natural_language,
      converted_language: ost$natural_language,
      leading_zeroes: boolean,
      log_status: ost$status,
      month_name: clt$name,
      need_preferred_language: boolean,
      preferred_language: ost$natural_language,
      rounded_up_millisecond_value: integer,
      selected_language: ^ost$natural_language,
      str_index: integer;

?? NEWTITLE := 'get_day_or_month_name', EJECT ??

    PROCEDURE [INLINE] get_day_or_month_name
      (    language: ost$natural_language;
       VAR day_or_month_name: clt$name;
       VAR status: ost$status);

      VAR
        day_ordinal: ost$day_of_week,
        day_number: 0 .. 6,
        ignore_status: ost$status,
        using_english: boolean,
        days_and_months_ptr: ^clt$day_and_month_names;


      day_or_month_name.value := '';
      days_and_months_ptr := NIL;
      using_english := FALSE;

      clp$find_day_and_month_names (language, days_and_months_ptr);
      IF days_and_months_ptr = NIL THEN
        clp$get_day_and_month_names (language, days_and_months_ptr, status);
        IF NOT status.normal THEN
*IF NOT $true(osv$unix)
          osp$generate_log_message ($pmt$ascii_logset [pmc$job_log, pmc$system_log], status, ignore_status);
*IFEND
          status.normal := TRUE;
          IF preferred_language = '' THEN
*IF NOT $true(osv$unix)
            osp$find_natural_language (selected_language);
            preferred_language := selected_language^;
*ELSE
            preferred_language := osc$english;
*IFEND
          IFEND;
          IF preferred_language <> language THEN
            clp$get_day_and_month_names (preferred_language, days_and_months_ptr, status);
            IF NOT status.normal THEN
*IF NOT $true(osv$unix)
              osp$generate_log_message ($pmt$ascii_logset [pmc$job_log, pmc$system_log], status,
                    ignore_status);
*IFEND
              status.normal := TRUE;
              days_and_months_ptr := ^clv$english_day_and_month_names;
              using_english := TRUE;
            IFEND;
          ELSE
            days_and_months_ptr := ^clv$english_day_and_month_names;
            using_english := TRUE;
          IFEND;
        IFEND;
      IFEND;

    /find_day_or_month/
      WHILE TRUE DO
        IF (format_data.piece [format_index] = clc$ma) OR (format_data.piece [format_index] =
              clc$ma_lang) THEN
          day_or_month_name.value := days_and_months_ptr^.months_abbrev [date_time.value.month].value;
          day_or_month_name.size := days_and_months_ptr^.months_abbrev [date_time.value.month].size;
          EXIT /find_day_or_month/;
        ELSEIF (format_data.piece [format_index] = clc$mn) OR (format_data.piece [format_index] =
              clc$mn_lang) THEN
          day_or_month_name.value := days_and_months_ptr^.months [date_time.value.month].value;
          day_or_month_name.size := days_and_months_ptr^.months [date_time.value.month].size;
          EXIT /find_day_or_month/;
        ELSEIF (format_data.piece [format_index] = clc$da) OR (format_data.piece [format_index] =
              clc$da_lang) THEN
          pmp$compute_day_of_week (date_time.value, day_ordinal, status);
          IF NOT status.normal THEN
            EXIT /find_day_or_month/;
          IFEND;
          #UNCHECKED_CONVERSION (day_ordinal, day_number);
          day_or_month_name.value := days_and_months_ptr^.days_abbrev [day_number + 1].value;
          day_or_month_name.size := days_and_months_ptr^.days_abbrev [day_number + 1].size;
          EXIT /find_day_or_month/;
        ELSEIF (format_data.piece [format_index] = clc$dn) OR (format_data.piece [format_index] =
              clc$dn_lang) THEN
          pmp$compute_day_of_week (date_time.value, day_ordinal, status);
          IF NOT status.normal THEN
            EXIT /find_day_or_month/;
          IFEND;
          #UNCHECKED_CONVERSION (day_ordinal, day_number);
          day_or_month_name.value := days_and_months_ptr^.days [day_number + 1].value;
          day_or_month_name.size := days_and_months_ptr^.days [day_number + 1].size;
          EXIT /find_day_or_month/;
        ELSEIF using_english THEN
          day_or_month_name.value := '';
          EXIT /find_day_or_month/;
        ELSE
          osp$set_status_abnormal ('CL', cle$unknown_date_time_format, format, status);
          EXIT /find_day_or_month/;
        IFEND;
        days_and_months_ptr := ^clv$english_day_and_month_names;
        using_english := TRUE;
      WHILEND /find_day_or_month/;

    PROCEND get_day_or_month_name;
?? TITLE := 'get_time_zone', EJECT ??

    PROCEDURE [INLINE] get_time_zone
      (    language: ost$natural_language;
           full_form: boolean;
       VAR tz_identifier: ost$string);

      VAR
        time_zone: ost$time_zone;


      pmp$get_time_zone (time_zone, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      clp$get_time_zone_identifier (time_zone, full_form, language, tz_identifier, status);

    PROCEND get_time_zone;
?? OLDTITLE, EJECT ??

    status.normal := TRUE;

    adjust := 0;
    count := 1;
    char_position := 1;
    default_format_string := '';
    format_string := NIL;
    found := FALSE;
    hour := 0;
    language := '';
    leading_zeroes := TRUE;
    need_preferred_language := FALSE;
    preferred_language := '';
    str.size := 0;
    str.value := '';
    str_index := 1;

    IF format = '' THEN
      pmp$get_default_date_time_form (default_date_format, default_time_format);
      default_date_format_size := clp$trimmed_string_size (default_date_format.format_string);
      default_time_format_size := clp$trimmed_string_size (default_time_format.format_string);
      IF date_time.date_specified THEN
        IF date_time.time_specified THEN
          STRINGREP (default_format_string, format_length, default_date_format.
                format_string (1, default_date_format_size), '.', default_time_format.
                format_string (1, default_time_format_size));
          format_string := ^default_format_string;
        ELSE
          format_string := ^default_date_format.format_string;
          format_length := default_date_format_size;
        IFEND;
      ELSEIF date_time.time_specified THEN
        format_string := ^default_time_format.format_string;
        format_length := default_time_format_size;
      ELSE
        osp$set_status_abnormal ('CL', cle$date_time_format_null, '', status);
        RETURN;
      IFEND;
    ELSE
      format_string := ^format;
      format_length := clp$trimmed_string_size (format_string^);
    IFEND;

{Verify input data.}
    clp$validate_date_time (date_time, '', status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

{Initialize format_data.}
    FOR count := 1 TO clc$max_total_date_time_pieces DO
      format_data.piece [count] := clc$undefined;
      format_data.index [count] := 0;
      format_data.size [count] := 0;
    FOREND;

{Find first character of format string.}
    #SCAN (clv$non_space, format_string^, char_position, found);

    count := char_position;

    read_format_string (format_string^, format_data, count, leading_zeroes, need_preferred_language, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    IF need_preferred_language THEN
*IF NOT $true(osv$unix)
      osp$find_natural_language (selected_language);
      preferred_language := selected_language^;
*ELSE
      preferred_language := osc$english;
*IFEND
    IFEND;

{ Now use pieces of format to transform date and time.}

    FOR format_index := 1 TO count DO
      CASE format_data.piece [format_index] OF

      = clc$h12 =
        hour := date_time.value.hour;
        IF hour > 12 THEN
          hour := hour - 12;
        ELSEIF hour = 0 THEN
          hour := 12;
        IFEND;
        adjust := $INTEGER (hour >= 10);
        convert_integer_to_rj_string (hour, '0', str.value (str_index, 1 + adjust));
        str_index := str_index + 1 + adjust;

      = clc$h24 =
        convert_integer_to_rj_string (date_time.value.hour, '0', str.value (str_index, 2));
        str_index := str_index + 2;

      = clc$mm =
        convert_integer_to_rj_string (date_time.value.minute, '0', str.value (str_index, 2));
        str_index := str_index + 2;

      = clc$ss =
        convert_integer_to_rj_string (date_time.value.second, '0', str.value (str_index, 2));
        str_index := str_index + 2;

      = clc$s10 =
        convert_integer_to_rj_string (date_time.value.millisecond DIV 100, '0', str.value (str_index));
        str_index := str_index + 1;

      = clc$s100 =
        IF (date_time.value.millisecond < 990) AND ((date_time.value.millisecond MOD 10) >= 5) THEN
          rounded_up_millisecond_value := (date_time.value.millisecond DIV 10) + 1;
        ELSE
          rounded_up_millisecond_value := (date_time.value.millisecond DIV 10);
        IFEND;
        convert_integer_to_rj_string (rounded_up_millisecond_value, '0', str.value (str_index, 2));
        str_index := str_index + 2;

      = clc$s1000 =
        convert_integer_to_rj_string (date_time.value.millisecond, '0', str.value (str_index, 3));
        str_index := str_index + 3;

      = clc$amorpm =
        IF date_time.value.hour < 12 THEN
          str.value (str_index, 2) := 'AM';
        ELSE
          str.value (str_index, 2) := 'PM';
        IFEND;
        str_index := str_index + 2;

      = clc$d2 =
        convert_integer_to_rj_string (date_time.value.day, '0', date_str.value (1, 2));
        IF (date_time.value.day < 10) AND NOT leading_zeroes THEN
          str.value (str_index) := date_str.value (2);
          str_index := str_index + 1;
        ELSE
          str.value (str_index, 2) := date_str.value;
          str_index := str_index + 2;
        IFEND;

      = clc$dn_lang, clc$da_lang =
        language := format (format_data.index [format_index], format_data.size [format_index]);
        #TRANSLATE (osv$lower_to_upper, language, converted_language);
        get_day_or_month_name (converted_language, day_name, status);
        IF NOT status.normal THEN
          RETURN;
        ELSEIF day_name.value = '' THEN
          osp$set_status_abnormal ('CL', cle$impossible_date_or_time, '', status);
          RETURN;
        IFEND;
        str.value (str_index, day_name.size) := day_name.value;
        str_index := str_index + day_name.size;

      = clc$dn, clc$da =
        get_day_or_month_name (preferred_language, day_name, status);
        IF NOT status.normal THEN
          RETURN;
        ELSEIF day_name.value = '' THEN
          osp$set_status_abnormal ('CL', cle$impossible_date_or_time, '', status);
          RETURN;
        IFEND;
        str.value (str_index, day_name.size) := day_name.value;
        str_index := str_index + day_name.size;

      = clc$m2 =
        convert_integer_to_rj_string (date_time.value.month, '0', date_str.value (1, 2));
        str.value (str_index, 2) := date_str.value;
        str_index := str_index + 2;

      = clc$mn, clc$ma =
        get_day_or_month_name (preferred_language, month_name, status);
        IF NOT status.normal THEN
          RETURN;
        ELSEIF month_name.value = '' THEN
          osp$set_status_abnormal ('CL', cle$impossible_date_or_time, '', status);
          RETURN;
        IFEND;
        str.value (str_index, month_name.size) := month_name.value;
        str_index := str_index + month_name.size;

      = clc$mn_lang, clc$ma_lang =
        language := format (format_data.index [format_index], format_data.size [format_index]);
        get_day_or_month_name (language, month_name, status);
        IF NOT status.normal THEN
          RETURN;
        ELSEIF month_name.value = '' THEN
          RETURN;
        IFEND;
        str.value (str_index, month_name.size) := month_name.value;
        str_index := str_index + month_name.size;

      = clc$tz =
        get_time_zone (preferred_language, TRUE, identifier);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        str.value (str_index, identifier.size) := identifier.value;
        str_index := str_index + identifier.size;

      = clc$tza =
        get_time_zone (preferred_language, FALSE, identifier);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        str.value (str_index, identifier.size) := identifier.value;
        str_index := str_index + identifier.size;

      = clc$tz_lang =
        language := format (format_data.index [format_index], format_data.size [format_index]);
        get_time_zone (language, TRUE, identifier);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        str.value (str_index, identifier.size) := identifier.value;
        str_index := str_index + identifier.size;

      = clc$tza_lang =
        language := format (format_data.index [format_index], format_data.size [format_index]);
        get_time_zone (language, FALSE, identifier);
        IF NOT status.normal THEN
          RETURN;
        IFEND;
        str.value (str_index, identifier.size) := identifier.value;
        str_index := str_index + identifier.size;

      = clc$y2 =
        convert_integer_to_rj_string (date_time.value.year, '0', date_str.value (1, 2));
        str.value (str_index, 2) := date_str.value;
        str_index := str_index + 2;

      = clc$y4 =
        convert_integer_to_rj_string (date_time.value.year + 1900, '0', date_str.value (1, 4));
        str.value (str_index, 4) := date_str.value;
        str_index := str_index + 4;

      = clc$j3 =
        IF NOT pmp$this_is_a_leap_year (date_time.value.year + 1900) THEN
          convert_integer_to_rj_string (clv$cumulative_days [date_time.value.month - 1] + date_time.value.day,
                '0', date_str.value (1, 3));
        ELSE
          convert_integer_to_rj_string (clv$cumulative_leap_days [date_time.value.month - 1] +
                date_time.value.day, '0', date_str.value (1, 3));
        IFEND;
        str.value (str_index, 3) := date_str.value;
        str_index := str_index + 3;

      = clc$hyphen =
        str.value (str_index) := '-';
        str_index := str_index + 1;

      = clc$space =
        str.value (str_index) := ' ';
        str_index := str_index + 1;

      = clc$slash =
        str.value (str_index) := '/';
        str_index := str_index + 1;

      = clc$dot =
        str.value (str_index) := '.';
        str_index := str_index + 1;

      = clc$colon =
        str.value (str_index) := ':';
        str_index := str_index + 1;

      = clc$comma =
        IF (format_data.piece [format_index + 1] = clc$s1000) OR
              (format_data.piece [format_index + 1] = clc$s100) OR
              (format_data.piece [format_index + 1] = clc$s10) THEN
          str.value (str_index) := ',';
          str_index := str_index + 1;
        ELSE
          str.value (str_index, 2) := ', ';
          str_index := str_index + 2;
        IFEND;
      CASEND;

    FOREND;
    str.size := str_index - 1;

  PROCEND clp$convert_date_time_to_string;
?? TITLE := 'clp$validate_date_time', EJECT ??

  PROCEDURE [XDCL, #GATE] clp$validate_date_time
    (    date_time: clt$date_time;
         str: string ( * );
     VAR status: ost$status);


    status.normal := TRUE;

?? FMT (FORMAT := OFF) ??

    IF ((date_time.value.month < 1) OR (date_time.value.month > 12))
       OR ((date_time.value.month = 2) AND pmp$this_is_a_leap_year (date_time.value.year + 1900) AND
            (date_time.value.day > 29))
       OR ((date_time.value.month = 2) AND
            NOT pmp$this_is_a_leap_year (date_time.value.year + 1900) AND (date_time.value.day > 28))
       OR ((date_time.value.day < 1) OR (date_time.value.day > clv$last_day_of_month [date_time.value.month]))
       OR (((date_time.value.hour < 0) OR (date_time.value.hour > 23)) OR
             ((date_time.value.minute < 0) OR (date_time.value.hour > 59)) OR
             ((date_time.value.second < 0) OR (date_time.value.second > 59)) OR
             ((date_time.value.millisecond < 0) OR (date_time.value.millisecond > 999))) THEN
      osp$set_status_abnormal ('CL', cle$impossible_date_or_time, str, status);
    ELSEIF (NOT date_time.date_specified) AND (NOT date_time.time_specified) THEN
      osp$set_status_abnormal ('CL', cle$date_time_format_null, str, status);
    IFEND;

?? FMT (FORMAT := ON) ??

  PROCEND clp$validate_date_time;
?? TITLE := 'clp$get_date_string', EJECT ??
*copyc clh$get_date_string

  PROCEDURE [XDCL, #GATE] clp$get_date_string
    (VAR str: ost$string;
     VAR status: ost$status);

    VAR
      clt_date_time: clt$date_time,
      time_format: ost$default_time_format,
      date_format: ost$default_date_format;


    pmp$get_default_date_time_form (date_format, time_format);

    pmp$get_compact_date_time (clt_date_time.value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clt_date_time.time_specified := FALSE;
    clt_date_time.date_specified := TRUE;

    clp$convert_date_time_to_string (clt_date_time, date_format.format_string, str, status);

  PROCEND clp$get_date_string;
?? TITLE := 'clp$get_time_string', EJECT ??
*copyc clh$get_time_string

  PROCEDURE [XDCL, #GATE] clp$get_time_string
    (VAR str: ost$string;
     VAR status: ost$status);

    VAR
      clt_date_time: clt$date_time,
      date_format: ost$default_date_format,
      time_format: ost$default_time_format;


    pmp$get_default_date_time_form (date_format, time_format);

    pmp$get_compact_date_time (clt_date_time.value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clt_date_time.time_specified := TRUE;
    clt_date_time.date_specified := FALSE;

    clp$convert_date_time_to_string (clt_date_time, time_format.format_string, str, status);

  PROCEND clp$get_time_string;
?? TITLE := 'clp$get_date_time_string', EJECT ??
*copyc clh$get_date_time_string

  PROCEDURE [XDCL, #GATE] clp$get_date_time_string
    (    format: clt$date_time_form_string;
     VAR str: ost$string;
     VAR status: ost$status);

    VAR
      clt_date_time: clt$date_time;


    pmp$get_compact_date_time (clt_date_time.value, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;

    clt_date_time.time_specified := TRUE;
    clt_date_time.date_specified := TRUE;
    clp$convert_date_time_to_string (clt_date_time, format, str, status);

  PROCEND clp$get_date_time_string;
?? TITLE := 'clp$get_day_name', EJECT ??
*copyc clh$get_day_name

  PROCEDURE [XDCL, #GATE] clp$get_day_name
    (    day_of_week: ost$day_of_week;
         full_form: boolean;
         natural_language: ost$natural_language;
     VAR day_name: ost$string;
     VAR status: ost$status);

    VAR
      day_number: 0 .. 6,
      ignore_status: ost$status,
      days_and_months_ptr: ^clt$day_and_month_names,
      log_status: ost$status,
      name_is_valid: boolean,
      preferred_language: ost$natural_language,
*IF NOT $true(osv$unix)
      selected_language: ^ost$natural_language,
      seed_name: pmt$program_name;
*ELSE
      selected_language: ^ost$natural_language;
*IFEND


    status.normal := TRUE;

    IF (day_of_week < LOWERVALUE (ost$day_of_week)) OR (day_of_week > UPPERVALUE (ost$day_of_week)) THEN
      osp$set_status_abnormal ('OS', ose$bad_day_of_week, '', status);
      RETURN;
    IFEND;

    IF natural_language = osc$null_name THEN
*IF NOT $true(osv$unix)
      osp$find_natural_language (selected_language);
      preferred_language := selected_language^;
*ELSE
      preferred_language := osc$english;
*IFEND
    ELSE
      clp$validate_name (natural_language, preferred_language, name_is_valid);
      IF NOT name_is_valid THEN
        osp$set_status_abnormal ('CL', ose$bad_natural_language, natural_language, status);
        RETURN;
      IFEND;
    IFEND;

    clp$find_day_and_month_names (preferred_language, days_and_months_ptr);
    IF days_and_months_ptr = NIL THEN
      clp$get_day_and_month_names (preferred_language, days_and_months_ptr, status);
      IF NOT status.normal THEN
*IF NOT $true(osv$unix)
        osp$generate_log_message ($pmt$ascii_logset [pmc$job_log, pmc$system_log], status, ignore_status);
*IFEND
        status.normal := TRUE;
        days_and_months_ptr := ^clv$english_day_and_month_names;
      IFEND;
    IFEND;

    #UNCHECKED_CONVERSION (day_of_week, day_number);

    IF full_form THEN
      day_name.value := days_and_months_ptr^.days [day_number + 1].value;
      day_name.size := days_and_months_ptr^.days [day_number + 1].size;
    ELSE
      day_name.value := days_and_months_ptr^.days_abbrev [day_number + 1].value;
      day_name.size := days_and_months_ptr^.days_abbrev [day_number + 1].size;
    IFEND;

  PROCEND clp$get_day_name;
?? TITLE := 'clp$get_month_name', EJECT ??
*copyc clh$get_month_name

  PROCEDURE [XDCL, #GATE] clp$get_month_name
    (    month_number: 1 .. 12;
         full_form: boolean;
         natural_language: ost$natural_language;
     VAR month_name: ost$string;
     VAR status: ost$status);

    VAR
      ignore_status: ost$status,
      days_and_months_ptr: ^clt$day_and_month_names,
      log_status: ost$status,
      name_is_valid: boolean,
      preferred_language: ost$natural_language,
*IF NOT $true(osv$unix)
      selected_language: ^ost$natural_language,
      seed_name: pmt$program_name;
*ELSE
      selected_language: ^ost$natural_language;
*IFEND


    status.normal := TRUE;

    IF natural_language = osc$null_name THEN
*IF NOT $true(osv$unix)
      osp$find_natural_language (selected_language);
      preferred_language := selected_language^;
*ELSE
      preferred_language := osc$english;
*IFEND
    ELSE
      clp$validate_name (natural_language, preferred_language, name_is_valid);
      IF NOT name_is_valid THEN
        osp$set_status_abnormal ('CL', ose$bad_natural_language, natural_language, status);
        RETURN;
      IFEND;
    IFEND;

    IF (month_number < 1) OR (month_number > 12) THEN
      osp$set_status_abnormal ('CL', cle$bad_month_number, '', status);
      RETURN;
    IFEND;

    clp$find_day_and_month_names (preferred_language, days_and_months_ptr);
    IF days_and_months_ptr = NIL THEN
      clp$get_day_and_month_names (preferred_language, days_and_months_ptr, status);
      IF NOT status.normal THEN
*IF NOT $true(osv$unix)
        osp$generate_log_message ($pmt$ascii_logset [pmc$job_log, pmc$system_log], status, ignore_status);
*IFEND
        status.normal := TRUE;
        days_and_months_ptr := ^clv$english_day_and_month_names;
      IFEND;
    IFEND;

    IF full_form THEN
      month_name.value := days_and_months_ptr^.months [month_number].value;
      month_name.size := days_and_months_ptr^.months [month_number].size;
    ELSE
      month_name.value := days_and_months_ptr^.months_abbrev [month_number].value;
      month_name.size := days_and_months_ptr^.months_abbrev [month_number].size;
    IFEND;

  PROCEND clp$get_month_name;
?? TITLE := 'clp$get_time_zone_identifier', EJECT ??
*copyc clh$get_time_zone_identifier

  PROCEDURE [XDCL, #GATE] clp$get_time_zone_identifier
    (    time_zone: ost$time_zone;
         full_form: boolean;
         natural_language: ost$natural_language;
     VAR time_zone_identifier: ost$string;
     VAR status: ost$status);

    VAR
      current_end: ost$string_size,
*IF NOT $true(osv$unix)
      help_module: ^ost$help_module,
*IFEND
      hours_string: ost$string,
*IF NOT $true(osv$unix)
      ignore_online_manual: ost$online_manual_name,
*IFEND
      index: ost$string_size,
      minutes_string: ost$string,
*IF NOT $true(osv$unix)
      time_zone_template: ^ost$message_template,
*IFEND
      name_is_valid: boolean,
      parameter_index: ost$string_size,
      parameter_name: clt$parameter_name,
      parse: clt$parse_state,
      preferred_language: ost$natural_language,
      selected_language: ^ost$natural_language,
      prompt_begin: ost$string_size,
*IF NOT $true(osv$unix)
      seed_name: pmt$program_name,
*IFEND
      time_zone_abbrev: string (osc$max_string_size);


    status.normal := TRUE;
    parameter_index := 1;
    current_end := 0;
    parameter_name := '';
    prompt_begin := 0;
    time_zone_abbrev := '';
    time_zone_identifier.value := '';
    time_zone_identifier.size := 0;

    IF natural_language = osc$null_name THEN
*IF NOT $true(osv$unix)
      osp$find_natural_language (selected_language);
      preferred_language := selected_language^;
    ELSE
      clp$validate_name (natural_language, preferred_language, name_is_valid);
      IF NOT name_is_valid THEN
        osp$set_status_abnormal ('CL', ose$bad_natural_language, natural_language, status);
        RETURN;
      IFEND;
*ELSE
      preferred_language := osc$english;
*IFEND
    IFEND;

{Construct parameter prompt name.}
    IF time_zone.daylight_saving_time THEN
      parameter_name (1, dst_string_length) := dst_string;
      parameter_index := parameter_index + dst_string_length;
    ELSE
      parameter_name (1, st_string_length) := st_string;
      parameter_index := parameter_index + st_string_length;
    IFEND;
    clp$convert_integer_to_string (time_zone.hours_from_gmt, 10, FALSE, hours_string, status);
    IF NOT status.normal THEN
      RETURN;
    IFEND;
    IF hours_string.value (1) = '-' THEN
      hours_string.value (1) := '_';
    IFEND;
    parameter_name (parameter_index) := '$';
    parameter_index := parameter_index + 1;
    parameter_name (parameter_index, hours_string.size) := hours_string.value;
    parameter_index := parameter_index + hours_string.size;
    IF time_zone.minutes_offset <> 0 THEN
      clp$convert_integer_to_string (time_zone.minutes_offset, 10, FALSE, minutes_string, status);
      IF NOT status.normal THEN
        RETURN;
      IFEND;
      IF minutes_string.value (1) = '-' THEN
        minutes_string.value (1) := '_';
      IFEND;
      parameter_name (parameter_index) := '$';
      parameter_index := parameter_index + 1;
      parameter_name (parameter_index, minutes_string.size) := minutes_string.value;
    IFEND;

  /find_time_zone/
    BEGIN
*IF NOT $true(osv$unix)
      seed_name := 'TIME_ZONES';
      clp$find_help_module (seed_name, preferred_language, help_module, ignore_online_manual, status);
      IF (NOT status.normal) OR (help_module = NIL) THEN
        IF (preferred_language <> 'ENGLISH') OR (preferred_language <> 'US_ENGLISH') THEN
          preferred_language := 'US_ENGLISH';
          clp$find_help_module (seed_name, preferred_language, help_module, ignore_online_manual, status);
          IF (NOT status.normal) OR (help_module = NIL) THEN
            EXIT /find_time_zone/;
          IFEND;
        ELSE
          EXIT /find_time_zone/;
        IFEND;
      IFEND;
      osp$find_parameter_prompt (help_module, parameter_name, time_zone_template, status);
      IF NOT (status.normal) OR (time_zone_template = NIL) THEN
        IF (preferred_language <> 'ENGLISH') OR (preferred_language <> 'US_ENGLISH') THEN
          preferred_language := 'US_ENGLISH';
          clp$find_help_module (seed_name, preferred_language, help_module, ignore_online_manual, status);
          IF (NOT status.normal) OR (help_module = NIL) THEN
            EXIT /find_time_zone/;
          IFEND;
          osp$find_parameter_prompt (help_module, parameter_name, time_zone_template, status);
          IF NOT (status.normal) OR (time_zone_template = NIL) THEN
            EXIT /find_time_zone/;
          IFEND;
        ELSE
          EXIT /find_time_zone/;
        IFEND;
      IFEND;

      clp$initialize_parse_state (time_zone_template, NIL, parse);
{Looking for something that could look like: Central Standard Time, CDT}
      clp$scan_lexical_unit (clc$slu_non_space, parse);
      IF parse.unit.kind <> clc$lex_name THEN
        EXIT /find_time_zone/;
      IFEND;
      prompt_begin := parse.unit_index;
      time_zone_abbrev (1) := time_zone_template^ (parse.unit_index);
      index := 2;

      WHILE TRUE DO
        clp$scan_lexical_unit (clc$slu_non_space, parse);
        CASE parse.unit.kind OF

        = clc$lex_name =
          IF parse.previous_non_space_unit.kind = clc$lex_comma THEN
            time_zone_abbrev := time_zone_template^ (parse.unit_index, parse.unit.size);
          ELSE
            time_zone_identifier.size := parse.index - prompt_begin;
            time_zone_identifier.value := time_zone_template^ (prompt_begin, parse.index - 1);
            time_zone_abbrev (index) := time_zone_template^ (parse.unit_index);
          IFEND;

        = clc$lex_comma =
          {Don't need to do anything.}

        = clc$lex_subtract =
          time_zone_identifier.size := parse.index - prompt_begin;
          time_zone_identifier.value := time_zone_template^ (prompt_begin, parse.index - 1);

        = clc$lex_end_of_line =
          EXIT /find_time_zone/;

        ELSE
          time_zone_identifier.value := '';
          time_zone_identifier.size := 0;
          EXIT /find_time_zone/;
        CASEND;
        index := index + 1;
      WHILEND;
*IFEND
    END /find_time_zone/;

    IF time_zone_identifier.size <> 0 THEN
      IF NOT full_form THEN
        time_zone_identifier.value := time_zone_abbrev;
        time_zone_identifier.size := clp$trimmed_string_size (time_zone_abbrev);
      IFEND;
    IFEND;

  PROCEND clp$get_time_zone_identifier;

?? TITLE := 'clp$verify_time_increment', EJECT ??
*copyc clh$verify_time_increment

  PROCEDURE [XDCL, #GATE] clp$verify_time_increment
    (    time_increment: pmt$time_increment;
     VAR status: ost$status);

    VAR
      ms: integer;

    ms := time_increment.year * 366 * 24 * 60 * 60 * 1000 +
          time_increment.month * 31 * 24 * 60 * 60 * 1000 +
          time_increment.day * 24 * 60 * 60 * 1000 +
          time_increment.hour * 60 * 60 * 1000 +
          time_increment.minute * 60 * 1000 +
          time_increment.second * 1000 +
          time_increment.millisecond;

    IF (ms < -1000*60*60*24*366*255) OR (ms > 1000*60*60*24*366*255) THEN
      osp$set_status_abnormal ('CL', cle$invalid_time_increment, '', status);
    ELSE
      status.normal := TRUE;
    IFEND;

  PROCEND clp$verify_time_increment;

MODEND clm$date_time_conversion;
