Operating System - OpenVMS
1825711 Members
3218 Online
109686 Solutions
New Discussion

Validating dates of format dd-mm-yyyy ?

 
Thomas Ritter
Respected Contributor

Validating dates of format dd-mm-yyyy ?

Is there a simple to way to valid date of the format dd-mm-yyyy ?

For example,

21-10-2007
32-02-2007
99-13-2007
231-1-3007

I thought I'd ask just in case someone has a DCL trick or similar to make this a straight forward validation.

The date format is not under our control. An end user project will be sending us a file of thousands or records each which requires the date to be validated :(

8 REPLIES 8
Hoff
Honored Contributor

Re: Validating dates of format dd-mm-yyyy ?

DCL simply isn't as capable in this regard as is bash, perl nor php.

Barring availability of perl or php or other such, I'd probably do a quick lib$table_parse grammar, and process the file using a program. There are RMS examples (for calling same from C) posted at the HoffmanLabs web site, and GNM on the Freeware distro is an example of calling lib$table_parse.

Here's GNM:
http://mvb.saic.com/freeware/freewarev80/gnm/

There's no regexp capability in DCL, though you could certainly take a programmatic tour through GNV and a bash script to get that capability.

sprintf can be an option when working in C.

In strict and straight DCL, you'll be reading the chunks using a READ command in a loop, with the parsing itself based on f$element on the dashes, f$integer on each of the chunks, then a range check on the value. The hard way. And then there's the fun of leap years, which would be any year divisible by four except every 100 except every 400 years.

XML would be an option if heading toward a production data transfer, and I'd certainly look toward verification closer to the source rather than downstream.

Hein van den Heuvel
Honored Contributor

Re: Validating dates of format dd-mm-yyyy ?

I don't think there is a trick, but the brute force is not too ugly.

It's best to shove the time into F$CVTIME and see whether that works.

Gotcha 1)
You could get a program to use LIB$DT_INPUT_FORMAT but I don't think you can get F$CVTIME to listen to alternative input formats

Gotcha 2)
F$CVTIME complains onto SYS$OUTPUT if it does not like the input. That may or might not be desirable.

I guess would use something like below.
With something like your sample input it would run as:

$ @tmp.com tmp.tmp
21-OCT-2007 21-10-2007
- bad - 31-02-2007
- very bad - 99-13-2007
- very bad - 231-1-3007

Enjoy,
Hein.

$clos/nolog input
$open/erro=error input 'p1
$define sys$output nl: ! No whining
$months = "-xxx-JAN-FEB-MAR-APR-MAY-JUN-JUL-AUG-SEP-OCT-NOV-DEC-"
$if f$type(year).NES."INTEGER" then goto report
$loop:
$read/end=done input record
$my_date = "- very bad -"
$year = f$elem(2,"-",record)
$if f$type(year).NES."INTEGER" then goto report
$month = f$elem(1,"-",record)
$if f$type(year).NES."INTEGER" then goto report
$day = f$elem(0,"-",record)
$if f$type(year).NES."INTEGER" then goto report
$if month.gt.12 .or. day.gt.31 .or. year.lt.1900 then goto report
$test = day + f$extr(month*4,5,months) + year
$my_date = f$cvtime(test,"ABSOLUTE")
$if .not.$status then my_date = "- bad -"
$report:
$ write sys$command f$fao("!12AS !AS", my_date, record)
$goto loop
$done:
$close/nolog input
$deas sys$output
$error:
$exit %xffffff .and. $status


Hein van den Heuvel
Honored Contributor

Re: Validating dates of format dd-mm-yyyy ?

btw, there is no 'simple' PERL solution either.

I'm sure someone has a nice package (google caljd.pl), but the basics like localtime/timelocal do not cut it.

Specifically timelocal, which takes an input array or time elements and outputs julian time, is documented to 'croak' (technical term!?) on very bad input, and just pretent on somewhat bad input.


$ type tmp.pl
use strict;
use Time::Local;
while (<>) {
my $time = "- very bad -";
if (/^\s*(\d+)-(\d+)-(\d{4})/) {
if ($1<32 && $2<13) {
my $temp = timelocal(0,0,0,$1,$2-1,$3);
$time = ($temp) ? scalar localtime($temp) : "- bad - ";
}
}
print "$time $_";
}

