Calendar routine similar to "classic" Web calendar

Web users have gotten used to what has become a standard approach to entering dates, namely a calendar where you can scroll by year and month, and then select a day.

The following code shows such a calendar implemented in Natural as a helproutine. The same code could be inserted in any object.

First, here is a program:

DEFINE DATA LOCAL
1 #DATE-N (N8)
1 REDEFINE #DATE-N
2 #YYP (N4)
2 #MMP (N2)
2 #DDP (N2)
END-DEFINE
*
SET KEY PF1=HELP
*
**MOVE 11 TO #MMP
*

  • UNCOMMENT THE MOVE ABOVE TO SEE THE EFFECT
  • OF A PARTIAL SELECTION

INPUT (AD=M)
5/10 ‘ENTER DATE (YYYYMMDD) OR HIT PF1 FOR HELP’
#DATE-N(EM=99999999 HE=‘CALEND10’)
*
IF #DATE-N NE 0
WRITE 5/10 ‘YOU SELECTED YEAR:’ #YYP
2X ‘MONTH:’ #MMP 2X ‘DAY:’ #DDP
ELSE
WRITE 5/10 ‘YOU DID NOT ENTER ANYTHING’
END-IF
*
END

And here is the helproutine

  • THERE ARE MANY THINGS TO NOTE ABOUT THIS HELPROUTINE.
  • IT IS ONLY DESIGNED TO WORK FOR THE YEARS 2000-2010.
  • YOU CAN EXTEND THE ARRAY #STARTING-DAY TO ENCOMPASS
  • ADDITIONAL YEARS.
  • HITTING ENTER IS THE SAME AS HITTING PF2 (PICK).
  • MONTH NAMES ARE IN ENGLISH. USING ANOTHER LANGUAGE
  • MIGHT REQUIRE CHANGING THE FORMAT TO BE LARGER THAN A10.
  • IF THERE IS A MONTH OR YEAR IN #DATE-N, THE
  • HELPROUTINE WILL USE IT FOR THE STARTING DISPLAY.

DEFINE DATA PARAMETER
1 #DATE-N (N8)
1 REDEFINE #DATE-N
2 #YYP (N4)
2 #MMP (N2)
2 #DDP (N2)
LOCAL
1 #MM (A2) INIT <’ 1’>
1 #DD (A2)
1 #YY (A4)
1 #WEEK (N2/1:6,1:7)
1 REDEFINE #WEEK
2 #WEEK-STRING (N2/1:42)
1 #WEEK-LINE (N2)
1 #WEEK-DAY (N2)
1 #DATN (A8)
1 #DAYS-IN-MONTH (N2/1:12)
CONST <31,28,31,30,31,30,31,31,30,31,30,31>
1 #STARTING-DAY (N1/2000:2010) INIT <7,2,3,4,5,7,1,2,3,5,6>
1 #MONTH-OF-DAYS (N2/1:31)
INIT <1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31>
1 #START (N4)
1 #END (N4)
1 #END-MINUS-ONE (N4)
1 #MONTH-TEXT (A10/1:12)
INIT <‘JANUARY’,‘FEBRUARY’,‘MARCH’,‘APRIL’,‘MAY’,‘JUNE’,‘JULY’,
‘AUGUST’,‘SEPTEMBER’,‘OCTOBER’,‘NOVEMBER’,‘DECEMBER’>
1 #MONTH-YEAR-FOR-MAP (A15)
1 #DATE (D)
1 #DATE-A (A8)
1 #A (A1) /* HOLDS DAY OF THE WEEK
1 #DUMMY (P5) /* USED FOR LEAP YEAR TESTS
1 #REM (P5) /* USED FOR LEAP YEAR TESTS
END-DEFINE
*


FORMAT KD=ON
SET KEY PF2 NAMED ‘PICK’ PF4 NAMED ‘<MON’ PF6 NAMED ‘>MON’
PF8 NAMED ‘<YEAR’ PF10 NAMED ‘>YEAR’


  • FIRST, ESTABLISH STARTING YEAR AND MONTH
  • EITHER USE #YYP AND #MMP FROM THE “CALLER”
  • OR USE THE CURRENT YEAR AND MONTH FOR MISSING DATA

IF #YYP = 0
MOVE EDITED *DATX (EM=YYYY) TO #YY
COMPUTE #YYP = VAL (#YY)
END-IF
*
IF #MMP = 0
MOVE EDITED *DATX (EM=MM) TO #MM
COMPUTE #MMP = VAL (#MM)
END-IF
*


  • NOW FIGURE OUT WHAT THAT MONTH LOOKS LIKE

