Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Parallel

Julian and Gregorian Calendars


We first need to ascertain whether a given year is a leap year (in the Julian or Gregorian calendars). Functions to do this are given in DATECONV.C (see Listing Two). A universal date-integer conversion method, as understood here, consists of two functions: The first takes a date (either Julian or Gregorian) and returns a positive or negative integer (long int); the second takes a long int and a calendrical specification (G or J) and returns a date in that calendar. It does not matter which date corresponds to day 0 as long as there is a quickly computable, one-to-one correspondence between dates in a calendar and numbers.

/*  DATETEST.C -- Tests date conversion routines -- Last mod.: 1992-10-10  */
/*  Link with DATECONV.OBJ by using CL DATETEST.C DATECONV.C */

#include <STDIO.H>
#include <STDLIB.H>     /*  for exit()  */
#include <CONIO.H>

#include "DATECONV.H"

void main(int argc, char **argv);
void display(long n);
void test(long n, char calendar);

Date date;

#define ESCAPE '\x1B'
#define N 3000
#define MAXIMUM_GDN 2146905911
/*  largest Gregorian day number that can be handled  */
void main(int argc, char **argv)
{
long n, m;
if ( argc < 3 )
    {
    printf("Syntax: DATETEST start increment\n");
    return;
    }
n = atol(argv[1]);          /*  number to start with  */
m = atol(argv[2]);          /*  increment  */
printf("Quit with Escape.");
while ( TRUE )
    {
    if ( n%(N*m) == 0 )
        {
        display(n);
        display(-n);
        }
    test(n,'G');
    test(n,'J');
    test(-n,'G');
    test(-n,'J');
    if ( n > MAXIMUM_GDN-m )
        {
        printf("\ngdn = %ld",n);
        return; /*  since next n is too large  */
        }
    n += m;
    if ( kbhit() )
        {
        if ( getch() == ESCAPE )
            break;
        }
    }
}
void display(long n)
{
date.gdn = n;
printf("\ngdn =%12ld",n);
gdn_to_date(&date,'G');
printf("   %02d/%02d/%ld (G)",date.month,date.day,date.year);
gdn_to_date(&date,'J');
printf("   %02d/%02d/%ld (J)",date.month,date.day,date.year);
}
void test(long n,char calendar)
{
date.gdn = n;
gdn_to_date(&date,calendar);
if ( !date.valid )
    {
    printf("\ngdn = %ld  %d/%d/%ld (%c)  Date invalid!",
        date.gdn,date.month,date.day,date.year,calendar);
    exit(1);
    }
date.gdn = 0L;
date_to_gdn(&date,calendar);
if ( date.gdn != n )
    {
    printf("\ngdn = %ld  %d/%d/%ld (%c)   n = %ld!",
        date.gdn,date.month,date.day,date.year,calendar,n);
    exit(1);
    }
}
Listing Two

The method presented here converts dates into the number of days before or after October 15, 1582--the day that the Gregorian calendar came into effect. Thus, October 15, 1582 (Gregorian) corresponds to day 0; October 16, 1582 (Gregorian) to day 1; and October 14, 1582 (Gregorian) to day -1. The number corresponding to a date is thus called the "Gregorian-day number." Dates in the Julian calendar, as well as those in the Gregorian calendar, are mapped into Gregorian-day numbers. Thus, the day preceding October 15, 1582 in the Gregorian calendar is both October 4 in the Julian calendar and October 14 in the Gregorian calendar--both have Gregorian-day number -1.

The code for the function to convert a date in one of the calendars to a Gregorian-day number, and for the function to convert a Gregorian-day number to a date in a specified calendar, is given in Listing Two. The Date structure uses long int variables (signed) for the year and the Gregorian-day number. The largest integer representable as a signed long int is 2,147,483,647. Due to the method of calculation, however, the largest Gregorian-day number that can be used is 2,146,905,911. This corresponds to the dates July 11, 5,879,611 (Gregorian) and October 19, 5,879,490 (Julian). By that time, dates in the Gregorian and Julian calendars will differ by about 121 years. (This will be of no practical importance since by that time both calendars will likely have been superseded.)

More Details

To use the conversion functions, declare a structure of type Date (defined in Listing One) and pass to the functions a pointer to the structure along with a calendrical specification (G or J). If you are converting from Gregorian-day number to date, define the gdn structure variable before calling gdn_to_date(). Conversely, define the variables day, month, and year before calling date_to_gdn(). On return from the functions, extract either gdn or the date values from the structure. Before using the gdn value, it is advisable to check the validity flag, which will be TRUE if the date passed was a valid date in the specified calendar, and FALSE otherwise. For example, the attempt to convert February 29, 1900 (Gregorian) to a Gregorian-day number will produce a FALSE in the validity variable.

The lfloor() function in Listing Two is analogous to the Microsoft floating-point library floor() function, and overcomes a small problem in integer arithmetic. The date-conversion functions described earlier need a long-integer division operation such that, for all long integers a and b, a/b is the largest integer not greater than the real number a/b. MSC's division operator produces this result if a and b are positive, but not if a is negative and b is positive. The lfloor() function provides what is needed.

Finally, DATECONV.C also contains a function to convert a Gregorian-day number into a day of the week. This is independent of the particular calendar used.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.