next up previous contents index
Next: Alignment Data Types Up: Simple Data Types and Previous: Four Tuples ( four_tuple   Contents   Index


A date interface ( date )

Definition

An instance of the data type date represents a date consisting of a day d, a month m and year y. It will be denoted by d.m.y. Valid dates range from 1.1.1 to 31.12.9999. A date is valid if it lies in the range and is correct according to the gregorian calendar, i.e. a year y is considered to be a leap year iff y is divisible by 4 but not by 100 or y is divisible by 400. The year part y is always a four digit number, so that each date in the valid range has an unambiguous representation.
With the date class there is associated an input and an output format, each is described by a string which determines how instances of type date are read from streams and how they are printed to streams. Printing the date 4.11.1973 using the format string "dd.mm.yy" will result in "04.11.73", whereas printing the same date using "mm/dd/yyyy" will produce "11/04/1973". The date type provides some predefined formats, it also allows user-defined formats and supports different languages (for month names and weekday names).
A format string consists of tokens, not all tokens are valid for both input and output formats. But any sequence of valid tokens forms a valid format string, the only exception to this rule is the delim token (see the table below). In order to avoid ambiguities when parsing a format string the longest prefix rule is applied, which ensures that dd is parsed as a single token and not as twice the token d.
An input format does not have to refer to all the three parts (day, month and year) of a date; the parts which do not appear in the format are left unchanged when the format is used in an update operation. Applying the format "d.m.", for example, changes the day and the month part but not the year part. (The result of using input formats referring twice to the same part as in "m M" is undefined.) Please see table Token Overview for an overview of all possible tokens.

Table: Token Overview
token input output description
d yes yes day with 1 or 2 digits
dd yes yes day with 2 digits (possibly with leading zero)
dth yes yes day as abbreviated english ordinal number (1st, 2nd, 3rd, 4th, ...)
m yes yes month with 1 or 2 digits
mm yes yes month with 2 digits (possibly with leading zero)
M yes yes month name (when used in an input format this token must be followed by a single char c which does not belong to any month name, c is used to determine the end of the name. e.g.: "d.M.yy")
M:l yes yes the first l characters of the month name (l must be a single digit)
yy yes yes year with 2 digits (yy is considered to represent a year in [1950;2049])
yyyy yes yes year with 4 digits
[ yy] yy yes yes input: year with 2 or 4 digits / output: same as yyyy
w no yes calendar week (in the range [ 1;53] ) (see get_week() for details)
diy no yes day in the year (in the range [ 1,366] )
dow no yes day of the week (1=Monday, ..., 7=Sunday)
DOW no yes name of the weekday
DOW:l no yes the first l characters of the weekday name (l must be a single digit)
"txt" yes yes matches/prints txt (txt must not contain a double quote)
'txt' yes yes matches/prints txt (txt must not contain a single quote)
c yes yes matches/prints c ( c $ \notin${d, m, M,?, * , ;})
? yes no matches a single arbitrary character
* c yes no matches any sequence of characters ending with c
; yes yes separates different formats, e.g. "d.M.yy;dd.mm.yy"
      input: the first format that matches the input is used
      output: all but the first format is ignored
delim:c yes no c serves as delimiter when reading input from streams (If this token is used, it must be the first in the format string.) When you use "delim: \ n;d.M.yy \ n;d.m.yyyy \ n" as input format to read a date from a stream, everything until the first occurence of " \ n" is read and then the format "d.M.yy \ n;d.m.yyyy \ n" is applied.

#include < LEDA/system/date.h >

Types

date::month { Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec }
  The enumeration above allows to specify months by their name. Of course, one can also specify months by their number writing date::month(m).

date::language { user_def_lang, local, english, german, french }
  When the language is set to local, the month names and weekday names are read from the local environment; the other identifiers are self-explanatory.

date::format { user_def_fmt, US_standard, german_standard, colons, hyphens }
  The format US_standard is an abbreviation for mm/dd/[yy]yy, the format german_standard is the same as dd.mm.[yy]yy, the other formats are the same as the latter except that the periods are replaced by colons/hyphens.

Creation

date D creates an instance D of type date and initializes it to the current date.

date D(int d, month m, int y) creates an instance D of type date and initializes it to d.m.y.
Precondition d.m.y represents a valid date.

date D(string date_str, bool swallow = true)
    creates an instance D of type date and initializes it to date given in date_str.
If swallow is true, then the format "m/d/[yy]yy;d?m?[yy]yy" is used to parse date_str, otherwise the current input format is applied.
Precondition date_str represents a valid date.

Operations

4.1 Languages and Input/Output Formats

void date::set_language(language l)
    sets the language to l, which means that the month names and the weekday names are set according to the language.
Precondition l! = user$ \_$def$ \_$lang

void date::set_month_names(const char* names[])
    sets the names for the months and changes the language to user_def_lang.
Precondition names[0..11] contains the names for the months from January to December.

void date::set_dow_names(const char* names[])
    sets the names for the weekdays and changes the language to user_def_lang.
Precondition names[0..6] contains the names for the weekdays from Monday to Sunday.

language date::get_language() returns the current language.

void date::set_input_format(format f)
    sets the input format to f.
Precondition f! = user$ \_$def$ \_$fmt

void date::set_input_format(string f)
    sets the input format to the user-defined format in f.
Precondition f is a valid format string

format date::get_input_format() returns the current input format.

string date::get_input_format_str()
    returns the current input format string.

void date::set_output_format(format f)
    sets the output format to f.
Precondition f! = user$ \_$def$ \_$fmt

void date::set_output_format(string f)
    sets the output format to the user-defined format in f.
Precondition f is a valid format string

format date::get_output_format() returns the current output format.

string date::get_output_format_str()
    returns the current output format string.

4.2 Access and Update Operations

All update operations which may fail have in common that the date is changed and true is returned if the new date is valid, otherwise false is returned and the date is left unchanged. (Note that the functions add_to_day, add_to_month and add_to_year can only fail if the valid range (1.1.1 - 31.12.9999) is exceeded.)


void D.set_to_current_date() sets D to the current date.

bool D.set_date(int d, month m, int y)
    D is set to d.m.y (if d.m.y is valid).

bool D.set_date(const string date_str, bool swallow = true)
    D is set to the date contained in date_str. If swallow is true, then the format "m/d/[yy]yy;d?m?[yy]yy" is used to parse date_str, otherwise the current input format is applied.

string D.get_date() returns a string representation of D in the current output format.

int D.get_day() returns the day part of D, i.e. if D is d.m.y then d is returned.

month D.get_month() returns the month part of D.

string D.get_month_name() returns the name of the month of D in the current language.

int D.get_year() returns the year part of D.

bool D.set_day(int d) sets the day part of D to d, i.e. if D is d'.m.y then D is set to d.m.y.

bool D.add_to_day(int d) adds d days to D (cf. arithmetic operations).

bool D.set_month(month m) sets the month part of D to m.

bool D.add_to_month(int m) adds m months to the month part of D.
Let D be d.m'.y, then it is set to d.(m'+m).y. If this produces an overflow (i.e. m' + m > 12 ) then the month part is repeatedly decremented by 12 and the year part is simultaneously incremented by 1, until the month part is valid. (An underflow (i.e. m' + m < 1 ) is treated analogously.) The day part of the result is set to the minimum of d and the number of days in the resulting month.

