v10i084: new version of weekday
Marcel Mol
marcel at duteca.tudelft.nl
Tue Feb 27 13:54:57 AEST 1990
Posting-number: Volume 10, Issue 84
Submitted-by: marcel at duteca.tudelft.nl (Marcel Mol)
Archive-name: weekday
[Shar, please!!! ++bsa]
This version of weekday repairs some bugs and adds the ISO date standard as
date input format. (The diffs were almost as large as the source so I send out
the soure).
-Marcel
------------------------- Cut here ---------------------------------------
#! /bin/sh
# This file was wrapped with "dummyshar". "sh" this file to extract.
# Contents: weekday.c
echo extracting 'weekday.c'
if test -f 'weekday.c' -a -z "$1"; then echo Not overwriting 'weekday.c'; else
sed 's/^X//' << \EOF > 'weekday.c'
X/* @(#) weekday.c 3.40 02/06/90 */
X/*************************************************************************
X ** **
X ** Name : weekday **
X ** Author : Marcel J.E. Mol **
X ** Date : 12/28/89 (first release) **
X ** Version : 3.40 **
X ** Files : weekday.c Main source file **
X ** **
X ** ------------------------- Revision List ------------------------- **
X ** Ver Date Name Remarks **
X ** 3.40 02/06/90 Marcel Mol Added ISO date standard YYYY-MM-DD **
X ** Suggested by mathew smm12 at cl.cam.ac.uk **
X ** 3.33 02/04/90 Marcel Mol Fixed bug when entering years in **
X ** 0 <= year <= 99 with leading '0' **
X ** 3.32 02/01/90 Marcel Mol Fixed typos in January February **
X ** October **
X ** 3.31 01/09/90 Marcel Mol Removed unnecessary code. **
X ** Added comments. **
X ** 3.30 01/08/90 Marcel Mol Improved option handling. **
X ** verbose works on more options. **
X ** use printf field length option to **
X ** get short day and month names. **
X ** 3.26 01/07/90 Marcel Mol Filled in usage function. **
X ** 3.25 01/04/90 Marcel Mol Use 'today' when no date is given. **
X ** 3.20 01/03/90 Marcel Mol Allow bsd `date` as input. **
X ** 3.11 01/03/90 Marcel Mol Documentation, typos, checkdate(). **
X ** Removed redundant checks. **
X ** 3.10 01/02/90 Marcel Mol Added -s and -v options. **
X ** allow yy.ddd input and implement **
X ** julian date conversion. **
X ** 3.00 12/30/89 Marcel Mol Set up user interface. **
X ** Allow mm/dd/yy and dd-mm-yy input. **
X ** Options to print different parts. **
X ** 2.10 12/28/89 Marcel Mol Added Julianday. **
X ** 2.00 12/27/89 Marcel Mol Made weekday and weeknr everlasting.**
X ** 1.00 12/26/89 Marcel Mol First release. **
X ** Set up algorithms weekday weeknr. **
X ** ================================================================= **
X ** **
X ** Compile as follows: cc weekday.c -Oso weekday **
X ** **
X ** Usage: weekday [-svdDmMywjnah] [<date>] **
X ** **
X ** Weekday outputs line on which it informs you about several **
X ** thing of the given <date>. **
X ** The <date> input may be in several formats: **
X ** **
X ** mm/dd/yy e.g. 10/30/89 or 1/2/510 **
X ** dd-mm-yy e.g. 30-10-89 or 2-1-510 **
X ** yyyy-mm-dd e.g. 1989-10-30 or 0510-1-2 **
X ** yy.ddd e.g. 89.303 or 510.2 **
X ** `date` output e.g. Mon Oct 30 99:99:99 1989 **
X ** **
X ** If no date argument is given, weekday uses the system date. **
X ** The yyyy-mm-dd date format must have 4 digits for the yyyy **
X ** part, 2 for the mm part and 2 for the dd part; it's just **
X ** the ISO date standard. (undocumented feature: it also works **
X ** if the mm and/or dd part is only one digit long.) **
X ** So the following trick does not apply to this date format: **
X ** When the year number is less than 100 and the string **
X ** forming the year does not start with a 0, the year is **
X ** converted to be in the current century. So 10/30/89 is **
X ** actually 10/30/1989. If the real year 89 is wanted specify **
X ** it as 10/30/089. (the current century is a constant in the **
X ** source code. If this programs survives 1999 this constant **
X ** must be changed, and the program recompiled.) **
X ** Note: make sure that `date` output is passed as one **
X ** argument, so enclose it with "s. **
X ** **
X ** The output, when no options are given, is something like **
X ** this: **
X ** **
X ** 30 October 1989 is on a Monday on julian day 303 in week 44 **
X ** **
X ** or: **
X ** **
X ** 2 January 510 is on a Friday on julian day 2 in week 1 **
X ** **
X ** Depending on the options the output changes: **
X ** **
X ** -s toggle short form output: Monday -> Mon, June -> Jun **
X ** and vice versa. **
X ** -v toggle verbose output; removes 'is on a' etc. **
X ** and vice versa. **
X ** -d prints day of week number: 1 is Monday, 7 is Sunday **
X ** -D gives day of week name, i.e Monday or Mon **
X ** -m prints the month number **
X ** -M outputs the month name, i.e. January or Jan **
X ** -y outputs the year number **
X ** -w gives the week number **
X ** -j outputs the julian day number **
X ** -n gives day of month **
X ** -a gives everything it knows. Without the -s and -v **
X ** options this outputs the same as the default case. **
X ** In fact -a is just short for -nmyDjw. **
X ** -h give a usage message **
X ** **
X ** With the verbose option on, each printing option speaks to **
X ** you in a more or less english way. **
X ** All options that print something also print a space **
X ** character (except -a). **
X ** The options may come in any order and as many times as **
X ** you like. The -s and -v options only have an effect on the **
X ** options that follow them. **
X ** When now option is given (except for the -v and -s option) **
X ** the -a option is default. **
X ** The output is ended with a newline **
X ** Examples: **
X ** **
X ** % weekday -yjMdD 12/31/89 **
X ** 89 365 December 7 Sunday **
X ** **
X ** % weekday -yjMsdD 12/31/89 **
X ** 89 365 December 7 Sun **
X ** **
X ** % weekday -yjsMsdD 12/31/89 **
X ** 89 365 Dec 7 Sunday **
X ** **
X ** % weekday -v 30/30/89 **
X ** 30 Oct 1989 is on a Mon on julian day 303 in week 44 **
X ** **
X ** BUGS: the program assumes there have always been leap years **
X ** so year 4 is a leap year as far as the program can tell... **
X ** **
X ** This software is copyrighted (c) 1989 1990 by M.J.E. Mol. **
X ** This code or part of this code may be used by freeware, **
X ** public domain or any other non-commercial product. I only ask **
X ** you to give me credit for the used code in the documentation **
X ** and in your source code. **
X ** **
X ** If you want to use this code or part of this code in your **
X ** shareware or any other commercial product, I ask you to contact **
X ** me so we can setup an arrangement for the use of the code or part **
X ** of the code. **
X ** **
X ** In any case, I can not be held responsible for any damage this **
X ** code or part of this code may cause you or anyone or anything **
X ** else. **
X ** **
X ** Mail bugs to: email: marcel at duteca.tudelft.nl **
X ** pmail: Marcel J.E. Mol **
X ** Karel Doormanlaan 58 **
X ** 2283AT Rijswijk **
X ** The Netherlands (Holland) **
X ** Phone: (+31) 070-3932390 **
X ** Bankaccount: 36.89.35.922 (In the Netherlands) **
X ** **
X ************************************************************************/
X
Xchar * copyright = "@(#) weekday.c 3.40 02/06/90 (c) M.J.E. Mol";
X
X#include <stdio.h>
X#include <string.h>
X#include <time.h>
X
X
X#define CENTURY 1900 /* prefix for years */
X#define LEAP(year) ((year%4 == 0) && (year%100 != 0) || (year%400 == 0))
X
X/*
X * Global variables
X */
X
Xchar *weekdays[8] = {"", "Monday", "Tuesday", "Wednesday", "Thursday",
X "Friday", "Saterday", "Sunday"};
Xchar days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
Xint juldays[13] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
Xchar *monthname[13] = {"", "January", "February", "March", "April",
X "May", "June", "July", "August",
X "September", "October", "November", "December"};
X
Xint shortflag = 0; /* short output of day and month name */
Xint verbose = 1; /* output in a 'sentence' */
Xchar * progname;
X
X
X/*
X * function declarations
X */
Xvoid main();
Xvoid scanmmddyy();
Xvoid scanyyyymmdd();
Xvoid scanddmmyy();
Xint scanjul();
Xint scandate();
Xint julianday();
Xvoid julian2day();
Xint weekday();
Xint weeknr();
Xvoid checkdate();
Xvoid usage();
X
X
Xvoid main(argc, argv)
Xint argc;
Xchar **argv;
X{
X int year, month, day, week;
X int wday = -1;
X int jday = -1;
X int opt, haveopt;
X char *date;
X extern int optind; /* For getopt */
X extern char * optarg; /* For getopt */
X
X progname = *argv;
X date = argv[argc-1];
X
X /*
X * pick up the date argument and scan it
X */
X if (*date == '-' || argc == 1) /* no date, take current */
X wday = scandate(NULL, &year, &month, &day);
X else if (strchr(date, '/') != NULL) /* mm/dd/yy format date */
X scanmmddyy(date, &year, &month, &day);
X else if (strchr(date, '-') == date+4) /* yyyy-mm-dd format */
X scanyyyymmdd(date, &year, &month, &day);
X else if (strchr(date, '-') != NULL) /* dd-mm-yy format date */
X scanddmmyy(date, &year, &month, &day);
X else if (strchr(date, '.') != NULL) /* yyyy.ddd format date */
X jday = scanjulian(date, &year, &month, &day);
X else /* unix date output format */
X wday = scandate(date, &year, &month, &day);
X
X /*
X * get missing data
X */
X if (jday == -1)
X jday = julianday(year, month, day);
X if (wday == -1)
X wday = weekday(year, month, day);
X week = weeknr(year, month, day);
X
X
X /*
X * print the wanted stuff ...
X */
X while ((opt = getopt(argc, argv, "svdDmMywjnah")) != EOF) {
X switch (opt) {
X case 's' : shortflag ^= 1;
X break;
X case 'v' : verbose ^= 1;
X break;
X case 'D' : printf("%s%.*s ",
X verbose ? "is on a " : "",
X shortflag ? 3 : 9 , weekdays[wday]);
X haveopt = 1;
X break;
X case 'd' : printf("%s%d ", verbose ? "is weekday " : "", wday);
X haveopt = 1;
X break;
X case 'm' : printf("%d ", month);
X haveopt = 1;
X break;
X case 'M' : printf("%.*s ", shortflag ? 3 : 9, monthname[month]);
X haveopt = 1;
X break;
X case 'y' : printf("%d ", year);
X haveopt = 1;
X break;
X case 'w' : printf("%s%d ", verbose ? "in week " : "", week);
X haveopt = 1;
X break;
X case 'j' : printf("%s%d ", verbose ? "on julian day " : "", jday);
X haveopt = 1;
X break;
X case 'n' : printf("%d ", day);
X haveopt = 1;
X break;
X case 'a' : if (verbose) {
X printf("%d %.*s %d is on a %.*s ",
X day, shortflag ? 3 : 9, monthname[month],
X year, shortflag ? 3 : 9, weekdays[wday]);
X printf("on julian day %d in week %d", jday, week);
X }
X else
X printf("%d %.*s %d %.*s %d %d",
X day, shortflag ? 3 : 9, monthname[month],
X year, shortflag ? 3 : 9, weekdays[wday],
X jday, week);
X haveopt = 1;
X break;
X case 'h' : usage();
X break;
X default : fprintf(stderr,
X "%s: use -h option for help\n", progname);
X exit(1);
X break;
X }
X }
X
X
X if (!haveopt) {
X if (verbose) {
X printf("%d %.*s %d is on a %.*s ",
X day, shortflag ? 3 : 9, monthname[month],
X year, shortflag ? 3 : 9, weekdays[wday]);
X printf("on julian day %d in week %d", jday, week);
X }
X else
X printf("%d %.*s %d %.*s %d %d",
X day, shortflag ? 3 : 9, monthname[month],
X year, shortflag ? 3 : 9, weekdays[wday],
X jday, week);
X }
X
X /*
X * finish with a newline
X */
X putchar('\n');
X
X exit(0);
X
X} /* main */
X/*************************************************************************
X ** **
X ** DATE SCANNING ROUTINES **
X ** **
X *************************************************************************/
X
X/*
X * scanmmddyy --- scan the date variable in the form MM/DD/YY.
X * MM, DD and YY may be variable sized numbers.
X * output is in output variables year, month and day.
X */
Xvoid scanmmddyy(date, year, month, day)
Xchar *date;
Xint *year, *month, *day;
X{
X char *i;
X
X if (sscanf(date, "%d/%d/%d", month, day, year) != 3 ||
X *month <= 0 || *day <= 0 || *year < 0) {
X fprintf(stderr, "%s: error in mm/dd/yy format date %s\n",
X progname, date);
X exit(4);
X }
X
X if (*year < 100) {
X i = strrchr(date, '/') + 1;
X if (*i != '0')
X *year += CENTURY;
X }
X
X return;
X
X} /* scanmmddyy */
X
X
X
X/*
X * scanyyyymmdd --- scan the date variable in the form YYYY-MM-DD.
X * YYYY, MM and DD must be 4, 2 and 2 digits wide.
X * output is in output variables year, month and day.
X */
Xvoid scanyyyymmdd(date, year, month, day)
Xchar *date;
Xint *year, *month, *day;
X{
X
X if (sscanf(date, "%4d-%2d-%2d", year, month, day) != 3 ||
X *month <= 0 || *day <= 0 || *year < 0) {
X fprintf(stderr, "%s: error in yyyy-mm-dd format date %s\n",
X progname, date);
X exit(4);
X }
X
X return;
X
X} /* scanyyyymmdd */
X
X
X/*
X * scanddmmyy --- scan the date variable in the form DD-MM-YY.
X * Also YYYY-MM-DD is recognized if YYYY > 31 and DD <= 31.
X * DD, MM and YY may be variable sized numbers.
X * output is in output variables year, month and day.
X */
Xvoid scanddmmyy(date, year, month, day)
Xchar *date;
Xint *year, *month, *day;
X{
X char *i;
X
X if (sscanf(date, "%d-%d-%d", day, month, year) != 3 ||
X *month <= 0 || *day <= 0 || *year < 0) {
X fprintf(stderr, "%s: error in dd-mm-yy format date %s\n",
X progname, date);
X exit(4);
X }
X
X if (*year < 100) {
X i = strrchr(date, '-') + 1;
X if (*i != '0')
X *year += CENTURY;
X }
X
X return;
X
X} /* scanddmmyy */
X
X
X
X/*
X * scanjulian --- scan the date variable in the form YY.DDD.
X * YY and DDD may be variable sized numbers.
X * output is in output variables year, month and day.
X * the return value is tha actual julian day DDD.
X */
Xint scanjulian(date, year, month, day)
Xchar *date;
Xint *year, *month, *day;
X{
X int jday;
X
X if (sscanf(date, "%d.%d", year, &jday) != 2 || *year < 0 || jday <= 0) {
X fprintf(stderr, "%s: error in julian date %s\n", progname, date);
X exit(4);
X }
X
X if ((*year < 100) && (*date != '0'))
X *year += CENTURY;
X julian2day(*year, jday, month, day);
X
X return jday;
X
X} /* scanjulian */
X
X
X
X/*
X * scandate --- scan the date variable in the Unix `date` form.
X * This can look like: "Mon Jan 8 20:10:10 MET 1990"
X * or: "Mon Jan 8 20:10:10 1990"
X * the number of spaces between the fields is not fixed
X * (although date output is always in the same with, see ctime(3).
X * output is in output variables year, month and day.
X * the return value is the day of the week number.
X * If the date input is the NULL pointer, the xurrent system date
X * is taken.
X */
Xint scandate(date, year, month, day)
Xchar *date;
Xint *year, *month, *day;
X{
X char *i;
X char dayname[4];
X char monname[10];
X int j, k;
X long tim;
X
X if (date == NULL) {
X tim = time((long *) 0);
X date= ctime(&tim);
X }
X
X if (sscanf(date, "%3s %3s %d %*s %d", /* date without time zone */
X dayname, monname, day, year) != 4 &&
X sscanf(date, "%3s %3s %d %*s %*s %d", /* date with time zone */
X dayname, monname, day, year) != 4) {
X fprintf(stderr, "%s: error in unix `date` format date %s\n",
X progname, date);
X exit(4);
X }
X
X for(j=1; j<12; j++) {
X if (strncmp(monname, monthname[j], 3) == NULL)
X break;
X }
X if (strncmp(monname, monthname[j], 3) != NULL) {
X fprintf(stderr, "%s: error in unix `date` format date %s\n",
X progname, date);
X exit(4);
X }
X *month = j;
X for(j=1; j<7; j++) {
X if (strncmp(dayname, weekdays[j], 3) == NULL)
X break;
X }
X if (strncmp(dayname, weekdays[j], 3) != NULL) {
X fprintf(stderr, "%s: error in unix `date` format date %s\n",
X progname, date);
X exit(4);
X }
X
X return j;
X
X} /* scandate */
X/*************************************************************************
X ** **
X ** DATE CONVERSION ROUTINES **
X ** **
X *************************************************************************/
X
X
X
X/*
X * julian2day -- converts year and julian day value to the corresponding
X * month and day of the month values for that year.
X * these values are returned in the ouput variables month and day.
X */
Xvoid julian2day(year, jday, month, day)
Xint year, jday;
Xint *month, *day;
X{
X int leap;
X
X leap = LEAP(year) ? 1 : 0;
X if (jday > 365+leap || jday <= 0) {
X fprintf(stderr, "%s: error in julian date %d.%d\n",
X progname, year, jday);
X exit(8);
X }
X
X if (jday <= 31) {
X *month = 1;
X *day = jday;
X return;
X }
X
X jday -= leap;
X if (jday <= 59) {
X *month = 2;
X *day = jday - 31 + leap;
X }
X else if (jday <= 90) {
X *month = 3;
X *day = jday - 59;
X }
X else if (jday <= 120) {
X *month = 4;
X *day = jday - 90;
X }
X else if (jday <= 151) {
X *month = 5;
X *day = jday - 120;
X }
X else if (jday <= 181) {
X *month = 6;
X *day = jday - 151;
X }
X else if (jday <= 212) {
X *month = 7;
X *day = jday - 181;
X }
X else if (jday <= 243) {
X *month = 8;
X *day = jday - 212;
X }
X else if (jday <= 273) {
X *month = 9;
X *day = jday - 243;
X }
X else if (jday <= 304) {
X *month = 10;
X *day = jday - 273;
X }
X else if (jday <= 334) {
X *month = 11;
X *day = jday - 304;
X }
X else {
X *month = 12;
X *day = jday - 334;
X }
X
X return;
X
X} /* julian2day */
X
X
X
X/*
X * julianday -- converts a year, mont and day value the corresponding julian
X * day number of that year.
X * the julian day is passed as a return value.
X */
Xjulianday(year, month, day)
Xint year, month, day;
X{
X register int doy;
X
X checkdate(year, month, day); /* exits if date in error */
X
X doy = juldays[month];
X if ((month > 2) && LEAP(year))
X doy++;
X doy += day;
X
X return doy;
X
X} /* julianday */
X
X
X
X/*
X * weekday -- returns the day of the week number based on the given
X * year, month and day of the month value.
X */
Xweekday(year, month, day)
Xint year, month, day;
X{
X register int dow;
X
X checkdate(year, month, day); /* exits if date in error */
X
X dow = 6 + /* the magic number */
X year + /* shift a day each year */
X year/4 - year/100 + year/400 + /* shift a day each leap year */
X juldays[month] + day; /* day of year */
X
X if ((month < 3) && LEAP(year)) /* first two months of leap don't */
X dow--; /* have the extra leap shift */
X
X dow %= 7;
X return (dow == 0) ? 7 : dow; /* convert 0 to 7 */
X
X} /* weekday */
X
X
X/*
X * weeknr -- returns the weeknumber of the given date (year, month and day of
X * the month) for that year.
X */
Xweeknr(year, month, day)
Xint year, month, day;
X{
X register int fday, jul, weeknum;
X
X checkdate(year, month, day); /* exits if date in error */
X
X fday = weekday(year, 1, 1);
X
X jul = julianday(year, month, day);
X weeknum = (jul + fday - 2)/7;
X if (fday <= 4)
X weeknum++;
X
X if (weeknum == 0) /* go into previous year */
X if ((fday == 5) || /* week 1 has 4 or 5 days and week */
X ((fday == 6) && LEAP(year-1)) ) /* 53 has 4 or 5 days in year-1 */
X return 53;
X else
X return 52;
X
X if (weeknum == 53) { /* only a week 53 if we have > 4 */
X fday = weekday(year, 12, 31); /* days in the week */
X if (fday < 4)
X weeknum = 1;
X }
X
X return weeknum;
X
X} /* weeknr */
X/*************************************************************************
X ** **
X ** OTHER ROUTINES **
X ** **
X *************************************************************************/
X
X
X
X/*
X * checkdate -- checks if the given date is a valid one.
X * if not, it just exits.
X */
Xvoid checkdate(year, month, day)
Xint year, month, day;
X{
X int dim;
X
X if (year < 0) {
X fprintf(stderr, "%s: %d is an invalid year\n", progname, year);
X exit(2);
X }
X
X if ((month < 1) || (month > 12)) {
X fprintf(stderr, "%s: %d is an invalid month\n", progname, month);
X exit(2);
X }
X
X dim = days[month];
X if ((month == 2) && LEAP(year))
X dim++;
X if ((day > dim) || (day < 1)) {
X fprintf(stderr, "%s: %d is an invalid day in %s %d\n", progname,
X day, monthname[month], year);
X exit(2);
X }
X
X return;
X
X} /* checkdate */
X
X
X
X/*
X * usage -- give usage message.
X */
Xvoid usage()
X{
X
X fprintf(stderr,"Usage: weekday [-svdDmMywjnah] [<date>]\n");
X fprintf(stderr," <date>: mm/dd/yy | dd-mm-yy | yyyy-mm-dd\n |");
X fprintf(stderr," yy.ddd | Unix date\n");
X fprintf(stderr," default is today\n");
X fprintf(stderr," options: -s toggle short form output\n");
X fprintf(stderr," -v toggle verbose output\n");
X fprintf(stderr," -d prints day of week number\n");
X fprintf(stderr," -D gives day of week name\n");
X fprintf(stderr," -m prints the month number\n");
X fprintf(stderr," -M outputs the month name\n");
X fprintf(stderr," -y outputs the year number\n");
X fprintf(stderr," -w gives the week number\n");
X fprintf(stderr," -j outputs the julian day number\n");
X fprintf(stderr," -n gives day of month\n");
X fprintf(stderr," -a gives everything it knows (default)\n");
X fprintf(stderr," -h give a usage message\n");
X
X return;
X
X} /* usage */
EOF
chars=`wc -c < 'weekday.c'`
if test $chars != 27998; then echo 'weekday.c' is $chars characters, should be 27998 characters!; fi
fi
exit 0
--
#########################################
# Marcel J.E. Mol ######################################
# Delft University of Technology Pink Elephant Management Services #
# The Netherlands Voorburg #
# UUCP: marcel at duteca.tudelft.nl Tel: 070-694231 #
# ######################################
#########################################
More information about the Comp.sources.misc
mailing list