Jump to content

Biorhythms

From Rosetta Code
Task
Biorhythms
You are encouraged to solve this task according to the task description, using any language you may know.

For a while in the late 70s, the pseudoscience of biorhythms was popular enough to rival astrology, with kiosks in malls that would give you your weekly printout. It was also a popular entry in "Things to Do with your Pocket Calculator" lists. You can read up on the history at Wikipedia, but the main takeaway is that unlike astrology, the math behind biorhythms is dead simple.

It's based on the number of days since your birth. The premise is that three cycles of unspecified provenance govern certain aspects of everyone's lives – specifically, how they're feeling physically, emotionally, and mentally. The best part is that not only do these cycles somehow have the same respective lengths for all humans of any age, gender, weight, genetic background, etc, but those lengths are an exact number of days. And the pattern is in each case a perfect sine curve. Absolutely miraculous!

To compute your biorhythmic profile for a given day, the first thing you need is the number of days between that day and your birth, so the answers in Days between dates are probably a good starting point. (Strictly speaking, the biorhythms start at 0 at the moment of your birth, so if you know time of day you can narrow things down further, but in general these operate at whole-day granularity.) Then take the residue of that day count modulo each of the the cycle lengths to calculate where the day falls on each of the three sinusoidal journeys.

The three cycles and their lengths are as follows:

Cycle Length
Physical 23 days
Emotional 28 days
Mental 33 days

The first half of each cycle is in "plus" territory, with a peak at the quarter-way point; the second half in "minus" territory, with a valley at the three-quarters mark. You can calculate a specific value between -1 and +1 for the kth day of an n-day cycle by computing sin( 2πk / n ). The days where a cycle crosses the axis in either direction are called "critical" days, although with a cycle value of 0 they're also said to be the most neutral, which seems contradictory.

The task: write a subroutine, function, or program that will, given a birthdate and a target date, output the three biorhythmic values for the day. You may optionally include a text description of the position and the trend (e.g. "up and rising", "peak", "up but falling", "critical", "down and falling", "valley", "down but rising"), an indication of the date on which the next notable event (peak, valley, or crossing) falls, or even a graph of the cycles around the target date. Demonstrate the functionality for dates of your choice.

Example run of my Raku implementation:

raku br.raku 1943-03-09 1972-07-11
Output:
Day 10717:
Physical day 22: -27% (down but rising, next transition 1972-07-12)
Emotional day 21: valley
Mental day 25: valley

Double valley! This was apparently not a good day for Mr. Fischer to begin a chess tournament...

11l