bool D.set_year(int y) sets the year part of D to y.

bool D.add_to_year(int y) adds y years to the year part of D.
(If D has the form 29.2.y' and y'+y is no leap year, then D is set to 28.2.(y'+y).)

int D.get_day_of_week() returns the day of the week of D.
(1=Monday, 2=Tuesday, ..., 7=Sunday)

string D.get_dow_name() returns the name of the weekday of D in the current language.

int D.get_week() returns the number of the calendar week of D (range [ 1,53] ).
A week always ends with a Sunday. Every week belongs to the year which covers most of its days. (If the first Sunday of a year occurs before the fourth day of the year, then all days up to this Sunday belong to the last week of the preceding year. Similarly, if there are less than 4 days left after the last Sunday of a year, then these days belong to the first week of the succeding year.)

int D.get_day_in_year() returns the number of the day in the year of D (range [ 1;366] ).

4.3 Arithmetic Operations

date D + int d returns the date d days after D.

date D - int d returns the date d days before D.

The related operators ++, -, +=, -= and all comparison operators are also provided.

int D - const date& D2 returns the difference between D and D2 in days.

int D.days_until(const date& D2)
    returns D2 - D.

int D.months_until(const date& D2)
    if D2 > = D then max{m : D.add$ \_$to$ \_$month(m)  < = D2} is returned; otherwise the result is - D2.months_until(D).

int D.years_until(const date& D2)
    if D2 > = D then max{y : D.add$ \_$to$ \_$year(y)  < = D2} is returned; otherwise the result is - D2.years_until(D).

4.4 Miscellaneous Predicates

bool date::is_valid(int d, month m, int y)
    returns true iff d.m.y represents a valid date.

bool date::is_valid(string d, bool swallow=true)
    returns true iff d represents a valid date. If swallow is true the swallow format (cf. set_date) is used, otherwise the current input format is tried.

bool date::is_leap_year(int y) returns true iff y is a leap year.

bool D.is_last_day_in_month() let D be d.m.y; the function return true iff d is the last day in the month m of the year y.

Example

We count the number of Sundays in the days from now to 1.1.2020 using the following code chunk:

    int number_of_Sundays = 0;
    for (date D; D<=date(1,date::Jan,2020); ++D)
      if (D.get_day_of_week() == 7) ++number_of_Sundays;

Now we show an example in which different output formats are used:

    date D(2,date::month(11),1973);
    date::set_output_format(date::german_standard);
    cout << D << endl; // prints "02.11.1973"
    date::set_language(date::english);
    date::set_output_format("dth M yyyy");
    cout << D << endl; // prints "2nd November 1973"

Finally, we give an example for the usage of a multi-format. One can choose among 3 different formats:

  1. If one enters only day and month, then the year part is set to the current year.
  2. If one enters day, month and year providing only 2 digits for the year, the year is considered to be in the range [1950, 2049]. (Note that the date 1.1.10 must be written as "1.1.0010".)
  3. One may also specify the date in full detail by entering 4 digits for the year.
The code to read the date in one of the formats described above looks like this:
    D.set_to_current_date(); // set year part to current year
    date::set_input_format("delim:\n;d.m.\n;d.m.[yy]yy\n");
    cin >> D; cout << D << endl;


next up previous contents index
Next: Alignment Data Types Up: Simple Data Types and Previous: Four Tuples ( four_tuple   Contents   Index
Christian Uhrig 2017-04-07