$ perl tmp.pl tmp.tmp
Sun Oct 21 00:00:00 2007 21-10-2007
- very bad - 21-10-2xx7
Sat Mar 3 00:00:00 2007 31-02-2007
- very bad - 99-13-2007
- very bad - 231-1-3007
$

And without the test for month < 13:


$ perl tmp.pl;-1 tmp.tmp
Sun Oct 21 00:00:00 2007 21-10-2007
- very bad - 21-10-2xx7
Sat Mar 3 00:00:00 2007 31-02-2007
Month '12' out of range 0..11 at tmp.pl;-2 line 6
%SYSTEM-F-ABORT, abort

fwiw,
Hein.
John Gillings
Honored Contributor

Re: Validating dates of format dd-mm-yyyy ?

Thomas,

If you want a one liner, try this (assume your date string is in symbol p1):

$ PIPE date=F$CVTIME(F$ELEMENT(0,"-",p1)+"-"+-
F$ELEMENT(F$INTEGER(F$ELEMENT(1,"-",p1)),"/",-
"/JAN/FEB/MAR/APR/MAY/JUN/JUL/AUG/SEP/OCT/NOV/DEC/")+"-"+-
F$ELEMENT(2,"-",p1),"ABSOLUTE") >nl: 2>nl:
$ WRITE SYS$OUTPUT $STATUS
$ SHOW SYM date

A valid date will be converted into VMS absolute format as symbol "date" and $STATUS will be successful (odd).

An invalid date will set $STATUS to %DCL-W-IVATIME and symbol date will be undefined (or unchanged).

the >nl: 2>nl: redirects SYS$OUTPUT and SYS$ERROR to NL: in order to suppress the error message. Since it's only -W- by default DCL will continue processing without needing SET NOON
A crucible of informative mistakes
Kris Clippeleyr
Honored Contributor

Re: Validating dates of format dd-mm-yyyy ?

Thomas,
Unfortunately most/some DCL utilities & lexical functions do not honour the LIB$DT_INPUT_FORMAT logical.
Otherwise it would be simple by defining LIB$DT_INPUT_FORMAT to be "!D0-!MN0-!Y4 !H04-!M0-!S0.!C2", and feeding your dates thru e.g. F$CVTIME.
Regards,
Kris (aka Qkcl)
I'm gonna hit the highway like a battering ram on a silver-black phantom bike...
Thomas Ritter
Respected Contributor

Re: Validating dates of format dd-mm-yyyy ?

Thanks for the good replies. Kris, I tried your suggestions before I posted, hoping I could use f$cvtime() in a one line contruct. No such luck :( Would be nice though.

Hoff the idea of validating closer to the source is sound, but we are the final destination and must avoid crash and burn situations.

Hein, I showed your example to the developer and she was so pleased she will adapt to her processes.

My choice would to use C.
DECxchange
Regular Advisor

Re: Validating dates of format dd-mm-yyyy ?

Hello,
I'm using OpenVMS Alpha 8.3 and if you doa a $ help lexical, you will see one command, F$DELTA_TIME. If you do a further help on F$DELTA_TIME and then help on Examples, you will see a simple DCL example about find the different in two different times.

You could conceivably plug one of these invalid time formats into either the START or END time parameter, with the other (START or END vice versa) being the current time. You could then capture the status of F$DELTA_TIME and that would probably report that an invalid time was used.

I haven't acutally tried it, but if you cut and paste the aforementioned example from help, it shouldn't take long to write!

Greg Miller
DECxchange
Joseph Huber_1
Honored Contributor

Re: Validating dates of format dd-mm-yyyy ?


Well, if the language of choice is not C, but Fortran, then maybe the following is of interest:

http://wwwvms.mppmu.mpg.de/~huber/util/eu_date_to_vms.FOR

together with the example
http://wwwvms.mppmu.mpg.de/~huber/util/main/cvdate.FOR


It converts (and thereby validates) these European date formats:
dd.mm.yyyy dd-mm-yyyy dd/mm/yyyy
(Year can be 2 digits), and
dd.mm.yyyy hh.min:sec

And it should not be too hard to rewrite it in C:
1. convert all delimiters to ","
2. read the resulting array of numbers
3. convert to VMS date/time via lib$convert_date_string
4. return code tells valid/invalid

http://www.mpp.mpg.de/~huber