Translation of: Python
F biorhythms(birthdate_str, targetdate_str)
   ‘
    Print out biorhythm data for targetdate assuming you were
    born on birthdate.

    birthdate and targetdata are strings in this format:

    YYYY-MM-DD e.g. 1964-12-26
   ’

   print(‘Born: ’birthdate_str‘ Target: ’targetdate_str)

   V birthdate = time:strptime(birthdate_str, ‘%Y-%m-%d’)
   V targetdate = time:strptime(targetdate_str, ‘%Y-%m-%d’)

   V days = (targetdate - birthdate).days()

   print(‘Day: ’days)

   V cycle_labels = [‘Physical’, ‘Emotional’, ‘Mental’]
   V cycle_lengths = [23, 28, 33]
   V quadrants = [(‘up and rising’, ‘peak’), (‘up but falling’, ‘transition’), (‘down and falling’, ‘valley’), (‘down but rising’, ‘transition’)]

   L(i) 3
      V label = cycle_labels[i]
      V length = cycle_lengths[i]
      V position = days % length
      V quadrant = Int(floor((4 * position) / length))
      V percentage = Int(round(100 * sin(2 * math:pi * position / length), 0))
      V transition_date = (targetdate + TimeDelta(days' floor((quadrant + 1) / 4 * length) - position)).strftime(‘%Y-%m-%d’)
      V (trend, next) = quadrants[quadrant]

      String description
      I percentage > 95
         description = ‘peak’
      E I percentage < -95
         description = ‘valley’
      E I abs(percentage) < 5
         description = ‘critical transition’
      E
         description = percentage‘% (’trend‘, next ’next‘ ’transition_date‘)’
      print(label‘ day ’position‘: ’description)

biorhythms(‘2043-03-09’, ‘2072-07-11’)
Output:
Born: 2043-03-09 Target: 2072-07-11
Day: 10717
Physical day 22: -27% (down but rising, next transition 2072-07-12)
Emotional day 21: valley
Mental day 25: valley

ALGOL 68

The main routine (input and graph drawing code) is translated from the Fortran sample with changes to use code from the Day of the week of Christmas and New Year and Days between dates tasks.

BEGIN # biorythms                                                            #

    # code from the Day of the week of Christmas and New Year task           #
    []STRING day name =
        []STRING( "SAT", "SUN", "MON", "TUE", "WED", "THU", "FRI" )[ AT 0 ];
    PROC day of week = ( INT y, m, d )INT:
         BEGIN
            INT mm := m;
            INT yy := y;
            IF mm <= 2 THEN
                mm +:= 12;
                yy -:= 1
            FI;
            INT j = yy OVER 100;
            INT k = yy MOD  100;
            ( d + ( ( mm + 1 ) * 26 ) OVER 10 + k + k OVER 4 + j OVER 4 + 5 * j ) MOD 7
         END # day of week # ;
    # end code from the Day of the week of Christmas and New Year task       #
    # code from the days between dates task                                  #
    PROC gregorian = ( INT y, m, d )INT:
         BEGIN
             INT n = ( m + 9 ) - ( ( ( m + 9 ) OVER 12 ) * 12 );
             INT w = y - ( n OVER 10 );
             ( 365 * w ) + ( w OVER 4 ) - ( w OVER 100 ) + ( w OVER 400 )
                         + ( ( ( n * 306 ) + 5 ) OVER 10 ) + ( d - 1 )
         END # gregorian # ;
    # end code from the days between dates task                              #

    BEGIN # main routine - translated from the Fortran sample's main program #
        PROC double line = VOID: print( ( "=" * 75, newline ) );
        PROC in range = ( REAL v, INT low, high )INT:
             IF v < low THEN low ELIF v > high THEN high ELSE ENTIER v FI;

        REAL pi2 = pi * 2;
      
        INT byear, bmon, bday, tyear, tmon, tday, nday;
        print( ( "ENTER YOUR BIRTHDAY YYYY MM DD: " ) );
        read( ( byear, bmon, bday ) );
        print( ( "ENTER START DATE    YYYY MM DD: " ) );
        read( ( tyear, tmon, tday ) );
        print( ( "ENTER NUMBER OF DAYS TO PLOT  : " ) );
        read( ( nday ) );

        INT jd0  = gregorian( tyear,    1,    1 );
        INT jd1  = gregorian( byear, bmon, bday );
        INT jd2 := gregorian( tyear, tmon, tday );
        INT dob  = day of week( byear, bmon, bday );
        INT dow := day of week( tyear, tmon, tday );

        double line;
        print( ( "YOU WERE BORN ON A (", day name[ dob MOD 7 ], ") YOU WERE " ) );
        print( ( whole( jd2 - jd1, 0 ), " DAYS OLD ON THE START DATE.", newline ) );
        print( ( "-1", 31 * " ", "0", 30 * " ", "+1     DOY", newline ) );
        TO nday DO
           INT dif = jd2 - jd1;
           INT phy = in range( 3.3e1+3.2e1*sin( pi2 * dif / 2.3e1 ), 1, 65 );
           INT emd = in range( 3.3e1+3.2e1*sin( pi2 * dif / 2.8e1 ), 1, 65 );
           INT men = in range( 3.3e1+3.2e1*sin( pi2 * dif / 3.3e1 ), 1, 65 );
           STRING g row := 65 * IF day name[ dow ] = "SUN" THEN "." ELSE " " FI;
           g row[   1 ] := "|";
           g row[  17 ] := ":";
           g row[  33 ] := "|";
           g row[  49 ] := ":";
           g row[  65 ] := "|";
           g row[ phy ] := "P";
           g row[ emd ] := "E";
           g row[ men ] := "M";
           IF phy = emd OR phy = men THEN g row[ phy ] := "*" FI;
           IF emd = men THEN g row[ emd ] := "*" FI;
           print( ( " ", g row, " ", day name[ dow ], " ", whole( jd2 - jd0 + 1, -3 ), newline ) );
           jd2 +:= 1;
           dow +:= 1 MODAB 7
        OD;
        double line
    END
END
Output:

Same as the Fortran sample, if given the same input.

Amazing Hopper

Esta es mi versión de la tarea: en vez de mostrar cifras frías, es mejor un gráfico, aunque este sea en texto.

Hopper permite usar la opción de preprocesamiento especial "High level", que consiste en que todo lo encerrado entre "#( )" será escrito de la forma infija formal, con expresiones como "(2+3)*sin(PI)" y cosas parecidas. En la tarea presente, la cantidad de cálculos y su complejidad hacen meritorio usar esta opción del preprocesador, que no es muy óptima debido a que realiza un preprocesado general, pero salva.

Un preprocesamiento general hace que una línea como "a+b" sea convertida a "{a};{b};add", cuando lo óptimo sería "{a} plus(b)", porque en el segundo caso no es necesario pasar "b" a la pila de trabajo. la instrucción "plus" no trabaja con expresiones.

Las expresiones dentro de "#()" deben escribirse cuidando el uso de paréntesis y sin espacios en blanco en los nombres de variables.

/* TASK: Bioritmo, Rosetta Code */

#include <jambo.h>

Main
   Set break
   Set stack 15
      
   Get total args
   If ( Is equal to '7' )
       /* argumentos del programa*/

       nombre="", año=0, mes=0, día=0, año a examinar=0, mes a examinar=0
          
       Set ' Arg str(2), Arg num(3) Arg num(4), Arg num(5) ', Move to 'nombre, año, mes, día'
       Set ' Arg num(6), Arg num(7) ',                        Move to 'mes a examinar, año a examinar'

       /* arrays de valores constantes */
       Void ' Etiquetas, Meses, Factores '
   
       /* otras variables utilitarias */
       b=año, g=año a examinar, l=g, r=0

       /* programa */
       Gosub 'Configuración del programa'
       Gosub 'Construcción del bioritmo'
       Locate (22, 1), Prnl
   Else
       Printnl ("Modo de uso: hopper bioritmo.jambo NOMBRE DD MM AA MME AAE")
       Printnl (Utf8("donde DD,MM,AA fecha de nacimiento, MME, AAE mes y año a examinar"))
   End If
   
End

Subrutines

Define 'Construcción del bioritmo'
   ak=0, b1=0, y=0
   
   Loop
 
      Gosub 'Análisis de año bisiesto'
   
      Let ( ak := #( Factores[mes]+28.5-día ) )
      ++mes
      x=12
      When ( #( mes < 13 ) ){ Set 'ak,x', Let( ak := Gosub 'Cálculo' ) }
       
      Let ( b1 := #( g-b-1 ) )
      
      Set decimal '0'
      Let ( ak := #( (b1*365+((g-1)/4)-((g-1)/100)+((g-1)/400)-((b/4)-(b/100)+(b/400))+ak) ) )
      Unset decimal
      
      y = ak
      Let (b := g)
   
      Gosub 'Análisis de año bisiesto'

      Let ( x := #( mesaexaminar - 1 ) )
      Let ( mes := 1 )
      If ( #( x <> 0 ) )
         Set 'ak, x', Let( ak := Gosub 'Cálculo' )
         y = ak
      End If

      Cls
      Set 'ak, y', Gosub 'Desplegar la malla'
      Pause
      ++mes a examinar
   Until ( #( mesaexaminar == 13 ) )
Return

Define 'Desplegar la malla, ak, y'
   i=4, j=0, i1=1, fi=3

   Loop
      Set 'i, i1, fi', Gosub 'Genera la malla'
      Set 'i, fi, i1', Gosub 'Escribe la identificación'
      Set 'ak, i, fi', Gosub 'Despliega el bioritmo'
      i += 34
      Let ( ak := y )
      ++i1
      ++j
   Until ( #( j == 3 ) )

Return

Define 'Genera la malla, i, i1, fi'
   j1=4, j2=0, ti=i, i2=0

   Let ( r := Get if( Equals( i1,1 ), 23, Get if( Equals( i1,2 ), 28, 33) ) )

   Loop
      Let ( j2 := Add( 4, i ) )

      Loop if ( #( j2 < ( (27+Factores[mesaexaminar])+i) ) )
         Locate ( #(j1+fi), j2 ), Printnl (" |")
         j2 += 5
      Back

      Locate ( #(j1+fi), #( 28+(Factores[mesaexaminar])+i) ), Printnl ("| ")
      ++j1
   Until ( #( j1 > 13 ) )

   Let ( i := ti )
   i2 = ti
   j2 = 1
   
   Loop if ( #( j2 < ((27 + Factores[mesaexaminar] )+1) ) )
      Locate ( #(8+fi), #(i2+1) ), Printnl ("-") 
      ++i2, ++j2
   Back

   Locate ( #(8+fi), #(5+i) ), Printnl ( "+" )
   Loccol ( #(10+i) ),         Printnl ( "+" )
   Loccol ( #(15+i) ),         Printnl ( "+" )
   Loccol ( #(20+i) ),         Printnl ( "+" )
   Loccol ( #(25+i) ),         Printnl ( "+" )

   Locate ( #(14+fi), #(1+i) ), Printnl ( "1...5...10...15...20...25..." )

   If ( #( (28+Factores[mesaexaminar]) == 29 ) )
      Locate ( #(14+fi), #(29+i) ), Printnl ( "." )
   Else If ( #( (28+ Factores[mesaexaminar]) == 30 ) )
      Locate ( #(14+fi), #(29+i) ), Printnl ( "30" )
      Locate ( #(8+fi), #(30+i) ),  Printnl ( "+" )
   Else If ( #( (28+Factores[mesaexaminar]) == 31 ) )
      Locate ( #(14+fi), #(29+i) ), Printnl ( "30." )
      Locate ( #(8+fi), #(30+i) ),  Printnl ( "+" )
   End If

Return

Define 'Escribe la identificación, i, fi, i1'
   Locate ( #(16+fi), #(1+i) ), Printnl ( #( Meses[mesaexaminar] ), " ", Int(l), " D. de C." )
   Locrow ( #(17+fi) ),         Printnl ( "Bioritmo para ", nombre )
   Locrow ( #(18+fi) ),         Printnl ( "Estado: ", #( Etiquetas[i1] ) )
Return

Define 'Despliega el bioritmo, ak, i, fi'
   n=0, j=0
   PI = M_PI

   Loop if( #( j < ( (28 + Factores[mesaexaminar]) * 2 ) ) )
      Let ( ak := #( ak + 0.5 ) )
      Let ( n := #( (10 * ( -(sin( ( 2 * PI * ak ) / r ) ) ) ) + 17 ) )

      If ( #( (int( int( j / 2 )-(( int( j / 2) / 5) * 5))) == 5 ) ) 
          Locate ( #( int( n / 2 ) + fi ), #( int( j / 2 ) + ( i + 1 )) )
      Else
          Locate ( #( (n / 2 ) + fi ), #( ( j / 2 ) + ( i + 1 ) ) )
      End If
      Printnl ("*")
      ++j
   Back

Return

Define 'Análisis de año bisiesto'
   x1=0, x2=0, x3=0
   /* "b" es variable global */
   Let ( x1 := Get if ( #( b - ( int( b / 4 ) * 4 ) == 0 ), 1, 0 ))
   Let ( x2 := Get if ( #( b - ( int( b / 100 ) * 100 ) == 0 ), 1, 0 ))
   Let ( x3 := Get if ( #( b - ( int( b / 400 ) * 400 ) == 0 ), 1, 0 ))
   [2] #( x1 - x2 + x3 ), Put 'Factores'
Return

Define 'Cálculo, ak,x'
   i = mes
   Loop if( #(i <= x) )
      Let ( ak := #( 28 + Factores[i] + ak ) )
      ++i
   Back
Return 'ak'

/* CONFIGURACION DEL PROGRAMA */

Define ' Configuración del programa '
   Set ' Utf8("Físico"), "Emocional", "Intelectual" '                      Apnd list 'Etiquetas'
   Set ' "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", \
         "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre" '     Apnd list 'Meses'
   Set ' 3, 0, 3, 2, 3, 2, 3, 3, 2, 3, 2, 3 '                              Apnd list 'Factores'
Return
Output:
$ hopper jm/bioritmo.jambo
Modo de uso: hopper bioritmo.jambo NOMBRE DD MM AA MME AAE
donde DD,MM,AA fecha de nacimiento, MME, AAE mes y año a examinar

$ hopper jm/bioritmo.jambo Mr.Dalien 18 1 1980 1 2022
               ***                    **                       *****    ****
        |    **   **   |    |    ||     **|    |    |    |    **   |*      **    |    |    |    |    |* 
        |   **    |**  |    |    ||      **    |    |    |   *|    ||       |**  |    |    |    |   **| 
        |   *|    | *  |    |    ||       **   |    |    |  * |    ||       | ** |    |    |    |  **|| 
        |  * |    |  * |    |    |*       |**  |    |    | *  |    ||       |  **|    |    |    | ** || 
    ----+-*--+----+---*+----+----*|   ----+-*--+----+----+*---+----+|   ----+---**----+----+----+**--+| 
        |**  |    |   **    |   **|       |  * |    |    **   |    ||       |    |*   |    |    *    || 
        |*   |    |    *    |   *||       |   *|    |   **    |    ||       |    | *  |    |   *|    || 
        *    |    |    |*   |  * ||       |    *    |  **|    |    ||       |    |  **|    | ** |    || 
      **|    |    |    | ** |**  ||       |    |**  | ** |    |    ||       |    |   **    |**  |    || 
    *** |    |    |    |  ****   ||       |    | *****   |    |    ||       |    |    |*****    |    || 
    1...5...10...15...20...25...30.   1...5...10...15...20...25...30.   1...5...10...15...20...25...30.

    Enero 2022 D. de C.               Enero 2022 D. de C.               Enero 2022 D. de C.
    Bioritmo para Mr.Dalien           Bioritmo para Mr.Dalien           Bioritmo para Mr.Dalien
    Estado: Físico                    Estado: Emocional                 Estado: Intelectual


       ***                    **                            *****       ******
     ** | ** |    |    |    ** |      *   |    |    |    | ** |  *      *   |**  |    |    |    |  | 
    **  |  **|    |    |   **  |      **  |    |    |    |*   |  |          |  **|    |    |    |  | 
    *   |   *|    |    |   *|  |       ** |    |    |    *    |  |          |   **    |    |    |  | 
        |    *    |    |  * |  |        **|    |    |   *|    |  |          |    **   |    |    |  | 
    ----+----+*---+----+-*--+--|      ---*+----+----+--*-+----+--|      ----+----+**--+----+----+--* 
        |    |**  |    |**  |  |          *    |    | ** |    |  |          |    |  * |    |    | *| 
        |    | *  |    |*   |  |          |*   |    |**  |    |  |          |    |   *|    |    |* | 
        |    |  * |    *    |  |          | *  |    **   |    |  |          |    |    **   |   **  | 
        |    |   **  **|    |  |          |  **|   **    |    |  |          |    |    |**  |  **|  | 
        |    |    **** |    |  |          |   ***** |    |    |  |          |    |    |  *****  |  | 
    1...5...10...15...20...25...      1...5...10...15...20...25...      1...5...10...15...20...25...

    Febrero 2022 D. de C.             Febrero 2022 D. de C.             Febrero 2022 D. de C.
    Bioritmo para Mr.Dalien           Bioritmo para Mr.Dalien           Bioritmo para Mr.Dalien
    Estado: Físico                    Estado: Emocional                 Estado: Intelectual

....
          ***                    **                    *****                      ******
        **   **   |    |    |  **||       |    |    | ** |  **|    ||       |    **   |**  |    |    || 
       **    |**  |    |    | ** ||       |    |    |*   |   **    ||       |  **|    |  **|    |    || 
       *|    | *  |    |    | *  ||       |    |    *    |    **   ||       | ** |    |   **    |    || 
      * |    |  * |    |    |*   ||       |    |   *|    |    |**  ||       |**  |    |    **   |    || 
    -*--+----+---*+----+----*----+|   ----+----+--*-+----+----+-*--+|   ----**---+----+----+**--+----+| 
    **  |    |   **    |   **    ||       |    | ** |    |    |  * ||      *|    |    |    |  * |    || 
    *   |    |    *    |   *|    ||   *   |    |**  |    |    |   *||     * |    |    |    |   *|    || 
        |    |    |*   |  * |    ||    *  |    **   |    |    |    *|   **  |    |    |    |    **   || 
        |    |    | ** |**  |    ||     **|   **    |    |    |    |*   *   |    |    |    |    |**  || 
        |    |    |  ****   |    ||      ***** |    |    |    |    ||       |    |    |    |    |  **** 
    1...5...10...15...20...25...30.   1...5...10...15...20...25...30.   1...5...10...15...20...25...30.

    Mayo 2022 D. de C.                Mayo 2022 D. de C.                Mayo 2022 D. de C.
    Bioritmo para Mr.Dalien           Bioritmo para Mr.Dalien           Bioritmo para Mr.Dalien
    Estado: Físico                    Estado: Emocional                 Estado: Intelectual

....

          ***                    *     *****                       *                            ******
        **   **   |    |    |  **|    **  | ** |    |    |    |   **        |    |    |    |   **    * 
       **    |**  |    |    | ** |        |  **|    |    |    |  * |        |    |    |    | ** |    | 
       *|    | *  |    |    | *  |        |   **    |    |    | *  |    *   |    |    |    |**  |    | 
      * |    |  * |    |    |*   |        |    **   |    |    |*   |    **  |    |    |    **   |    | 
    -*--+----+---*+----+----*----+    ----+----+*---+----+----*----+    -**-+----+----+---**----+----+ 
    **  |    |   **    |   **    |        |    | *  |    |   **    |       *|    |    |  * |    |    | 
    *   |    |    *    |   *|    |        |    |  * |    |  **|    |        *    |    | *  |    |    | 
        |    |    |*   |  * |    |        |    |   *|    | ** |    |        |**  |    **   |    |    | 
        |    |    | ** |**  |    |        |    |    **   |**  |    |        | ** |   **    |    |    | 
        |    |    |  ****   |    |        |    |    |*****    |    |        |   ***** |    |    |    | 
    1...5...10...15...20...25...30    1...5...10...15...20...25...30    1...5...10...15...20...25...30

    Noviembre 2022 D. de C.           Noviembre 2022 D. de C.           Noviembre 2022 D. de C.
    Bioritmo para Mr.Dalien           Bioritmo para Mr.Dalien           Bioritmo para Mr.Dalien
    Estado: Físico                    Estado: Emocional                 Estado: Intelectual


    **                    ***         ****                       ****                              ****
      **|    |    |    |**  |**  ||       **   |    |    |    | ** ||   *   |    |    |    |    | ** || 
       **    |    |    **   | ** ||       |**  |    |    |    |*   ||    ** |    |    |    |    **   || 
        *    |    |    *    |  * ||       | ** |    |    |    *    ||     **|    |    |    |   **    || 
        |*   |    |   *|    |   *||       |  **|    |    |   *|    ||      **    |    |    |  **|    || 
    ----+-*--+----+--*-+----+----*|   ----+---*+----+----+--*-+----+|   ----**---+----+----+-**-+----+| 
        | ** |    | ** |    |    **       |    *    |    | ** |    ||       | *  |    |    |*   |    || 
        |  * |    | *  |    |    |*       |    |*   |    |**  |    ||       |  * |    |    *    |    || 
        |   *|    |*   |    |    ||       |    | *  |    **   |    ||       |   **    |  **|    |    || 
        |    **  **    |    |    ||       |    |  **|   **    |    ||       |    **   | ** |    |    || 
        |    |****|    |    |    ||       |    |   ***** |    |    ||       |    | *****   |    |    || 
    1...5...10...15...20...25...30.   1...5...10...15...20...25...30.   1...5...10...15...20...25...30.

    Diciembre 2022 D. de C.           Diciembre 2022 D. de C.           Diciembre 2022 D. de C.
    Bioritmo para Mr.Dalien           Bioritmo para Mr.Dalien           Bioritmo para Mr.Dalien
    Estado: Físico                    Estado: Emocional                 Estado: Intelectual

C

Translation of: Locomotive Basic
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int day(int y, int m, int d) {
    return 367 * y - 7 * (y + (m + 9) / 12) / 4 + 275 * m / 9 + d - 730530;
}

void cycle(int diff, int l, char *t) {
    int p = round(100 * sin(2 * M_PI * diff / l));
    printf("%12s cycle: %3i%%", t, p);
    if (abs(p) < 15)
        printf(" (critical day)");
    printf("\n");
}

int main(int argc, char *argv[]) {
    int diff;

    if (argc < 7) {
        printf("Usage:\n");
        printf("cbio y1 m1 d1 y2 m2 d2\n");
        exit(1);
    }
    diff = abs(day(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]))
             - day(atoi(argv[4]), atoi(argv[5]), atoi(argv[6])));
    printf("Age: %u days\n", diff);
    cycle(diff, 23, "Physical");
    cycle(diff, 28, "Emotional");
    cycle(diff, 33, "Intellectual");
}

Test:

gcc -o cbio cbio.c -lm
./cbio 1972 7 11 1943 3 9
Age: 10717 days
    Physical cycle: -27%
   Emotional cycle: -100%

Intellectual cycle: -100%</syntaxhighlight>

C++

#include <chrono>
#include <cmath>
#include <cstdint>
#include <iostream>
#include <numbers>
#include <sstream>
#include <string>
#include <vector>

const double tau = 2 * std::numbers::pi;
const std::vector<std::string> cycles { "PHYSICAL", "EMOTIONAL", "MENTAL" };
const std::vector<std::int32_t> cycle_lengths { 23, 28, 33 };
const std::vector<std::vector<std::string>> descriptions { { "up and rising", "peak" },
										                   { "up but falling", "transition" },
										                   { "down and falling", "valley" },
									                       { "down but rising", "transition" } };

std::string to_string(const std::chrono::sys_days& sys_date) {
	std::stringstream stream;
	stream << sys_date;
	std::string iso_date;
	stream >> iso_date;
	return iso_date;
}

std::chrono::sys_days create_date(const std::string& iso_date) {
	const int year = std::stoi(iso_date.substr(0, 4));
	const unsigned int month = std::stoi(iso_date.substr(5, 7));
	const unsigned int day = std::stoi(iso_date.substr(8, 10));

	std::chrono::year_month_day date{std::chrono::year{year}, std::chrono::month{month}, std::chrono::day{day}};
	return std::chrono::sys_days(date);
}

void biorhythms(const std::vector<std::string>& date_pair) {
	std::chrono::sys_days birth_date = create_date(date_pair[0]);
	std::chrono::sys_days target_date = create_date(date_pair[1]);
	int32_t days_between = ( target_date - birth_date ).count();
	std::cout << "Birth date " << birth_date << ", Target date " << target_date << std::endl;
	std::cout << "Days between: " << days_between << std::endl;

	for ( int32_t i = 0; i < 3; ++i ) {
		const int32_t cycle_length = cycle_lengths[i];
		const int32_t position_in_cycle = days_between % cycle_length;
		const int32_t quadrant_index = 4 * position_in_cycle / cycle_length;
		const int32_t percentage = round(100 * sin(tau * position_in_cycle / cycle_length));

		std::string description;
		if ( percentage > 95 ) {
			description = "peak";
		} else if ( percentage < -95 ) {
			description = "valley";
		} else if ( abs(percentage) < 5 ) {
			description = "critical transition";
		} else {
			const int32_t days_to_transition = ( cycle_length * ( quadrant_index + 1 ) / 4 ) - position_in_cycle;
			std::chrono::sys_days transition_date = target_date + std::chrono::days{days_to_transition};
			std::string trend = descriptions[quadrant_index][0];
			std::string next_transition = descriptions[quadrant_index][1];
			description = std::to_string(percentage) + "% (" + trend + ", next " + next_transition
				+ " " + to_string(transition_date) + ")";
		}

		std::cout << cycles[i] << " day " << position_in_cycle  << ": " << description << std::endl;
	}
	std::cout << std::endl;
}

int main() {
	const std::vector<std::vector<std::string>> date_pairs = {
		{ "1943-03-09", "1972-07-11" },
		{ "1809-01-12", "1863-11-19" },
		{ "1809-02-12", "1863-11-19" } };

	for ( const std::vector<std::string>& date_pair : date_pairs ) {
		biorhythms(date_pair);
	}
}
Output:
Birth date 1943-03-09, Target date 1972-07-11
Days between: 10717
PHYSICAL day 22: -27% (down but rising, next transition 1972-07-12)
EMOTIONAL day 21: valley
MENTAL day 25: valley

Birth date 1809-01-12, Target date 1863-11-19
Days between: 20034
PHYSICAL day 1: 27% (up and rising, next peak 1863-11-23)
EMOTIONAL day 14: critical transition
MENTAL day 3: 54% (up and rising, next peak 1863-11-24)

Birth date 1809-02-12, Target date 1863-11-19
Days between: 20003
PHYSICAL day 16: -94% (down and falling, next valley 1863-11-20)
EMOTIONAL day 11: 62% (up but falling, next transition 1863-11-22)
MENTAL day 5: 81% (up and rising, next peak 1863-11-22)

COBOL

Translation of: Locomotive Basic
 

       identification division.
       program-id.             bio.
       environment division. 
      *************************************************************
      **** To execute on command line enter program name followed 
      **** by birth date ccyymmdd and then target date. 
      **** Example: bio 18090102 18631117
      **** Will display the three cycles:  
      **** Physcial 23 days, Emotional 28 days, Mental 33 days 
      **** for that date. 
      ****
      *************************************************************
       configuration section.
       source-computer.
           System76 
      *           with debugging mode
           .
       repository.    
           function all intrinsic.

       data division.
       working-storage section.
       01 w-d1                                              pic x(08).
       01 w-d2                                              pic x(08).
       01 n-d1                                              pic 9(08).
       01 n-d2                                              pic 9(08).
       01 w-i1                                       comp-x pic x(04).
       01 w-i2                                       comp-x pic x(04).
       01 w-days                                            pic 9(07).
       01 arg-knt                                    comp-5 pic x(01).
       01 bx                                       pic 9.    
       01 bio-tbl  value 'Physical 23Emotional28Mental   33'.
               05  bio-entry  occurs 3 times.
                   10  bio-cyc                     pic x(09).
                   10  bio-lth                     pic 9(02).
       01 bio-data occurs 3 times.
          05  bio-mod                              pic 9(02).
          05  bio-sin                              pic s999v9.     
          05  bio-dsc                              pic x(09). 

       procedure division.
           accept arg-knt from argument-number
           if arg-knt <> 2
           then
            display 'two arguments are required:' upon SYSERR
            display ' 1. first  date ccyymmdd'    upon SYSERR
            display ' 2. second date ccyymmdd'    upon SYSERR
            stop run returning -1
           end-if
           accept w-d1 from argument-value
           if  w-d1 not numeric
               display ' first date not numeric ' upon syserr
               move 2 to return-code
               stop run 
           end-if
           move w-d1 to n-d1
           if  (n-d1 > 99991231)
               display ' first date must be less than 99991232' 
                       upon syserr
               move 3 to return-code
               stop run
           end-if
           if  (n-d1 < 16010101)
               display ' first date must be greater than 16010100' 
                       upon syserr
               move 4 to return-code
               stop run
           end-if
           if  ((n-d1(5:2) = '00') 
               or
                (n-d1(5:2) > '12'))
               display ' invalid month for first date ' upon syserr
               move 5 to return-code
               stop run
           end-if
           if  ((n-d1(7:2) = '00')
               or
                (n-d1(7:2) > '31'))
               display ' invalid day for first date ' upon syserr
               move 6 to return-code
               stop run
           end-if
           accept w-d2 from argument-value
           if  w-d2 not numeric
               display 'second date not numeric ' upon syserr
               move 12 to return-code
               stop run
           end-if
           move w-d2 to n-d2
           if  (n-d2 > 99991231)
               display ' second date must be less than 99991232' 
                       upon syserr
               move 13 to return-code
               stop run
           end-if
           if  (n-d2 < 16010101)
               display ' second date must be greater than 16010100'  
                       upon syserr
               move 14 to return-code
               stop run
           end-if
           if  ((n-d2(5:2) = '00')
               or
                (n-d2(5:2) > '12'))
               display ' invalid month for second date ' upon syserr
               move 15 to return-code
               stop run
           end-if
           if  ((n-d2(7:2) = '00')
               or
                (n-d2(7:2) > '31'))
               display ' invalid day for second date ' upon syserr
               move 16 to return-code
               stop run
           end-if
           move w-d1 to n-d1
           move w-d2 to n-d2
           move integer-of-date(n-d1) to w-i1
           move integer-of-date(n-d2) to w-i2
           compute w-days = w-i1 - w-i2
           display w-days
           perform  varying  bx from 1 by 1 until bx greater than 3 
               move mod(w-days, bio-lth(bx)) to bio-mod(bx) 
               compute bio-sin(bx) rounded 
                  = 100 * sin(2 * PI * bio-mod(bx) / bio-lth(bx)) 
               end-compute
               display bio-cyc(bx) " " 
                       bio-mod(bx) ":" 
                       bio-sin(bx) "%" with no advancing 
               end-display                 
               if  bio-sin(bx) > 95
                   move  " peak" to bio-dsc(bx)
               end-if 
               if  bio-sin(bx) < -95
                   move  " valley" to bio-dsc(bx)
               end-if   
               if  abs(bio-sin(bx)) < 5
                   move " critical" to bio-dsc(bx)  
               end-if        
               display bio-dsc(bx)  
           end-perform
           move 0 to return-code
           goback
           .

Test:

Compile and Test 
C:\GnuCOBOL>
C:\GnuCOBOL>cobc -x bio.cbl

C:\GnuCOBOL>bio 18090112 18631119
0020034
Physical  01:+027.0%
Emotional 14:+000.0% critical
Mental    03:+054.1%

Common Lisp

Translation of: Locomotive Basic
;;;; Common Lisp biorhythms

;;; Get the days to J2000
;;; FNday only works between 1901 to 2099 - see Meeus chapter 7

(defun day (y m d) 
    (+ (truncate (* -7 (+ y (truncate (+ m 9) 12))) 4) 
       (truncate (* 275 m) 9) d -730530 (* 367 y)))

;;; Get the difference in days between two dates

(defun diffday (y1 m1 d1 y2 m2 d2)
    (abs (- (day y2 m2 d2) (day y1 m1 d1))))

;;; Print state of a single cycle

(defun print-cycle (diff len nm)
    (let ((perc (round (* 100 (sin (* 2 pi diff (/ 1 len)))))))
          (format t "~A cycle: ~D% " nm perc)
          (if (< (abs perc) 15)
              (format t "(critical)~%")
              (format t "~%"))))

;;; Print all cycles

(defun print-bio (y1 m1 d1 y2 m2 d2)
    (let ((diff (diffday y1 m1 d1 y2 m2 d2)))
          (format t "Age in days: ~D ~%" diff)
          (print-cycle diff 23 "physical")
          (print-cycle diff 28 "emotional")
          (print-cycle diff 33 "intellectual")))
Output:
* (print-bio 1972 7 11 1943 3 9)
Age in days: 10717 
physical cycle: -27% 
emotional cycle: -100% 
intellectual cycle: -100% 

Delphi

Library: System.Math
Translation of: Go
program Biorhythms;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.Math;

var
  cycles: array[0..2] of string = ('Physical day ', 'Emotional day', 'Mental day   ');
  lengths: array[0..2] of Integer = (23, 28, 33);
  quadrants: array[0..3] of array[0..1] of string = (('up and rising', 'peak'),
    ('up but falling', 'transition'), ('down and falling', 'valley'), ('down but rising',
    'transition'));
  datePairs: array[0..2] of array[0..1] of string = (('1943-03-09', '1972-07-11'),
    ('1809-01-12', '1863-11-19'), ('1809-02-12', '1863-11-19') // correct DOB for Abraham Lincoln
    );

procedure Check(err: string);
begin
  if not err.IsEmpty then
    raise Exception.Create(err);
end;

function ParseDate(sDate: string; var Date: TDateTime): string;
var
  dtFormat: TFormatSettings;
begin
  Result := '';
  with dtFormat do
  begin
    DateSeparator := '-';
    ShortDateFormat := 'yyyy-mm-dd';
  end;

  try
    Date := StrtoDateTime(sDate, dtFormat);
  except
    on E: Exception do
      Result := E.Message;
  end;
end;

function DateToStr(dt: TDateTime): string;
var
  dtFormat: TFormatSettings;
begin
  Result := '';
  with dtFormat do
  begin
    DateSeparator := '-';
    ShortDateFormat := 'yyyy-mm-dd';
  end;
  Result := DateTimeToStr(dt, dtFormat);
end;

// Parameters assumed to be in YYYY-MM-DD format.
procedure CalcBiorhythms(birthDate, targetDate: string);
var
  bd, td: TDateTime;
  days: Integer;
begin
  Check(ParseDate(birthDate, bd));
  Check(ParseDate(targetDate, td));
  days := Trunc(td - bd);
  writeln('Born ', birthDate, ', Target ', targetDate);
  Writeln('Days ', days);
  for var i := 0 to 2 do
  begin
    var len := lengths[i];
    var cycle := cycles[i];
    var position := days mod len;
    var quadrant: Integer := trunc(position * 4 / len);
    var percent := sin(2.0 * PI * position / len);

    percent := floor(percent * 1000) / 10;
    var descript := '';
    if percent > 95 then
      descript := ' peak'
    else if percent < -95 then
      descript := ' valley'
    else if abs(percent) < 5 then
      descript := ' critical transition'
    else
    begin
      var daysToAdd := trunc((quadrant + 1) * len / 4 - position);
      var transition := td + daysToAdd;
      var trend := quadrants[quadrant, 0];
      var next := quadrants[quadrant, 1];
      var transStr := DateToStr(transition);
      var percentRounded := percent;
      descript := format('%5.3f%% (%s, next %s %s)', [percentRounded, trend,
        next, transStr]);
    end;
    writeln(format('%s %2d : %s', [cycle, position, descript]));
  end;
  writeln;
end;

begin
  for var i := 0 to High(datePairs) do
    CalcBiorhythms(datePairs[i, 0], datePairs[i, 1]);
  readln;
end.

EasyLang

Run it

birth$ = "1943-03-09"
date$ = "1972-07-11"
# date$ = substr timestr systime 1 10
# 
func day d$ .
   y = number substr d$ 1 4
   m = number substr d$ 6 2
   d = number substr d$ 9 2
   return 367 * y - 7 * (y + (m + 9) div 12) div 4 + 275 * m div 9 + d - 730530
.
textsize 4
func init b$ d$ .
   linewidth 0.2
   move 50 0
   line 50 100
   move 0 50
   line 100 50
   for d = -20 to 20
      move x 50
      circle 0.5
      x += 2.5
   .
   move 4 94
   text b$
   move 4 88
   text d$
   days = day date$ - day birth$
   move 4 80
   text days & " days"
   return days
.
proc cycle now cyc t$ col . .
   color col
   move 4 cyc * 1.2 - 20
   text t$
   linewidth 0.5
   for d = now - 20 to now + 20
      p = 20 * sin (360 * d / cyc)
      line x 50 + p
      x += 2.5
   .
.
days = init birth$ date$
cycle days 23 "Physical" 900
cycle days 28 "Emotional" 090
cycle days 33 "Intellectual" 009

Emacs Lisp

For Emacs, it makes sense to implement this as an interactive command which is personalized to the user's birthdate and computes the biorhythm for today. So if you put this code into your .emacs file (note that the birthdate has to be in MDY order in Emacs!):

(require 'calendar)

(setq biorhythm-birthdate '(3 16 1953))

(defun biorhythm ()
  "Show today's biorhythm."
  (interactive)
  (let* ((diff (abs (- (string-to-number (calendar-astro-date-string
               biorhythm-birthdate)) (string-to-number
               (calendar-astro-date-string)))))
         (rhyt '(23 28 33))
         (perc (mapcar (lambda (x) (round (* 100 (sin
               (* 2 pi diff (/ 1.0 x)))))) rhyt)))
    (message "age: %i  physical: %i%%  emotional: %i%%  intellectual: %i%%"
             diff (car perc) (cadr perc) (caddr perc))))

Then typing "M-x biorhythm" will produce this output in the Emacs echo area on 2022-04-21:

age: 25238  physical: 94%  emotional: 78%  intellectual: -97%

Factor

USING: calendar calendar.parser formatting io kernel math
math.constants math.functions ;

: days-between ( ymd-str ymd-str -- n )
    [ ymd>timestamp ] bi@ time- duration>days abs ;

: trend ( pos len -- str ) / 4 * floor 3 divisor? "↑" "↓" ? ;

: percent ( pos len -- x ) [ 2pi * ] [ / sin 100 * ] bi* ;

: .day ( days cycle-length day-type -- )
    write [ mod ] keep [ drop ] [ percent ] [ trend ] 2tri
    " day %d: %.1f%%%s\n" printf ;

: .biorhythm ( ymd-str ymd-str -- )
    2dup "Born %s, Target %s\n" printf days-between dup
    "Day %d\n" printf
    [ 23 "Physical" .day ]
    [ 28 "Emotional" .day ]
    [ 33 "Mental" .day ] tri ;

"1809-02-12" "1863-11-19" .biorhythm
Output:
Born 1809-02-12, Target 1863-11-19
Day 20003
Physical day 16: -94.2%↓
Emotional day 11: 62.3%↓
Mental day 5: 81.5%↑

FOCAL

Translation of: Locomotive Basic
1.01 T "Enter birthdate (y,m,d)",!
1.02 ASK Y,M,D
1.03 D 2; S BZ=Z
1.04 T "Enter today's date (y,m,d)",!
1.05 ASK Y,M,D
1.06 D 2; S DI=Z - BZ
1.07 T %6,"Age in days", DI,!
1.08 T "Physical cycle:     "
1.09 S L=23; D 3
1.10 T "Emotional cycle:    "
1.11 S L=28; D 3
1.12 T "Intellectual cycle: "
1.13 S L=33; D 3
1.14 Q

2.1 S QA = FITR((M + 9) / 12)
2.2 S QB = FITR(275 * M / 9)
2.3 S QC = FITR(7 * (Y + QA) / 4)
2.4 S Z = 367 * Y - QC + QB + D - 730530

3.1 S P = 100 * FSIN(2*3.1415926536*DI/L)
3.2 T %3,P,"%"
3.3 I (FABS(P)-15)4.1,5.1,5.1

4.1 T "  CRITICAL",!

5.1 T !
Output:
*G
Enter birthdate (y,m,d)
:1943,:3,:9
Enter today's date (y,m,d)
:1972,:7,:11
Age in days=  10717
Physical cycle:     =- 27%
Emotional cycle:    =-100%
Intellectual cycle: =-100%

Fortran

C     ------------------------------------------------------------------
      PROGRAM BIORHYTHM
C     ------------------------------------------------------------------
      DOUBLE PRECISION GETJD
      CHARACTER*3 DOW
      
      DOUBLE PRECISION JD0, JD1, JD2, PI2, DIF
      
      INTEGER BYEAR, BMON, BDAY, TYEAR, TMON, TDAY
      INTEGER I, J, PHY, EMO, MEN, NDAY, DNUM, YR, DOY
      CHARACTER*3 DNAME
      CHARACTER*1 GRID, ROW(65)
C     ------------------------------------------------------------------

      PI2 = ACOS(-1.0D0)*2.0D0
      
      WRITE(*,*) 'ENTER YOUR BIRTHDAY YYYY MM DD'
      READ(*,*) BYEAR, BMON, BDAY

      WRITE(*,*) 'ENTER START DATE YYYY MM DD'
      READ(*,*) TYEAR, TMON, TDAY

      WRITE(*,*) 'ENTER NUMBER OF DAYS TO PLOT'
      READ(*,*) NDAY

      JD0 = GETJD( TYEAR, 1,  1 )
      JD1 = GETJD( BYEAR, BMON, BDAY )
      JD2 = GETJD( TYEAR, TMON, TDAY )

      WRITE(*,1010)
      WRITE(*,1000) DOW(JD1), INT( JD2-JD1 )
      WRITE(*,1010)
      WRITE(*,1020)
      DO I=1,NDAY
         DIF = JD2 - JD1
         PHY = INT(3.3D1+3.2D1*SIN( PI2 * DIF / 2.3D1 ))
         EMO = INT(3.3D1+3.2D1*SIN( PI2 * DIF / 2.8D1 ))
         MEN = INT(3.3D1+3.2D1*SIN( PI2 * DIF / 3.3D1 ))

         IF ( PHY.LT.1  ) PHY = 1
         IF ( EMO.LT.1  ) EMO = 1
         IF ( MEN.LT.1  ) MEN = 1
         IF ( PHY.GT.65 ) PHY = 65
         IF ( EMO.GT.65 ) EMO = 65
         IF ( MEN.GT.65 ) MEN = 65
         
         DNAME = DOW(JD2)
         DOY = INT(JD2-JD0)+1
         IF ( DNAME.EQ.'SUN' ) THEN
            GRID = '.'
         ELSE
            GRID = ' '
         END IF
         DO J=1,65
            ROW(J) = GRID
         END DO
         ROW(1)  = '|'
         ROW(17) = ':'
         ROW(33) = '|'
         ROW(49) = ':'
         ROW(65) = '|'
         ROW(PHY) = 'P'
         ROW(EMO) = 'E'
         ROW(MEN) = 'M'
         IF ( PHY.EQ.EMO ) ROW(PHY) = '*'
         IF ( PHY.EQ.MEN ) ROW(PHY) = '*'
         IF ( EMO.EQ.MEN ) ROW(EMO) = '*'
         WRITE(*,1030) ROW,DNAME,DOY
         JD2 = JD2 + 1.0D0
      END DO
      WRITE(*,1010)

C     ------------------------------------------------------------------
      
 1000 FORMAT( 'YOU WERE BORN ON A (', A3, ') YOU WERE ',I0,
     $        ' DAYS OLD AT THE START.' )
 1010 FORMAT( 75('=') )
 1020 FORMAT( '-1',31X,'0',30X,'+1     DOY' )
 1030 FORMAT( 1X,65A1, 1X, A3, 1X, I3 )

      STOP
      END

C     ------------------------------------------------------------------
      FUNCTION DOW( JD )
C     ------------------------------------------------------------------
C     RETURN THE ABBREVIATION FOR THE DAY OF THE WEEK
C     JD  JULIAN DATE - GREATER THAN 1721423.5 (JAN 1, 0001 SATURDAY)
C     ------------------------------------------------------------------
      DOUBLE PRECISION JD
      INTEGER IDX
      CHARACTER*3 DOW, NAMES(7)
      DATA NAMES/'SAT','SUN','MON','TUE','WED','THR','FRI'/

      IDX = INT(MODULO(JD-1.721423500D6,7.0D0)+1)

      DOW = NAMES(IDX)
      RETURN
      END
      
C     ------------------------------------------------------------------
      FUNCTION ISGREG( Y, M, D )
C     ------------------------------------------------------------------
C     IS THIS DATE ON IN THE GREGORIAN CALENDAR
C     DATES BEFORE OCT  5 1582 ARE JULIAN
C     DATES AFTER  OCT 14 1582 ARE GREGORIAN
C     DATES OCT 5-14 1582 INCLUSIVE DO NOT EXIST
C     ------------------------------------------------------------------
C     YEAR    1-ANYTHING
C     MONTH   1-12
C     DAY     1-31
C     ------------------------------------------------------------------
      LOGICAL ISGREG
      INTEGER Y, M, D
C     ------------------------------------------------------------------
      ISGREG=.TRUE.
      IF ( Y.LT.1582 ) GOTO 888
      IF ( Y.GT.1582 ) GOTO 999
      IF ( M.LT.10 )   GOTO 888
      IF ( M.GT.10 )   GOTO 999
      IF ( D.LT.5 )    GOTO 888
      IF ( D.GT.14 )   GOTO 999

      WRITE(*,*) Y,M,D,' DOES NOT EXIST'
      GOTO 999

 888  CONTINUE
      ISGREG=.FALSE.
 999  CONTINUE
      RETURN
      END
      
C     ------------------------------------------------------------------
      FUNCTION GETJD( YEAR, MONTH, DAY )
C     ------------------------------------------------------------------
C     RETURN THE JULIAN DATE
C     YEAR    1-ANYTHING
C     MONTH   1-12
C     DAY     1-31
C     ------------------------------------------------------------------
      DOUBLE PRECISION GETJD
      INTEGER YEAR, MONTH, DAY
      INTEGER Y, M, D, A, B, P1, P2
C     ------------------------------------------------------------------
      DOUBLE PRECISION TEMP
      LOGICAL ISGREG, IG

      IG = ISGREG( YEAR, MONTH, DAY )
      Y  = YEAR
      M  = MONTH
      D  = DAY

      IF (M.LT.3) THEN
         Y = Y - 1
         M = M + 12
      ENDIF

      IF (IG) THEN
         A =         FLOOR( DBLE(Y) * 1.0D-2 )
         B = 2 - A + FLOOR( DBLE(A) * 2.5D-1 )
      ELSE
         A = 0
         B = 0
      ENDIF
     
      P1 = FLOOR( 3.65250D2 * DBLE(Y + 4716) )
      P2 = FLOOR( 3.06001D1 * DBLE(M + 1) )

      GETJD = DBLE(P1 + P2 + D + B) - 1.5245D3
      
      RETURN
      END
Input:
 ENTER YOUR BIRTHDAY YYYY MM DD
1992 4 10
 ENTER START DATE YYYY MM DD
2021 02 14
 ENTER NUMBER OF DAYS TO PLOT
40
Output:
===========================================================================
YOU WERE BORN ON A (FRI) YOU WERE 10537 DAYS OLD AT THE START.
===========================================================================
-1                               0                              +1     DOY
 |...............:...............|...............:......P....E.M.| SUN  45
 |               :               |               :        E MP   | MON  46
 |               :               |               :  E    M      P| TUE  47
 |               :               |            E  :  M           P| WED  48
 |               :               |      E      M :             P | THR  49
 |               :               E        M      :         P     | FRI  50
 |               :       E       |  M            :   P           | SAT  51
 |...............:.E.........M...|...........P...:...............| SUN  52
 |           E   :     M         |   P           :               | MON  53
 |     E         :M         P    |               :               | TUE  54
 |  E        M   :  P            |               :               | WED  55
 E      M   P    :               |               :               | THR  56
 E   MP          :               |               :               | FRI  57
 E*              :               |               :               | SAT  58
 *..E............:...............|...............:...............| SUN  59
 *     E         :               |               :               | MON  60
 M  P        E   :               |               :               | TUE  61
 | M     P       : E             |               :               | WED  62
 |    M         P:       E       |               :               | THR  63
 |        M      :      P        E               :               | FRI  64
 |             M :              P|      E        :               | SAT  65
 |...............:...M...........|.......P....E..:...............| SUN  66
 |               :        M      |               P  E            | MON  67
 |               :              M|               :      P E      | TUE  68
 |               :               |     M         :           *   | WED  69
 |               :               |          M    :              *| THR  70
 |               :               |               :M             PE FRI  71
 |               :               |               :     M       PE| SAT  72
 |...............:...............|...............:.........*.E...| SUN  73
 |               :               |               :   P    E   M  | MON  74
 |               :               |           P   :  E           M| TUE  75
 |               :               |   P        E  :              M| WED  76
 |               :          P    |      E        :              M| THR  77
 |               :  P           E|               :             M | FRI  78
 |          P    :       E       |               :          M    | SAT  79
 |....P..........:.E.............|...............:.......M.......| SUN  80
 |P          E   :               |               :  M            | MON  81
 P     E         :               |             M :               | TUE  82
 P  E            :               |        M      :               | WED  83
 E  P            :               |  M            :               | THR  84
===========================================================================

FreeBASIC

Translation of: VBA
#define floor(x) ((x*2.0-0.5) Shr 1)
#define pi (4 * Atn(1))

Function Gregorian(db As String) As Integer
    Dim As Integer M, Y, D
    Y = Valint(Left(db,4)) :  M = Valint(Mid(db,6,2)) : D = Valint(Right(db,2))
    Dim As Integer N = (M+9) - Int((M+9)/12) * 12
    Dim As Integer W = Y - Int(N/10)
    Dim As Integer G = 365 * W + Int(W/4) - Int(W/100) + Int(W/400)
    G += Int((N*306+5)/10)+(D-1)
    Return G
End Function

Function Biorhythm(Birthdate As String, Targetdate As String) As String
    'Jagged Array
    Dim As String TextArray(4,2) = {{"up and rising", "peak"}, {"up but falling", "transition"}, {"down and falling", "valley"}, {"down but rising", "transition"}}
    
    Dim As Integer DaysBetween = Gregorian(Targetdate) - Gregorian(Birthdate)
    
    Dim As Integer positionP = DaysBetween Mod 23
    Dim As Integer positionE = DaysBetween Mod 28
    Dim As Integer positionM = DaysBetween Mod 33
    
    'return the positions - just to return something
    Biorhythm = Str(positionP) & "/" & Str(positionE) & "/" & Str(positionM)
    
    Dim As Integer quadrantP = Int(4 * positionP / 23)
    Dim As Integer quadrantE = Int(4 * positionE / 28)
    Dim As Integer quadrantM = Int(4 * positionM / 33)
    
    Dim As Single percentageP = Fix(100 * Sin(2 * pi * (positionP / 23)))
    Dim As Single percentageE = Fix(100 * Sin(2 * pi * (positionE / 28)))
    Dim As Single percentageM = Fix(100 * Sin(2 * pi * (positionM / 33)))
    
    Dim As Single transitionP = Val(Targetdate) + floor((quadrantP + 1) / 4 * 23) - positionP
    Dim As Single transitionE = Val(Targetdate) + floor((quadrantE + 1) / 4 * 28) - positionE
    Dim As Single transitionM = Val(Targetdate) + floor((quadrantM + 1) / 4 * 33) - positionM
    
    Dim As String textP, textE, textM, Header1Text, Header2Text
    Select Case percentageP
    Case Is > 95
        textP = "Physical day  " & positionP & " : " & "peak"
    Case Is < -95
        textP = "Physical day  " & positionP & " : " & "valley"
    Case -5 To 5
        textP = "Physical day  " & positionP & " : " & "critical transition"
    Case Else
        textP = "Physical day  " & positionP & " : " & percentageP & "% (" & TextArray(quadrantP,0) & ", next " & TextArray(quadrantP,1) & " " & transitionP & ")"
    End Select
    
    Select Case percentageE
    Case Is > 95
        textE = "Emotional day " & positionE & " : " & "peak"
    Case Is < -95
        textE = "Emotional day " & positionE & " : " & "valley"
    Case -5 To 5
        textE = "Emotional day " & positionE & " : " & "critical transition"
    Case Else
        textE = "Emotional day " & positionE & " : " & percentageE & "% (" & TextArray(quadrantE,0) & ", next " & TextArray(quadrantE,1) & " " & transitionE & ")"
    End Select
    
    Select Case percentageM
    Case Is > 95
        textM = "Mental day " & positionM & "    : " & "peak"
    Case Is < -95
        textM = "Mental day " & positionM & "    : " & "valley"
    Case -5 To 5
        textM = "Mental day " & positionM & "    : " & "critical transition"
    Case Else
        textM = "Mental day " & positionM & "    : " & percentageM & "% (" & TextArray(quadrantM,0) & ", next " & TextArray(quadrantM,1) & " " & transitionM & ")"
    End Select
    
    Header1Text = "Born " & Birthdate & ", Target " & Targetdate
    Header2Text = "Day " & DaysBetween
    
    Print Header1Text
    Print Header2Text
    Print textP
    Print textE
    Print textM
    Print
End Function

Biorhythm("1943-03-09", "1972-07-11")
Biorhythm("1809-02-12", "1863-11-19")   'correct DOB for Abraham Lincoln
Biorhythm("1809-01-12", "1863-11-19")

FutureBasic

Oct 16, 2024 fixed the percentage amounts

/*
Biorhythms task for Rosetta Code
https://rosettacode.org/wiki/Biorhythms

Translated from FreeBASIC to FutureBasic
Rich Love May 24, 2024

Oct 16, 2024 fixed the percentage amounts

*/



local fn Gregorian(db As str255) As short
  short M, Y, D
  Y = val(Left$(db,4)) :  M = Val(Mid$(db,6,2)) : D = Val(Right$(db,2))
  short N = (M+9) - Int((M+9)/12) * 12
  short W = Y - Int(N/10)
  short G = 365 * W + Int(W/4) - Int(W/100) + Int(W/400)
  G += Int((N*306+5)/10)+(D-1)
end fn = G


void local fn Biorhythm(Birthdate As str255, Targetdate As str255)
  
  str255 TextArray(4,2)
  TextArray(0,0) = "up and rising"
  TextArray(1,0) = "up but falling"
  TextArray(2,0) = "down and falling"
  TextArray(3,0) = "down but rising"
  TextArray(0,1) = "peak"
  TextArray(1,1) = "transition"
  TextArray(2,1) = "valley"
  TextArray(3,1) = "transition"
  
  
  short DaysBetween = fn Gregorian(Targetdate) - fn Gregorian(Birthdate) + 1
  short positionP = DaysBetween Mod 23
  short positionE = DaysBetween Mod 28
  short positionM = DaysBetween Mod 33
  short quadrantP = Int(4 * positionP / 23)
  short quadrantE = Int(4 * positionE / 28)
  short quadrantM = Int(4 * positionM / 33)
  short percentageP = int(100 * Sin(2 * (pi * positionP) / 23))
  short percentageE = int(100 * Sin(2 * (pi * positionE) / 28))
  short percentageM = int(100 * Sin(2 * (pi * positionM) / 33))
  
  str255 textP, textE, textM, Header1Text, Header2Text
  
  
  Select Case percentageP
    Case  > 95
      textP  = "Physical day  " + str$(positionP) + " : " + "peak"
    Case  < -95
      textP = "Physical day  " + str$(positionP) + " : " + "valley"
    Case -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5
      textP = "Physical day  " + str$(positionP) + " : " + "critical transition"
    Case Else
      textP = "Physical day  " + str$(positionP) + " : " + str$(percentageP) + "% (" + TextArray(quadrantP,0) + ")"
  End Select
  
  Select Case percentageE
    Case  > 95
      textE = "Emotional day " + STR$(positionE) + " : " + "peak"
    Case  < -95
      textE = "Emotional day " + STR$(positionE) + " : " + "valley"
    Case -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5
      textE = "Emotional day " + STR$(positionE) + " : " + "critical transition"
    Case Else
      textE = "Emotional day " + STR$(positionE) + " : " + str$(percentageE) + "% (" + TextArray(quadrantE,0) + ")"
  End Select
  
  Select Case percentageM
    Case  > 95
      textM = "Mental day " + str$(positionM)+ "    : " + "peak"
    Case  < - 95
      textM = "Mental day " + str$(positionM) + "    : " + "valley"
    Case -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5
      textM = "Mental day " + str$(positionM) + "    : " + "critical transition"
    Case Else
      textM = "Mental day " + str$(positionM) + "    : " + str$(percentageM) + "% (" + TextArray(quadrantM,0) + ")"
  End Select
  
  Header1Text = "Born " + Birthdate + ", Target " + Targetdate
  Header2Text = "Day " + str$(DaysBetween)
  
  Print Header1Text
  Print Header2Text
  Print textP
  Print textE
  Print textM
  Print
end fn

window 1, @"Biorhythms"
windowcenter(1)
WindowSetBackgroundColor(1,fn ColorBlack)

print

// Lets do four different birthdates and target dates
text ,,fn colorCyan
fn Biorhythm("1943-03-09", "1972-07-11")
text ,,fn colorGreen
fn Biorhythm("1809-02-12", "1863-11-19")   // DOB for Abraham Lincoln
text ,,fn colorYellow
fn Biorhythm("1809-01-12", "1863-11-19")
text ,,fn colorWhite
fn Biorhythm("1943-03-09", "1972-07-11")  // Bobby Fisher Chess Tournament


handleevents
Output:
Born 1943-03-09, Target 1972-07-11
Day 10717
Physical day 22: -27% (down but rising)
Emotional day 21: valley
Mental day 25:  valley


Born 1809-02-12, Target 1863-11-19
Day 20003
Physical day 16: -94% (down and falling)
Emotional day 11 : 62% (up but falling)
Mental day 5: 81% (up and rising)

Born 1809-01-12, Target 1863-11-19
Day 20034
Physical day 1 : 27% (up and rising)
Emotional day 14 : critical transition
Mental day 3: 54% (up and rising)

Born 1943-03-09, Target 1972-07-11
Day 10717
Physical day
22: -27% (down but rising)
Emotional day 21: valley
Mental day 25: valley

Go

Translation of: Wren
package main

import (
    "fmt"
    "log"
    "math"
    "time"
)

const layout = "2006-01-02" // template for time.Parse

var cycles = [3]string{"Physical day ", "Emotional day", "Mental day   "}
var lengths = [3]int{23, 28, 33}
var quadrants = [4][2]string{
    {"up and rising", "peak"},
    {"up but falling", "transition"},
    {"down and falling", "valley"},
    {"down but rising", "transition"},
}

func check(err error) {
    if err != nil {
        log.Fatal(err)
    }
}

// Parameters assumed to be in YYYY-MM-DD format.
func biorhythms(birthDate, targetDate string) {
    bd, err := time.Parse(layout, birthDate)
    check(err)
    td, err := time.Parse(layout, targetDate)
    check(err)
    days := int(td.Sub(bd).Hours() / 24)
    fmt.Printf("Born %s, Target %s\n", birthDate, targetDate)
    fmt.Println("Day", days)
    for i := 0; i < 3; i++ {
        length := lengths[i]
        cycle := cycles[i]
        position := days % length
        quadrant := position * 4 / length
        percent := math.Sin(2 * math.Pi * float64(position) / float64(length))
        percent = math.Floor(percent*1000) / 10
        descript := ""
        if percent > 95 {
            descript = " peak"
        } else if percent < -95 {
            descript = " valley"
        } else if math.Abs(percent) < 5 {
            descript = " critical transition"
        } else {
            daysToAdd := (quadrant+1)*length/4 - position
            transition := td.Add(time.Hour * 24 * time.Duration(daysToAdd))
            trend := quadrants[quadrant][0]
            next := quadrants[quadrant][1]
            transStr := transition.Format(layout)
            descript = fmt.Sprintf("%5.1f%% (%s, next %s %s)", percent, trend, next, transStr)
        }
        fmt.Printf("%s %2d : %s\n", cycle, position, descript)
    }
    fmt.Println()
}

func main() {
    datePairs := [][2]string{
        {"1943-03-09", "1972-07-11"},
        {"1809-01-12", "1863-11-19"},
        {"1809-02-12", "1863-11-19"}, // correct DOB for Abraham Lincoln
    }
    for _, datePair := range datePairs {
        biorhythms(datePair[0], datePair[1])
    }
}
Output:
Born 1943-03-09, Target 1972-07-11
Day 10717
Physical day  22 : -27.0% (down but rising, next transition 1972-07-12)
Emotional day 21 :  valley
Mental day    25 :  valley

Born 1809-01-12, Target 1863-11-19
Day 20034
Physical day   1 :  26.9% (up and rising, next peak 1863-11-23)
Emotional day 14 :  critical transition
Mental day     3 :  54.0% (up and rising, next peak 1863-11-24)

Born 1809-02-12, Target 1863-11-19
Day 20003
Physical day  16 : -94.3% (down and falling, next valley 1863-11-20)
Emotional day 11 :  62.3% (up but falling, next transition 1863-11-22)
Mental day     5 :  81.4% (up and rising, next peak 1863-11-22)

J

Let's presume the content of file br.ijs :

use=: 'Use: ', (;:inv 2 {. ARGV) , ' YYYY-MM-DD YYYY-MM-DD'

3 :0 ::echo use
 TAU=: 2p1  NB. tauday.com

 require'plot ~addons/types/datetime/datetime.ijs'

 span=: (i.7) + daysDiff&(1 0 0 0 1 0 1 0 ".;.1 -.&'-')~
 Length=: 23 5 p. i. 3
 arg=: Length *inv TAU * Length |/ span
 brtable=: 1 o. arg
 biorhythm=: 'title biorythms for the week ahead; key Physical Emotional Mental' plot (i.7) (j."1) brtable~
 biorhythm/ 2 3 {::"0 1 ARGV
 echo 'find new graph (plot.pdf) in directory ' , jpath '~temp/'

 brs=. brtable/ 2 3 {::"0 1 ARGV
 echo (a:,'values';'interpretation') ,: (4 10 $ 'days aheadPhysical  Emotional Mental     ') ; (1 3 # 6 6j1)&(":"0 1) L:0 (; |) brs ,~ i. 7
)

exit 0

Then bash commands could be

$ ijconsole /tmp/br.ijs help
Use: ijconsole /tmp/br.ijs YYYY-MM-DD YYYY-MM-DD
$ ijconsole  /tmp/br.ijs 1960-05-04 $( date '+%Y-%m-%d' )
find new graph (plot.pdf) in directory /home/username/j902-user/temp/
┌──────────┬──────────────────────────────────────────┬──────────────────────────────────────────┐
│          │values                                    │interpretation                            │
├──────────┼──────────────────────────────────────────┼──────────────────────────────────────────┤
│days ahead│     0     1     2     3     4     5     6│     0     1     2     3     4     5     6│
│Physical  │  _0.4  _0.6  _0.8  _0.9  _1.0  _1.0  _0.9│   0.4   0.6   0.8   0.9   1.0   1.0   0.9│
│Emotional │  _0.2   0.0   0.2   0.4   0.6   0.8   0.9│   0.2   0.0   0.2   0.4   0.6   0.8   0.9│
│Mental    │  _0.9  _0.9  _1.0  _1.0  _1.0  _0.9  _0.8│   0.9   0.9   1.0   1.0   1.0   0.9   0.8│
└──────────┴──────────────────────────────────────────┴──────────────────────────────────────────┘

Java

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;

public final class Biorythms {

	public static void main(String[] aArgs) {    
	    List<List<String>> datePairs = List.of(
	    	List.of( "1943-03-09", "1972-07-11" ),
	    	List.of( "1809-01-12", "1863-11-19" ),
	    	List.of( "1809-02-12", "1863-11-19" ));
	    
	    for ( List<String> datePair : datePairs ) {
	    	biorhythms(datePair);
	    }
	}
	
	private static void biorhythms(List<String> aDatePair) {
		DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE;
	    LocalDate birthDate = LocalDate.parse(aDatePair.get(0), formatter);
	    LocalDate targetDate = LocalDate.parse(aDatePair.get(1), formatter);
	    final int daysBetween = (int) ChronoUnit.DAYS.between(birthDate, targetDate);
	    System.out.println("Birth date " + birthDate + ", Target date " + targetDate);
	    System.out.println("Days between: " + daysBetween);
	    
	    for ( Cycle cycle : Cycle.values() ) {
	        final int cycleLength = cycle.length();
	        final int positionInCycle = daysBetween % cycleLength;
	        final int quadrantIndex = 4 * positionInCycle / cycleLength;	        
	        final int percentage = (int) Math.round(100 * Math.sin(2 * Math.PI * positionInCycle / cycleLength));
	        
	        String description;
	        if ( percentage > 95 ) {
	        	description = "peak";
	        } else if ( percentage < -95 ) {
	        	description = "valley";
	        } else if ( Math.abs(percentage) < 5 ) {
	            description = "critical transition";
	        } else {
	        	final int daysToTransition = ( cycleLength * ( quadrantIndex + 1 ) / 4 ) - positionInCycle;
		        LocalDate transitionDate = targetDate.plusDays(daysToTransition);
		        List<String> descriptions = cycle.descriptions(quadrantIndex);
		        String trend = descriptions.get(0);
		        String nextTransition = descriptions.get(1);
	            description = percentage + "% (" + trend + ", next " + nextTransition + " " + transitionDate + ")";
	        }
	        
	        System.out.println(cycle + " day " + positionInCycle  + ": " + description);
	    }
	    System.out.println();
	}
	
	private enum Cycle {		
		PHYSICAL(23), EMOTIONAL(28), MENTAL(33);
		
		public int length() {
			return length;
		}
		
		public List<String> descriptions(int aNumber) {
			return DESCRIPTIONS.get(aNumber);
		}
				
		private Cycle(int aLength) {
			length = aLength;
		}	
		
		private final int length;
		
		private static final List<List<String>> DESCRIPTIONS = List.of(
			List.of( "up and rising", "peak" ), List.of( "up but falling", "transition" ),
		    List.of( "down and falling", "valley" ), List.of( "down but rising", "transition" )); 		
	}

}
Birth date 1943-03-09, Target date 1972-07-11
Days between: 10717
PHYSICAL day 22: -27% (down but rising, next transition 1972-07-12)
EMOTIONAL day 21: valley
MENTAL day 25: valley

Birth date 1809-01-12, Target date 1863-11-19
Days between: 20034
PHYSICAL day 1: 27% (up and rising, next peak 1863-11-23)
EMOTIONAL day 14: critical transition
MENTAL day 3: 54% (up and rising, next peak 1863-11-24)

Birth date 1809-02-12, Target date 1863-11-19
Days between: 20003
PHYSICAL day 16: -94% (down and falling, next valley 1863-11-20)
EMOTIONAL day 11: 62% (up but falling, next transition 1863-11-22)
MENTAL day 5: 81% (up and rising, next peak 1863-11-22)

Julia

Translation of: Raku
using Dates

const cycles = ["Physical" => 23, "Emotional" => 28,"Mental" => 33]
const quadrants = [("up and rising", "peak"), ("up but falling", "transition"),
                   ("down and falling", "valley"), ("down but rising", "transition")]

function tellfortune(birthday::Date, date = today())
    days = (date - birthday).value
    target = (date - Date(0)).value
    println("Born $birthday, target date $date\nDay $days:")
    for (label, length) in cycles
        position = days % length
        quadrant = Int(floor((4 * position) / length)) + 1
        percentage = round(100 * sinpi(2 * position / length), digits=1)
        transition = target - position + (length * quadrant) ÷ 4
        trend, next = quadrants[quadrant]
        description = (percentage > 95) ? "peak" :
                      (percentage < -95) ? "valley" :
                      (abs(percentage) < 5) ? "critical transition" :
                      "$percentage% ($trend, next $next $(Date(0) + Dates.Day(transition)))"
        println("$label day $position: $description")
    end
    println()
end

tellfortune(Date("1943-03-09"), Date("1972-07-11"))
tellfortune(Date("1809-01-12"), Date("1863-11-19"))
tellfortune(Date("1809-02-12"), Date("1863-11-19"))
Output:
Born 1943-03-09, target date 1972-07-11
Day 10717:
Physical day 22: -27.0% (down but rising, next transition 1972-07-12)
Emotional day 21: valley
Mental day 25: valley

Born 1809-01-12, target date 1863-11-19
Day 20034:
Physical day 1: 27.0% (up and rising, next peak 1863-11-23)
Emotional day 14: critical transition
Mental day 3: 54.1% (up and rising, next peak 1863-11-24)

Born 1809-02-12, target date 1863-11-19
Day 20003:
Physical day 16: -94.2% (down and falling, next valley 1863-11-20)
Emotional day 11: 62.3% (up but falling, next transition 1863-11-22)
Mental day 5: 81.5% (up and rising, next peak 1863-11-22)


Kotlin

Translation of: Java
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
import kotlin.math.roundToInt
import kotlin.math.sin

fun main() {
    val datePairs = listOf(
        listOf("1943-03-09", "1972-07-11"),
        listOf("1809-01-12", "1863-11-19"),
        listOf("1809-02-12", "1863-11-19")
    )

    for (datePair in datePairs) {
        calculateBiorhythms(datePair)
    }
}

fun calculateBiorhythms(datePair: List<String>) {
    val formatter = DateTimeFormatter.ISO_LOCAL_DATE
    val birthDate = LocalDate.parse(datePair[0], formatter)
    val targetDate = LocalDate.parse(datePair[1], formatter)
    val daysBetween = ChronoUnit.DAYS.between(birthDate, targetDate).toInt()
    println("Birth date $birthDate, Target date $targetDate")
    println("Days between: $daysBetween")

    for (cycle in Cycle.values()) {
        val cycleLength = cycle.getLength()
        val positionInCycle = daysBetween % cycleLength
        val quadrantIndex = 4 * positionInCycle / cycleLength
        val percentage = (100 * sin(2 * Math.PI * positionInCycle / cycleLength)).roundToInt()

        val description = when {
            percentage > 95 -> "peak"
            percentage < -95 -> "valley"
            Math.abs(percentage) < 5 -> "critical transition"
            else -> {
                val daysToTransition = (cycleLength * (quadrantIndex + 1) / 4) - positionInCycle
                val transitionDate = targetDate.plusDays(daysToTransition.toLong())
                val (trend, nextTransition) = cycle.descriptions(quadrantIndex)
                "$percentage% ($trend, next $nextTransition $transitionDate)"
            }
        }

        println("${cycle.name} day $positionInCycle: $description")
    }
    println()
}

enum class Cycle(private val length: Int) {
    PHYSICAL(23), EMOTIONAL(28), MENTAL(33);

    fun getLength() = length

    fun descriptions(index: Int): Pair<String, String> {
        val descriptions = listOf(
            listOf("up and rising", "peak"),
            listOf("up but falling", "transition"),
            listOf("down and falling", "valley"),
            listOf("down but rising", "transition")
        )
        return descriptions[index][0] to descriptions[index][1]
    }
}
Output:
Birth date 1943-03-09, Target date 1972-07-11
Days between: 10717
PHYSICAL day 22: -27% (down but rising, next transition 1972-07-12)
EMOTIONAL day 21: valley
MENTAL day 25: valley

Birth date 1809-01-12, Target date 1863-11-19
Days between: 20034
PHYSICAL day 1: 27% (up and rising, next peak 1863-11-23)
EMOTIONAL day 14: critical transition
MENTAL day 3: 54% (up and rising, next peak 1863-11-24)

Birth date 1809-02-12, Target date 1863-11-19
Days between: 20003
PHYSICAL day 16: -94% (down and falling, next valley 1863-11-20)
EMOTIONAL day 11: 62% (up but falling, next transition 1863-11-22)
MENTAL day 5: 81% (up and rising, next peak 1863-11-22)



Locomotive Basic

10 input "Birthday (y,m,d) ",y,m,d:gosub 3000
20 gosub 1000
30 bday = day
40 input "Today's date (y,m,d) ",y,m,d:gosub 3000
50 gosub 1000
60 diff = day - bday
70 print:print "Age in days:" tab(22) diff
80 t$ = "physical":l = 23:gosub 2000
90 t$ = "emotional":l = 28:gosub 2000
100 t$ = "intellectual":l = 33:gosub 2000
999 end
1000 ' Get the days to J2000
1010 ' FNday only works between 1901 to 2099 - see Meeus chapter 7
1020 day = 367 * y - 7 * (y + (m + 9) \ 12) \ 4 + 275 * m \ 9 + d - 730530
1030 return
2000 p = 100 * sin(2*pi*diff/l)
2010 print t$; " cycle: " tab(22)
2020 print using "+###"; int(p);
2030 print "%";
2040 if abs(p) < 15 then print " (critical)" else print
2050 return
3000 if y < 1901 or y > 2099 then print "Year must be between 1901 and 2099!":run
3010 return
Output:
Birthday (y,m,d) 1943,3,9
Today's date (y,m,d) 1972,7,11

Age in days:          10717 
physical cycle:       -27%
emotional cycle:     -100%
intellectual cycle:  -100%

Lua

Translation of: Phix
cycles = {"Physical day ", "Emotional day", "Mental day   "}
lengths = {23, 28, 33}
quadrants = {
	{"up and rising", "peak"},
	{"up but falling", "transition"},
	{"down and falling", "valley"},
	{"down but rising", "transition"},
}
 
function parse_date_string (birthDate)
	local year, month, day = birthDate:match("(%d+)-(%d+)-(%d+)")
	return {year=tonumber(year), month=tonumber(month), day=tonumber(day)}
end
 
function days_diffeternce (d1, d2)
	if d1.year >= 1970 and d2.year >= 1970 then
		return math.floor(os.difftime(os.time(d2), os.time(d1))/(60*60*24))
	else
		local t1 = math.max (1970-d1.year, 1970-d2.year)
		t1 = math.ceil(t1/4)*4
		d1.year = d1.year + t1
		d2.year = d2.year + t1
		return math.floor(os.difftime(os.time(d2), os.time(d1))/(60*60*24))
	end
end
 
function biorhythms (birthDate, targetDate)
	local bd = parse_date_string(birthDate)
	local td = parse_date_string(targetDate)
	local days = days_diffeternce (bd, td)
 
	print('Born: '.. birthDate .. ', Target: ' .. targetDate)
	print("Day: ", days)
	for i=1, #lengths do
		local len = lengths[i]
		local posn = days%len
		local quadrant = math.floor(posn/len*4)+1
		local percent  = math.floor(math.sin(2*math.pi*posn/len)*1000)/10
		local cycle = cycles[i]
		local desc = percent > 95 and "peak" or
			percent < -95 and "valley" or
			math.abs(percent) < 5 and "critical transition" or "other"
		if desc == "other" then
			local t = math.floor(quadrant/4*len)-posn
			local qtrend, qnext = quadrants[quadrant][1], quadrants[quadrant][2]
			desc = percent .. '% (' .. qtrend .. ', next transition in ' .. t ..' days)'
		end
		print(cycle, posn..'/'..len, ': '.. desc)
	end
	print(' ')
end
 
datePairs = {
	{"1943-03-09", "1972-07-11"},
	{"1809-01-12", "1863-11-19"},
	{"1809-02-12", "1863-11-19"},
	{"2021-02-25", "2022-04-18"},
}
 
for i=1, #datePairs do 
	biorhythms(datePairs[i][1], datePairs[i][2]) 
end
Output:
Born: 1943-03-09, Target: 1972-07-11
Day: 	10716
Physical day 	21/23	: -52.0% (down but rising, next transition in 2 days)
Emotional day	20/28	: valley
Mental day   	24/33	: valley
 
Born: 1809-01-12, Target: 1863-11-19
Day: 	20034
Physical day 	1/23	: 26.9% (up and rising, next transition in 4 days)
Emotional day	14/28	: critical transition
Mental day   	3/33	: 54.0% (up and rising, next transition in 5 days)
 
Born: 1809-02-12, Target: 1863-11-19
Day: 	20003
Physical day 	16/23	: -94.3% (down and falling, next transition in 1 days)
Emotional day	11/28	: 62.3% (up but falling, next transition in 3 days)
Mental day   	5/33	: 81.4% (up and rising, next transition in 3 days)
 
Born: 2021-02-25, Target: 2022-04-18
Day: 	416
Physical day 	2/23	: 51.9% (up and rising, next transition in 3 days)
Emotional day	24/28	: -78.2% (down but rising, next transition in 4 days)
Mental day   	20/33	: -61.9% (down and falling, next transition in 4 days)

M2000 Interpreter

Module Biorhythms {
	form 80
	enum bio {Physical=23,	Emotional=28,Mental=33}
	quadrants=(("up and rising", "peak"), ("up but falling", "transition"), ("down and falling", "valley"), ("down but rising", "transition"))
	date birth="1943-03-09"
	date bioDay="1972-07-11", transition
	for k=1 to 1
		long Days=bioDay-birth
		Print "Day "+(bioDay)+":"

		string frm="{0:-20} : {1}", pword, dfmt="YYYY-MM-DD"
		long position, percentage, length, targetday
		k=each(bio)
		while k
			length=eval(k)
		
			position=days mod length
			quadrant=int(4*position/length)
			targetday=bioDay  // get the long value of day from date type
			percentage=100*sin(360*position/length)
			transition=bioDay+floor((quadrant+1)/4*23)-position
			select case percentage
			case >95
				pword="peak"
			case <-95
				pword="valley"
			case -5 to 5
				pword="critical "
			case else
			{
				pword=percentage+"% ("+quadrants#val(quadrant)#val$(0)+", next "
				pword+=quadrants#val(quadrant)#val$(1)+" "+str$(transition,dfmt)+")"
			}
			end select
			print format$(frm, eval$(k)+" day "+(days mod length), pword)
		End while
		bioDay++
	next k
}
Biorhythms
Output:
Day 10717:
 Physical day 22: -27% (down but rising, next transition 1972-07-12)
Emotional day 21: valley
   Mental day 25: valley

Mathematica / Wolfram Language

targetdate = "1972-07-11";
birthdate = "1943-03-09";
targetdate //= DateObject;
birthdate //= DateObject;

cyclelabels = {"Physical", "Emotional", "Mental"};
cyclelengths = {23, 28, 33};
quadrants = {{"up and rising", "peak"}, {"up but falling", 
    "transition"}, {"down and falling", "valley"}, {"down but rising",
     "transition"}};

d = QuantityMagnitude[DateDifference[birthdate, targetdate], "Days"];
Print["Day ", d, ":"];
Do[
 label = cyclelabels[[i]];
 length = cyclelengths[[i]];
 position = Mod[d, length];
 quadrant = Floor[4 (position + 1)/length];
 percentage = Round[100*Sin[2*Pi*position/length]];
 transitiondate = 
  DatePlus[targetdate, Floor[(quadrant + 1)/4*length] - position];
 {trend, next} = quadrants[[quadrant]];
 If[percentage > 95,
  description = "peak"
  ,
  If[percentage < -95,
   description = "valley"
   ,
   If[Abs[percentage] < 5,
    description = "critical transition"
    ,
    description = 
     ToString[percentage] <> "% (" <> trend <> ", next " <> next <> 
      " " <> DateString[transitiondate, "ISODate"] <> ")"
    ]
   ]
  ];
 Print[label <> " day " <> ToString[position] <> ": " <> 
   description];
 ,
 {i, 3}
 ]
Output:
Day 10717:
Physical day 22: -27% (down but rising, next transition 1972-07-17)
Emotional day 21: valley
Mental day 25: valley

Nim

Translation of: Go
import math
import strformat
import times

type Cycle {.pure.} = enum Physical, Emotional, Mental

const

  Lengths: array[Cycle, int] = [23, 28, 33]

  Quadrants = [("up and rising", "peak"),
               ("up but falling", "transition"),
               ("down and falling", "valley"),
               ("down but rising", "transition")]

  DateFormat = "YYYY-MM-dd"

#---------------------------------------------------------------------------------------------------

proc biorythms(birthDate: DateTime; targetDate: DateTime = now()) =
  ## Display biorythms data. Arguments are DateTime values.

  echo fmt"Born {birthDate.format(DateFormat)}, target date {targetDate.format(DateFormat)}"
  let days = (targetDate - birthDate).inDays
  echo "Day ", days

  for cycle, length in Lengths:

    let position = int(days mod length)
    let quadrant = int(4 * position / length)
    let percentage = round(100 * sin(2 * PI * (position / length)), 1)

    var description: string
    if percentage > 95:
      description = "peak"
    elif percentage < -95:
      description = "valley"
    elif abs(percentage) < 5:
      description = "critical transition"
    else:
      let (trend, next) = Quadrants[quadrant]
      let transition = targetDate + initDuration(days = (quadrant + 1) * length div 4 - position)
      description = fmt"{percentage}% ({trend}, next {next} {transition.format(DateFormat)})"

    echo fmt"{cycle} day {position}: {description}"

  echo ""

#---------------------------------------------------------------------------------------------------

proc biorythms(birthDate, targetDate = "") =
  ## Display biorythms data. Arguments are strings in ISO format year-month-day.
  let date = if targetDate.len == 0: now() else: targetDate.parse(DateFormat)
  biorythms(birthDate.parse(DateFormat), date)

#———————————————————————————————————————————————————————————————————————————————————————————————————

when isMainModule:

  biorythms("1943-03-09", "1972-07-11")
  biorythms("1809-01-12", "1863-11-19")
  biorythms("1809-02-12", "1863-11-19")
Output:
Born 1943-03-09, target date 1972-07-11
Day 10717
Physical day 22: -27.0% (down but rising, next transition 1972-07-12)
Emotional day 21: valley
Mental day 25: valley

Born 1809-01-12, target date 1863-11-19
Day 20034
Physical day 1: 27.0% (up and rising, next peak 1863-11-23)
Emotional day 14: critical transition
Mental day 3: 54.1% (up and rising, next peak 1863-11-24)

Born 1809-02-12, target date 1863-11-19
Day 20003
Physical day 16: -94.2% (down and falling, next valley 1863-11-20)
Emotional day 11: 62.3% (up but falling, next transition 1863-11-22)
Mental day 5: 81.5% (up and rising, next peak 1863-11-22)

Perl

Translation of: Raku
use strict;
use warnings;
use DateTime;

use constant PI => 2 * atan2(1, 0);

my %cycles = ( 'Physical' => 23, 'Emotional' => 28, 'Mental' => 33 );
my @Q = ( ['up and rising',    'peak'],
          ['up but falling',   'transition'],
          ['down and falling', 'valley'],
          ['down but rising',  'transition']
        );

my $target = DateTime->new(year=>1863, month=>11, day=>19);
my $bday   = DateTime->new(year=>1809, month=> 2, day=>12);

my $days   = $bday->delta_days( $target )->in_units('days');

print "Day $days:\n";
for my $label (sort keys %cycles) {
    my($length) = $cycles{$label};
    my $position = $days % $length;
    my $quadrant = int $position / $length * 4;
    my $percentage = int(sin($position / $length * 2 * PI )*1000)/10;
    my $description;
    if    (    $percentage  >  95) { $description = 'peak' }
    elsif (    $percentage  < -95) { $description = 'valley' }
    elsif (abs($percentage) <   5) { $description = 'critical transition' }
    else {
        my $transition = $target->clone->add( days => (int(($quadrant + 1)/4 * $length) - $position))->ymd;
        my ($trend, $next) = @{$Q[$quadrant]};
        $description = sprintf "%5.1f%% ($trend, next $next $transition)", $percentage;
    }
    printf "%-13s %2d: %s", "$label day\n", $position, $description;
}
Output:
Day 20003:
Emotional day 11:  62.3% (up but falling, next transition 1863-11-22)
Mental day     5:  81.4% (up and rising, next peak 1863-11-22)
Physical day  16: -94.2% (down and falling, next valley 1863-11-20)

Phix

Translation of: Wren
with javascript_semantics
include timedate.e
 
constant cycles = {"Physical day ", "Emotional day", "Mental day   "},
         lengths = {23, 28, 33},
         quadrants = {{"up and rising",    "peak"},
                      {"up but falling",   "transition"},
                      {"down and falling", "valley"},
                      {"down but rising",  "transition"}}
 
procedure biorhythms(string birthDate, targetDate)
    timedate bd = parse_date_string(birthDate,{"YYYY-MM-DD"}),
             td = parse_date_string(targetDate,{"YYYY-MM-DD"})
    integer days = floor(timedate_diff(bd, td, DT_DAY)/(60*60*24))
    printf(1,"Born %s, Target %s\n",{birthDate,targetDate})
    printf(1,"Day %d\n",days)
    for i=1 to 3 do
        integer len = lengths[i],
                posn = remainder(days,len),
                quadrant = floor(posn/len*4)+1
        atom percent  = floor(sin(2*PI*posn/len)*1000)/10
        string cycle = cycles[i],
               desc = iff(percent>95 ? " peak" :
                      iff(percent<-95 ? " valley" :
                      iff(abs(percent)<5 ? " critical transition" : "other")))
        if desc == "other" then
            timedate t = adjust_timedate(td,timedelta(days:=floor(quadrant/4*len)-posn))
            string transition = format_timedate(t,"YYYY-MM-DD"),
                   {trend,next} = quadrants[quadrant]
            desc = sprintf("%5.1f%% (%s, next %s %s)", {percent, trend, next, transition})
        end if
        printf(1,"%s %2d : %s\n", {cycle, posn, desc})
    end for
    printf(1,"\n")
end procedure
 
constant datePairs = {
    {"1943-03-09", "1972-07-11"},
    {"1809-01-12", "1863-11-19"},
    {"1809-02-12", "1863-11-19"}  // correct DOB for Abraham Lincoln
}
for i=1 to length(datePairs) do biorhythms(datePairs[i][1], datePairs[i][2]) end for
Output:
Born 1943-03-09, Target 1972-07-11
Day 10717
Physical day  22 : -27.0% (down but rising, next transition 1972-07-12)
Emotional day 21 :  valley
Mental day    25 :  valley

Born 1809-01-12, Target 1863-11-19
Day 20034
Physical day   1 :  26.9% (up and rising, next peak 1863-11-23)
Emotional day 14 :  critical transition
Mental day     3 :  54.0% (up and rising, next peak 1863-11-24)

Born 1809-02-12, Target 1863-11-19
Day 20003
Physical day  16 : -94.3% (down and falling, next valley 1863-11-20)
Emotional day 11 :  62.3% (up but falling, next transition 1863-11-22)
Mental day     5 :  81.4% (up and rising, next peak 1863-11-22)

Python

"""

Python implementation of

http://rosettacode.org/wiki/Biorhythms

"""

from datetime import date, timedelta
from math import floor, sin, pi

def biorhythms(birthdate,targetdate):
    """
    Print out biorhythm data for targetdate assuming you were
    born on birthdate.
    
    birthdate and targetdata are strings in this format:
    
    YYYY-MM-DD e.g. 1964-12-26
    """
    
    # print dates
    
    print("Born: "+birthdate+" Target: "+targetdate)    
    
    # convert to date types - Python 3.7 or later
    
    birthdate = date.fromisoformat(birthdate)
    targetdate = date.fromisoformat(targetdate)
    
    # days between
    
    days = (targetdate - birthdate).days
    
    print("Day: "+str(days))
    
    # cycle logic - mostly from Julia example
    
    cycle_labels = ["Physical", "Emotional", "Mental"]
    cycle_lengths = [23, 28, 33]
    quadrants = [("up and rising", "peak"), ("up but falling", "transition"),
                   ("down and falling", "valley"), ("down but rising", "transition")]
    
    for i in range(3):
        label = cycle_labels[i]
        length = cycle_lengths[i]
        position = days % length
        quadrant = int(floor((4 * position) / length))
        percentage = int(round(100 * sin(2 * pi * position / length),0))
        transition_date = targetdate + timedelta(days=floor((quadrant + 1)/4 * length) - position)
        trend, next = quadrants[quadrant]
        
        if percentage > 95:
            description = "peak"
        elif percentage < -95:
             description = "valley"
        elif abs(percentage) < 5:
             description = "critical transition"
        else:
             description = str(percentage)+"% ("+trend+", next "+next+" "+str(transition_date)+")"
        print(label+" day "+str(position)+": "+description)
    
    
biorhythms("1943-03-09","1972-07-11")
Output:
Born: 1943-03-09 Target: 1972-07-11
Day: 10717
Physical day 22: -27% (down but rising, next transition 1972-07-12)
Emotional day 21: valley
Mental day 25: valley

R

Also creates a plot showing past and future 30-day cycles

bioR <- function(bDay, targetDay) {
    bDay <- as.Date(bDay)
    targetDay <- as.Date(targetDay)
    n <- as.numeric(targetDay - bDay)
    
    cycles <- c(23, 28, 33)
    mods <- n %% cycles
    bioR <- c(sin(2 * pi * mods / cycles))
    loc <- mods / cycles
    current <- ifelse(bioR > 0, ': Up', ': Down')
    current <- paste(current, ifelse(loc < 0.25 | loc > 0.75,
                                     "and rising",
                                     "and falling"))
    
    df <- data.frame(dates = seq.Date(from = targetDay - 30, 
                                      to = targetDay + 30,
                                      by = 1))
    df$n <- as.numeric(df$dates - bDay)
    df$P <- sin(2 * pi * (df$n %% cycles[1]) / cycles[1])
    df$E <- sin(2 * pi * (df$n %% cycles[2]) / cycles[2])
    df$M <- sin(2 * pi * (df$n %% cycles[3]) / cycles[3])
    
    plot(df$dates, df$P, col = 'blue', 
         main = paste(targetDay, 'Biorhythm for Birthday on', bDay),
         xlab = "",
         ylab = "Intensity")
    points(df$dates, df$E, col = 'green')
    points(df$dates, df$M, col = 'red')
    abline(v = targetDay)
    legend('topleft', legend = c("Phys", "Emot", "Ment"),
           col =c("blue", "green", "red"),
           cex = 0.8,
           pch = 21)
    
    cat(paste0('Birthday = ', as.character(bDay),
               '\nTarget Date = ', as.character(targetDay),
               '\n', n, ' days',
               '\nPhysical = ', mods[1], current[1],
               '\nEmotional = ', mods[2], current[2],
               '\nMental = ', mods[3], current[3]))
}

bioR('1943-03-09', '1972-07-11')
Output:
Birthday = 1943-03-09
Target Date = 1972-07-11
10717 days
Physical = 22: Down and rising
Emotional = 21: Down and falling
Mental = 25: Down and rising

Raku

#!/usr/bin/env raku
unit sub MAIN($birthday=%*ENV<BIRTHDAY>, $date = Date.today()) {

my %cycles = ( :23Physical, :28Emotional, :33Mental );
my @quadrants = [ ('up and rising',    'peak'),
                  ('up but falling',   'transition'),
                  ('down and falling', 'valley'),
                  ('down but rising',  'transition') ];

if !$birthday {
    die "Birthday not specified.\n" ~
        "Supply --birthday option or set \$BIRTHDAY in environment.\n";
}

my ($bday, $target) = ($birthday, $date).map: { Date.new($_) };
my $days = $target - $bday;

say "Day $days:";
for %cycles.sort(+*.value)».kv -> ($label, $length) {
    my $position = $days % $length;
    my $quadrant = floor($position / $length * 4);
    my $percentage = floor(sin($position / $length * 2 * π )*1000)/10;
    my $description;
    if $percentage > 95 {
        $description = 'peak';
    } elsif $percentage < -95 {
        $description = 'valley'; 
    } elsif abs($percentage) < 5 {
        $description = 'critical transition'
    } else {
        my $transition = $target + floor(($quadrant + 1)/4 * $length) - $position;
        my ($trend, $next) = @quadrants[$quadrant];
        $description = "$percentage% ($trend, next $next $transition)";
    }
    say "$label day $position: $description";
  }
}
Output:
$ br 1809-01-12 1863-11-19
Day 20034:
Physical day 1: 26.9% (up and rising, next peak 1863-11-23)
Emotional day 14: critical transition
Mental day 3: 54% (up and rising, next peak 1863-11-24)

Red

Translation of: Raku
Red [
	Title: "Biorythms"
	Source: https://rosettacode.org/wiki/Biorhythms#Red
	Purpose: "Calculates biorythmic values for given birthday and target date"
]

biorythms: function [
	"Calculates biorythmic values for given birthday and target date"
	bday	[date!]
	target	[date!]
][
	cycles: [
		"Physical day  " 23
		"Emotional day " 28
		"Mental day    " 33
	]

	quadrants: [
		["(up and rising" "peak"]
		["(up but falling" "transition"]
		["(down and falling" "valley"]
		["(down but rising" "transition"]
	]

		days:	target - bday

	print [
		#"^(line)"
		"Birthday   :" bday #"^(line)"
		"Target date:" target #"^(line)"
		"Days       :" days "days"
	]

	foreach [cycle len] cycles [
		posn:		days % len
		quadrant:	to-integer ((posn / len * 4) + 1)
		ampl:		to-percent round/to sin (days / len * 2 * pi) 0.01
		trend:		quadrants/(quadrant)
		case [
			ampl > 0.95				[desc: " Peak"]
			ampl < -0.95			[desc: " Valley"]
			(absolute ampl) <= 0.05	[desc: " Critical transition"]
			true [
				t: to-integer (quadrant / 4 * len) - posn
				desc: reduce [pad/left ampl 4 trend/(1) ", next" trend/(2) "in" t "days)"]
			]
		]
		print [cycle pad/left reduce [posn "of" len] 8 ":" desc]
	]
]

biorythms	1943-03-09	1972-07-11 ; Bobby Fisher won the World Chess Championship
biorythms	1987-05-22	2023-01-29 ; Novak Đoković won the Australian Open for the 11th time
biorythms	1969-01-03	2013-09-13 ; Michael Schuhmacher's bad skiing accident
Output:
Birthday   : 9-Mar-1943 
Target date: 11-Jul-1972 
Days       : 10717 days
Physical day   22 of 23 : -27% (down but rising , next transition in 1 days)
Emotional day  21 of 28 :  Valley
Mental day     25 of 33 :  Valley

Birthday   : 22-May-1987 
Target date: 29-Jan-2023 
Days       : 13036 days
Physical day   18 of 23 :  Valley
Emotional day  16 of 28 : -43% (down and falling , next valley in 5 days)
Mental day      1 of 33 :  19% (up and rising , next peak in 7 days)

Birthday   : 3-Jan-1969 
Target date: 13-Sep-2013 
Days       : 16324 days
Physical day   17 of 23 :  Valley
Emotional day   0 of 28 :  Critical transition
Mental day     22 of 33 : -87% (down and falling , next valley in 2 days)

REXX

It is usual to use the birth date of a person.

/*REXX pgm shows the states of a person's biorhythms                   */
/*                                 (physical, emotional, intellectual) */
Parse Arg birthdate targetdate .  /* obtain one or two dates from CL   */
If birthdate='?' Then Do
  Say 'rexx bio birthdate (yyyymmdd) shows you today''s biorhythms'
  Say 'or enter your birthday now'
  Parse Pull birthdate
  If birthdate='' Then Exit
  End
If birthdate='' Then
  Parse Value 19460906 20200906 With birthdate targetdate
If targetdate='' Then
  targetdate=Date('S')
days=daysbet2(birthdate,targetdate)
If days==0 Then Do
  Say
  Say 'The two dates specified are exacty the same.'
  Exit 1
  End
cycles='physical emotional intellectual' /*the biorhythm cycle names   */
cycle='negative neutral positive'
period.1=23
period.2=28
period.3=33
pid2=pi()*2*days
say 'Birthdate:   ' birthdate  '('translate('gh.ef.abcd',birthdate,'abcdefgh')')'
say 'Today:       ' targetdate '('translate('gh.ef.abcd',targetdate,'abcdefgh')')'
Say 'Elapsed days:' days
Do j=1 To 3
  state=2+sign(sin(pid2/period.j))  /* obtain state for each biorhythm */
  Say 'biorhythm for the' right(word(cycles,j),12) 'cycle is',
                                                      word(cycle,state)
  End
Exit
/*---------------------------------------------------------------------*/
pi:
  pi=3.1415926535897932384626433832795028841971693993751058209749445923078
  Return pi
r2r:
  Return arg(1)//(pi()*2)           /* normalize radians --? a unit ci*/
/*--------------------------------------------------------------------------------------*/
sin: Procedure
  Parse Arg x
  x=r2r(x)
  _=x
  Numeric Fuzz min(5,max(1,digits()-3))
  If x=pi*.5 Then
    Return 1
  If x==pi*1.5 Then
    Return-1
  If abs(x)=pi|x=0 Then
    Return 0
  q=x*x
  z=x
  Do k=2 By 2 Until p=z
    p=z
    _=-_*q/(k*k+k)
    z=z+_
    End
  Return z

daysbet2: Procedure
/* compute the number of days between fromdate and todate */
  Parse Arg fromdate,todate
  fromday=date('B',fromdate,'S')
  today=date('B',todate,'S')
  Return today-fromday
output   when using the default dates
Birthdate:    19460906 (06.09.1946)
Today:        20200906 (06.09.2020)
Elapsed days: 27029
biorhythm for the     physical cycle is positive
biorhythm for the    emotional cycle is positive
biorhythm for the intellectual cycle is positive

Ruby

require 'date'
CYCLES = {physical: 23, emotional: 28, mental: 33}

def biorhythms(date_of_birth, target_date = Date.today.to_s)
  days_alive = Date.parse(target_date) - Date.parse(date_of_birth) 
  CYCLES.each do |name, num_days|
    cycle_day = days_alive % num_days
    state = case cycle_day
      when 0, num_days/2 then "neutral"
      when (1.. num_days/2) then "positive"
      when (num_days/2+1..num_days) then "negative"
    end
    puts "%-10s: cycle day %2s, %s" % [name, cycle_day.to_i, state]    
  end
end
      
biorhythms("1943-03-09", "1972-07-11")
Output:
physical  : cycle day 22, negative
emotional : cycle day 21, negative
mental    : cycle day 25, negative

Rust

Translation of: Go
use chrono::{NaiveDate, ParseError, TimeDelta};
use num_traits::float::FloatConst;

const PHYSICAL_WAVE: i64 = 23;
const EMOTIONAL_WAVE: i64 = 28;
const MENTAL_WAVE: i64 = 33;
const CYCLES: [&str; 3] = ["Physical day ", "Emotional day", "Mental day   "];
const LENGTHS: [i64; 3] = [PHYSICAL_WAVE, EMOTIONAL_WAVE, MENTAL_WAVE];
const QUADRANTS: [[&str; 2]; 4] = [
    ["up and rising", "peak"],
    ["up but falling", "transition"],
    ["down and falling", "valley"],
    ["down but rising", "transition"],
];

/// Parameters assumed to be in YYYY-MM-DD format.
fn biorhythms(birth_date: &str, target_date: &str) -> Result<i64, ParseError> {
    let bd = NaiveDate::parse_from_str(birth_date, "%Y-%m-%d")?;
    let td = NaiveDate::parse_from_str(target_date, "%Y-%m-%d")?;
    let days = (td - bd).num_days();
    println!("Born {}, Target {}", birth_date, target_date);
    println!("Day {}:", days);
    for i in 0..3 {
        let length = LENGTHS[i];
        let cycle = CYCLES[i];
        let position = days % length;
        let quadrant: usize = (4 * position as usize) / length as usize;
        let mut percent = f64::sin(2. * f64::PI() * position as f64 / length as f64);
        percent = percent * 100.0;
        let description: String;
        if percent > 95. {
            description = " peak".to_owned();
        } else if percent < -95. {
            description = " valley".to_owned();
        } else if percent.abs() < 5. {
            description = " critical transition".to_owned();
        } else {
            let days_to_add = (quadrant as i64 + 1) * length / 4 - position;
            let transition = td + TimeDelta::days(days_to_add);
            let trend = QUADRANTS[quadrant][0];
            let next = QUADRANTS[quadrant][1];
            description = format!("{:5.1}% ({}, next {} {})", percent, trend, next, transition);
        }
        println!("{} {:>2} : {}", cycle, position, description);
    }
    println!();
    Ok(0)
}

fn main() {
    let date_pairs = [
        ["1943-03-09", "1972-07-11"],
        ["1809-01-12", "1863-11-19"],
        ["1809-02-12", "1863-11-19"], // correct DOB for Abraham Lincoln
    ];

    for date_pair in date_pairs {
        match biorhythms(date_pair[0], date_pair[1]) {
            Err(_) => println!("Error in biorhythms function parsing {:?}", date_pair),
            _ => {}
        }
    }
}
Output:
Born 1943-03-09, Target 1972-07-11
Day 10717:
Physical day  22 : -27.0% (down but rising, next transition 1972-07-12)
Emotional day 21 :  valley
Mental day    25 :  valley

Born 1809-01-12, Target 1863-11-19
Day 20034:
Physical day   1 :  27.0% (up and rising, next peak 1863-11-23)
Emotional day 14 :  critical transition
Mental day     3 :  54.1% (up and rising, next peak 1863-11-24)

Born 1809-02-12, Target 1863-11-19
Day 20003:
Physical day  16 : -94.2% (down and falling, next valley 1863-11-20)
Emotional day 11 :  62.3% (up but falling, next transition 1863-11-22)
Mental day     5 :  81.5% (up and rising, next peak 1863-11-22)

Scala

Translation of: Java
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
import scala.collection.JavaConverters._

object Biorythms extends App {

  val datePairs = List(
    List("1943-03-09", "1972-07-11"),
    List("1809-01-12", "1863-11-19"),
    List("1809-02-12", "1863-11-19")
  )

  datePairs.foreach(biorhythms)

  def biorhythms(aDatePair: List[String]): Unit = {
    val formatter = DateTimeFormatter.ISO_LOCAL_DATE
    val birthDate = LocalDate.parse(aDatePair.head, formatter)
    val targetDate = LocalDate.parse(aDatePair(1), formatter)
    val daysBetween = ChronoUnit.DAYS.between(birthDate, targetDate).toInt
    println(s"Birth date $birthDate, Target date $targetDate")
    println(s"Days between: $daysBetween")

    for (cycle <- Cycle.values) {
      val cycleLength = cycle.length
      val positionInCycle = daysBetween % cycleLength
      val quadrantIndex = 4 * positionInCycle / cycleLength
      val percentage = Math.round(100 * Math.sin(2 * Math.PI * positionInCycle / cycleLength)).toInt

      val description = if (percentage > 95) {
        "peak"
      } else if (percentage < -95) {
        "valley"
      } else if (Math.abs(percentage) < 5) {
        "critical transition"
      } else {
        val daysToTransition = (cycleLength * (quadrantIndex + 1) / 4) - positionInCycle
        val transitionDate = targetDate.plusDays(daysToTransition)
        val descriptions = cycle.descriptions(quadrantIndex).asScala
        val trend = descriptions.head
        val nextTransition = descriptions(1)
        s"$percentage% ($trend, next $nextTransition $transitionDate)"
      }

      println(s"${cycle} day $positionInCycle: $description")
    }
    println()
  }

  enum Cycle(val length: Int) {
    case PHYSICAL extends Cycle(23)
    case EMOTIONAL extends Cycle(28)
    case MENTAL extends Cycle(33)

    def descriptions(number: Int): java.util.List[String] = Cycle.DESCRIPTIONS.get(number)
  }

  object Cycle {
    private val DESCRIPTIONS = java.util.List.of(
      java.util.List.of("up and rising", "peak"),
      java.util.List.of("up but falling", "transition"),
      java.util.List.of("down and falling", "valley"),
      java.util.List.of("down but rising", "transition")
    )
  }

}
Output:
Birth date 1943-03-09, Target date 1972-07-11
Days between: 10717
PHYSICAL day 22: -27% (down but rising, next transition 1972-07-12)
EMOTIONAL day 21: valley
MENTAL day 25: valley

Birth date 1809-01-12, Target date 1863-11-19
Days between: 20034
PHYSICAL day 1: 27% (up and rising, next peak 1863-11-23)
EMOTIONAL day 14: critical transition
MENTAL day 3: 54% (up and rising, next peak 1863-11-24)

Birth date 1809-02-12, Target date 1863-11-19
Days between: 20003
PHYSICAL day 16: -94% (down and falling, next valley 1863-11-20)
EMOTIONAL day 11: 62% (up but falling, next transition 1863-11-22)
MENTAL day 5: 81% (up and rising, next peak 1863-11-22)



Translation of: Java
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
import scala.jdk.CollectionConverters._

object Biorhythms extends App {

  private val datePairs = List(
    ("1943-03-09", "1972-07-11"),
    ("1809-01-12", "1863-11-19"),
    ("1809-02-12", "1863-11-19")
  )

  datePairs.foreach(calculateBiorhythms)

  private def calculateBiorhythms(dates: (String, String)): Unit = {
    val formatter = DateTimeFormatter.ISO_LOCAL_DATE
    val birthDate = LocalDate.parse(dates._1, formatter)
    val targetDate = LocalDate.parse(dates._2, formatter)
    val daysBetween = ChronoUnit.DAYS.between(birthDate, targetDate).toInt

    println(s"Birth Date: $birthDate, Target Date: $targetDate")
    println(s"Days Between: $daysBetween")

    Cycle.values.foreach(processCycle(daysBetween, targetDate, _))
    
    println()
  }

  private def processCycle(daysBetween: Int, targetDate: LocalDate, cycle: Cycle): Unit = {
    val position = daysBetween % cycle.length
    val angle = 2 * Math.PI * position / cycle.length
    val percentage = Math.round(100 * Math.sin(angle)).toInt

    val description = percentage match {
      case p if p > 95 => "peak"
      case p if p < -95 => "valley"
      case p if Math.abs(p) < 5 => "critical transition"
      case _ =>
        val quadrant = Quadrant.fromPosition(position, cycle.length)
        val daysToTransition = quadrant.daysToTransition(position, cycle.length)
        val transitionDate = targetDate.plusDays(daysToTransition)
        val (trend, nextTransition) = quadrant.getDescriptions
        s"$percentage% ($trend, $nextTransition on $transitionDate)"
    }

    println(s"${cycle} day $position: $description")
  }

  private enum Cycle(val length: Int) {
    private case PHYSICAL extends Cycle(23)
    private case EMOTIONAL extends Cycle(28)
    private case MENTAL extends Cycle(33)

    override def toString: String = this match {
      case PHYSICAL => "Physical"
      case EMOTIONAL => "Emotional"
      case MENTAL => "Mental"
    }
  }

  enum Quadrant {
    case UpAndRising
    case UpButFalling
    case DownAndFalling
    case DownButRising

    def getDescriptions: (String, String) = this match {
      case UpAndRising => ("up and rising", "next peak")
      case UpButFalling => ("up but falling", "next transition")
      case DownAndFalling => ("down and falling", "next valley")
      case DownButRising => ("down but rising", "next transition")
    }

    def daysToTransition(position: Int, cycleLength: Int): Int = {
      val quarter = cycleLength / 4
      val positionInQuadrant = position % quarter
      quarter - positionInQuadrant
    }
  }

  private object Quadrant {
    def fromPosition(position: Int, cycleLength: Int): Quadrant = {
      val relativePosition = position.toDouble / cycleLength
      relativePosition match {
        case p if p >= 0.0 && p < 0.25 => Quadrant.UpAndRising
        case p if p >= 0.25 && p < 0.5 => Quadrant.UpButFalling
        case p if p >= 0.5 && p < 0.75 => Quadrant.DownAndFalling
        case p if p >= 0.75 && p < 1.0 => Quadrant.DownButRising
        case _ => throw new IllegalArgumentException("Position out of bounds")
      }
    }
  }
}
Output:
Birth Date: 1943-03-09, Target Date: 1972-07-11
Days Between: 10717
Physical day 22: -27% (down but rising, next transition on 1972-07-14)
Emotional day 21: valley
Mental day 25: valley

Birth Date: 1809-01-12, Target Date: 1863-11-19
Days Between: 20034
Physical day 1: 27% (up and rising, next peak on 1863-11-23)
Emotional day 14: critical transition
Mental day 3: 54% (up and rising, next peak on 1863-11-24)

Birth Date: 1809-02-12, Target Date: 1863-11-19
Days Between: 20003
Physical day 16: -94% (down and falling, next valley on 1863-11-23)
Emotional day 11: 62% (up but falling, next transition on 1863-11-22)
Mental day 5: 81% (up and rising, next peak on 1863-11-22)

Tcl

Works with: Wish

A graphing version using Tcl+Tk:

#!/usr/bin/env wish
# Biorhythm calculator
set today [clock format [clock seconds] -format %Y-%m-%d ]
proc main [list birthday [list target $today]] {
  set day [days-between $birthday $target]

  array set cycles { 
    Physical  {23 red}
    Emotional {28 green}
    Mental    {33 blue}
  }

  set pi [expr atan2(0,-1)]

  canvas .c -width 306 -height 350 -bg black
  .c create rectangle 4 49 306 251 -outline grey
  .c create line 5 150 305 150 -fill grey
  .c create line 145 50 145 250 -fill cyan
  .c create text 145 15 -text "$target" -fill cyan 
  .c create text 145 30 -text "(Day $day)" -fill cyan 
  set ly 305
  foreach {name data} [array get cycles] {
    lassign $data length color
    .c create text 60 $ly -anchor nw -text $name -fill $color
    set pos [expr $day % $length]
    for {set dd -14} {$dd <= 16} {incr dd} {
      set d [expr $pos + $dd]
      set x [expr 145 + 10 * $dd]
      .c create line $x 145 $x 155 -fill grey
      set v [expr sin(2*$pi*$d/$length)]
      set y [expr 150 - 100 * $v]
      if {$dd == 0} {
        .c create text 10 $ly -anchor nw \
            -text "[format %+04.1f%% [expr $v * 100]]" -fill $color
      }
      if [info exists ox] {
        .c create line $ox $oy $x $y -fill $color
      }
      set ox $x
      set oy $y
    }
    unset ox oy
    set ly [expr $ly - 25]
  }
  pack .c
}

proc days-between {from to} {
  expr int([rd $to] - [rd $from])
}

# parse an (ISO-formatted) date into a day number
proc rd {date} {
  lassign [scan $date %d-%d-%d] year month day
  set elapsed [expr $year - 1]
  expr {$elapsed * 365 +
       floor($elapsed/4) -
       floor($elapsed/100) +
       floor($elapsed/400) +
       floor( (367*$month-362)/12 ) +
       ($month < 3 ? 0 : ([is-leap $year] ? -1 : -2)) +
       $day}
}

proc is-leap {year} {
  expr {$year % 4 == 0 && ($year % 100 || $year % 400 == 0)}
}

main {*}$argv
Output:

Output of

wish br.wish 1809-02-12 1863-11-19

- Lincoln's biorhythms at Gettysburg:

https://i.imgur.com/U2izZOM.png

VBA

Translation of: Wren
Function Biorhythm(Birthdate As Date, Targetdate As Date) As String

'Jagged Array
TextArray = Array(Array("up and rising", "peak"), Array("up but falling", "transition"), Array("down and falling", "valley"), Array("down but rising", "transition"))

DaysBetween = Targetdate - Birthdate

positionP = DaysBetween Mod 23
positionE = DaysBetween Mod 28
positionM = DaysBetween Mod 33

'return the positions - just to return something
Biorhythm = CStr(positionP) & "/" & CStr(positionE) & "/" & CStr(positionM)

quadrantP = Int(4 * positionP / 23)
quadrantE = Int(4 * positionE / 28)
quadrantM = Int(4 * positionM / 33)

percentageP = Round(100 * Sin(2 * WorksheetFunction.Pi * (positionP / 23)), 1)
percentageE = Round(100 * Sin(2 * WorksheetFunction.Pi * (positionE / 28)), 1)
percentageM = Round(100 * Sin(2 * WorksheetFunction.Pi * (positionM / 33)), 1)

transitionP = Targetdate + WorksheetFunction.Floor((quadrantP + 1) / 4 * 23, 1) - positionP
transitionE = Targetdate + WorksheetFunction.Floor((quadrantE + 1) / 4 * 28, 1) - positionE
transitionM = Targetdate + WorksheetFunction.Floor((quadrantM + 1) / 4 * 33, 1) - positionM

Select Case True
    Case percentageP > 95
        textP = "Physical day " & positionP & " : " & "peak"
    Case percentageP < -95
        textP = "Physical day " & positionP & " : " & "valley"
    Case percentageP < 5 And percentageP > -5
        textP = "Physical day " & positionP & " : " & "critical transition"
    Case Else
        textP = "Physical day " & positionP & " : " & percentageP & "% (" & TextArray(quadrantP)(0) & ", next " & TextArray(quadrantP)(1) & " " & transitionP & ")"
End Select

Select Case True
    Case percentageE > 95
        textE = "Emotional day " & positionE & " : " & "peak"
    Case percentageE < -95
        textE = "Emotional day " & positionE & " : " & "valley"
    Case percentageE < 5 And percentageE > -5
        textE = "Emotional day " & positionE & " : " & "critical transition"
    Case Else
        textE = "Emotional day " & positionE & " : " & percentageE & "% (" & TextArray(quadrantE)(0) & ", next " & TextArray(quadrantE)(1) & " " & transitionE & ")"
End Select

Select Case True
    Case percentageM > 95
        textM = "Mental day " & positionM & " : " & "peak"
    Case percentageM < -95
        textM = "Mental day " & positionM & " : " & "valley"
    Case percentageM < 5 And percentageM > -5
        textM = "Mental day " & positionM & " : " & "critical transition"
    Case Else
        textM = "Mental day " & positionM & " : " & percentageM & "% (" & TextArray(quadrantM)(0) & ", next " & TextArray(quadrantM)(1) & " " & transitionM & ")"
End Select

Header1Text = "Born " & Birthdate & ", Target " & Targetdate
Header2Text = "Day " & DaysBetween

'Print Result
Debug.Print Header1Text
Debug.Print Header2Text
Debug.Print textP
Debug.Print textE
Debug.Print textM
Debug.Print ""

End Function
Output:
Born 09.03.1943, Target 11.07.1972
Day 10717
Physical day 22 : -27% (down but rising, next transition 12.07.1972)
Emotional day 21 : valley
Mental day 25 : valley

Born 12.02.1809, Target 19.11.1863
Day 20003
Physical day 16 : -94.2% (down and falling, next valley 20.11.1863)
Emotional day 11 : 62.3% (up but falling, next transition 22.11.1863)
Mental day 5 : 81.5% (up and rising, next peak 22.11.1863)

Born 12.01.1809, Target 19.11.1863
Day 20034
Physical day 1 : 27% (up and rising, next peak 23.11.1863)
Emotional day 14 : critical transition
Mental day 3 : 54.1% (up and rising, next peak 24.11.1863)

V (Vlang)

Translation of: Go
import time
import math
 
const cycles = ["Physical day ", "Emotional day", "Mental day   "]
const lengths = [23, 28, 33]
const quadrants = [
    ["up and rising", "peak"],
    ["up but falling", "transition"],
    ["down and falling", "valley"],
    ["down but rising", "transition"],
]
 
// Parameters assumed to be in YYYY-MM-DD format.
fn biorhythms(birth_date string, target_date string) ? {
    bd := time.parse_iso8601(birth_date)?
    td := time.parse_iso8601(target_date)?
    days := int((td-bd).hours() / 24)
    println("Born $birth_date, Target $target_date")
    println("Day $days")
    for i in 0..3 {
        length := lengths[i]
        cycle := cycles[i]
        position := days % length
        quadrant := position * 4 / length
        mut percent := math.sin(2 * math.pi * f64(position) / f64(length))
        percent = math.floor(percent*1000) / 10
        mut descript := ""
        if percent > 95 {
            descript = " peak"
        } else if percent < -95 {
            descript = " valley"
        } else if math.abs(percent) < 5 {
            descript = " critical transition"
        } else {
            days_to_add := (quadrant+1)*length/4 - position
            transition := td.add(time.hour * 24 * time.Duration(days_to_add))
            trend := quadrants[quadrant][0]
            next := quadrants[quadrant][1]
            trans_str := transition.custom_format('YYYY-MM-DD')
            descript = "${percent:5.1f}% ($trend, next $next $trans_str)"
        }
        println("$cycle ${position:2} : $descript")
    }
    println('')
}
 
fn main() {
    date_pairs := [
        ["1943-03-09", "1972-07-11"],
        ["1809-01-12", "1863-11-19"],
        ["1809-02-12", "1863-11-19"], // correct DOB for Abraham Lincoln
	]
    for date_pair in date_pairs {
        biorhythms(date_pair[0], date_pair[1])?
    }
}
Output:
Born 1943-03-09, Target 1972-07-11
Day 10717
Physical day  22 : -27.0% (down but rising, next transition 1972-07-12)
Emotional day 21 :  valley
Mental day    25 :  valley

Born 1809-01-12, Target 1863-11-19
Day 20034
Physical day   1 :  26.9% (up and rising, next peak 1863-11-23)
Emotional day 14 :  critical transition
Mental day     3 :  54.0% (up and rising, next peak 1863-11-24)

Born 1809-02-12, Target 1863-11-19
Day 20003
Physical day  16 : -94.3% (down and falling, next valley 1863-11-20)
Emotional day 11 :  62.3% (up but falling, next transition 1863-11-22)
Mental day     5 :  81.4% (up and rising, next peak 1863-11-22)

Wren

Translation of: Raku
Library: Wren-date
Library: Wren-fmt
import "./date" for Date
import "./fmt" for Fmt

var cycles = ["Physical day ", "Emotional day", "Mental day   "]
var lengths = [23, 28, 33]
var quadrants = [ 
    ["up and rising",    "peak"],
    ["up but falling",   "transition"],
    ["down and falling", "valley"],
    ["down but rising",  "transition"]
]

var biorhythms = Fn.new { |birthDate, targetDate|
    var bd = Date.parse(birthDate)
    var td = Date.parse(targetDate)
    var days = (td - bd).days
    Date.default = Date.isoDate
    System.print("Born %(birthDate), Target %(targetDate)")
    System.print("Day %(days)")
    for (i in 0..2) {
        var length   = lengths[i]
        var cycle    = cycles[i]
        var position = days % length
        var quadrant = (position / length * 4).floor
        var percent  = ((2 * Num.pi * position / length).sin * 1000).floor / 10
        var descript = (percent > 95)    ? " peak" :
                       (percent < -95)   ? " valley" :
                       (percent.abs < 5) ? " critical transition" : "other"
        if (descript == "other") {
            var transition  = td.addDays(((quadrant + 1) / 4 * length).floor - position)
            var tn = quadrants[quadrant]
            var trend = tn[0]
            var next = tn[1]
            descript = Fmt.swrite("$5.1f\% ($s, next $s $s)", percent, trend, next, transition)
        }
        Fmt.print("$s $2d : $s", cycle, position, descript)
    }
    System.print()
}

var datePairs = [
    ["1943-03-09", "1972-07-11"],
    ["1809-01-12", "1863-11-19"],
    ["1809-02-12", "1863-11-19"]  // correct DOB for Abraham Lincoln
]
for (datePair in datePairs) biorhythms.call(datePair[0], datePair[1])
Output:
Born 1943-03-09, Target 1972-07-11
Day 10717
Physical day  22 : -27.0% (down but rising, next transition 1972-07-12)
Emotional day 21 :  valley
Mental day    25 :  valley

Born 1809-01-12, Target 1863-11-19
Day 20034
Physical day   1 :  26.9% (up and rising, next peak 1863-11-23)
Emotional day 14 :  critical transition
Mental day     3 :  54.0% (up and rising, next peak 1863-11-24)

Born 1809-02-12, Target 1863-11-19
Day 20003
Physical day  16 : -94.3% (down and falling, next valley 1863-11-20)
Emotional day 11 :  62.3% (up but falling, next transition 1863-11-22)
Mental day     5 :  81.4% (up and rising, next peak 1863-11-22)
Cookies help us deliver our services. By using our services, you agree to our use of cookies.