PERFORM MONTH-TO-SCREEN
*


DEFINE SUBROUTINE MONTH-TO-SCREEN
COMPRESS #MONTH-TEXT (#MMP) #YYP INTO #MONTH-YEAR-FOR-MAP
**
** NOW GET THE STARTING DAY OF WEEK FOR CURRENT YEAR - MONTH
MOVE #MMP TO SUBSTRING (#DATE-A,1,2)
MOVE ‘01’ TO SUBSTRING (#DATE-A,3,2)
MOVE #YYP TO SUBSTRING (#DATE-A,5,4)
MOVE EDITED #DATE-A TO #DATE (EM=MMDDYYYY)
MOVE EDITED #DATE (EM=O) TO #A
COMPUTE #START = VAL (#A) + 1
IF #START = 8
MOVE 1 TO #START
END-IF
COMPUTE #END = #DAYS-IN-MONTH (#MMP)
COMPUTE #END-MINUS-ONE = #END - 1
**
** FIX FOR LEAP YEAR FEBRUARY
*
REPEAT
IF #MMP NE 2
ESCAPE BOTTOM
END-IF
*
DIVIDE 400 INTO #YYP GIVING #DUMMY REMAINDER #REM
IF #REM = 0
ADD 1 TO #END
ADD 1 TO #END-MINUS-ONE
ESCAPE BOTTOM
END-IF
*
DIVIDE 100 INTO #YYP GIVING #DUMMY REMAINDER #REM
IF #REM = 0
ESCAPE BOTTOM
END-IF
*
DIVIDE 4 INTO #YYP GIVING #DUMMY REMAINDER #REM
IF #REM = 0
ADD 1 TO #END
ADD 1 TO #END-MINUS-ONE
ESCAPE BOTTOM
END-IF
*
ESCAPE BOTTOM
END-REPEAT
*
RESET #WEEK-STRING (*)
MOVE #MONTH-OF-DAYS (1:#END) TO
#WEEK-STRING (#START:#START+#END-MINUS-ONE)
ESCAPE ROUTINE
END-SUBROUTINE


  • NOW DISPLAY THE STARTING MONTH

INPUT (IP=OFF AD=M ZP=OFF)
1/2 ‘SUN MON TUE WED THU FRI SAT’
2/2 #WEEK (1,)
3/2 #WEEK (2,
)
4/2 #WEEK (3,)
5/2 #WEEK (4,
)
6/2 #WEEK (5,)
7/2 #WEEK (6,
)
8/2 #MONTH-YEAR-FOR-MAP (AD=O SG=OFF)


IF *PF-NAME = ‘>MON’
ADD 1 TO #MMP
IF #MMP GT 12
COMPUTE #MMP = 12
REINPUT ‘ERROR, MONTH IS DECEMBER CANNOT GO FORWARD’
END-IF
PERFORM MONTH-TO-SCREEN
REINPUT FULL ’ ’
END-IF


IF *PF-NAME = ‘<MON’
SUBTRACT 1 FROM #MMP
IF #MMP LT 1
COMPUTE #MMP = 1
REINPUT ‘ERROR, MONTH IS JANUARY CANNOT GO BACKWARD’
END-IF
PERFORM MONTH-TO-SCREEN
REINPUT FULL ’ ’
END-IF


IF *PF-NAME = ‘>YEAR’
ADD 1 TO #YYP
PERFORM MONTH-TO-SCREEN

REINPUT FULL ' '
END-IF

IF *PF-NAME = ‘<YEAR’
SUBTRACT 1 FROM #YYP

PERFORM MONTH-TO-SCREEN

REINPUT FULL ' '
END-IF

IF *PF-NAME = ‘PICK’ OR *PF-KEY = ‘ENTR’
COMPUTE #WEEK-LINE = *CURS-LINE - 1
COMPUTE #WEEK-DAY = ((*CURS-COL - 2) / 4 ) + 1
MOVE #WEEK (#WEEK-LINE,#WEEK-DAY) TO #DDP
IF #DDP = 0
REINPUT ‘YOU DID NOT SELECT A DAY’
END-IF
ESCAPE ROUTINE
END-IF
END

Questions or suggestions, please post, or e-mail me at steve@slr-assoc.com

steve

Hello Steve,

it is a good idea to post such a nice utility. As many users live in Germany or use international multilingual applications, the English constants are not so useful. Also the handling is not as good as I whished it could be (why is december the last month? January is follwing!

With this in mind I improved the calendar routine and no it looks like this:


 = << < Mae V 2006 > >>
   Mo Di Mi Do Fr Sa So
09 27 28  1  2  3  4  5
10  6  7  8  9 10 11 12
11 13 14 15 16 17 18 19
12 20 21 22 23 24 25 26
13 27 28 29 30 31  1  2
14  3  4  5  6  7  8  9

The improvements are:

  • The literals are taken from *language (using EM)
  • The first day of week is selected according to DTFORM
  • The week number is displayed (again according to DTFORM)
  • selectable “Buttons” today (“=”), prev/next year (“<<”/“>>”), prev/next month(“<”/“>”) and month dropdown “V”)
  • supports any date that is supported by NATURAL
  • the days of the displayed month are higlighted
  • today is displayed in reverse video

And here is the

[code]

  • Calendar : Displays a Calendar to pick a date
  • Author : Wilfried B

and not to forget: a small test program:

DEFINE DATA                   
LOCAL                         
1 #DATE (N8) /* INIT<20060101>
END-DEFINE                    
CALLNAT 'CALENDAR' #DATE      
DISPLAY #DATE                 
END                           

Hello Wilfried B

Hi Matthias;

re the NAT0480; Selection Boxes do no exist on the PC, hence the error.

cute leap year test. let natural do the work instead of coding it yourself.

steve

Matthias,

SB is for Mainframes only. It is not necessary as you have the < and > “buttons”. But it was a nice gimmick.

On Windows you should do this with a drop-down-list (better: use the windows calendar control).

At our Company, the natural-Programs should be executable on Windows and Solaris. So it’s better to stay platform-independent in our case.

@Wilfried if would prefer the following DECIDE at FILL-CALENDAR:


    DECIDE FOR EVERY CONDITION
      WHEN #WDATE.DD = #DATE.DD AND #WDATE.MM = #DATE.MM
        IF #CURS-FIELD = 0
          #CURS-FIELD := POS(#DAY.DD(#IWEEK,#DAYOFWEEK))
        END-IF
      WHEN #WDATE.MM = #DATE.MM
        #DAY.CV(#IWEEK,#DAYOFWEEK) := (AD=D)
      WHEN NONE
        #DAY.CV(#IWEEK,#DAYOFWEEK) := (AD=I)
    END-DECIDE

It’s a litttle bit shorter and better to read i think.

Greetings Sascha

Ain’t it ironic :wink:

Correction to that one:

Selection Boxes are, of course, available on the PC.
However, they may be defined in the map editor only, not explicitely on an INPUT statement.

Mine is better :wink:

DearSir,

Good Day…

This is Murali from Johannesburg, South Africa.

I am facing a problem while protecting a particular field(Sales Type) in a MAP.

The field has to be protected, when the Captured Date is Less than 10-10-20016.

Eventhough the field is protected, if we place the cursor on the field and press PF1, Help Window is opening and we are able to select a different field

I have tried using SET PF1 KEY OFF option and ESCAPE ROUTINE in my Help Routine.

SET PF1 KEY OFF is protecting the other fields of the MAP also. I just need only this particular SalesType field has to be protected.
ESCAPE Routine is running fine and PF1 is not working on the screen.But the requirement is the field should be protected only for the beneficiaries whose captured Date is Less than 10-10-2016.

Note : there is another field in the map, where PF1-KEY should work all the time.

I heard, PRR in Map editor can be used to write Rules to protect that particular field.

Could you please help me with this?

Best Regards
S.P.Murali

Have you tried using a Control Variable for the Sales Type? If I am correct in my assumptions below, this would allow you to achieve what I interpret as being your requirement. You should be able, in your helproutine, to look at the Captured Dates, and selectively alter the Control Variables, then do a REINPUT FULL.

As mentioned above, I am actually not certain about the nature of the problem.

I assume from your post that on the screen there are two fields, Sales Type and Captured Date, as well as other fields. I am assuming there is actually an array of Sales Type and Captured Date. Is this correct?

You are concerned that you might “stay” on the screen as a result of being “caught” by a REINPUT on some other field? Or is this interpretation totally wrong?

If correct, then, you are susceptible to a Help request. Is this a correct interpretation?

Also, are you using REINPUT or REINPUT FULL?