pax_global_header 0000666 0000000 0000000 00000000064 14321307032 0014505 g ustar 00root root 0000000 0000000 52 comment=d2ad63325bca1ec98ff0d292183614924df2668c
calendar-3.0.0/ 0000775 0000000 0000000 00000000000 14321307032 0013256 5 ustar 00root root 0000000 0000000 calendar-3.0.0/.github/ 0000775 0000000 0000000 00000000000 14321307032 0014616 5 ustar 00root root 0000000 0000000 calendar-3.0.0/.github/CODEOWNERS 0000664 0000000 0000000 00000000232 14321307032 0016206 0 ustar 00root root 0000000 0000000 # These are the default owners for everything in the repo. They will
# receive review requests when someone opens a pull request.
* @Drup @loxs @pmetzger
calendar-3.0.0/.gitignore 0000664 0000000 0000000 00000000037 14321307032 0015246 0 ustar 00root root 0000000 0000000 _build
*.install
.merlin
_opam
calendar-3.0.0/.travis.yml 0000664 0000000 0000000 00000001247 14321307032 0015373 0 ustar 00root root 0000000 0000000 language: c
install: wget https://raw.githubusercontent.com/ocaml/ocaml-ci-scripts/master/.travis-docker.sh
script: bash -ex .travis-docker.sh
services:
- docker
env:
global:
- PINS="calendar:."
- DISTRO="ubuntu-16.04"
matrix:
- PACKAGE="calendar" OCAML_VERSION="4.03" TESTS=1 EXTRA_DEPS="alcotest"
- PACKAGE="calendar" OCAML_VERSION="4.04" TESTS=1 EXTRA_DEPS="alcotest"
- PACKAGE="calendar" OCAML_VERSION="4.05" TESTS=1 EXTRA_DEPS="alcotest"
- PACKAGE="calendar" OCAML_VERSION="4.06" TESTS=1 EXTRA_DEPS="alcotest"
- PACKAGE="calendar" OCAML_VERSION="4.07" TESTS=1 EXTRA_DEPS="alcotest"
- PACKAGE="calendar" OCAML_VERSION="4.08" TESTS=1 EXTRA_DEPS="alcotest"
calendar-3.0.0/CHANGES 0000664 0000000 0000000 00000022205 14321307032 0014252 0 ustar 00root root 0000000 0000000 ===============================================================================
Preliminary notes:
------------------
Mark "o": new feature
Mark "*": bug fixed.
Mark "!": change that can break compatibility with older version of the library
===============================================================================
version 3.0.0, 2022-10-11:
==========================
* Fix Date.week_first_last according to ISO 8601 (@balat)
* Remove incorrect time zone bound check (@vouillon)
! Switch from Str to Re (@vouillon)
! Remove date function from the version API (@c-cube)
o Add some uility function for comparing dates (@loxs)
* Switch the build-system to dune (@c-cube)
version 2.04, 2014-10-29:
===========================
* [Makefile] Fix minor issues with ocamlfind and 'make install' (from
Christopher Zimmermann).
o [Printer] In function from_fstring of sub-module Ftime, Fcalendar, and
Precise_Fcalendar, the number of seconds corresponding to %S may be a floating
point number (from Christophe Troestler' suggestion).
version 2.03.2, 2012-06-26:
===========================
o [Compilation] Compatibility with OCaml 4
version 2.03.1, 2011-03-24:
===========================
* [Calendar] Fixed bug in Calendar.prev and Fcalendar.prev: mostly raised
exception Date.Out_of_bounds before.
* [Printer] `Thurday' was printed instead of `Thursday'
version 2.03, 2010-07-05:
=========================
o [Date] new function Date.precise_sub
o [Calendar] new function Calendar.precise_sub
(from Dario Teixeira's suggestion)
* [Compilation] detect whether native dynlink works
(prevents compilation bug on Mac OS X)
version 2.02, 2009-12-11:
=========================
o [License] add the usual Ocaml linking exception in the license
o [Calendar] Calendar_sig.Period.to_time is deprecated.
Replaced by a new function Calendar_sig.Period.safe_to_time
o [Date] Date.Period.nb_days is deprecated.
Replaced by a new function Date.Period.safe_nb_days
o [Compilation] calendarLib.cmxs provided if ocaml >= 3.11 is installed
(patch of Mehdi Dogguy)
o [Date] new functions Date.make_year and Date.make_year_month
o [Date] improve memory representation of Date.Period.t
* [Compilation] remove installation of packed *.cmi
* [Compilation] bug fixed under Cygwin
* [Compilation] META files was incorrect, so "ocamlfind ocamlopt" did not work
* [Compilation] file date_sig.mli, time_sig.mli and calendar_sig.mli was not
properly linked
version 2.01.1, 2009-02-23:
===========================
o [Date] add a missing coercion rule for months
(e.g. "Date.make 2008 18 1" is now equal to "Date.make 2009 6 1")
* [Date] bug fixed in date arithmetic operations due to the missing above
feature
version 2.01, 2009-01-26:
=========================
o [Printer] new formats available for printers and parsers
- %C century: as %Y without the two last digits
- %F replace %i which is now deprecated
- %P am or pm
- %R shortcut for %H:%M
- %s number of seconds since 1970/1/1
- %z time zone in the form +hhmm (from Warren Harris' suggestion)
- %:z time zone in the form +hh:mm (from Warren Harris' suggestion)
- %::z time zone in the form +hh:mm:ss (from Warren Harris' suggestion)
- %:::z time zone in the form +hh (from Warren Harris' suggestion)
o [Printer] new paddings available for printers
- 0 (zero): pad fields with zeroes like by default
- ^: use uppercase if possible
o [Compilation] calendarLib.cma and calendarLib.cmxa are now installed
(Janne Hellsten and Guillaume Yziquel's suggestion)
* [Tests] test suite now uses Utils.Float.equal if required
(patch of Richard Jones)
* [Compilation] small bug fixed in make install
* [Compilation] support of win64 (patch of David Allsopp)
version 2.0.4, 2008-07-07:
==========================
o [Printer] support of "%w" and "%V" in parsers of date from string
* [Printer] bug fixed with "%j"
version 2.0.3, 2008-05-22:
==========================
* [Compilation] module Period was not properly linked
version 2.0.2, 2008-03-17:
==========================
* [Compilation] Windows build problems fixed (patch of David Allsopp)
version 2.0.1, 2008-02-22:
==========================
* [Printer] bug fixed in printers which displayed "Mars" (instead of "March")
* [Printer] bug fixed in printers when %p cannot be parsed
(error message was bad) (patch of Yaron Minski)
* [Compilation] bug fixed in "make install" (patch of Sean Seefried)
version 2.0, 2008-02-08:
========================
o! [License] license changes from LGPLv2 to LGPLv2.1
(from a suggestion of Hezekiah M. Carty)
o! [Compilation] use -pack: all modules of the library are packed inside a
single module CalendarLib (calendar now requires ocaml >= 3.09.1)
o new modules Time_sig, Date_sig and Calendar_sig
o new module Ftime (time implementation in which seconds are floats)
(Hezekiah M. Carty's suggestion)
o new module Calendar_builder (generic calendar implementation)
o new module Fcalendar (calendar implementation using Ftime)
o new module Calendar.Precise (calendar with a best precision)
o hash functions are provided
o [Printer] new modules Printer.Ftime and Printer.Fcalendar
o [Printer] modules Printer.Date, Printer.Time and Printer.Calendar
respectively replace Printer.DatePrinter, Printer.TimePrinter and
Printer.CalendarPrinter. These last modules still exist but are deprecated.
o [Time_Zone] new function Time_Zone.on
o [Date] new function Date.from_day_of_year (Hezekiah M. Carty's suggestion)
o [Date] new function Date.is_valid_date (Richard Jones' suggestion)
o new module Utils
o new module Version (information about version of calendar)
o [Documentation] add tags @example, @raise and @see in the API documentation
version 1.10, 2007-05-14:
=========================
o [Printer] "from_fstring" in printers recognizes more formats.
(Sean Seefried's suggestion)
o [Printer] add Printer.set_word_regexp
version 1.09.6, 2006-07-07:
===========================
* [Date] bug fixed in Date.to_business
(on some dates in the last days of january)
version 1.09.5, 2006-05-26:
===========================
* [Date] bug fixed in Date.nth_weekday_of_month
version 1.09.4, 2006-02-13:
===========================
o [Time_Zone] add Time_Zone.is_dst and Time_Zone.hour_of_dst
(Daniel Peng's suggestion)
* [Printer] bug fixed in printers with %I, %l, %p and %r
(patch of Jerry Charumilind)
* [Time_Zone] bug fixed when checking bounds in Time_Zone (patch of Daniel Peng)
version 1.09.3, 2005-01-17:
===========================
* [Date] bug fixed in Date.to_business
version 1.09.2, 2004-12-15:
===========================
* [Date] bug fixed in Date.from_unixfloat and Date.from_unixtm with
time zones <> UTC
version 1.09.1, 2004-11-17:
===========================
o [Documentation] add tag @since in the API documentation
* [Calendar] bug fixed in Calendar.to/from_unixfloat with time zones <> UTC
* [Compilation] META file is now writable
version 1.09.0, 2004-11-13:
===========================
o [Date] add Date.to_business and Date.from_business (Richard Jone's suggestion)
o [Date] add the optional parameter ?month to Date.days_in_year
(Richard Jones' suggestion)
o [Date] add Date.nth_weekday_of_month (Richard Jones' suggestion)
o [Date] Date: add some Christian dates (Richard Jones' suggestion)
o [Date] add Date.Period.ymd and Calendar.Period.ymds
o [Printer] add the format string %i corresponding to the ISO-8601 notation
o add "equal" in all the modules
*! [Printer] ISO-8601 notation is now the default format
* [Calendar.Period] bug fixed with negative period
* [Calendar] bug fixed in Calendar.to/from_unixfloat and Date.to/from_unixfloat
* [Date] bug fixed in Date.weeks_in_year
version 1.08, 2004-05-18:
=========================
o [Date] add "week_first_last" computing the first and last days of a week in a
year
version 1.07, 2004-03-22:
=========================
o [Documentation] documentation of the API with ocamldoc
* [Compilation] compile even if no ocaml native compiler is available
(from a patch of Stefano Zacchiroli)
version 1.06, 2003-12-05:
=========================
o [Compilation] improved "make install"
* [Compilation] compile with an optimized compiler (ocamlopt.opt or ocamlc.opt)
if possible
version 1.05, 2003-09-18:
=========================
o add module Printer (from a suggestion of Stefano Zacchiroli)
o! remove to_string and from_string from Date, Time and Calendar
(replaced by functions of Printer)
o Str library is no longer necessary
o add labelled version of make in Date, Time and Calendar
version 1.04, 2003-08-31:
=========================
o [Period] add getters in Time.Period, Date.Period and Calendar.Period
(from a suggestion of Christoph Bauer)
version 1.03, 2003-08-25:
=========================
o [Calendar] add "to_time" in Calendar (Julien Forest's suggestion)
version 1.02, 2003-08-18:
=========================
* [Compilation] bug fixed in configure.in (calendar now works with
caml version > 3.06)
version 1.01, 2003-07-16:
=========================
o add to_unixtm, from_unixtm, to_unixfloat and from_unixfloat in
Date and Calendar
*! change "minut" by "minute"
*! change "egal" by "equal"
*! change "GMT" by "UTC"
(Thank's to Eric C. Cooper for those suggestions)
version 1.0, 2003-07-11:
========================
o first release
calendar-3.0.0/CONFIGURE_HEADER 0000664 0000000 0000000 00000001241 14321307032 0015530 0 ustar 00root root 0000000 0000000
autoconf input for Objective Caml programs
Copyright (C) 2001 Jean-Christophe Filliātre
from a first script by Georges Mariano
Script modified by Julien Signoles for the Calendar library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Library General Public License version 2 for more
details (see ).
calendar-3.0.0/COPYING 0000664 0000000 0000000 00000001165 14321307032 0014314 0 ustar 00root root 0000000 0000000 Calendar library
Copyright (C) 2003-2009 Julien Signoles
you can redistribute it and/or modify it under the terms of the GNU
Lesser General Public License version 2.1 as published by the
Free Software Foundation, with a special linking exception (usual
for Objective Caml libraries).
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR
See the GNU Lesser General Public Licence version 2.1 for more
details (enclosed in the file LGPL).
The special linking exception is detailled in the enclosed file
LICENSE.
calendar-3.0.0/HEADER 0000664 0000000 0000000 00000001176 14321307032 0014136 0 ustar 00root root 0000000 0000000
This file is part of Calendar.
Copyright (C) 2003-2011 Julien Signoles
you can redistribute it and/or modify it under the terms of the GNU
Lesser General Public License version 2.1 as published by the
Free Software Foundation, with a special linking exception (usual
for Objective Caml libraries).
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR
See the GNU Lesser General Public Licence version 2.1 for more
details (enclosed in the file LGPL).
The special linking exception is detailled in the enclosed file
LICENSE.
calendar-3.0.0/LGPL 0000664 0000000 0000000 00000063502 14321307032 0013745 0 ustar 00root root 0000000 0000000 GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
Copyright (C)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
calendar-3.0.0/LICENSE 0000664 0000000 0000000 00000065512 14321307032 0014274 0 ustar 00root root 0000000 0000000
===============================================================================
OCAML SPECIAL EXCEPTION
As a special exception to the GNU Library General Public License, you may link,
statically or dynamically, a "work that uses the Library" with a publicly
distributed version of the Library to produce an executable file containing
portions of the Library, and distribute that executable file under terms of
your choice, without any of the additional requirements listed in clause 6 of
the GNU Library General Public License. By "a publicly distributed version of
the Library", we mean either the unmodified Library as distributed by the
original author, or a modified version of the Library that is distributed under
the conditions defined in clause 3 of the GNU Library General Public License.
This exception does not however invalidate any other reasons why the executable
file might be covered by the GNU Library General Public License.
===============================================================================
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
Copyright (C)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
calendar-3.0.0/Makefile 0000664 0000000 0000000 00000000242 14321307032 0014714 0 ustar 00root root 0000000 0000000
all: build test
build:
@dune build @install
clean:
@dune clean
test:
@dune runtest --no-buffer --force
doc:
@dune build @doc
.PHONY: all clean test doc
calendar-3.0.0/README.md 0000664 0000000 0000000 00000004371 14321307032 0014542 0 ustar 00root root 0000000 0000000 # Calendar
A calendar library for OCaml. [API documentation](https://ocaml-community.github.io/calendar/calendar/CalendarLib/index.html)
[](https://travis-ci.org/ocaml-community/calendar)
1. [Introduction](#1--introduction)
2. [Contents](#2--contents)
3. [Copyright](#3--copyright)
4. [Installation](#4--installation)
5. [How to use](#5--how-to-use)
6. [Documentation](#6--documentation)
7. [Makefile](#7--makefile)
8. [Contact the developers](#8--contact-the-developers)
## 1- Introduction
The Calendar library provides types and operations over dates and times.
This library requires OCaml 4.03.0 or higher.
Older OCaml versions are unsupported.
## 2- Contents
- `CHANGES` Information about the last changes
- `COPYING` Information about copyright
- `LGPL` Information about LGPL
- `README.md` This file
- `calendar_faq.txt` FAQ frow which some algorithms come
- `doc` HTML documentation of the API
- `src` Source files directory
- `_build/default/` Directory containing the built library
- `tests` Test files directory
- `utils` Some utilities
## 3- Copyright
This program is distributed under the GNU LGPL 2.1.
See the enclosed file COPYING for more details.
## 4- Installation
Easiest way is `opam install calendar`.
To manually install the library, you first need to install `dune` and `re`.
Then:
```
$ dune build @install
$ dune install
```
You can remove files installed with :
`dune uninstall`
## 5- How to use
Use the `calendar` library using ocamlfind. In dune, it means having
an entry `(libraries calendar)`.
## 6- Documentation
The doc directory contains an html documentation of the .mli files.
This documentation is available online at http://calendar.forge.ocamlcore.org/doc/
## 7- Makefile
A description of some Makefile entries follows :
- `make test` will execute some tests. You'll need [alcotest](https://github.com/mirage/alcotest).
To run only some tests: `dune exec ./tests/test.exe test time` (for example)
- `make doc` to produce the documentation of the API. You need [odoc](https://github.com/ocaml/odoc)
## 8- Contact the developers
You can report bugs at https://github.com/ocaml-community/calendar/issues
calendar-3.0.0/TODO 0000664 0000000 0000000 00000000102 14321307032 0013737 0 ustar 00root root 0000000 0000000
Not used anymore.
See http://forge.ocamlcore.org/pm/?group_id=83
calendar-3.0.0/calendar.opam 0000664 0000000 0000000 00000001526 14321307032 0015711 0 ustar 00root root 0000000 0000000 opam-version: "2.0"
version: "3.0.0"
author: "Julien Signoles"
maintainer: "ocaml-community"
license: "LGPL-2.1 with OCaml linking exception"
synopsis: "Library for handling dates and times in your program"
build: [
["dune" "build" "-p" name "-j" jobs]
["dune" "build" "@doc" "-p" name "-j" jobs] {with-doc}
["dune" "runtest" "-p" name "-j" jobs] {with-test}
]
depends: [
"ocaml" {>= "4.03"}
"re" {>= "1.7.2"}
"dune" {>= "1.0"}
"odoc" {with-doc}
"alcotest" {with-test}
]
tags: [ "calendar" "date" "time" "datetime" ]
homepage: "https://github.com/ocaml-community/calendar"
doc: "https://ocaml-community.github.io/calendar/"
bug-reports: "https://github.com/ocaml-community/calendar/issues"
dev-repo: "git+https://github.com/ocaml-community/calendar"
description:"""
Calendar is a library for handling dates and times in your program.
"""
calendar-3.0.0/calendarFAQ-2.6.txt 0000664 0000000 0000000 00000341103 14321307032 0016425 0 ustar 00root root 0000000 0000000 URL: http://www.tondering.dk/claus/calendar.html
FREQUENTLY ASKED QUESTIONS ABOUT
CALENDARS
Version 2.6 - 24 June 2003
Copyright and disclaimer
------------------------
This document is Copyright (C) 2003 by Claus Tondering.
E-mail: claus@tondering.dk.
The document may be freely distributed, provided this
copyright notice is included and no money is charged for
the document.
This document is provided "as is". No warranties are made as
to its correctness.
Introduction
------------
This is the calendar FAQ. Its purpose is to give an overview
of the Christian, Hebrew, Persian, and Islamic calendars in
common use. It will provide a historical background for the
Christian calendar, plus an overview of the French
Revolutionary calendar, the Maya calendar, and the Chinese
calendar.
Comments are very welcome. My e-mail address is given above.
I would like to thank
- Dr Monzur Ahmed of the University of Birmingham, UK,
- Michael J Appel,
- Jay Ball,
- Tom Box,
- Chris Carrier,
- Simon Cassidy,
- Claus Dobesch,
- Leofranc Holford-Strevens,
- David B. Kelley of the Hamamatsu University School of
Medicine in Japan,
- H. Koenig,
- Graham Lewis,
- Duncan MacGregor,
- Marcos Montes,
- James E. Morrison,
- Waleed A. Muhanna of the Fisher College of Business,
Columbus, Ohio, USA,
- Stefan Potthast,
- Yves Sagnier of the Centre d'Etudes de la Navigation
Aerienne,
- Paul Schlyter of the Swedish Amateur Astronomer's Society,
- Dr John Stockton
for their help with this document.
Changes in version 2.6
----------------------
The names for the six additional days of the French
revolutionary calendar have been corrected.
A few minor corrections have been made.
Changes in version 2.5
----------------------
A new section 2.12.4 has been added and the following sections
renumbered.
The description of the calculation of the Epact in section
2.12.5 has been rewritten.
Chapter 5 about the Persian calendar has been added and the
following chapters renumbered.
Section 10.5 now mentions a couple of calendar books.
A few minor corrections have been made.
Writing dates and years
-----------------------
Dates will be written in the British format (1 January)
rather than the American format (January 1). Dates will
occasionally be abbreviated: "1 Jan" rather than "1 January".
Years before and after the "official" birth year of Christ
will be written "45 BC" or "AD 1997", respectively. I prefer
this notation over the secular "45 BCE" and "1997 CE"
(See also section 2.13.4.)
The 'mod' operator
------------------
Throughout this document the operator 'mod' will be used to
signify the modulo or remainder operator. For example,
17 mod 7=3 because the result of the division 17/7 is 2 with a
remainder of 3.
The text in square brackets
---------------------------
Square brackets [like this] identify information that I am
unsure about and about which I would like more
information. Please write me at claus@tondering.dk.
Index:
------
1. What Astronomical Events Form the Basis of Calendars?
1.1. What are equinoxes and solstices?
2. The Christian Calendar
2.1. What is the Julian calendar?
2.1.1. What years are leap years?
2.1.2. What consequences did the use of the Julian
calendar have?
2.2. What is the Gregorian calendar?
2.2.1. What years are leap years?
2.2.2. Isn't there a 4000-year rule?
2.2.3. Don't the Greek do it differently?
2.2.4. When did country X change from the Julian to
the Gregorian calendar?
2.3. What day is the leap day?
2.4. What is the Solar Cycle?
2.5. What day of the week was 2 August 1953?
2.6. When can I reuse my 1992 calendar?
2.7. What is the Roman calendar?
2.7.1. How did the Romans number days?
2.8. What is the proleptic calendar?
2.9. Has the year always started on 1 January?
2.10. Then what about leap years?
2.11. What is the origin of the names of the months?
2.12. What is Easter?
2.12.1. When is Easter? (Short answer)
2.12.2. When is Easter? (Long answer)
2.12.3. What is the Golden Number?
2.12.4. How does one calculate Easter then?
2.12.5. What is the Epact?
2.12.6. How does one calculate Gregorian Easter then?
2.12.7. Isn't there a simpler way to calculate Easter?
2.12.8. Is there a simple relationship between two
consecutive Easters?
2.12.9. How frequently are the dates for Easter repeated?
2.12.10. What about Greek Orthodox Easter?
2.12.11. Did the Easter dates change in 2001?
2.13. How does one count years?
2.13.1. How did Dionysius date Christ's birth?
2.13.2. Was Jesus born in the year 0?
2.13.3. When does the 3rd millennium start?
2.13.4. What do AD, BC, CE, and BCE stand for?
2.14. What is the Indiction?
2.15. What is the Julian period?
2.15.1. Is there a formula for calculating the Julian
day number?
2.15.2. What is the modified Julian day number?
2.15.3. What is the Lilian day number?
2.16. What is the correct way to write dates?
3. The Hebrew Calendar
3.1. What does a Hebrew year look like?
3.2. What years are leap years?
3.3. What years are deficient, regular, and complete?
3.4. When is New Year's day?
3.5. When does a Hebrew day begin?
3.6. When does a Hebrew year begin?
3.7. When is the new moon?
3.8. How does one count years?
4. The Islamic Calendar
4.1. What does an Islamic year look like?
4.2. So you can't print an Islamic calendar in advance?
4.3. How does one count years?
4.4. When will the Islamic calendar overtake the Gregorian
calendar?
4.5. Doesn't Saudi Arabia have special rules?
5. The Persian Calendar
5.1. What does a Persian year look like?
5.2. When does the Persian year begin?
5.3. How does one count years?
5.4. What years are leap years?
6. The Week
6.1. What is the origin of the 7-day week?
6.2. What do the names of the days of the week mean?
6.3. What is the system behind the planetary day names?
6.4. Has the 7-day week cycle ever been interrupted?
6.5. Which day is the day of rest?
6.6. What is the first day of the week?
6.7. What is the week number?
6.8. How can I calculate the week number?
6.9. Do weeks of different lengths exist?
7. The French Revolutionary Calendar
7.1. What does a Republican year look like?
7.2. How does one count years?
7.3. What years are leap years?
7.4. How does one convert a Republican date to a Gregorian one?
8. The Maya Calendar
8.1. What is the Long Count?
8.1.1. When did the Long Count start?
8.2. What is the Tzolkin?
8.2.1. When did the Tzolkin start?
8.3. What is the Haab?
8.3.1. When did the Haab start?
8.4. Did the Mayas think a year was 365 days?
9. The Chinese Calendar
9.1. What does the Chinese year look like?
9.2. What years are leap years?
9.3. How does one count years?
9.4. What is the current year in the Chinese calendar?
10. Frequently Asked Questions about this FAQ
10.1. Why doesn't the FAQ describe calendar X?
10.2. Why doesn't the FAQ contain information X?
10.3. Why don't you reply to my e-mail?
10.4. How do I know that I can trust your information?
10.5. Can you recommend any good books about calendars?
10.6. Do you know a web site where I can find information
about X?
11. Date
1. What Astronomical Events Form the Basis of Calendars?
--------------------------------------------------------
Calendars are normally based on astronomical events, and the two most
important astronomical objects are the sun and the moon. Their cycles
are very important in the construction and understanding of calendars.
Our concept of a year is based on the earth's motion around the sun.
The time from one fixed point, such as a solstice or equinox, to the
next is called a "tropical year". Its length is currently 365.242190
days, but it varies. Around 1900 its length was 365.242196 days, and
around 2100 it will be 365.242184 days. (This definition of the
tropical year is not quite accurate, see section 1.1 for more
details.)
Our concept of a month is based on the moon's motion around the earth,
although this connection has been broken in the calendar commonly used
now. The time from one new moon to the next is called a "synodic
month", and its length is currently 29.5305889 days, but it
varies. Around 1900 its length was 29.5305886 days, and around 2100 it
will be 29.5305891 days.
Note that these numbers are averages. The actual length of a
particular year may vary by several minutes due to the influence of
the gravitational force from other planets. Similarly, the time
between two new moons may vary by several hours due to a number of
factors, including changes in the gravitational force from the sun,
and the moon's orbital inclination.
It is unfortunate that the length of the tropical year is not a
multiple of the length of the synodic month. This means that with 12
months per year, the relationship between our month and the moon
cannot be maintained.
However, 19 tropical years is 234.997 synodic months, which is very
close to an integer. So every 19 years the phases of the moon fall on
the same dates (if it were not for the skewness introduced by leap
years). 19 years is called a Metonic cycle (after Meton, an astronomer
from Athens in the 5th century BC).
So, to summarise: There are three important numbers to note:
A tropical year is 365.24219 days.
A synodic month is 29.53059 days.
19 tropical years is close to an integral number of synodic months.
The Christian calendar is based on the motion of the earth around the
sun, while the months retain no connection with the motion of the moon.
On the other hand, the Islamic calendar is based on the motion of the
moon, while the year has no connection with the motion of the earth
around the sun.
Finally, the Hebrew calendar combines both, in that its years are
linked to the motion of the earth around the sun, and its months are
linked to the motion of the moon.
1.1. What are equinoxes and solstices?
--------------------------------------
Equinoxes and solstices are frequently used as anchor points for
calendars. For people in the northern hemisphere:
- Winter solstice is the time in December when the sun reaches its
southernmost latitude. At this time we have the shortest day. The
date is near 21 December.
- Summer solstice is the time in June when the sun reaches its
northernmost latitude. At this time we have the longest day. The
date is near 21 June.
- Vernal equinox is the time in March when the sun passes the equator
moving from the southern to the northern hemisphere. Day and night
have approximately the same length. The date is near 20 March.
- Autumnal equinox is the time in September when the sun passes the
equator moving from the northern to the southern hemisphere. Day and
night have approximately the same length. The date is near
22 September.
For people in the southern hemisphere these events are shifted half a
year.
The astronomical "tropical year" is frequently defined as the time
between, say, two vernal equinoxes, but this is not actually true.
Currently the time between two vernal equinoxes is slightly greater
than the tropical year. The reason is that the earth's position in its
orbit at the time of solstices and equinoxes shifts slightly each year
(taking approximately 21,000 years to move all the way around the
orbit). This, combined with the fact that the earth's orbit is not
completely circular, causes the equinoxes and solstices to shift with
respect to each other.
The astronomer's mean tropical year is really a somewhat artificial
average of the period between the time when the sun is in any given
position in the sky with respect to the equinoxes and the next time
the sun is in the same position.
2. The Christian Calendar
-------------------------
The "Christian calendar" is the term traditionally used to designate
the calendar commonly in use, although its connection with
Christianity is highly debatable.
The Christian calendar has years of 365 or 366 days. It is divided into
12 months that have no relationship to the motion of the moon. In
parallel with this system, the concept of "weeks" groups the days in
sets of 7.
Two main versions of the Christian calendar have existed in recent
times: The Julian calendar and the Gregorian calendar. The difference
between them lies in the way they approximate the length of the
tropical year and their rules for calculating Easter.
2.1. What is the Julian calendar?
---------------------------------
The Julian calendar was introduced by Julius Caesar in 45 BC. It was
in common use until the 1500s, when countries started changing to the
Gregorian calendar (section 2.2). However, some countries (for
example, Greece and Russia) used it into the 1900s, and the Orthodox
church in Russia still uses it, as do some other Orthodox churches.
In the Julian calendar, the tropical year is approximated as 365 1/4
days = 365.25 days. This gives an error of 1 day in approximately 128
years.
The approximation 365 1/4 is achieved by having 1 leap year every 4
years.
2.1.1. What years are leap years?
---------------------------------
The Julian calendar has 1 leap year every 4 years:
Every year divisible by 4 is a leap year.
However, the 4-year rule was not followed in the first years after the
introduction of the Julian calendar in 45 BC. Due to a counting error,
every 3rd year was a leap year in the first years of this calendar's
existence. The leap years were:
45 BC(?), 42 BC, 39 BC, 36 BC, 33 BC, 30 BC,
27 BC, 24 BC, 21 BC, 18 BC, 15 BC, 12 BC, 9 BC,
AD 8, AD 12, and every 4th year from then on.
Authorities disagree about whether 45 BC was a leap year or not.
There were no leap years between 9 BC and AD 8 (or, according to some
authorities, between 12 BC and AD 4). This period without leap years
was decreed by emperor Augustus in order to make up for the surplus of
leap years introduced previously, and it earned him a place in the
calendar as the 8th month was named after him.
It is a curious fact that although the method of reckoning years after
the (official) birthyear of Christ was not introduced until the 6th
century, by some stroke of luck the Julian leap years coincide with
years of our Lord that are divisible by 4.
2.1.2. What consequences did the use of the Julian calendar have?
-----------------------------------------------------------------
The Julian calendar introduces an error of 1 day every 128 years. So
every 128 years the tropical year shifts one day backwards with
respect to the calendar. Furthermore, the method for calculating the
dates for Easter was inaccurate and needed to be refined.
In order to remedy this, two steps were necessary: 1) The Julian
calendar had to be replaced by something more adequate. 2) The extra
days that the Julian calendar had inserted had to be dropped.
The solution to problem 1) was the Gregorian calendar described in
section 2.2.
The solution to problem 2) depended on the fact that it was felt that
21 March was the proper day for vernal equinox (because 21 March was
the date for vernal equinox during the Council of Nicaea in AD
325). The Gregorian calendar was therefore calibrated to make that day
vernal equinox.
By 1582 vernal equinox had moved (1582-325)/128 days = approximately
10 days backwards. So 10 days had to be dropped.
2.2. What is the Gregorian calendar?
------------------------------------
The Gregorian calendar is the one commonly used today. It was proposed
by Aloysius Lilius, a physician from Naples, and adopted by Pope
Gregory XIII in accordance with instructions from the Council of Trent
(1545-1563) to correct for errors in the older Julian Calendar. It was
decreed by Pope Gregory XIII in a papal bull on 24 February 1582. This
bull is named "Inter Gravissimas" after its first two words.
In the Gregorian calendar, the tropical year is approximated as
365 97/400 days = 365.2425 days. Thus it takes approximately 3300
years for the tropical year to shift one day with respect to the
Gregorian calendar.
The approximation 365 97/400 is achieved by having 97 leap years
every 400 years.
2.2.1. What years are leap years?
---------------------------------
The Gregorian calendar has 97 leap years every 400 years:
Every year divisible by 4 is a leap year.
However, every year divisible by 100 is not a leap year.
However, every year divisible by 400 is a leap year after all.
So, 1700, 1800, 1900, 2100, and 2200 are not leap years. But 1600,
2000, and 2400 are leap years.
(Destruction of a myth: There are no double leap years, i.e. no
years with 367 days. See, however, the note on Sweden in section
2.2.4.)
2.2.2. Isn't there a 4000-year rule?
------------------------------------
It has been suggested (by the astronomer John Herschel (1792-1871)
among others) that a better approximation to the length of the
tropical year would be 365 969/4000 days = 365.24225 days. This would
dictate 969 leap years every 4000 years, rather than the 970 leap
years mandated by the Gregorian calendar. This could be achieved by
dropping one leap year from the Gregorian calendar every 4000 years,
which would make years divisible by 4000 non-leap years.
This rule has, however, not been officially adopted.
2.2.3. Don't the Greek do it differently?
-----------------------------------------
When the Orthodox church in Greece finally decided to switch to the
Gregorian calendar in the 1920s, they tried to improve on the
Gregorian leap year rules, replacing the "divisible by 400" rule by
the following:
Every year which when divided by 900 leaves a remainder of 200
or 600 is a leap year.
This makes 1900, 2100, 2200, 2300, 2500, 2600, 2700, 2800 non-leap
years, whereas 2000, 2400, and 2900 are leap years. This will not
create a conflict with the rest of the world until the year 2800.
This rule gives 218 leap years every 900 years, which gives us an
average year of 365 218/900 days = 365.24222 days, which is certainly
more accurate than the official Gregorian number of 365.2425 days.
However, this rule is *not* official in Greece.
2.2.4. When did country X change from the Julian to the Gregorian calendar?
---------------------------------------------------------------------------
The papal bull of February 1582 decreed that 10 days should be dropped
from October 1582 so that 15 October should follow immediately after
4 October, and from then on the reformed calendar should be used.
This was observed in Italy, Poland, Portugal, and Spain. Other Catholic
countries followed shortly after, but Protestant countries were
reluctant to change, and the Greek orthodox countries didn't change
until the start of the 1900s.
Changes in the 1500s required 10 days to be dropped.
Changes in the 1600s required 10 days to be dropped.
Changes in the 1700s required 11 days to be dropped.
Changes in the 1800s required 12 days to be dropped.
Changes in the 1900s required 13 days to be dropped.
(Exercise for the reader: Why is the error in the 1600s the same as
in the 1500s.)
The following list contains the dates for changes in a number of
countries. It is very strange that in many cases there seems to be
some doubt among authorities about what the correct days are.
Different sources give very different dates in some cases. The list
below does not include all the different opinions about when the
change took place.
Albania: December 1912
Austria: Different regions on different dates
Brixen, Salzburg and Tyrol:
5 Oct 1583 was followed by 16 Oct 1583
Carinthia and Styria:
14 Dec 1583 was followed by 25 Dec 1583
See also Czechoslovakia and Hungary
Belgium: See the Netherlands
Bulgaria: 31 Mar 1916 was followed by 14 Apr 1916
Canada: Different areas changed at different times.
Newfoundland and Hudson Bay coast:
2 Sep 1752 was followed by 14 Sep 1752
Mainland Nova Scotia:
Gregorian 1605 - 13 Oct 1710
Julian 2 Oct 1710 - 2 Sep 1752
Gregorian since 14 Sep 1752
Rest of Canada:
Gregorian from first European settlement
China: The Gregorian calendar replaced the Chinese calendar
in 1912, but the Gregorian calendar was not used
throughout the country until the communist revolution
of 1949.
Czechoslovakia (i.e. Bohemia and Moravia):
6 Jan 1584 was followed by 17 Jan 1584
Denmark (including Norway):
18 Feb 1700 was followed by 1 Mar 1700
Egypt: 1875
Estonia: 31 Jan 1918 was followed by 14 Feb 1918
Finland: Then part of Sweden. (Note, however, that Finland later
became part of Russia, which then still used the
Julian calendar. The Gregorian calendar remained
official in Finland, but some use of the Julian
calendar was made.)
France: 9 Dec 1582 was followed by 20 Dec 1582
Alsace: 5 Feb 1682 was followed by 16 Feb 1682
Lorraine: 16 Feb 1760 was followed by 28 Feb 1760
Strasbourg: February 1682
Germany: Different states on different dates:
Catholic states on various dates in 1583-1585
Prussia: 22 Aug 1610 was followed by 2 Sep 1610
Protestant states: 18 Feb 1700 was followed by 1 Mar 1700
(Many local variations)
Great Britain and Dominions:
2 Sep 1752 was followed by 14 Sep 1752
Greece: [9 Mar 1924 was followed by 23 Mar 1924
(Some sources say 1916 and 1920)]
Hungary: 21 Oct 1587 was followed by 1 Nov 1587
Ireland: See Great Britain
Italy: 4 Oct 1582 was followed by 15 Oct 1582
Japan: The Gregorian calendar was introduced to supplement the
traditional Japanese calendar on 1 Jan 1873.
Latvia: During German occupation 1915 to 1918
Lithuania: 1915
Luxemburg: 14 Dec 1582 was followed by 25 Dec 1582
Netherlands (including Belgium):
Zeeland, Brabrant, and the "Staten Generaal":
14 Dec 1582 was followed by 25 Dec 1582
Holland:
1 Jan 1583 was followed by 12 Jan 1583
Limburg and the southern provinces (currently Belgium):
20 Dec 1582 was followed by 31 Dec 1582
or
21 Dec 1582 was followed by 1 Jan 1583
Groningen:
10 Feb 1583 was followed by 21 Feb 1583
Went back to Julian in the summer of 1594
31 Dec 1700 was followed by 12 Jan 1701
Gelderland:
30 Jun 1700 was followed by 12 Jul 1700
Utrecht and Overijssel:
30 Nov 1700 was followed by 12 Dec 1700
Friesland:
31 Dec 1700 was followed by 12 Jan 1701
Drenthe:
30 Apr 1701 was followed by 12 May 1701
Norway: Then part of Denmark.
Poland: 4 Oct 1582 was followed by 15 Oct 1582
Portugal: 4 Oct 1582 was followed by 15 Oct 1582
Romania: 31 Mar 1919 was followed by 14 Apr 1919
[The Greek Orthodox parts of the country may have
changed later.]
Russia: 31 Jan 1918 was followed by 14 Feb 1918
[In the eastern parts of the country the change may
not have occurred until 1920.]
Scotland: Much confusion exists regarding Scotland's change. Different
authorities disagree about whether Scotland changed together
with the rest of Great Britain, or if they had changed
earlier.
Spain: 4 Oct 1582 was followed by 15 Oct 1582
Sweden (including Finland):
17 Feb 1753 was followed by 1 Mar 1753 (see note below)
Switzerland:
Catholic cantons: 1583, 1584 or 1597
Protestant cantons:
31 Dec 1700 was followed by 12 Jan 1701
(Many local variations)
Turkey: Gregorian calendar introduced 1 Jan 1927
United States: Different areas changed at different times.
Along the Eastern seaboard: With Great Britain in 1752.
Mississippi valley: With France in 1582.
Texas, Florida, California, Nevada, Arizona, New Mexico:
With Spain in 1582
Washington, Oregon: With Britain in 1752.
Alaska: October 1867 when Alaska became part of the USA.
Wales: See Great Britain
Yugoslavia: 1919
Sweden has a curious history. Sweden decided to make a gradual change
from the Julian to the Gregorian calendar. By dropping every leap year
from 1700 through 1740 the eleven superfluous days would be omitted
and from 1 Mar 1740 they would be in sync with the Gregorian
calendar. (But in the meantime they would be in sync with nobody!)
So 1700 (which should have been a leap year in the Julian calendar)
was not a leap year in Sweden. However, by mistake 1704 and 1708
became leap years. This left Sweden out of synchronisation with both
the Julian and the Gregorian world, so they decided to go *back* to
the Julian calendar. In order to do this, they inserted an extra day
in 1712, making that year a double leap year! So in 1712, February had
30 days in Sweden.
Later, in 1753, Sweden changed to the Gregorian calendar by dropping 11
days like everyone else.
2.3. What day is the leap day?
------------------------------
It is 24 February!
Weird? Yes! The explanation is related to the Roman calendar and is
found in section 2.7.1.
From a numerical point of view, of course 29 February is the extra
day. But from the point of view of celebration of feast days, the
following correspondence between days in leap years and non-leap
years has traditionally been used:
Non-leap year Leap year
------------- ----------
22 February 22 February
23 February 23 February
24 February (extra day)
24 February 25 February
25 February 26 February
26 February 27 February
27 February 28 February
28 February 29 February
For example, the feast of St. Leander has been celebrated on 27
February in non-leap years and on 28 February in leap years.
Many countries are gradually changing the leap day from the 24th to
the 29th. This affects countries such as Sweden and Austria that
celebrate "name days" (i.e. each day is associated with a name).
2.4. What is the Solar Cycle?
-----------------------------
In the Julian calendar the relationship between the days of the week
and the dates of the year is repeated in cycles of 28 years. In the
Gregorian calendar this is still true for periods that do not cross
years that are divisible by 100 but not by 400.
A period of 28 years is called a Solar Cycle. The "Solar Number" of a
year is found as:
Solar Number = (year + 8) mod 28 + 1
In the Julian calendar there is a one-to-one relationship between the
Solar Number and the day on which a particular date falls.
(The leap year cycle of the Gregorian calendar is 400 years, which is
146,097 days, which curiously enough is a multiple of 7. So in the
Gregorian calendar the equivalent of the "Solar Cycle" would be 400
years, not 7*400=2800 years as one might be tempted to believe.)
2.5. What day of the week was 2 August 1953?
--------------------------------------------
To calculate the day on which a particular date falls, the following
algorithm may be used (the divisions are integer divisions, in which
remainders are discarded):
a = (14 - month) / 12
y = year - a
m = month + 12*a - 2
For Julian calendar: d = (5 + day + y + y/4 + (31*m)/12) mod 7
For Gregorian calendar: d = (day + y + y/4 - y/100 + y/400 + (31*m)/12) mod 7
The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc.
Example: On what day of the week was the author born?
My birthday is 2 August 1953 (Gregorian, of course).
a = (14 - 8) / 12 = 0
y = 1953 - 0 = 1953
m = 8 + 12*0 - 2 = 6
d = (2 + 1953 + 1953/4 - 1953/100 + 1953/400 + (31*6)/12) mod 7
= (2 + 1953 + 488 - 19 + 4 + 15 ) mod 7
= 2443 mod 7
= 0
I was born on a Sunday.
2.6. When can I reuse my 1992 calendar?
---------------------------------------
Let us first assume that you are only interested in which dates fall
on which days of the week; you are not interested in the dates for
Easter and other irregular holidays.
Let us further confine ourselves to the years 1901-2099.
With these restrictions, the answer is as follows:
- If year X is a leap year, you can reuse its calendar in year X+28.
- If year X is the first year after a leap year, you can reuse its
calendar in years X+6, X+17, and X+28.
- If year X is the second year after a leap year, you can reuse its
calendar in years X+11, X+17, and X+28.
- If year X is the third year after a leap year, you can reuse its
calendar in years X+11, X+22, and X+28.
Note that the expression X+28 occurs in all four items above. So you
can always reuse your calendar every 28 years.
But if you also want your calendar's indication of Easter and other
Christian holidays to be correct, the rules are far too complex to be
put to a simple formula. Sometimes calendars can be reused after just
six years. For example, the calendars for the years 1981 and 1987 are
identical, even when it comes to the date for Easter. But sometimes a
very long time can pass before a calendar can be reused; if you happen
to have a calendar from 1940, you won't be able to reuse it until the
year 5280!
2.7. What is the Roman calendar?
--------------------------------
Before Julius Caesar introduced the Julian calendar in 45 BC, the
Roman calendar was a mess, and much of our so-called "knowledge" about
it seems to be little more than guesswork.
Originally, the year started on 1 March and consisted of only 304 days
or 10 months (Martius, Aprilis, Maius, Junius, Quintilis, Sextilis,
September, October, November, and December). These 304 days were
followed by an unnamed and unnumbered winter period. The Roman king
Numa Pompilius (c. 715-673 BC, although his historicity is disputed)
allegedly introduced February and January (in that order) between
December and March, increasing the length of the year to 354 or 355
days. In 450 BC, February was moved to its current position between
January and March.
In order to make up for the lack of days in a year, an extra month,
Intercalaris or Mercedonius, (allegedly with 22 or 23 days though some
authorities dispute this) was introduced in some years. In an 8 year
period the length of the years were:
1: 12 months or 355 days
2: 13 months or 377 days
3: 12 months or 355 days
4: 13 months or 378 days
5: 12 months or 355 days
6: 13 months or 377 days
7: 12 months or 355 days
8: 13 months or 378 days
A total of 2930 days corresponding to a year of 366 1/4 days. This
year was discovered to be too long, and therefore 7 days were later
dropped from the 8th year, yielding 365.375 days per year.
This is all theory. In practice it was the duty of the priesthood to
keep track of the calendars, but they failed miserably, partly due to
ignorance, partly because they were bribed to make certain years long
and other years short. Furthermore, leap years were considered unlucky
and were therefore avoided in time of crisis, such as the Second Punic
War.
In order to clean up this mess, Julius Caesar made his famous calendar
reform in 45 BC. We can make an educated guess about the length of the
months in the years 47 and 46 BC:
47 BC 46 BC
January 29 29
February 28 24
Intercalaris 27
March 31 31
April 29 29
May 31 31
June 29 29
Quintilis 31 31
Sextilis 29 29
September 29 29
October 31 31
November 29 29
Undecember 33
Duodecember 34
December 29 29
--- ---
Total 355 445
The length of the months from 45 BC onward were the same as the ones
we know today.
Occasionally one reads the following story:
"Julius Caesar made all odd numbered months 31 days long, and
all even numbered months 30 days long (with February having 29
days in non-leap years). In 44 BC Quintilis was renamed
'Julius' (July) in honour of Julius Caesar, and in 8 BC
Sextilis became 'Augustus' in honour of emperor Augustus. When
Augustus had a month named after him, he wanted his month to
be a full 31 days long, so he removed a day from February and
shifted the length of the other months so that August would
have 31 days."
This story, however, has no basis in actual fact. It is a fabrication
possibly dating back to the 14th century.
2.7.1. How did the Romans number days?
--------------------------------------
The Romans didn't number the days sequentially from 1. Instead they
had three fixed points in each month:
"Kalendae" (or "Calendae"), which was the first day of the month.
"Idus", which was the 13th day of January, February, April,
June, August, September, November, and December, or
the 15th day of March, May, July, or October.
"Nonae", which was the 9th day before Idus (counting Idus
itself as the 1st day).
The days between Kalendae and Nonae were called "the 5th day before
Nonae", "the 4th day before Nonae", "the 3rd day before Nonae", and
"the day before Nonae". (There was no "2nd day before Nonae". This was
because of the inclusive way of counting used by the Romans: To them,
Nonae itself was the first day, and thus "the 2nd day before" and "the
day before" would mean the same thing.)
Similarly, the days between Nonae and Idus were called "the Xth day
before Idus", and the days after Idus were called "the Xth day before
Kalendae (of the next month)".
Julius Caesar decreed that in leap years the "6th day before Kalendae
of March" should be doubled. So in contrast to our present system, in
which we introduce an extra date (29 February), the Romans had the
same date twice in leap years. The doubling of the 6th day before
Kalendae of March is the origin of the word "bissextile". If we
create a list of equivalences between the Roman days and our current
days of February in a leap year, we get the following:
7th day before Kalendae of March 23 February
6th day before Kalendae of March 24 February
6th day before Kalendae of March 25 February
5th day before Kalendae of March 26 February
4th day before Kalendae of March 27 February
3rd day before Kalendae of March 28 February
the day before Kalendae of March 29 February
Kalendae of March 1 March
You can see that the extra 6th day (going backwards) falls on what is
today 24 February. For this reason 24 February is still today
considered the "extra day" in leap years (see section 2.3). However,
at certain times in history the second 6th day (25 Feb) has been
considered the leap day.
Why did Caesar choose to double the 6th day before Kalendae of March?
It appears that the leap month Intercalaris/Mercedonius of the
pre-reform calendar was not placed after February, but inside it,
namely between the 7th and 6th day before Kalendae of March. It was
therefore natural to have the leap day in the same position.
2.8. What is the proleptic calendar?
------------------------------------
The Julian calendar was introduced in 45 BC, but when historians date
events prior to that year, they normally extend the Julian calendar
backward in time. This extended calendar is known as the "Julian
Proleptic Calendar".
Similarly, it is possible to extend the Gregorian calendar backward in
time before 1582. However, this "Gregorian Proleptic Calendar" is
rarely used.
If someone refers to, for example, 15 March 429 BC, they are probably
using the Julian proleptic calendar.
In the Julian proleptic calendar, year X BC is a leap year, if X-1 is
divisible by 4. This is the natural extension of the Julian leap year
rules.
2.9. Has the year always started on 1 January?
----------------------------------------------
For the man in the street, yes. When Julius Caesar introduced his
calendar in 45 BC, he made 1 January the start of the year, and it was
always the date on which the Solar Number and the Golden Number (see
section 2.12.3) were incremented.
However, the church didn't like the wild parties that took place at
the start of the new year, and in AD 567 the council of Tours declared
that having the year start on 1 January was an ancient mistake that
should be abolished.
Through the middle ages various New Year dates were used. If an
ancient document refers to year X, it may mean any of 7 different
periods in our present system:
- 1 Mar X to 28/29 Feb X+1
- 1 Jan X to 31 Dec X
- 1 Jan X-1 to 31 Dec X-1
- 25 Mar X-1 to 24 Mar X
- 25 Mar X to 24 Mar X+1
- Saturday before Easter X to Friday before Easter X+1
- 25 Dec X-1 to 24 Dec X
Choosing the right interpretation of a year number is difficult, so
much more as one country might use different systems for religious and
civil needs.
The Byzantine Empire used a year starting on 1 Sep, but they didn't
count years since the birth of Christ, instead they counted years
since the creation of the world which they dated to 1 September 5509 BC.
Since about 1600 most countries have used 1 January as the first day
of the year. Italy and England, however, did not make 1 January official
until around 1750.
In England (but not Scotland) three different years were used:
- The historical year, which started on 1 January.
- The liturgical year, which started on the first Sunday in advent.
- The civil year, which
from the 7th to the 12th century started on 25 December,
from the 12th century until 1751 started on 25 March,
from 1752 started on 1 January.
2.10. Then what about leap years?
---------------------------------
If the year started on, for example, 1 March, two months later than
our present year, when was the leap day inserted?
[The following information is to the best of my knowledge true. If
anyone can confirm or refute it, please let me know.]
When it comes to determining if a year is a leap year, since AD 8 the
Julian calendar has always had 48 months between two leap days. So, in
a country using a year starting on 1 March, 1439 would have been a
leap year, because their February 1439 would correspond to February
1440 in the January-based reckoning.
2.11. What is the origin of the names of the months?
---------------------------------------------------
A lot of languages, including English, use month names based on Latin.
Their meaning is listed below. However, some languages (Czech and
Polish, for example) use quite different names.
January Latin: Januarius. Named after the god Janus.
February Latin: Februarius. Named after Februa, the purification
festival.
March Latin: Martius. Named after the god Mars.
April Latin: Aprilis. Named either after the goddess Aphrodite or
the Latin word "aperire", to open.
May Latin: Maius. Probably named after the goddess Maia.
June Latin: Junius. Probably named after the goddess Juno.
July Latin: Julius. Named after Julius Caesar in 44 BC. Prior
to that time its name was Quintilis from the word
"quintus", fifth, because it was the 5th month in the old
Roman calendar.
August Latin: Augustus. Named after emperor Augustus in 8
BC. Prior to that time the name was Sextilis from the
word "sextus", sixth, because it was the 6th month in the
old Roman calendar.
September Latin: September. From the word "septem", seven, because
it was the 7th month in the old Roman calendar.
October Latin: October. From the word "octo", eight, because it
was the 8th month in the old Roman calendar.
November Latin: November. From the word "novem", nine, because it
was the 9th month in the old Roman calendar.
December Latin: December. From the word "decem", ten, because it
was the 10th month in the old Roman calendar.
2.12. What is Easter?
---------------------
In the Christian world, Easter (and the days immediately preceding it)
is the celebration of the death and resurrection of Jesus in
(approximately) AD 30.
2.12.1. When is Easter? (Short answer)
--------------------------------------
Easter Sunday is the first Sunday after the first full moon after
vernal equinox.
2.12.2. When is Easter? (Long answer)
-------------------------------------
The calculation of Easter is complicated because it is linked to (an
inaccurate version of) the Hebrew calendar.
Jesus was crucified immediately before the Jewish Passover, which is a
celebration of the Exodus from Egypt under Moses. Celebration of
Passover started on the 14th or 15th day of the (spring) month of
Nisan. Jewish months start when the moon is new, therefore the 14th or
15th day of the month must be immediately after a full moon.
It was therefore decided to make Easter Sunday the first Sunday after
the first full moon after vernal equinox. Or more precisely: Easter
Sunday is the first Sunday after the *official* full moon on or after
the *official* vernal equinox.
The official vernal equinox is always 21 March.
The official full moon may differ from the *real* full moon by one or
two days.
(Note, however, that historically, some countries have used the *real*
(astronomical) full moon instead of the official one when calculating
Easter. This was the case, for example, of the German Protestant states,
which used the astronomical full moon in the years 1700-1776. A
similar practice was used Sweden in the years 1740-1844 and in Denmark
in the 1700s.)
The full moon that precedes Easter is called the Paschal full
moon. Two concepts play an important role when calculating the Paschal
full moon: The Golden Number and the Epact. They are described in the
following sections.
The following sections give details about how to calculate the date
for Easter. Note, however, that while the Julian calendar was in use,
it was customary to use tables rather than calculations to determine
Easter. The following sections do mention how to calculate Easter
under the Julian calendar, but the reader should be aware that this is
an attempt to express in formulas what was originally expressed in
tables. The formulas can be taken as a good indication of when Easter
was celebrated in the Western Church from approximately the 6th
century.
2.12.3. What is the Golden Number?
----------------------------------
Each year is associated with a Golden Number.
Considering that the relationship between the moon's phases and the
days of the year repeats itself every 19 years (as described in
section 1), it is natural to associate a number between 1 and 19
with each year. This number is the so-called Golden Number. It is
calculated thus:
GoldenNumber = (year mod 19)+1
In years which have the same Golden Number, the new moon will fall on
(approximately) the same date. The Golden Number is sufficient to
calculate the Paschal full moon in the Julian calendar.
2.12.4. How does one calculate Easter then?
-------------------------------------------
Under the Julian calendar the method was simple. If you know the
Golden Number of the year, you can find the Paschal full moon in this
table:
Golden Golden Golden
Number Full moon Number Full moon Number Full moon
------------------ ------------------ ------------------
1 5 April 8 18 April 15 1 April
2 25 March 9 7 April 16 21 March
3 13 April 10 27 March 17 9 April
4 2 April 11 15 April 18 29 March
5 22 March 12 4 April 19 17 April
6 10 April 13 24 March
7 30 March 14 12 April
Easter Sunday is the first Sunday following the above full moon date.
If the full moon falls on a Sunday, Easter Sunday is the following
Sunday.
But under the Gregorian calendar, things became much more complicated.
One of the changes made in the Gregorian calendar reform was a
modification of the way Easter was calculated. There were two reasons
for this. First, the 19 year cycle of the phases of moon (the Metonic
cycle) was known not to be perfect. Secondly, the Metonic cycle fitted
the Gregorian calendar year worse than it fitted the Julian calendar
year.
It was therefore decided to base Easter calculations on the so-called
Epact.
2.12.5. What is the Epact?
--------------------------
Each year is associated with an Epact.
The Epact is a measure of the age of the moon (i.e. the number of days
that have passed since an "official" new moon) on a particular date.
In the Julian calendar, the Epact is the age of the moon on 22 March.
In the Gregorian calendar, the Epact is the age of the moon at the
start of the year.
The Epact is linked to the Golden Number in the following manner:
Under the Julian calendar, 19 years were assumed to be exactly an
integral number of synodic months, and the following relationship
exists between the Golden Number and the Epact:
Epact = (11 * (GoldenNumber-1)) mod 30
If this formula yields zero, the Epact is by convention frequently
designated by the symbol * and its value is said to be 30. Weird?
Maybe, but people didn't like the number zero in the old days.
Since there are only 19 possible golden numbers, the Epact can have
only 19 different values: 1, 3, 4, 6, 7, 9, 11, 12, 14, 15, 17, 18, 20,
22, 23, 25, 26, 28, and 30.
In the Gregorian calendar reform, some modifications were made to the
simple relationship between the Golden Number and the Epact.
In the Gregorian calendar the Epact should be calculated thus (the
divisions are integer divisions, in which remainders are discarded):
1) Use the Julian formula:
JulianEpact = (11 * (GoldenNumber-1)) mod 30
2) Calculate the so-called "Solar Equation":
S = (3*century)/4
The Solar Equation is an expression of the difference between the
Julian and the Gregorian calendar. The value of S increases by one
in every century year that is not a leap year.
(For the purpose of this calculation century=20 is used for the
years 1900 through 1999, and similarly for other centuries,
although this contradicts the rules in section 2.13.3.)
3) Calculate the so-called "Lunar Equation":
L = (8*century + 5)/25
The Lunar Equation is an expression of the difference between the
Julian calendar and the Metonic cycle. The value of L increases by
one 8 times every 2500 years.
4) Calculate the Gregorian epact thus:
GregorianEpact = JulianEpact - S + L + 8
The number 8 is a constant that calibrates the starting point of
the Gregorian Epact so that it matches the actual age of the moon
on new year's day. Actually, this constant should have been 9, but
8 was probably chosen as a safety precaution; the calculation was
known to be inaccurate, and the sentiment was that it was better to
celebrate Easter too late than too early.
5) Add or subtract 30 until GregorianEpact lies between 1 and 30.
In the Gregorian calendar, the Epact can have any value from 1 to 30.
Example: What was the Epact for 1992?
GoldenNumber = 1992 mod 19 + 1 = 17
1) JulianEpact = (11 * (17-1)) mod 30 = 26
2) S = (3*20)/4 = 15
3) L = (8*20 + 5)/25 = 6
4) GregorianEpact = 26 - 15 + 6 + 8 = 25
5) No adjustment is necessary
The Epact for 1992 was 25.
2.12.6. How does one calculate Gregorian Easter then?
-----------------------------------------------------
Look up the Epact in this table to find the date for the Paschal full
moon:
Epact Full moon Epact Full moon Epact Full moon
----------------- ----------------- -----------------
1 12 April 11 2 April 21 23 March
2 11 April 12 1 April 22 22 March
3 10 April 13 31 March 23 21 March
4 9 April 14 30 March 24 18 April
5 8 April 15 29 March 25 18 or 17 April
6 7 April 16 28 March 26 17 April
7 6 April 17 27 March 27 16 April
8 5 April 18 26 March 28 15 April
9 4 April 19 25 March 29 14 April
10 3 April 20 24 March 30 13 April
Easter Sunday is the first Sunday following the above full moon date.
If the full moon falls on a Sunday, Easter Sunday is the following
Sunday.
An Epact of 25 requires special treatment, as it has two dates in the
above table. There are two equivalent methods for choosing the correct
full moon date:
A) Choose 18 April, unless the current century contains years with an
epact of 24, in which case 17 April should be used.
B) If the Golden Number is > 11 choose 17 April, otherwise choose 18 April.
The proof that these two statements are equivalent is left as an
exercise to the reader. (The frustrated ones may contact me for the
proof.)
Example: When was Easter in 1992?
In the previous section we found that the Golden Number for 1992 was
17 and the Epact was 25. Looking in the table, we find that the
Paschal full moon was either 17 or 18 April. By rule B above, we
choose 17 April because the Golden Number > 11.
17 April 1992 was a Friday. Easter Sunday must therefore have been
19 April.
2.12.7. Isn't there a simpler way to calculate Easter?
------------------------------------------------------
This is an attempt to boil down the information given in the previous
sections (the divisions are integer divisions, in which remainders are
discarded):
G = year mod 19
For the Julian calendar:
I = (19*G + 15) mod 30
J = (year + year/4 + I) mod 7
For the Gregorian calendar:
C = year/100
H = (C - C/4 - (8*C+13)/25 + 19*G + 15) mod 30
I = H - (H/28)*(1 - (29/(H + 1))*((21 - G)/11))
J = (year + year/4 + I + 2 - C + C/4) mod 7
Thereafter, for both calendars:
L = I - J
EasterMonth = 3 + (L + 40)/44
EasterDay = L + 28 - 31*(EasterMonth/4)
This algorithm is based in part on the algorithm of Oudin (1940) as
quoted in "Explanatory Supplement to the Astronomical Almanac",
P. Kenneth Seidelmann, editor.
People who want to dig into the workings of this algorithm, may be
interested to know that
G is the Golden Number-1
H is 23-Epact (modulo 30)
I is the number of days from 21 March to the Paschal full moon
J is the weekday for the Paschal full moon (0=Sunday, 1=Monday,
etc.)
L is the number of days from 21 March to the Sunday on or before
the Paschal full moon (a number between -6 and 28)
2.12.8. Is there a simple relationship between two consecutive Easters?
-----------------------------------------------------------------------
Suppose you know the Easter date of the current year, can you easily
find the Easter date in the next year? No, but you can make a
qualified guess.
If Easter Sunday in the current year falls on day X and the next year
is not a leap year, Easter Sunday of next year will fall on one of the
following days: X-15, X-8, X+13 (rare), or X+20.
If Easter Sunday in the current year falls on day X and the next year
is a leap year, Easter Sunday of next year will fall on one of the
following days: X-16, X-9, X+12 (extremely rare), or X+19. (The jump
X+12 occurs only once in the period 1800-2200, namely when going from
2075 to 2076.)
If you combine this knowledge with the fact that Easter Sunday never
falls before 22 March and never falls after 25 April, you can
narrow the possibilities down to two or three dates.
2.12.9. How frequently are the dates for Easter repeated?
---------------------------------------------------------
The sequence of Easter dates repeats itself every 532 years in the
Julian calendar. The number 532 is the product of the following
numbers:
19 (the Metonic cycle or the cycle of the Golden Number)
28 (the Solar cycle, see section 2.4)
The sequence of Easter dates repeats itself every 5,700,000 years in
the Gregorian calendar. Calculating this is not as simple as for the
Julian calendar, but the number 5,700,000 turns out to be the product
of the following numbers:
19 (the Metonic cycle or the cycle of the Golden Number)
400 (the Gregorian equivalent of the Solar cycle, see section 2.4)
25 (the cycle used in step 3 when calculating the Epact)
30 (the number of different Epact values)
2.12.10. What about Greek Orthodox Easter?
------------------------------------------
The Greek Orthodox Church does not always celebrate Easter on the same
day as the Catholic and Protestant countries. The reason is that the
Orthodox Church uses the Julian calendar when calculating Easter. This
is case even in the churches that otherwise use the Gregorian
calendar.
When the Greek Orthodox Church in 1923 decided to change to the
Gregorian calendar (or rather: a Revised Julian Calendar), they chose
to use the astronomical full moon as the basis for calculating Easter,
rather than the "official" full moon described in the previous
sections. And they chose the meridian of Jerusalem to serve as
definition of when a Sunday starts. However, except for some sporadic
use the 1920s, this system was never adopted in practice.
2.12.11. Did the Easter dates change in 2001?
---------------------------------------------
No.
At a meeting in Aleppo, Syria (5-10 March 1997), organised by the
World Council of Churches and the Middle East Council of Churches,
representatives of several churches and Christian world communions
suggested that the discrepancies between Easter calculations in the
Western and the Eastern churches could be resolved by adopting
astronomically accurate calculations of the vernal equinox and the
full moon, instead of using the algorithm presented in section 2.12.6.
The meridian of Jerusalem should be used for the astronomical
calculations.
The new method for calculating Easter should have taken effect from
the year 2001. In that year the Julian and Gregorian Easter dates
coincided (on 15 April Gregorian/2 April Julian), and it would
therefore be a reasonable starting point for the new system.
However, the Eastern churches (especially the Russian Orthodox Church)
are reluctant to change, having already experienced a schism in the
calendar question. So nothing will happen in the near future.
If the new system were introduced, churches using the Gregorian
calendar will hardly notice the change. Only once during the period
2001-2025 would these churches note a difference: In 2019 the
Gregorian method gives an Easter date of 21 April, but the proposed
new method gives 24 March.
Note that the new method makes an Easter date of 21 March possible.
This date was not possible under the Julian or Gregorian algorithms.
(Under the new method, Easter will fall on 21 March in the year 2877.
You're all invited to my house on that date!)
2.13. How does one count years?
-------------------------------
In about AD 523, the papal chancellor, Bonifatius, asked a monk by the
name of Dionysius Exiguus to devise a way to implement the rules from
the Nicean council (the so-called "Alexandrine Rules") for general
use.
Dionysius Exiguus (in English known as Denis the Little) was a monk
from Scythia, he was a canon in the Roman curia, and his assignment
was to prepare calculations of the dates of Easter. At that time it
was customary to count years since the reign of emperor Diocletian;
but in his calculations Dionysius chose to number the years since the
birth of Christ, rather than honour the persecutor Diocletian.
Dionysius (wrongly) fixed Jesus' birth with respect to Diocletian's
reign in such a manner that it falls on 25 December 753 AUC (ab urbe
condita, i.e. since the founding of Rome), thus making the current era
start with AD 1 on 1 January 754 AUC.
How Dionysius established the year of Christ's birth is not known (see
section 2.13.1 for a couple of theories). Jesus was born under the
reign of king Herod the Great, who died in 750 AUC, which means that
Jesus could have been born no later than that year. Dionysius'
calculations were disputed at a very early stage.
When people started dating years before 754 AUC using the term "Before
Christ", they let the year 1 BC immediately precede AD 1 with no
intervening year zero.
Note, however, that astronomers frequently use another way of
numbering the years BC. Instead of 1 BC they use 0, instead of 2 BC
they use -1, instead of 3 BC they use -2, etc.
See also section 2.13.2.
It is sometimes claimed that it was the Venerable Bede (673-735) who
introduced BC dating. Although Bede seems to have used the term on at
least one occasion, it is generally believed that BC dates were not
used until the middle of the 17th century.
In this section I have used AD 1 = 754 AUC. This is the most likely
equivalence between the two systems. However, some authorities state
that AD 1 = 753 AUC or 755 AUC. This confusion is not a modern one, it
appears that even the Romans were in some doubt about how to count
the years since the founding of Rome.
2.13.1. How did Dionysius date Christ's birth?
----------------------------------------------
There are quite a few theories about this. And many of the theories
are presented as if they were indisputable historical fact.
Here are two theories that I personally consider likely:
1. According to the Gospel of Luke (3:1 & 3:23) Jesus was "about
thirty years old" shortly after "the fifteenth year of the reign of
Tiberius Caesar". Tiberius became emperor in AD 14. If you combine
these numbers you reach a birthyear for Jesus that is strikingly
close to the beginning of our year reckoning. This may have been
the basis for Dionysius' calculations.
2. Dionysius' original task was to calculate an Easter table. In the
Julian calendar, the dates for Easter repeat every 532 years (see
section 2.12.9). The first year in Dionysius' Easter tables is AD
532. Is it a coincidence that the number 532 appears twice here? Or
did Dionysius perhaps fix Jesus' birthyear so that his own Easter
tables would start exactly at the beginning of the second Easter
cycle after Jesus' birth?
2.13.2. Was Jesus born in the year 0?
-------------------------------------
No.
There are two reasons for this:
- There is no year 0.
- Jesus was born before 4 BC.
The concept of a year "zero" is a modern myth (but a very popular one).
Roman numerals do not have a figure designating zero, and treating zero
as a number on an equal footing with other numbers was not common in
the 6th century when our present year reckoning was established by
Dionysius Exiguus (see section 2.13). Dionysius let the year AD 1
start one week after what he believed to be Jesus' birthday.
Therefore, AD 1 follows immediately after 1 BC with no intervening
year zero. So a person who was born in 10 BC and died in AD 10,
would have died at the age of 19, not 20.
Furthermore, Dionysius' calculations were wrong. The Gospel of
Matthew tells us that Jesus was born under the reign of king Herod the
Great, who died in 4 BC. It is likely that Jesus was actually born
around 7 BC. The date of his birth is unknown; it may or may not be 25
December.
2.13.3. When did the 3rd millennium start?
------------------------------------------
The first millennium started in AD 1, so the millennia are counted in
this manner:
1st millennium: 1-1000
2nd millennium: 1001-2000
3rd millennium: 2001-3000
Thus, the 3rd millennium and, similarly, the 21st century started on
1 Jan 2001.
This is the cause of some heated debate, especially since some
dictionaries and encyclopaedias say that a century starts in years
that end in 00. Furthermore, the change 1999/2000 is obviously much
more spectacular than the change 2000/2001.
Let me propose a few compromises:
Any 100-year period is a century. Therefore the period from 23 June 2004
to 22 June 2104 is a century. So please feel free to celebrate the
start of a century any day you like!
Although the 20th century started in 1901, the 1900s started in 1900.
Similarly, the 21st century started in 2001, but the 2000s started in
2000.
2.13.4. What do AD, BC, CE, and BCE stand for?
----------------------------------------------
Years before the birth of Christ are in English traditionally
identified using the abbreviation BC ("Before Christ").
Years after the birth of Christ are traditionally identified using the
Latin abbreviation AD ("Anno Domini", that is, "In the Year of the
Lord").
Some people, who want to avoid the reference to Christ that is implied
in these terms, prefer the abbreviations BCE ("Before the Common Era"
or "Before the Christian Era") and CE ("Common Era" or "Christian Era").
2.14. What is the Indiction?
----------------------------
The Indiction was used in the middle ages to specify the position of a
year in a 15 year taxation cycle. It was introduced by emperor
Constantine the Great on 1 September 312 and ceased to be used in
1806.
The Indiction may be calculated thus:
Indiction = (year + 2) mod 15 + 1
The Indiction has no astronomical significance.
The Indiction did not always follow the calendar year. Three different
Indictions may be identified:
1) The Pontifical or Roman Indiction, which started on New Year's Day
(being either 25 December, 1 January, or 25 March).
2) The Greek or Constantinopolitan Indiction, which started on 1 September.
3) The Imperial Indiction or Indiction of Constantine, which started
on 24 September.
2.15. What is the Julian Period?
--------------------------------
The Julian period (and the Julian day number) must not be confused
with the Julian calendar.
The French scholar Joseph Justus Scaliger (1540-1609) was interested
in assigning a positive number to every year without having to worry
about BC/AD. He invented what is today known as the "Julian Period".
The Julian Period probably takes its name from the Julian calendar,
although it has been claimed that it is named after Scaliger's father,
the Italian scholar Julius Caesar Scaliger (1484-1558).
Scaliger's Julian period starts on 1 January 4713 BC (Julian calendar)
and lasts for 7980 years. AD 2003 is thus year 6716 in the Julian
period. After 7980 years the number starts from 1 again.
Why 4713 BC and why 7980 years? Well, in 4713 BC the Indiction (see
section 2.14), the Golden Number (see section 2.12.3) and the Solar
Number (see section 2.4) were all 1. The next times this happens is
15*19*28=7980 years later, in AD 3268.
Astronomers have used the Julian period to assign a unique number to
every day since 1 January 4713 BC. This is the so-called Julian Day
(JD). JD 0 designates the 24 hours from noon UTC on 1 January 4713 BC
to noon UTC on 2 January 4713 BC.
This means that at noon UTC on 1 January AD 2000, JD 2,451,545
started.
This can be calculated thus:
From 4713 BC to AD 2000 there are 6712 years.
In the Julian calendar, years have 365.25 days, so 6712 years
correspond to 6712*365.25=2,451,558 days. Subtract from this
the 13 days that the Gregorian calendar is ahead of the Julian
calendar, and you get 2,451,545.
Often fractions of Julian day numbers are used, so that 1 January AD
2000 at 15:00 UTC is referred to as JD 2,451,545.125.
Note that some people use the term "Julian day number" to refer to any
numbering of days. NASA, for example, uses the term to denote the
number of days since 1 January of the current year.
2.15.1. Is there a formula for calculating the Julian day number?
-----------------------------------------------------------------
Try this one (the divisions are integer divisions, in which remainders
are discarded):
a = (14-month)/12
y = year+4800-a
m = month + 12*a - 3
For a date in the Gregorian calendar:
JD = day + (153*m+2)/5 + y*365 + y/4 - y/100 + y/400 - 32045
For a date in the Julian calendar:
JD = day + (153*m+2)/5 + y*365 + y/4 - 32083
JD is the Julian day number that starts at noon UTC on the specified
date.
The algorithm works fine for AD dates. If you want to use it for BC
dates, you must first convert the BC year to a negative year (e.g.,
10 BC = -9). The algorithm works correctly for all dates after 4800 BC,
i.e. at least for all positive Julian day numbers.
To convert the other way (i.e., to convert a Julian day number, JD,
to a day, month, and year) these formulas can be used (again, the
divisions are integer divisions):
For the Gregorian calendar:
a = JD + 32044
b = (4*a+3)/146097
c = a - (b*146097)/4
For the Julian calendar:
b = 0
c = JD + 32082
Then, for both calendars:
d = (4*c+3)/1461
e = c - (1461*d)/4
m = (5*e+2)/153
day = e - (153*m+2)/5 + 1
month = m + 3 - 12*(m/10)
year = b*100 + d - 4800 + m/10
2.15.2. What is the modified Julian day number?
-----------------------------------------------
Sometimes a modified Julian day number (MJD) is used which is
2,400,000.5 less than the Julian day number. This brings the numbers
into a more manageable numeric range and makes the day numbers change
at midnight UTC rather than noon.
MJD 0 thus started on 17 Nov 1858 (Gregorian) at 00:00:00 UTC.
2.15.3. What is the Lilian day number?
--------------------------------------
The Lilian day number is similar to the Julian day number, except that
Lilian day number 1 started at midnight on the first day of the
Gregorian calendar, that is, 15 October 1582.
The Lilian day number is named after Aloysius Lilius mentioned in
section 2.2.
2.16. What is the correct way to write dates?
---------------------------------------------
The answer to this question depends on what you mean by "correct".
Different countries have different customs.
Most countries use a day-month-year format, such as:
25.12.1998 25/12/1998 25/12-1998 25.XII.1998
In the U.S.A. a month-day-year format is common:
12/25/1998 12-25-1998
International standard ISO-8601 mandates a year-month-day format,
namely either 1998-12-25 or 19981225. This format is gaining
popularity in some countries.
In all of these systems, the first two digits of the year are
frequently omitted:
25.12.98 12/25/98 98-12-25
This confusion leads to misunderstandings. What is 02-03-04? To most
people it is 2 Mar 2004; to an American it is 3 Feb 2004; and to a
person using the international standard it would be 4 Mar 2002.
If you want to be sure that people understand you, I recommend that
you
* write the month with letters instead of numbers, and
* write the years as 4-digit numbers.
3. The Hebrew Calendar
----------------------
The current definition of the Hebrew calendar is generally said to
have been set down by the Sanhedrin president Hillel II in
approximately AD 359. The original details of his calendar are,
however, uncertain.
The Hebrew calendar is used for religious purposes by Jews all over
the world, and it is the official calendar of Israel.
The Hebrew calendar is a combined solar/lunar calendar, in that it
strives to have its years coincide with the tropical year and its
months coincide with the synodic months. This is a complicated goal,
and the rules for the Hebrew calendar are correspondingly
fascinating.
3.1. What does a Hebrew year look like?
---------------------------------------
An ordinary (non-leap) year has 353, 354, or 355 days.
A leap year has 383, 384, or 385 days.
The three lengths of the years are termed, "deficient", "regular",
and "complete", respectively.
An ordinary year has 12 months, a leap year has 13 months.
Every month starts (approximately) on the day of a new moon.
The months and their lengths are:
Length in a Length in a Length in a
Name deficient year regular year complete year
------- -------------- ------------ -------------
Tishri 30 30 30
Heshvan 29 29 30
Kislev 29 30 30
Tevet 29 29 29
Shevat 30 30 30
(Adar I 30 30 30)
Adar II 29 29 29
Nisan 30 30 30
Iyar 29 29 29
Sivan 30 30 30
Tammuz 29 29 29
Av 30 30 30
Elul 29 29 29
------- -------------- ------------ -------------
Total: 353 or 383 354 or 384 355 or 385
The month Adar I is only present in leap years. In non-leap years
Adar II is simply called "Adar".
Note that in a regular year the numbers 30 and 29 alternate; a
complete year is created by adding a day to Heshvan, whereas a
deficient year is created by removing a day from Kislev.
The alteration of 30 and 29 ensures that when the year starts with a
new moon, so does each month.
3.2. What years are leap years?
-------------------------------
A year is a leap year if the number 'year mod 19' is one of the
following: 0, 3, 6, 8, 11, 14, or 17.
The value for year in this formula is the "Anno Mundi" described in
section 3.8.
3.3. What years are deficient, regular, and complete?
-----------------------------------------------------
That is the wrong question to ask. The correct question to ask is: When
does a Hebrew year begin? Once you have answered that question (see
section 3.6), the length of the year is the number of days between
1 Tishri in one year and 1 Tishri in the following year.
3.4. When is New Year's day?
----------------------------
That depends. Jews have 4 different days to choose from:
1 Tishri: "Rosh HaShanah". This day is a celebration of the creation
of the world and marks the start of a new calendar
year. This will be the day we shall base our calculations on
in the following sections.
15 Shevat: "Tu B'shevat". The new year for trees, when fruit tithes
should be brought.
1 Nisan: "New Year for Kings". Nisan is considered the first month,
although it occurs 6 or 7 months after the start of the
calendar year.
1 Elul: "New Year for Animal Tithes (Taxes)".
Only the first two dates are celebrated nowadays.
3.5. When does a Hebrew day begin?
----------------------------------
A Hebrew-calendar day does not begin at midnight, but at either sunset
or when three medium-sized stars should be visible, depending on the
religious circumstance.
Sunset marks the start of the 12 night hours, whereas sunrise marks the
start of the 12 day hours. This means that night hours may be longer
or shorter than day hours, depending on the season.
3.6. When does a Hebrew year begin?
-----------------------------------
The first day of the calendary year, Rosh HaShanah, on 1 Tishri is
determined as follows:
1) The new year starts on the day of the new moon that occurs about
354 days (or 384 days if the previous year was a leap year) after
1 Tishri of the previous year
2) If the new moon occurs after noon on that day, delay the new year
by one day. (Because in that case the new crescent moon will not be
visible until the next day.)
3) If this would cause the new year to start on a Sunday, Wednesday,
or Friday, delay it by one day. (Because we want to avoid that
Yom Kippur (10 Tishri) falls on a Friday or Sunday, and that
Hoshanah Rabba (21 Tishri) falls on a Sabbath (Saturday)).
4) If two consecutive years start 356 days apart (an illegal year
length), delay the start of the first year by two days.
5) If two consecutive years start 382 days apart (an illegal year
length), delay the start of the second year by one day.
Note: Rule 4 can only come into play if the first year was supposed
to start on a Tuesday. Therefore a two day delay is used rather that a
one day delay, as the year must not start on a Wednesday as stated in
rule 3.
3.7. When is the new moon?
--------------------------
A calculated new moon is used. In order to understand the
calculations, one must know that an hour is subdivided into 1080
"parts".
The calculations are as follows:
The new moon that started the year AM 1, occurred 5 hours and 204
parts after sunset (i.e. just before midnight on Julian date 6 October
3761 BC).
The new moon of any particular year is calculated by extrapolating
from this time, using a synodic month of 29 days 12 hours and 793
parts.
Note that 18:00 Jerusalem time (15:39 UTC) is used instead of sunset in
all these calculations.
3.8. How does one count years?
------------------------------
Years are counted since the creation of the world, which is assumed to
have taken place in 3761 BC. In that year, AM 1 started (AM = Anno
Mundi = year of the world).
In the year AD 2003 we witness the start of Hebrew year AM 5764.
4. The Islamic Calendar
-----------------------
The Islamic calendar (or Hijri calendar) is a purely lunar
calendar. It contains 12 months that are based on the motion of the
moon, and because 12 synodic months is only 12*29.53=354.36 days, the
Islamic calendar is consistently shorter than a tropical year, and
therefore it shifts with respect to the Christian calendar.
The calendar is based on the Qur'an (Sura IX, 36-37) and its proper
observance is a sacred duty for Muslims.
The Islamic calendar is the official calendar in countries around the
Gulf, especially Saudi Arabia (but see section 4.5). But other Muslim
countries use the Gregorian calendar for civil purposes and only turn
to the Islamic calendar for religious purposes.
4.1. What does an Islamic year look like?
-----------------------------------------
The names of the 12 months that comprise the Islamic year are:
1. Muharram 7. Rajab
2. Safar 8. Sha'ban
3. Rabi' al-awwal (Rabi' I) 9. Ramadan
4. Rabi' al-thani (Rabi' II) 10. Shawwal
5. Jumada al-awwal (Jumada I) 11. Dhu al-Qi'dah
6. Jumada al-thani (Jumada II) 12. Dhu al-Hijjah
(Due to different transliterations of the Arabic alphabet, other
spellings of the months are possible.)
Each month starts when the lunar crescent is first seen (by an actual
human being) after a new moon.
Although new moons may be calculated quite precisely, the actual
visibility of the crescent is much more difficult to predict. It
depends on factors such as weather, the optical properties of the
atmosphere, and the location of the observer. It is therefore very
difficult to give accurate information in advance about when a new
month will start.
Furthermore, some Muslims depend on a local sighting of the moon,
whereas others depend on a sighting by authorities somewhere in the
Muslim world. Both are valid Islamic practices, but they may lead to
different starting days for the months.
4.2. So you can't print an Islamic calendar in advance?
-------------------------------------------------------
Not a reliable one. However, calendars are printed for planning
purposes, but such calendars are based on estimates of the visibility
of the lunar crescent, and the actual month may start a day earlier or
later than predicted in the printed calendar.
Different methods for estimating the calendars are used.
Some sources mention a crude system in which all odd numbered months
have 30 days and all even numbered months have 29 days with an extra
day added to the last month in "leap years" (a concept otherwise
unknown in the calendar). Leap years could then be years in which the
number 'year mod 30' is one of the following: 2, 5, 7, 10, 13, 16, 18,
21, 24, 26, or 29. (This is the algorithm used in the calendar program
of the Gnu Emacs editor.)
Such a calendar would give an average month length of 29.53056 days,
which is quite close to the synodic month of 29.53059 days, so *on the
average* it would be quite accurate, but in any given month it is
still just a rough estimate.
Better algorithms for estimating the visibility of the new moon have
been devised, and a number of computer programs with this purpose
exist.
4.3. How does one count years?
------------------------------
Years are counted since the Hijra, that is, Mohammed's emigration to
Medina in AD 622. On 16 July (Julian calendar) of that year, AH 1
started (AH = Anno Hegirae = year of the Hijra).
In the year AD 2003 we have witnessed the start of Islamic year AH 1424.
Note that although only 2003-622=1381 years have passed in the
Christian calendar, 1423 years have passed in the Islamic calendar,
because its year is consistently shorter (by about 11 days) than the
tropical year used by the Christian calendar.
4.4. When will the Islamic calendar overtake the Gregorian calendar?
--------------------------------------------------------------------
As the year in the Islamic calendar is about 11 days shorter than the
year in the Christian calendar, the Islamic years are slowly gaining
in on the Christian years. But it will be many years before the two
coincide. The 1st day of the 5th month of AD 20874 in the Gregorian
calendar will also be (approximately) the 1st day of the 5th month of
AH 20874 of the Islamic calendar.
4.5. Doesn't Saudi Arabia have special rules?
---------------------------------------------
Saudi Arabia doesn't rely on a visual sighting of the crescent moon to
fix the start of a new month. Instead they base their calendar on a
calculated astronomical moon.
Since 1999 (1420 AH) the rule has been as follows: On the 29th day of
an Islamic month, the times when the sun and the moon set are
compared. If the sun sets before the moon, the next day will be the
first of a new month; but if the moon sets before the sun, the next
day will be the last (30th) of the current month.
The times for the setting of the sun and the moon are calculated for
the coordinates of Mecca.
5. The Persian Calendar
-----------------------
The Persian calendar is a solar calendar with a starting point that
matches that of the Islamic calendar. Its origin can be traced back to
the 11th century when a group of astronomers (including the well-known
poet Omar Khayyam) created what is known as the Jalaali calendar.
However, a number of changes have been made to the calendar since
then.
The current calendar has been used in Iran since 1925 and in
Afghanistan since 1957. However, Afghanistan used the Islamic calendar
in the years 1999-2002.
5.1. What does a Persian year look like?
----------------------------------------
The names and lengths of the 12 months that comprise the Persian year
are:
1. Farvardin (31 days) 7. Mehr (30 days)
2. Ordibehesht (31 days) 8. Aban (30 days)
3. Khordad (31 days) 9. Azar (30 days)
4. Tir (31 days) 10. Day (30 days)
5. Mordad (31 days) 11. Bahman (30 days)
6. Shahrivar (31 days) 12. Esfand (29/30 days)
(Due to different transliterations of the Persian alphabet, other
spellings of the months are possible.) In Afghanistan the months are
named differently.
The month of Esfand has 29 days in an ordinary year, 30 days in a leap
year.
5.2. When does the Persian year begin?
--------------------------------------
The Persian year starts at vernal equinox. If the astronomical vernal
equinox falls before noon (Tehran true time) on a particular day, then
that day is the first day of the year. If the astronomical vernal
equinox falls after noon, the following day is the first day of the
year.
5.3. How does one count years?
------------------------------
As in the Islamic calendar (section 4.3), years are counted since
Mohammed's emigration to Medina in AD 622. At vernal equinox of that
year, AP 1 started (AP = Anno Persico/Anno Persarum = Persian year).
Note that contrary to the Islamic calendar, the Persian calendar
counts solar years. In the year AD 2003 we have therefore witnessed
the start of Persian year 1382, but the start of Islamic year 1424.
5.4. What years are leap years?
-------------------------------
Since the Persian year is defined by the astronomical vernal equinox,
the answer is simply: Leap years are years in which there are 366 days
between two Persian new year's days.
However, basing the Persian calendar purely on an astronomical
observation of the vernal equinox is rejected by many, and a few
mathematical rules for determining the length of the year have been
suggested.
The most popular (and complex) of these is probably the following:
The calendar is divided into periods of 2820 years. These periods are
then divided into 88 cycles whose lengths follow this pattern:
29, 33, 33, 33, 29, 33, 33, 33, 29, 33, 33, 33, ...
This gives 2816 years. The total of 2820 years is achieved by
extending the last cycle by 4 years (for a total of 37 years).
If you number the years within each cycle starting with 0, then leap
years are the years that are divisible by 4, except that the year 0 is
not a leap year.
So within, say, a 29 year cycle, this is the leap year pattern:
Year Year Year Year
0 Ordinary 8 Leap 16 Leap 24 Leap
1 Ordinary 9 Ordinary 17 Ordinary 25 Ordinary
2 Ordinary 10 Ordinary 18 Ordinary 26 Ordinary
3 Ordinary 11 Ordinary 19 Ordinary 27 Ordinary
4 Leap 12 Leap 20 Leap 28 Leap
5 Ordinary 13 Ordinary 21 Ordinary
6 Ordinary 14 Ordinary 22 Ordinary
7 Ordinary 15 Ordinary 23 Ordinary
This gives a total of 683 leap years every 2820 years, which
corresponds to an average year length of 365 683/2820 = 365.24220
days. This is a better approximation to the tropical year than the
365.2425 days of the Gregorian calendar.
The current 2820 year period started in the year AP 475 (AD 1096).
This "mathematical" calendar currently coincides closely with the
purely astronomical calendar. In the years between AP 1244 and 1531
(AD 1865 and 2152) a discrepancy of one day is seen twice, namely in
AP 1404 and 1437 (starting at vernal equinox of AD 2025 and 2058).
However, outside this period, discrepancies are more frequent.
6. The Week
-----------
The Christian, the Hebrew, the Islamic, and the Persian calendars all
have a 7-day week.
6.1. What is the origin of the 7-day week?
------------------------------------------
Digging into the history of the 7-day week is a very complicated
matter. Authorities have very different opinions about the history of
the week, and they frequently present their speculations as if they
were indisputable facts. The only thing we seem to know for certain
about the origin of the 7-day week is that we know nothing for
certain.
The first pages of the Bible explain how God created the world in six
days and rested on the seventh. This seventh day became the Jewish
day of rest, the Sabbath, Saturday.
Extra-biblical locations sometimes mentioned as the birthplace of the
7-day week include: Babylon, Persia, and several others. The week was
known in Rome before the advent of Christianity.
6.2. What do the names of the days of the week mean?
----------------------------------------------------
An answer to this question is necessarily closely linked to the
language in question. Whereas most languages use the same names for
the months (with a few Slavonic languages as notable exceptions),
there is great variety in names that various languages use for the
days of the week. A few examples will be given here.
Except for the Sabbath, Jews simply number their week days.
A related method is partially used in Portuguese and Russian:
English Portuguese Russian Meaning of Russian name
------- ---------- ------- -----------------------
Monday segunda-feira ponedelnik After "do-nothing"
Tuesday terca-feira vtornik Second
Wednesday quarta-feira sreda Middle
Thursday quinta-feira chetverg Fourth
Friday sexta-feira pyatnitsa Fifth
Saturday sabado subbota Sabbath
Sunday domingo voskresenye Resurrection
Most Latin-based languages connect each day of the week with one of
the seven "planets" of the ancient times: Sun, Moon, Mercury, Venus,
Mars, Jupiter, and Saturn. French, for example, uses:
English French "Planet"
------- ------ --------
Monday lundi Moon
Tuesday mardi Mars
Wednesday mercredi Mercury
Thursday jeudi Jupiter
Friday vendredi Venus
Saturday samedi Saturn
Sunday dimanche (Sun)
The link with the sun has been broken in French, but Sunday was
called "dies solis" (day of the sun) in Latin.
It is interesting to note that also some Asiatic languages (for
example, Hindi, Japanese, and Korean) have a similar relationship
between the week days and the planets.
English has retained the original planets in the names for Saturday,
Sunday, and Monday. For the four other days, however, the names of
Anglo-Saxon or Nordic gods have replaced the Roman gods that gave
name to the planets. Thus, Tuesday is named after Tiw, Wednesday is
named after Woden, Thursday is named after Thor, and Friday is named
after Freya.
6.3. What is the system behind the planetary day names?
-------------------------------------------------------
As we saw in the previous section, the planets have given the week
days their names following this order:
Moon, Mars, Mercury, Jupiter, Venus, Saturn, Sun
Why this particular order?
One theory goes as follows: If you order the "planets" according to
either their presumed distance from Earth (assuming the Earth to be
the centre of the universe) or their period of revolution around the
Earth, you arrive at this order:
Moon, Mercury, Venus, Sun, Mars, Jupiter, Saturn
Now, assign (in reverse order) these planets to the hours of the day:
1=Saturn, 2=Jupiter, 3=Mars, 4=Sun, 5=Venus, 6=Mercury, 7=Moon,
8=Saturn, 9=Jupiter, etc., 23=Jupiter, 24=Mars
The next day will then continue where the old day left off:
1=Sun, 2=Venus, etc., 23=Venus, 24=Mercury
And the next day will go
1=Moon, 2=Saturn, etc.
If you look at the planet assigned to the first hour of each day, you
will note that the planets come in this order:
Saturn, Sun, Moon, Mars, Mercury, Jupiter, Venus
This is exactly the order of the associated week days.
Coincidence? Maybe.
6.4. Has the 7-day week cycle ever been interrupted?
----------------------------------------------------
There is no record of the 7-day week cycle ever having been broken.
Calendar changes and reform have never interrupted the 7-day cycles.
It very likely that the week cycles have run uninterrupted at least
since the days of Moses (c. 1400 BC), possibly even longer.
Some sources claim that the ancient Jews used a calendar in which an
extra Sabbath was occasionally introduced. But this is probably not
true.
6.5. Which day is the day of rest?
----------------------------------
For the Jews, the Sabbath (Saturday) is the day of rest and
worship. On this day God rested after creating the world.
Most Christians have made Sunday their day of rest and worship,
because Jesus rose from the dead on a Sunday.
Muslims use Friday as their day of rest and worship. The Qur'an
calls Friday a holy day, the "king of days".
6.6. What is the first day of the week?
---------------------------------------
The Bible clearly makes Saturday (the Sabbath) the last day of the
week. Therefore it is common Jewish and Christian practice to regard
Sunday as the first day of the week (as is also evident from the
Portuguese names for the week days mentioned in section 6.2). However,
the fact that, for example, Russian uses the name "second" for
Tuesday, indicates that some nations regard Monday as the first day.
In international standard ISO-8601 the International Organization for
Standardization has decreed that Monday shall be the first day of the
week.
6.7. What is the week number?
-----------------------------
International standard ISO-8601 (mentioned in section 6.6) assigns a
number to each week of the year. A week that lies partly in one year
and partly in another is assigned a number in the year in which most
of its days lie. This means that
Week 1 of any year is the week that contains 4 January,
or equivalently
Week 1 of any year is the week that contains the first
Thursday in January.
Most years have 52 weeks, but years that start on a Thursday and leap
years that start on a Wednesday have 53 weeks.
Note: This week numbering system is not commonly used in the United
States.
6.8. How can I calculate the week number?
-----------------------------------------
If you know the date, how do you calculate the corresponding week
number (as defined in ISO-8601)?
1) Using the formulas in section 2.15.1, calculate the Julian Day
Number, J.
2) Perform the following calculations (in which the divisions are
integer divisions in which the remainder is discarded):
d4 = (J+31741 - (J mod 7)) mod 146097 mod 36524 mod 1461
L = d4/1460
d1 = ((d4-L) mod 365) + L
WeekNumber = d1/7+1
(I am very grateful to Stefan Potthast for this algorithm.)
Note that if the week number is 1, 52, or 53, the week may lie in two
different calendar years. However, the week is always considered to
lie in the year in which it is counted. Thus, 31 December of year X,
may belong to week 1 of year X+1; similarly 1 January of year X may
belong to week 52 or 53 or year X-1.
6.9. Do weeks of different lengths exist?
-----------------------------------------
If you define a "week" as a 7-day period, obviously the answer is
no. But if you define a "week" as a named interval that is greater
than a day and smaller than a month, the answer is yes.
The ancient Egyptians used a 10-day "week", as did the French
Revolutionary calendar (see section 7.1).
The Maya calendar uses a 13 and a 20-day "week" (see section 8.2).
The Soviet Union has used both a 5-day and a 6-day week. In 1929-30
the USSR gradually introduced a 5-day week. Every worker had one day
off every week, but there was no fixed day of rest. On 1 September
1931 this was replaced by a 6-day week with a fixed day of rest,
falling on the 6th, 12th, 18th, 24th, and 30th day of each month (1
March was used instead of the 30th day of February, and the last day
of months with 31 days was considered an extra working day outside
the normal 6-day week cycle). A return to the normal 7-day week was
decreed on 26 June 1940.
7. The French Revolutionary Calendar
------------------------------------
The French Revolutionary Calendar (or Republican Calendar) was
introduced in France on 24 November 1793 and abolished on 1 January
1806. It was used again briefly during the Paris Commune in 1871.
7.1. What does a Republican year look like?
-------------------------------------------
A year consists of 365 or 366 days, divided into 12 months of 30 days
each, followed by 5 or 6 additional days. The months were:
1. Vendemiaire 7. Germinal
2. Brumaire 8. Floreal
3. Frimaire 9. Prairial
4. Nivose 10. Messidor
5. Pluviose 11. Thermidor
6. Ventose 12. Fructidor
(The second e in Vendemiaire and the e in Floreal carry an acute
accent. The o's in Nivose, Pluviose, and Ventose carry a circumflex
accent.)
The year was not divided into weeks, instead each month was divided
into three "decades" of 10 days, of which the final day was a day of
rest. This was an attempt to de-Christianize the calendar, but it was
an unpopular move, because now there were 9 work days between each day
of rest, whereas the Gregorian Calendar had only 6 work days between
each Sunday.
The ten days of each decade were called, respectively, Primidi, Duodi,
Tridi, Quartidi, Quintidi, Sextidi, Septidi, Octidi, Nonidi, Decadi.
The 5 or 6 additional days followed the last day of Fructidor and were
called:
1. Fete de la vertu (Celebration of virtue)
2. Fete du genie (Celebration of genius)
3. Fete du travail (Celebration of labour)
4. Fete de l'opinion (Celebration of opinion)
5. Fete des recompenses (Celebration of rewards)
6. Jour de la revolution (Day of the revolution) (the leap day)
Each year was supposed to start on autumnal equinox (around 22
September), but this created problems as will be seen in section 7.3.
7.2. How does one count years?
------------------------------
Years are counted since the establishment of the first French Republic
on 22 September 1792. That day became 1 Vendemiaire of the year 1 of
the Republic. (However, the Revolutionary Calendar was not introduced
until 24 November 1793.)
7.3. What years are leap years?
-------------------------------
Leap years were introduced to keep New Year's Day on autumnal
equinox. But this turned out to be difficult to handle, because
equinox is not completely simple to predict.
In fact, the first decree implementing the calendar (5 Oct 1793)
contained two contradictory rules, as it stated that:
- the first day of each year would be that of the autumnal equinox
- every 4th year would be a leap year
In practice, the first calendars were based on the equinoxial
condition.
To remove the confusion, a rule similar to the one used in the
Gregorian Calendar (including a 4000 year rule as described in section
2.2.2) was proposed by the calendar's author, Charles Rommes, but his
proposal ran into political problems.
In short, during the time when the French Revolutionary Calendar was
in use, the following years were leap years: 3, 7, and 11.
7.4. How does one convert a Republican date to a Gregorian one?
---------------------------------------------------------------
The following table lists the Gregorian date on which each year of the
Republic started:
Year 1: 22 Sep 1792 Year 8: 23 Sep 1799
Year 2: 22 Sep 1793 Year 9: 23 Sep 1800
Year 3: 22 Sep 1794 Year 10: 23 Sep 1801
Year 4: 23 Sep 1795 Year 11: 23 Sep 1802
Year 5: 22 Sep 1796 Year 12: 24 Sep 1803
Year 6: 22 Sep 1797 Year 13: 23 Sep 1804
Year 7: 22 Sep 1798 Year 14: 23 Sep 1805
8. The Maya Calendar
--------------------
(I am very grateful to Chris Carrier for providing most of the
information about the Maya calendar.)
Among their other accomplishments, the ancient Mayas invented a
calendar of remarkable accuracy and complexity. The Maya calendar was
adopted by the other Mesoamerican nations, such as the Aztecs and the
Toltec, which adopted the mechanics of the calendar unaltered but
changed the names of the days of the week and the months.
The Maya calendar uses three different dating systems in parallel, the
"Long Count", the "Tzolkin" (divine calendar), and the "Haab" (civil
calendar). Of these, only the Haab has a direct relationship to the
length of the year.
A typical Mayan date looks like this: 12.18.16.2.6, 3 Cimi 4 Zotz.
12.18.16.2.6 is the Long Count date.
3 Cimi is the Tzolkin date.
4 Zotz is the Haab date.
8.1. What is the Long Count?
----------------------------
The Long Count is really a mixed base-20/base-18 representation of a
number, representing the number of days since the start of the Mayan
era. It is thus akin to the Julian Day Number (see section 2.15).
The basic unit is the "kin" (day), which is the last component of the
Long Count. Going from right to left the remaining components are:
uinal (1 uinal = 20 kin = 20 days)
tun (1 tun = 18 uinal = 360 days = approx. 1 year)
katun (1 katun = 20 tun = 7,200 days = approx. 20 years)
baktun (1 baktun = 20 katun = 144,000 days = approx. 394 years)
The kin, tun, and katun are numbered from 0 to 19.
The uinal are numbered from 0 to 17.
The baktun are numbered from 1 to 13.
Although they are not part of the Long Count, the Mayas had names for
larger time spans. The following names are sometimes quoted, although
they are not ancient Maya terms:
1 pictun = 20 baktun = 2,880,000 days = approx. 7885 years
1 calabtun = 20 pictun = 57,600,000 days = approx. 158,000 years
1 kinchiltun = 20 calabtun = 1,152,000,000 days = approx. 3 million years
1 alautun = 20 kinchiltun = 23,040,000,000 days = approx. 63 million years
The alautun is probably the longest named period in any calendar.
8.1.1. When did the Long Count start?
-------------------------------------
Logically, the first date in the Long Count should be 0.0.0.0.0, but
as the baktun (the first component) are numbered from 1 to 13 rather
than 0 to 12, this first date is actually written 13.0.0.0.0.
The authorities disagree on what 13.0.0.0.0 corresponds to in our
calendar. I have come across three possible equivalences:
13.0.0.0.0 = 8 Sep 3114 BC (Julian) = 13 Aug 3114 BC (Gregorian)
13.0.0.0.0 = 6 Sep 3114 BC (Julian) = 11 Aug 3114 BC (Gregorian)
13.0.0.0.0 = 11 Nov 3374 BC (Julian) = 15 Oct 3374 BC (Gregorian)
Assuming one of the first two equivalences, the Long Count will again
reach 13.0.0.0.0 on 21 or 23 December AD 2012 - a not too distant future.
The date 13.0.0.0.0 may have been the Mayas' idea of the date of the
creation of the world.
8.2. What is the Tzolkin?
-------------------------
The Tzolkin date is a combination of two "week" lengths.
While our calendar uses a single week of seven days, the Mayan
calendar used two different lengths of week:
- a numbered week of 13 days, in which the days were numbered from
1 to 13
- a named week of 20 days, in which the names of the days were:
0. Ahau 5. Chicchan 10. Oc 15. Men
1. Imix 6. Cimi 11. Chuen 16. Cib
2. Ik 7. Manik 12. Eb 17. Caban
3. Akbal 8. Lamat 13. Ben 18. Etznab
4. Kan 9. Muluc 14. Ix 19. Caunac
As the named week is 20 days and the smallest Long Count digit is 20
days, there is synchrony between the two; if, for example, the last
digit of today's Long Count is 0, today must be Ahau; if it is 6, it
must be Cimi. Since the numbered and the named week were both "weeks",
each of their name/number change daily; therefore, the day after 3
Cimi is not 4 Cimi, but 4 Manik, and the day after that, 5 Lamat. The
next time Cimi rolls around, 20 days later, it will be 10 Cimi instead
of 3 Cimi. The next 3 Cimi will not occur until 260 (or 13*20) days
have passed. This 260-day cycle also had good-luck or bad-luck
associations connected with each day, and for this reason, it became
known as the "divinatory year."
The "years" of the Tzolkin calendar are not counted.
8.2.1. When did the Tzolkin start?
----------------------------------
Long Count 13.0.0.0.0 corresponds to 4 Ahau. The authorities agree on
this.
8.3. What is the Haab?
----------------------
The Haab was the civil calendar of the Mayas. It consisted of 18
"months" of 20 days each, followed by 5 extra days, known as
"Uayeb". This gives a year length of 365 days.
The names of the month were:
1. Pop 7. Yaxkin 13. Mac
2. Uo 8. Mol 14. Kankin
3. Zip 9. Chen 15. Muan
4. Zotz 10. Yax 16. Pax
5. Tzec 11. Zac 17. Kayab
6. Xul 12. Ceh 18. Cumku
In contrast to the Tzolkin dates, the Haab month names changed every
20 days instead of daily; so the day after 4 Zotz would be 5 Zotz,
followed by 6 Zotz ... up to 19 Zotz, which is followed by 0 Tzec.
The days of the month were numbered from 0 to 19. This use of a 0th
day of the month in a civil calendar is unique to the Maya system; it
is believed that the Mayas discovered the number zero, and the uses to
which it could be put, centuries before it was discovered in Europe or
Asia.
The Uayeb days acquired a very derogatory reputation for bad luck;
known as "days without names" or "days without souls," and were
observed as days of prayer and mourning. Fires were extinguished and
the population refrained from eating hot food. Anyone born on those
days was "doomed to a miserable life."
The years of the Haab calendar are not counted.
The length of the Tzolkin year was 260 days and the length of the Haab
year was 365 days. The smallest number that can be divided evenly by
260 and 365 is 18,980, or 365*52; this was known as the Calendar
Round. If a day is, for example, "4 Ahau 8 Cumku," the next day
falling on "4 Ahau 8 Cumku" would be 18,980 days or about 52 years
later. Among the Aztec, the end of a Calendar Round was a time of
public panic as it was thought the world might be coming to an
end. When the Pleiades crossed the horizon on 4 Ahau 8 Cumku, they
knew the world had been granted another 52-year extension.
8.3.1. When did the Haab start?
-------------------------------
Long Count 13.0.0.0.0 corresponds to 8 Cumku. The authorities agree on
this.
8.4. Did the Mayas think a year was 365 days?
---------------------------------------------
Although there were only 365 days in the Haab year, the Mayas were
aware that a year is slightly longer than 365 days, and in fact, many
of the month-names are associated with the seasons; Yaxkin, for
example, means "new or strong sun" and, at the beginning of the Long
Count, 1 Yaxkin was the day after the winter solstice, when the sun
starts to shine for a longer period of time and higher in the
sky. When the Long Count was put into motion, it was started at
7.13.0.0.0, and 0 Yaxkin corresponded with Midwinter Day, as it did at
13.0.0.0.0 back in 3114 B.C. The available evidence indicates that the
Mayas estimated that a 365-day year precessed through all the seasons
twice in 7.13.0.0.0 or 1,101,600 days.
We can therefore derive a value for the Mayan estimate of the year by
dividing 1,101,600 by 365, subtracting 2, and taking that number and
dividing 1,101,600 by the result, which gives us an answer of
365.242036 days, which is slightly more accurate than the 365.2425
days of the Gregorian calendar.
(This apparent accuracy could, however, be a simple coincidence. The
Mayas estimated that a 365-day year precessed through all the seasons
*twice* in 7.13.0.0.0 days. These numbers are only accurate to 2-3
digits. Suppose the 7.13.0.0.0 days had corresponded to 2.001 cycles
rather than 2 cycles of the 365-day year, would the Mayas have noticed?)
9. The Chinese Calendar
-----------------------
Although the People's Republic of China uses the Gregorian calendar
for civil purposes, a special Chinese calendar is used for determining
festivals. Various Chinese communities around the world also use this
calendar.
The beginnings of the Chinese calendar can be traced back to the 14th
century BC. Legend has it that the Emperor Huangdi invented the
calendar in 2637 BC.
The Chinese calendar is based on exact astronomical observations of
the longitude of the sun and the phases of the moon. This means that
principles of modern science have had an impact on the Chinese
calendar.
I can recommend visiting Helmer Aslaksen's web site at
http://www.chinesecalendar.net for more information about the Chinese
calendar.
9.1. What does the Chinese year look like?
------------------------------------------
The Chinese calendar - like the Hebrew - is a combined solar/lunar
calendar in that it strives to have its years coincide with the
tropical year and its months coincide with the synodic months. It is
not surprising that a few similarities exist between the Chinese and
the Hebrew calendar:
* An ordinary year has 12 months, a leap year has 13 months.
* An ordinary year has 353, 354, or 355 days, a leap year has 383,
384, or 385 days.
When determining what a Chinese year looks like, one must make a
number of astronomical calculations:
First, determine the dates for the new moons. Here, a new moon is the
completely "black" moon (that is, when the moon is in conjunction with
the sun), not the first visible crescent used in the Islamic and
Hebrew calendars. The date of a new moon is the first day of a new
month.
Secondly, determine the dates when the sun's longitude is a multiple
of 30 degrees. (The sun's longitude is 0 at Vernal Equinox, 90 at
Summer Solstice, 180 at Autumnal Equinox, and 270 at Winter Solstice.)
These dates are called the "Principal Terms" and are used to determine
the number of each month:
Principal Term 1 occurs when the sun's longitude is 330 degrees.
Principal Term 2 occurs when the sun's longitude is 0 degrees.
Principal Term 3 occurs when the sun's longitude is 30 degrees.
etc.
Principal Term 11 occurs when the sun's longitude is 270 degrees.
Principal Term 12 occurs when the sun's longitude is 300 degrees.
Each month carries the number of the Principal Term that occurs in
that month.
In rare cases, a month may contain two Principal Terms; in this case
the months numbers may have to be shifted. Principal Term 11 (Winter
Solstice) must always fall in the 11th month.
All the astronomical calculations are carried out for the meridian 120
degrees east of Greenwich. This roughly corresponds to the east coast
of China.
Some variations in these rules are seen in various Chinese
communities.
9.2. What years are leap years?
-------------------------------
Leap years have 13 months. To determine if a year is a leap year,
calculate the number of new moons between the 11th month in one year
(i.e., the month containing the Winter Solstice) and the 11th month in
the following year. If there are 13 new moons from the start of the
11th month in the first year to the start of the 11th month in the
second year, a leap month must be inserted.
In leap years, at least one month does not contain a Principal Term.
The first such month is the leap month. It carries the same number as
the previous month, with the additional note that it is the leap
month.
9.3. How does one count years?
------------------------------
Unlike most other calendars, the Chinese calendar does not count years
in an infinite sequence. Instead years have names that are repeated
every 60 years.
(Historically, years used to be counted since the accession of an
emperor, but this was abolished after the 1911 revolution.)
Within each 60-year cycle, each year is assigned name consisting of
two components:
The first component is a "Celestial Stem":
1. jia 6. ji
2. yi 7. geng
3. bing 8. xin
4. ding 9. ren
5. wu 10. gui
These words have no English equivalent.
The second component is a "Terrestrial Branch":
1. zi (rat) 7. wu (horse)
2. chou (ox) 8. wei (sheep)
3. yin (tiger) 9. shen (monkey)
4. mao (hare, rabbit) 10. you (rooster)
5. chen (dragon) 11. xu (dog)
6. si (snake) 12. hai (pig)
The names of the corresponding animals in the zodiac cycle of 12
animals are given in parentheses.
Each of the two components is used sequentially. Thus, the 1st year of
the 60-year cycle becomes jia-zi, the 2nd year is yi-chou, the 3rd
year is bing-yin, etc. When we reach the end of a component, we start
from the beginning: The 10th year is gui-you, the 11th year is jia-xu
(restarting the Celestial Stem), the 12th year is yi-hai, and the 13th
year is bing-zi (restarting the Terrestrial Branch). Finally, the 60th
year becomes gui-hai.
This way of naming years within a 60-year cycle goes back
approximately 2000 years. A similar naming of days and months has
fallen into disuse, but the date name is still listed in calendars.
It is customary to number the 60-year cycles since 2637 BC, when the
calendar was supposedly invented. In that year the first 60-year cycle
started.
9.4. What is the current year in the Chinese calendar?
------------------------------------------------------
The current 60-year cycle started on 2 Feb 1984. That date bears the name
bing-yin in the 60-day cycle, and the first month of that first year
bears the name gui-chou in the 60-month cycle.
This means that the year gui-wei, the 20th year in the 78th cycle,
started on 1 Feb 2003.
10. Frequently Asked Questions about this FAQ
---------------------------------------------
This chapter does not answer questions about calendars. Instead it
answers questions that I am often asked about this document.
10.1. Why doesn't the FAQ describe calendar X?
----------------------------------------------
I am frequently asked to add a chapter describing the Japanese
calendar, the Ethiopian calendar, the Hindu calendar, etc.
But I have to stop somewhere. I have discovered that the more calendars
I include in the FAQ, the more difficult it becomes to ensure that the
information given is correct. I want to work on the quality rather
than the quantity of information in this document. It is therefore not
likely that other calendars will be added in the near future.
10.2. Why doesn't the FAQ contain information X?
------------------------------------------------
Obviously, I cannot include everything. So I have to prioritize. The
things that are most likely to be omitted from the FAQ are:
- Information that is relevant to a single country only.
- Views that are controversial and not supported by recognized
authorities.
10.3. Why don't you reply to my e-mail?
---------------------------------------
I try to reply to all the e-mail I receive. But occasionally the
amount of mail I receive is so large that I have to ignore some
letters. If this has caused your letter to be lost, I apologize.
But please don't let this stop you from writing to me. I enjoy
receiving letters, even if I can't answer them all.
10.4. How do I know that I can trust your information?
------------------------------------------------------
I have tried to be accurate in everything I have described. If you are
unsure about something that I write, I suggest that you try to verify
the information yourself. If you come across a recognized authority
that contradicts something that I've written, please let me know.
10.5. Can you recommend any good books about calendars?
-------------------------------------------------------
This is a big question because there are so many excellent books. At
this point I shall only recommend two books:
Edward M. Reingold & Nachum Dershowitz: "Calendrical Calculations.
The Millennium Edition". Cambridge University Press 2001.
ISBN 0-521-77752-6.
http://emr.cs.iit.edu/home/reingold/calendar-book/second-edition/index.html
This book contains a lot of information about a huge number of
calendars. As the title indicates, it has a strong emphasis on
algorithms for calendrical calculations, so if you want to use your
computer to compute calendars, this is a great book.
R. W. Bauer: "Calender for Aarene fra 601 til 2200". First published
in 1868. Reprinted 1993 by Dansk Historisk Faellesraad.
ISBN 87-7423-083-2
Unfortunately, this book is in Danish, but if you can read the
Scandinavian languages, this book will provide you with a wealth of
information, despite its age. Its main strength is a huge collection
of tables of various calendars. It does, however, only describe the
Christian calendar.
10.6. Do you know a web site where I can find information about X?
------------------------------------------------------------------
Probably not.
Good places to start your calendar search include:
http://www.calendarzone.com
http://personal.ecu.edu/mccartyr/calendar-reform.html
11. Date
--------
This version 2.6 of this document was finished on
Tuesday after the first Sunday after Trinity, the 24 of June
anno ab Incarnatione Domini MMIII, indict. XI, epacta XVII,
luna XXIV, anno post Margaretam Reginam Daniae natam LXIII, on
the feast of Saint John the Baptist.
The 24th day of Sivan, Anno Mundi 5763.
The 23rd day of Rabi' al-thani, Anno Hegirae 1424.
The 3rd day of Tir, Anno Persico 1382.
The 25th day of the 5th month of the year gui-wei of the 78th
cycle.
Julian Day 2,452,815.
calendar-3.0.0/calendar_faq.txt 0000664 0000000 0000000 00000316055 14321307032 0016431 0 ustar 00root root 0000000 0000000 URL: http://www.tondering.dk/claus/calendar.html
FREQUENTLY ASKED QUESTIONS ABOUT
CALENDARS
Version 2.3 - 25 Sep 2000
Copyright and disclaimer
------------------------
This document is Copyright (C) 2000 by Claus Tondering.
E-mail: claus@tondering.dk.
The document may be freely distributed, provided this
copyright notice is included and no money is charged for
the document.
This document is provided "as is". No warranties are made as
to its correctness.
Introduction
------------
This is the calendar FAQ. Its purpose is to give an overview
of the Christian, Hebrew, and Islamic calendars in common
use. It will provide a historical background for the Christian
calendar, plus an overview of the French Revolutionary
calendar, the Maya calendar, and the Chinese calendar.
Comments are very welcome. My e-mail address is given above.
I would like to thank
- Dr. Monzur Ahmed of the University of Birmingham, UK,
- Michael J Appel,
- Jay Ball,
- Tom Box,
- Chris Carrier,
- Simon Cassidy,
- Claus Dobesch,
- Leofranc Holford-Strevens,
- David B. Kelley of the Hamamatsu University School of
Medicine in Japan,
- H. Koenig,
- Graham Lewis,
- Duncan MacGregor,
- Marcos Montes,
- James E. Morrison,
- Waleed A. Muhanna of the Fisher College of Business,
Columbus, Ohio, USA,
- Stefan Potthast,
- Yves Sagnier of the Centre d'Etudes de la Navigation
Aerienne,
- Paul Schlyter of the Swedish Amateur Astronomer's Society
for their help with this document.
Changes since version 2.2
-------------------------
A few minor corrections have been made, the most interesting
being the new algorithm in section 5.8.
Writing dates and years
-----------------------
Dates will be written in the British format (1 January)
rather than the American format (January 1). Dates will
occasionally be abbreviated: "1 Jan" rather than "1 January".
Years before and after the "official" birth year of Christ
will be written "45 BC" or "AD 1997", respectively. I prefer
this notation over the secular "45 BCE" and "1997 CE"
(See also section 2.13.4.)
The 'mod' operator
------------------
Throughout this document the operator 'mod' will be used to
signify the modulo or remainder operator. For example,
17 mod 7=3 because the result of the division 17/7 is 2 with a
remainder of 3.
The text in square brackets
---------------------------
Square brackets [like this] identify information that I am
unsure about and about which I would like more
information. Please write me at claus@tondering.dk.
Index:
------
1. What Astronomical Events Form the Basis of Calendars?
1.1. What are equinoxes and solstices?
2. The Christian Calendar
2.1. What is the Julian calendar?
2.1.1. What years are leap years?
2.1.2. What consequences did the use of the Julian
calendar have?
2.2. What is the Gregorian calendar?
2.2.1. What years are leap years?
2.2.2. Isn't there a 4000-year rule?
2.2.3. Don't the Greek do it differently?
2.2.4. When did country X change from the Julian to
the Gregorian calendar?
2.3. What day is the leap day?
2.4. What is the Solar Cycle?
2.5. What day of the week was 2 August 1953?
2.6. When can I reuse my 1992 calendar?
2.7. What is the Roman calendar?
2.7.1. How did the Romans number days?
2.8. What is the proleptic calendar?
2.9. Has the year always started on 1 January?
2.10. Then what about leap years?
2.11. What is the origin of the names of the months?
2.12. What is Easter?
2.12.1. When is Easter? (Short answer)
2.12.2. When is Easter? (Long answer)
2.12.3. What is the Golden Number?
2.12.4. What is the Epact?
2.12.5. How does one calculate Easter then?
2.12.6. Isn't there a simpler way to calculate Easter?
2.12.7. Is there a simple relationship between two
consecutive Easters?
2.12.8. How frequently are the dates for Easter repeated?
2.12.9. What about Greek Easter?
2.12.10. Will the Easter dates change after 2001?
2.13. How does one count years?
2.13.1. How did Dionysius date Christ's birth?
2.13.2. Was Jesus born in the year 0?
2.13.3. When does the 3rd millennium start?
2.13.4. What do AD, BC, CE, and BCE stand for?
2.14. What is the Indiction?
2.15. What is the Julian period?
2.15.1. Is there a formula for calculating the Julian
day number?
2.15.2. What is the modified Julian day number?
2.16. What is the correct way to write dates?
3. The Hebrew Calendar
3.1. What does a Hebrew year look like?
3.2. What years are leap years?
3.3. What years are deficient, regular, and complete?
3.4. When is New Year's day?
3.5. When does a Hebrew day begin?
3.6. When does a Hebrew year begin?
3.7. When is the new moon?
3.8. How does one count years?
4. The Islamic Calendar
4.1. What does an Islamic year look like?
4.2. So you can't print an Islamic calendar in advance?
4.3. How does one count years?
4.4. When will the Islamic calendar overtake the Gregorian
calendar?
5. The Week
5.1. What is the origin of the 7-day week?
5.2. What do the names of the days of the week mean?
5.3. What is the system behind the planetary day names?
5.4. Has the 7-day week cycle ever been interrupted?
5.5. Which day is the day of rest?
5.6. What is the first day of the week?
5.7. What is the week number?
5.8. How can I calculate the week number?
5.9. Do weeks of different lengths exist?
6. The French Revolutionary Calendar
6.1. What does a Republican year look like?
6.2. How does one count years?
6.3. What years are leap years?
6.4. How does one convert a Republican date to a Gregorian one?
7. The Maya Calendar
7.1. What is the Long Count?
7.1.1. When did the Long Count start?
7.2. What is the Tzolkin?
7.2.1. When did the Tzolkin start?
7.3. What is the Haab?
7.3.1. When did the Haab start?
7.4. Did the Mayas think a year was 365 days?
8. The Chinese Calendar
8.1. What does the Chinese year look like?
8.2. What years are leap years?
8.3. How does one count years?
8.4. What is the current year in the Chinese calendar?
9. Frequently Asked Questions about this FAQ
9.1. Why doesn't the FAQ describe calendar X?
9.2. Why doesn't the FAQ contain information X?
9.3. Why don't you reply to my e-mail?
9.4. How do I know that I can trust your information?
9.5. Can you recommend any good books about calendars?
9.6. Do you know a web site where I can find information
about X?
10. Date
1. What Astronomical Events Form the Basis of Calendars?
--------------------------------------------------------
Calendars are normally based on astronomical events, and the two most
important astronomical objects are the sun and the moon. Their cycles
are very important in the construction and understanding of calendars.
Our concept of a year is based on the earth's motion around the sun.
The time from one fixed point, such as a solstice or equinox, to the
next is called a "tropical year". Its length is currently 365.242190
days, but it varies. Around 1900 its length was 365.242196 days, and
around 2100 it will be 365.242184 days. (This definition of the
tropical year is not quite accurate, see section 1.1 for more
details.)
Our concept of a month is based on the moon's motion around the earth,
although this connection has been broken in the calendar commonly used
now. The time from one new moon to the next is called a "synodic
month", and its length is currently 29.5305889 days, but it
varies. Around 1900 its length was 29.5305886 days, and around 2100 it
will be 29.5305891 days.
Note that these numbers are averages. The actual length of a
particular year may vary by several minutes due to the influence of
the gravitational force from other planets. Similary, the time between
two new moons may vary by several hours due to a number of factors,
including changes in the gravitational force from the sun, and the
moon's orbital inclination.
It is unfortunate that the length of the tropical year is not a
multiple of the length of the synodic month. This means that with 12
months per year, the relationship between our month and the moon
cannot be maintained.
However, 19 tropical years is 234.997 synodic months, which is very
close to an integer. So every 19 years the phases of the moon fall on
the same dates (if it were not for the skewness introduced by leap
years). 19 years is called a Metonic cycle (after Meton, an astronomer
from Athens in the 5th century BC).
So, to summarise: There are three important numbers to note:
A tropical year is 365.24219 days.
A synodic month is 29.53059 days.
19 tropical years is close to an integral number of synodic months.
The Christian calendar is based on the motion of the earth around the
sun, while the months retain no connection with the motion of the moon.
On the other hand, the Islamic calendar is based on the motion of the
moon, while the year has no connection with the motion of the earth
around the sun.
Finally, the Hebrew calendar combines both, in that its years are
linked to the motion of the earth around the sun, and its months are
linked to the motion of the moon.
1.1. What are equinoxes and solstices?
--------------------------------------
Equinoxes and solstices are frequently used as anchor points for
calendars. For people in the northern hemisphere:
- Winter solstice is the time in December when the sun reaches its
southernmost latitude. At this time we have the shortest day. The
date is near 21 December.
- Summer solstice is the time in June when the sun reaches its
northernmost latitude. At this time we have the longest day. The
date is near 21 June.
- Vernal equinox is the time in March when the sun passes the equator
moving from the southern to the northern hemisphere. Day and night
have approximately the same length. The date is near 20 March.
- Autumnal equinox is the time in September when the sun passes the
equator moving from the northern to the southern hemisphere. Day and
night have approximately the same length. The date is near
22 September.
For people in the southern hemisphere these events are shifted half a
year.
The astronomical "tropical year" is frequently defined as the time
between, say, two vernal equinoxes, but this is not actually true.
Currently the time between two vernal equinoxes is slightly greater
than the tropical year. The reason is that the earth's position in its
orbit at the time of solstices and equinoxes shifts slightly each year
(taking approximately 21,000 years to move all the way around the
orbit). This, combined with the fact that the earth's orbit is not
completely circular, causes the equinoxes and solstices to shift with
respect to each other.
The astronomer's mean tropical year is really a somewhat artificial
average of the period between the time when the sun is in any given
position in the sky with respect to the equinoxes and the next time
the sun is in the same position.
2. The Christian Calendar
-------------------------
The "Christian calendar" is the term traditionally used to designate
the calendar commonly in use, although its connection with
Christianity is highly debatable.
The Christian calendar has years of 365 or 366 days. It is divided into
12 months that have no relationship to the motion of the moon. In
parallel with this system, the concept of "weeks" groups the days in
sets of 7.
Two main versions of the Christian calendar have existed in recent
times: The Julian calendar and the Gregorian calendar. The difference
between them lies in the way they approximate the length of the
tropical year and their rules for calculating Easter.
2.1. What is the Julian calendar?
---------------------------------
The Julian calendar was introduced by Julius Caesar in 45 BC. It was
in common use until the 1500s, when countries started changing to the
Gregorian calendar (section 2.2). However, some countries (for
example, Greece and Russia) used it into the 1900s, and the Orthodox
church in Russia still uses it, as do some other Orthodox churches.
In the Julian calendar, the tropical year is approximated as 365 1/4
days = 365.25 days. This gives an error of 1 day in approximately 128
years.
The approximation 365 1/4 is achieved by having 1 leap year every 4
years.
2.1.1. What years are leap years?
---------------------------------
The Julian calendar has 1 leap year every 4 years:
Every year divisible by 4 is a leap year.
However, the 4-year rule was not followed in the first years after the
introduction of the Julian calendar in 45 BC. Due to a counting error,
every 3rd year was a leap year in the first years of this calendar's
existence. The leap years were:
45 BC(?), 42 BC, 39 BC, 36 BC, 33 BC, 30 BC,
27 BC, 24 BC, 21 BC, 18 BC, 15 BC, 12 BC, 9 BC,
AD 8, AD 12, and every 4th year from then on.
Authorities disagree about whether 45 BC was a leap year or not.
There were no leap years between 9 BC and AD 8 (or, according to some
authorities, between 12 BC and AD 4). This period without leap years
was decreed by emperor Augustus in order to make up for the surplus of
leap years introduced previously, and it earned him a place in the
calendar as the 8th month was named after him.
It is a curious fact that although the method of reckoning years after
the (official) birthyear of Christ was not introduced until the 6th
century, by some stroke of luck the Julian leap years coincide with
years of our Lord that are divisible by 4.
2.1.2. What consequences did the use of the Julian calendar have?
-----------------------------------------------------------------
The Julian calendar introduces an error of 1 day every 128 years. So
every 128 years the tropical year shifts one day backwards with
respect to the calendar. Furthermore, the method for calculating the
dates for Easter was inaccurate and needed to be refined.
In order to remedy this, two steps were necessary: 1) The Julian
calendar had to be replaced by something more adequate. 2) The extra
days that the Julian calendar had inserted had to be dropped.
The solution to problem 1) was the Gregorian calendar described in
section 2.2.
The solution to problem 2) depended on the fact that it was felt that
21 March was the proper day for vernal equinox (because 21 March was
the date for vernal equinox during the Council of Nicaea in AD
325). The Gregorian calendar was therefore calibrated to make that day
vernal equinox.
By 1582 vernal equinox had moved (1582-325)/128 days = approximately
10 days backwards. So 10 days had to be dropped.
2.2. What is the Gregorian calendar?
------------------------------------
The Gregorian calendar is the one commonly used today. It was proposed
by Aloysius Lilius, a physician from Naples, and adopted by Pope
Gregory XIII in accordance with instructions from the Council of Trent
(1545-1563) to correct for errors in the older Julian Calendar. It was
decreed by Pope Gregory XIII in a papal bull on 24 February 1582. This
bull is named "Inter Gravissimas" after its first two words.
In the Gregorian calendar, the tropical year is approximated as
365 97/400 days = 365.2425 days. Thus it takes approximately 3300
years for the tropical year to shift one day with respect to the
Gregorian calendar.
The approximation 365 97/400 is achieved by having 97 leap years
every 400 years.
2.2.1. What years are leap years?
---------------------------------
The Gregorian calendar has 97 leap years every 400 years:
Every year divisible by 4 is a leap year.
However, every year divisible by 100 is not a leap year.
However, every year divisible by 400 is a leap year after all.
So, 1700, 1800, 1900, 2100, and 2200 are not leap years. But 1600,
2000, and 2400 are leap years.
(Destruction of a myth: There are no double leap years, i.e. no
years with 367 days. See, however, the note on Sweden in section
2.2.4.)
2.2.2. Isn't there a 4000-year rule?
------------------------------------
It has been suggested (by the astronomer John Herschel (1792-1871)
among others) that a better approximation to the length of the
tropical year would be 365 969/4000 days = 365.24225 days. This would
dictate 969 leap years every 4000 years, rather than the 970 leap
years mandated by the Gregorian calendar. This could be achieved by
dropping one leap year from the Gregorian calendar every 4000 years,
which would make years divisible by 4000 non-leap years.
This rule has, however, not been officially adopted.
2.2.3. Don't the Greek do it differently?
-----------------------------------------
When the Orthodox church in Greece finally decided to switch to the
Gregorian calendar in the 1920s, they tried to improve on the
Gregorian leap year rules, replacing the "divisible by 400" rule by
the following:
Every year which when divided by 900 leaves a remainder of 200
or 600 is a leap year.
This makes 1900, 2100, 2200, 2300, 2500, 2600, 2700, 2800 non-leap
years, whereas 2000, 2400, and 2900 are leap years. This will not
create a conflict with the rest of the world until the year 2800.
This rule gives 218 leap years every 900 years, which gives us an
average year of 365 218/900 days = 365.24222 days, which is certainly
more accurate than the official Gregorian number of 365.2425 days.
However, this rule is *not* official in Greece.
2.2.4. When did country X change from the Julian to the Gregorian calendar?
---------------------------------------------------------------------------
The papal bull of February 1582 decreed that 10 days should be dropped
from October 1582 so that 15 October should follow immediately after
4 October, and from then on the reformed calendar should be used.
This was observed in Italy, Poland, Portugal, and Spain. Other Catholic
countries followed shortly after, but Protestant countries were
reluctant to change, and the Greek orthodox countries didn't change
until the start of the 1900s.
Changes in the 1500s required 10 days to be dropped.
Changes in the 1600s required 10 days to be dropped.
Changes in the 1700s required 11 days to be dropped.
Changes in the 1800s required 12 days to be dropped.
Changes in the 1900s required 13 days to be dropped.
(Exercise for the reader: Why is the error in the 1600s the same as
in the 1500s.)
The following list contains the dates for changes in a number of
countries. It is very strange that in many cases there seems to be
some doubt among authorities about what the correct days are.
Different sources give very different dates in some cases. The list
below does not include all the different opinions about when the
change took place.
Albania: December 1912
Austria: Different regions on different dates
Brixen, Salzburg and Tyrol:
5 Oct 1583 was followed by 16 Oct 1583
Carinthia and Styria:
14 Dec 1583 was followed by 25 Dec 1583
See also Czechoslovakia and Hungary
Belgium: See the Netherlands
Bulgaria: 31 Mar 1916 was followed by 14 Apr 1916
Canada: Different areas changed at different times.
Newfoundland and Hudson Bay coast:
2 Sep 1752 was followed by 14 Sep 1752
Mainland Nova Scotia:
Gregorian 1605 - 13 Oct 1710
Julian 2 Oct 1710 - 2 Sep 1752
Gregorian since 14 Sep 1752
Rest of Canada:
Gregorian from first European settlement
China: The Gregorian calendar replaced the Chinese calendar
in 1912, but the Gregorian calendar was not used
throughout the country until the communist revolution
of 1949.
Czechoslovakia (i.e. Bohemia and Moravia):
6 Jan 1584 was followed by 17 Jan 1584
Denmark (including Norway):
18 Feb 1700 was followed by 1 Mar 1700
Egypt: 1875
Estonia: 31 Jan 1918 was followed by 14 Feb 1918
Finland: Then part of Sweden. (Note, however, that Finland later
became part of Russia, which then still used the
Julian calendar. The Gregorian calendar remained
official in Finland, but some use of the Julian
calendar was made.)
France: 9 Dec 1582 was followed by 20 Dec 1582
Alsace: 5 Feb 1682 was followed by 16 Feb 1682
Lorraine: 16 Feb 1760 was followed by 28 Feb 1760
Strasbourg: February 1682
Germany: Different states on different dates:
Catholic states on various dates in 1583-1585
Prussia: 22 Aug 1610 was followed by 2 Sep 1610
Protestant states: 18 Feb 1700 was followed by 1 Mar 1700
(Many local variations)
Great Britain and Dominions:
2 Sep 1752 was followed by 14 Sep 1752
Greece: 9 Mar 1924 was followed by 23 Mar 1924
(Some sources say 1916 and 1920)
Hungary: 21 Oct 1587 was followed by 1 Nov 1587
Ireland: See Great Britain
Italy: 4 Oct 1582 was followed by 15 Oct 1582
Japan: The Gregorian calendar was introduced to supplement the
traditional Japanese calendar on 1 Jan 1873.
Latvia: During German occupation 1915 to 1918
Lithuania: 1915
Luxemburg: 14 Dec 1582 was followed by 25 Dec 1582
Netherlands (including Belgium):
Zeeland, Brabrant, and the "Staten Generaal":
14 Dec 1582 was followed by 25 Dec 1582
Holland:
1 Jan 1583 was followed by 12 Jan 1583
Limburg and the southern provinces (currently Belgium):
20 Dec 1582 was followed by 31 Dec 1582
or
21 Dec 1582 was followed by 1 Jan 1583
Groningen:
10 Feb 1583 was followed by 21 Feb 1583
Went back to Julian in the summer of 1594
31 Dec 1700 was followed by 12 Jan 1701
Gelderland:
30 Jun 1700 was followed by 12 Jul 1700
Utrecht and Overijssel:
30 Nov 1700 was followed by 12 Dec 1700
Friesland:
31 Dec 1700 was followed by 12 Jan 1701
Drenthe:
30 Apr 1701 was followed by 12 May 1701
Norway: Then part of Denmark.
Poland: 4 Oct 1582 was followed by 15 Oct 1582
Portugal: 4 Oct 1582 was followed by 15 Oct 1582
Romania: 31 Mar 1919 was followed by 14 Apr 1919
(The Greek Orthodox parts of the country may have
changed later)
Russia: 31 Jan 1918 was followed by 14 Feb 1918
(In the eastern parts of the country the change may
not have occured until 1920)
Scotland: Much confusion exists regarding Scotland's change. Different
authorities disagree about whether Scotland changed together
with the rest of Great Britain, or if they had changed
earlier.
Spain: 4 Oct 1582 was followed by 15 Oct 1582
Sweden (including Finland):
17 Feb 1753 was followed by 1 Mar 1753 (see note below)
Switzerland:
Catholic cantons: 1583, 1584 or 1597
Protestant cantons:
31 Dec 1700 was followed by 12 Jan 1701
(Many local variations)
Turkey: Gregorian calendar introduced 1 Jan 1927
United States: Different areas changed at different times.
Along the Eastern seaboard: With Great Britain in 1752.
Mississippi valley: With France in 1582.
Texas, Florida, California, Nevada, Arizona, New Mexico:
With Spain in 1582
Washington, Oregon: With Britain in 1752.
Alaska: October 1867 when Alaska became part of the USA.
Wales: See Great Britain
Yugoslavia: 1919
Sweden has a curious history. Sweden decided to make a gradual change
from the Julian to the Gregorian calendar. By dropping every leap year
from 1700 through 1740 the eleven superfluous days would be omitted
and from 1 Mar 1740 they would be in sync with the Gregorian
calendar. (But in the meantime they would be in sync with nobody!)
So 1700 (which should have been a leap year in the Julian calendar)
was not a leap year in Sweden. However, by mistake 1704 and 1708
became leap years. This left Sweden out of synchronisation with both
the Julian and the Gregorian world, so they decided to go *back* to
the Julian calendar. In order to do this, they inserted an extra day
in 1712, making that year a double leap year! So in 1712, February had
30 days in Sweden.
Later, in 1753, Sweden changed to the Gregorian calendar by dropping 11
days like everyone else.
2.3. What day is the leap day?
------------------------------
It is 24 February!
Weird? Yes! The explanation is related to the Roman calendar and is
found in section 2.7.1.
From a numerical point of view, of course 29 February is the extra
day. But from the point of view of celebration of feast days, the
following correspondence between days in leap years and non-leap
years has traditionally been used:
Non-leap year Leap year
------------- ----------
22 February 22 February
23 February 23 February
24 February (extra day)
24 February 25 February
25 February 26 February
26 February 27 February
27 February 28 February
28 February 29 February
For example, the feast of St. Leander has been celebrated on 27
February in non-leap years and on 28 February in leap years.
Many countries are gradually changing the leap day from the 24th to
the 29th. This affects countries such as Sweden and Austria that
celebrate "name days" (i.e. each day is associated with a name).
2.4. What is the Solar Cycle?
-----------------------------
In the Julian calendar the relationship between the days of the week
and the dates of the year is repeated in cycles of 28 years. In the
Gregorian calendar this is still true for periods that do not cross
years that are divisible by 100 but not by 400.
A period of 28 years is called a Solar Cycle. The "Solar Number" of a
year is found as:
Solar Number = (year + 8) mod 28 + 1
In the Julian calendar there is a one-to-one relationship between the
Solar Number and the day on which a particular date falls.
(The leap year cycle of the Gregorian calendar is 400 years, which is
146,097 days, which curiously enough is a multiple of 7. So in the
Gregorian calendar the equivalent of the "Solar Cycle" would be 400
years, not 7*400=2800 years as one might be tempted to believe.)
2.5. What day of the week was 2 August 1953?
--------------------------------------------
To calculate the day on which a particular date falls, the following
algorithm may be used (the divisions are integer divisions, in which
remainders are discarded):
a = (14 - month) / 12
y = year - a
m = month + 12*a - 2
For Julian calendar: d = (5 + day + y + y/4 + (31*m)/12) mod 7
For Gregorian calendar: d = (day + y + y/4 - y/100 + y/400 + (31*m)/12) mod 7
The value of d is 0 for a Sunday, 1 for a Monday, 2 for a Tuesday, etc.
Example: On what day of the week was the author born?
My birthday is 2 August 1953 (Gregorian, of course).
a = (14 - 8) / 12 = 0
y = 1953 - 0 = 1953
m = 8 + 12*0 - 2 = 6
d = (2 + 1953 + 1953/4 - 1953/100 + 1953/400 + (31*6)/12) mod 7
= (2 + 1953 + 488 - 19 + 4 + 15 ) mod 7
= 2443 mod 7
= 0
I was born on a Sunday.
2.6. When can I reuse my 1992 calendar?
---------------------------------------
Let us first assume that you are only interested in which dates fall
on which days of the week; you are not interested in the dates for
Easter and other irregular holidays.
Let us further confine ourselves to the years 1901-2099.
With these restrictions, the answer is as follows:
- If year X is a leap year, you can reuse its calendar in year X+28.
- If year X is the first year after a leap year, you can reuse its
calendar in years X+6, X+17, and X+28.
- If year X is the second year after a leap year, you can reuse its
calendar in years X+11, X+17, and X+28.
- If year X is the third year after a leap year, you can reuse its
calendar in years X+11, X+22, and X+28.
Note that the expression X+28 occurs in all four items above. So you
can always reuse your calendar every 28 years.
2.7. What is the Roman calendar?
--------------------------------
Before Julius Caesar introduced the Julian calendar in 45 BC, the
Roman calendar was a mess, and much of our so-called "knowledge" about
it seems to be little more than guesswork.
Originally, the year started on 1 March and consisted of only 304 days
or 10 months (Martius, Aprilis, Maius, Junius, Quintilis, Sextilis,
September, October, November, and December). These 304 days were
followed by an unnamed and unnumbered winter period. The Roman king
Numa Pompilius (c. 715-673 BC, although his historicity is disputed)
allegedly introduced February and January (in that order) between
December and March, increasing the length of the year to 354 or 355
days. In 450 BC, February was moved to its current position between
January and March.
In order to make up for the lack of days in a year, an extra month,
Intercalaris or Mercedonius, (allegedly with 22 or 23 days though some
authorities dispute this) was introduced in some years. In an 8 year
period the length of the years were:
1: 12 months or 355 days
2: 13 months or 377 days
3: 12 months or 355 days
4: 13 months or 378 days
5: 12 months or 355 days
6: 13 months or 377 days
7: 12 months or 355 days
8: 13 months or 378 days
A total of 2930 days corresponding to a year of 366 1/4 days. This
year was discovered to be too long, and therefore 7 days were later
dropped from the 8th year, yielding 365.375 days per year.
This is all theory. In practice it was the duty of the priesthood to
keep track of the calendars, but they failed miserably, partly due to
ignorance, partly because they were bribed to make certain years long
and other years short. Furthermore, leap years were considered unlucky
and were therefore avoided in time of crisis, such as the Second Punic
War.
In order to clean up this mess, Julius Caesar made his famous calendar
reform in 45 BC. We can make an educated guess about the length of the
months in the years 47 and 46 BC:
47 BC 46 BC
January 29 29
February 28 24
Intercalaris 27
March 31 31
April 29 29
May 31 31
June 29 29
Quintilis 31 31
Sextilis 29 29
September 29 29
October 31 31
November 29 29
Undecember 33
Duodecember 34
December 29 29
--- ---
Total 355 445
The length of the months from 45 BC onward were the same as the ones
we know today.
Occasionally one reads the following story:
"Julius Caesar made all odd numbered months 31 days long, and
all even numbered months 30 days long (with February having 29
days in non-leap years). In 44 BC Quintilis was renamed
'Julius' (July) in honour of Julius Caesar, and in 8 BC
Sextilis became 'Augustus' in honour of emperor Augustus. When
Augustus had a month named after him, he wanted his month to
be a full 31 days long, so he removed a day from February and
shifted the length of the other months so that August would
have 31 days."
This story, however, has no basis in actual fact. It is a fabrication
possibly dating back to the 14th century.
2.7.1. How did the Romans number days?
--------------------------------------
The Romans didn't number the days sequentially from 1. Instead they
had three fixed points in each month:
"Kalendae" (or "Calendae"), which was the first day of the month.
"Idus", which was the 13th day of January, February, April,
June, August, September, November, and December, or
the 15th day of March, May, July, or October.
"Nonae", which was the 9th day before Idus (counting Idus
itself as the 1st day).
The days between Kalendae and Nonae were called "the 5th day before
Nonae", "the 4th day before Nonae", "the 3rd day before Nonae", and
"the day before Nonae". (There was no "2nd day before Nonae". This was
because of the inclusive way of counting used by the Romans: To them,
Nonae itself was the first day, and thus "the 2nd day before" and "the
day before" would mean the same thing.)
Similarly, the days between Nonae and Idus were called "the Xth day
before Idus", and the days after Idus were called "the Xth day before
Kalendae (of the next month)".
Julius Caesar decreed that in leap years the "6th day before Kalendae
of March" should be doubled. So in contrast to our present system, in
which we introduce an extra date (29 February), the Romans had the
same date twice in leap years. The doubling of the 6th day before
Kalendae of March is the origin of the word "bissextile". If we
create a list of equivalences between the Roman days and our current
days of February in a leap year, we get the following:
7th day before Kalendae of March 23 February
6th day before Kalendae of March 24 February
6th day before Kalendae of March 25 February
5th day before Kalendae of March 26 February
4th day before Kalendae of March 27 February
3rd day before Kalendae of March 28 February
the day before Kalendae of March 29 February
Kalendae of March 1 March
You can see that the extra 6th day (going backwards) falls on what is
today 24 February. For this reason 24 February is still today
considered the "extra day" in leap years (see section 2.3). However,
at certain times in history the second 6th day (25 Feb) has been
considered the leap day.
Why did Caesar choose to double the 6th day before Kalendae of March?
It appears that the leap month Intercalaris/Mercedonius of the
pre-reform calendar was not placed after February, but inside it,
namely between the 7th and 6th day before Kalendae of March. It was
therefore natural to have the leap day in the same position.
2.8. What is the proleptic calendar?
------------------------------------
The Julian calendar was introduced in 45 BC, but when historians date
events prior to that year, they normally extend the Julian calendar
backward in time. This extended calendar is known as the "Julian
Proleptic Calendar".
Similarly, it is possible to extend the Gregorian calendar backward in
time before 1582. However, this "Gregorian Proleptic Calendar" is
rarely used.
If someone refers to, for example, 15 March 429 BC, they are probably
using the Julian proleptic calendar.
In the Julian proleptic calendar, year X BC is a leap year, if X-1 is
divisble by 4. This is the natural extension of the Julian leap year
rules.
2.9. Has the year always started on 1 January?
----------------------------------------------
For the man in the street, yes. When Julius Caesar introduced his
calendar in 45 BC, he made 1 January the start of the year, and it was
always the date on which the Solar Number and the Golden Number (see
section 2.12.3) were incremented.
However, the church didn't like the wild parties that took place at
the start of the new year, and in AD 567 the council of Tours declared
that having the year start on 1 January was an ancient mistake that
should be abolished.
Through the middle ages various New Year dates were used. If an
ancient document refers to year X, it may mean any of 7 different
periods in our present system:
- 1 Mar X to 28/29 Feb X+1
- 1 Jan X to 31 Dec X
- 1 Jan X-1 to 31 Dec X-1
- 25 Mar X-1 to 24 Mar X
- 25 Mar X to 24 Mar X+1
- Saturday before Easter X to Friday before Easter X+1
- 25 Dec X-1 to 24 Dec X
Choosing the right interpretation of a year number is difficult, so
much more as one country might use different systems for religious and
civil needs.
The Byzantine Empire used a year starting on 1 Sep, but they didn't
count years since the birth of Christ, instead they counted years
since the creation of the world which they dated to 1 September 5509 BC.
Since about 1600 most countries have used 1 January as the first day
of the year. Italy and England, however, did not make 1 January official
until around 1750.
In England (but not Scotland) three different years were used:
- The historical year, which started on 1 January.
- The liturgical year, which started on the first Sunday in advent.
- The civil year, which
from the 7th to the 12th century started on 25 December,
from the 12th century until 1751 started on 25 March,
from 1752 started on 1 January.
2.10. Then what about leap years?
---------------------------------
If the year started on, for example, 1 March, two months later than
our present year, when was the leap day inserted?
[The following information is to the best of my knowledge true. If
anyone can confirm or refute it, please let me know.]
When it comes to choosing a leap year, a year starting on 1 January
has always been used. So, in a country using a year starting on 1 March,
1439 would have been a leap year, because their February 1439 would
correspond to February 1440 in the January-based reckoning, and 1440
is divisible by 4.
2.11. What is the origin of the names of the months?
---------------------------------------------------
A lot of languages, including English, use month names based on Latin.
Their meaning is listed below. However, some languages (Czech and
Polish, for example) use quite different names.
January Latin: Januarius. Named after the god Janus.
February Latin: Februarius. Named after Februa, the purification
festival.
March Latin: Martius. Named after the god Mars.
April Latin: Aprilis. Named either after the goddess Aphrodite or
the Latin word "aperire", to open.
May Latin: Maius. Probably named after the goddess Maia.
June Latin: Junius. Probably named after the goddess Juno.
July Latin: Julius. Named after Julius Caesar in 44 BC. Prior
to that time its name was Quintilis from the word
"quintus", fifth, because it was the 5th month in the old
Roman calendar.
August Latin: Augustus. Named after emperor Augustus in 8
BC. Prior to that time the name was Sextilis from the
word "sextus", sixth, because it was the 6th month in the
old Roman calendar.
September Latin: September. From the word "septem", seven, because
it was the 7th month in the old Roman calendar.
October Latin: October. From the word "octo", eight, because it
was the 8th month in the old Roman calendar.
November Latin: November. From the word "novem", nine, because it
was the 9th month in the old Roman calendar.
December Latin: December. From the word "decem", ten, because it
was the 10th month in the old Roman calendar.
2.12. What is Easter?
---------------------
In the Christian world, Easter (and the days immediately preceding it)
is the celebration of the death and resurrection of Jesus in
(approximately) AD 30.
2.12.1. When is Easter? (Short answer)
--------------------------------------
Easter Sunday is the first Sunday after the first full moon after
vernal equinox.
2.12.2. When is Easter? (Long answer)
-------------------------------------
The calculation of Easter is complicated because it is linked to (an
inaccurate version of) the Hebrew calendar.
Jesus was crucified immediately before the Jewish Passover, which is a
celebration of the Exodus from Egypt under Moses. Celebration of
Passover started on the 14th or 15th day of the (spring) month of
Nisan. Jewish months start when the moon is new, therefore the 14th or
15th day of the month must be immediately after a full moon.
It was therefore decided to make Easter Sunday the first Sunday after
the first full moon after vernal equinox. Or more precisely: Easter
Sunday is the first Sunday after the *official* full moon on or after
the *official* vernal equinox.
The official vernal equinox is always 21 March.
The official full moon may differ from the *real* full moon by one or
two days.
(Note, however, that historically, some countries have used the *real*
(astronomical) full moon instead of the official one when calculating
Easter. This was the case, for example, of the German Protestant states,
which used the astronomical full moon in the years 1700-1776. A
similar practice was used Sweden in the years 1740-1844 and in Denmark
in the 1700s.)
The full moon that precedes Easter is called the Paschal full
moon. Two concepts play an important role when calculating the Paschal
full moon: The Golden Number and the Epact. They are described in the
following sections.
The following sections give details about how to calculate the date
for Easter. Note, however, that while the Julian calendar was in use,
it was customary to use tables rather than calculations to determine
Easter. The following sections do mention how to calcuate Easter under
the Julian calendar, but the reader should be aware that this is an
attempt to express in formulas what was originally expressed in
tables. The formulas can be taken as a good indication of when Easter
was celebrated in the Western Church from approximately the 6th
century.
2.12.3. What is the Golden Number?
----------------------------------
Each year is associated with a Golden Number.
Considering that the relationship between the moon's phases and the
days of the year repeats itself every 19 years (as described in
section 1), it is natural to associate a number between 1 and 19
with each year. This number is the so-called Golden Number. It is
calculated thus:
GoldenNumber = (year mod 19)+1
In years which have the same Golden Number, the new moon will fall on
(approximately) the same date.
2.12.4. What is the Epact?
--------------------------
Each year is associated with an Epact.
The Epact is a measure of the age of the moon (i.e. the number of days
that have passed since an "official" new moon) on a particular date.
In the Julian calendar, 8 + the Epact is the age of the moon at the
start of the year.
In the Gregorian calendar, the Epact is the age of the moon at the
start of the year.
The Epact is linked to the Golden Number in the following manner:
Under the Julian calendar, 19 years were assumed to be exactly an
integral number of synodic months, and the following relationship
exists between the Golden Number and the Epact:
Epact = (11 * (GoldenNumber-1)) mod 30
If this formula yields zero, the Epact is by convention frequently
designated by the symbol * and its value is said to be 30. Weird?
Maybe, but people didn't like the number zero in the old days.
Since there are only 19 possible golden numbers, the Epact can have
only 19 different values: 1, 3, 4, 6, 7, 9, 11, 12, 14, 15, 17, 18, 20,
22, 23, 25, 26, 28, and 30.
The Julian system for calculating full moons was inaccurate, and under
the Gregorian calendar, some modifications are made to the simple
relationship between the Golden Number and the Epact.
In the Gregorian calendar the Epact should be calculated thus (the
divisions are integer divisions, in which remainders are discarded):
1) Use the Julian formula:
Epact = (11 * (GoldenNumber-1)) mod 30
2) Adjust the Epact, taking into account the fact that 3 out of 4
centuries have one leap year less than a Julian century:
Epact = Epact - (3*century)/4
(For the purpose of this calculation century=20 is used for the
years 1900 through 1999, and similarly for other centuries,
although this contradicts the rules in section 2.13.3.)
3) Adjust the Epact, taking into account the fact that 19 years is not
exactly an integral number of synodic months:
Epact = Epact + (8*century + 5)/25
(This adds one to the Epact 8 times every 2500 years.)
4) Add 8 to the Epact to make it the age of the moon on 1 January:
Epact = Epact + 8
5) Add or subtract 30 until the Epact lies between 1 and 30.
In the Gregorian calendar, the Epact can have any value from 1 to 30.
Example: What was the Epact for 1992?
GoldenNumber = 1992 mod 19 + 1 = 17
1) Epact = (11 * (17-1)) mod 30 = 26
2) Epact = 26 - (3*20)/4 = 11
3) Epact = 11 + (8*20 + 5)/25 = 17
4) Epact = 17 + 8 = 25
5) Epact = 25
The Epact for 1992 was 25.
2.12.5. How does one calculate Easter then?
-------------------------------------------
To find Easter the following algorithm is used:
1) Calculate the Epact as described in the previous section.
2) For the Julian calendar: Add 8 to the Epact. (For the Gregorian
calendar, this has already been done in step 4 of the calculation of
the Epact). Subtract 30 if the sum exceeds 30.
3) Look up the Epact (as possibly modified in step 2) in this table to
find the date for the Paschal full moon:
Epact Full moon Epact Full moon Epact Full moon
----------------- ----------------- -----------------
1 12 April 11 2 April 21 23 March
2 11 April 12 1 April 22 22 March
3 10 April 13 31 March 23 21 March
4 9 April 14 30 March 24 18 April
5 8 April 15 29 March 25 18 or 17 April
6 7 April 16 28 March 26 17 April
7 6 April 17 27 March 27 16 April
8 5 April 18 26 March 28 15 April
9 4 April 19 25 March 29 14 April
10 3 April 20 24 March 30 13 April
4) Easter Sunday is the first Sunday following the above full moon
date. If the full moon falls on a Sunday, Easter Sunday is the
following Sunday.
An Epact of 25 requires special treatment, as it has two dates in the
above table. There are two equivalent methods for choosing the correct
full moon date:
A) Choose 18 April, unless the current century contains years with an
epact of 24, in which case 17 April should be used.
B) If the Golden Number is > 11 choose 17 April, otherwise choose 18 April.
The proof that these two statements are equivalent is left as an
exercise to the reader. (The frustrated ones may contact me for the
proof.)
Example: When was Easter in 1992?
In the previous section we found that the Golden Number for 1992 was
17 and the Epact was 25. Looking in the table, we find that the
Paschal full moon was either 17 or 18 April. By rule B above, we
choose 17 April because the Golden Number > 11.
17 April 1992 was a Friday. Easter Sunday must therefore have been
19 April.
2.12.6. Isn't there a simpler way to calculate Easter?
------------------------------------------------------
This is an attempt to boil down the information given in the previous
sections (the divisions are integer divisions, in which remainders are
discarded):
G = year mod 19
For the Julian calendar:
I = (19*G + 15) mod 30
J = (year + year/4 + I) mod 7
For the Gregorian calendar:
C = year/100
H = (C - C/4 - (8*C+13)/25 + 19*G + 15) mod 30
I = H - (H/28)*(1 - (H/28)*(29/(H + 1))*((21 - G)/11))
J = (year + year/4 + I + 2 - C + C/4) mod 7
Thereafter, for both calendars:
L = I - J
EasterMonth = 3 + (L + 40)/44
EasterDay = L + 28 - 31*(EasterMonth/4)
This algorithm is based in part on the algorithm of Oudin (1940) as
quoted in "Explanatory Supplement to the Astronomical Almanac",
P. Kenneth Seidelmann, editor.
People who want to dig into the workings of this algorithm, may be
interested to know that
G is the Golden Number-1
H is 23-Epact (modulo 30)
I is the number of days from 21 March to the Paschal full moon
J is the weekday for the Paschal full moon (0=Sunday, 1=Monday,
etc.)
L is the number of days from 21 March to the Sunday on or before
the Paschal full moon (a number between -6 and 28)
2.12.7. Is there a simple relationship between two consecutive Easters?
-----------------------------------------------------------------------
Suppose you know the Easter date of the current year, can you easily
find the Easter date in the next year? No, but you can make a
qualified guess.
If Easter Sunday in the current year falls on day X and the next year
is not a leap year, Easter Sunday of next year will fall on one of the
following days: X-15, X-8, X+13 (rare), or X+20.
If Easter Sunday in the current year falls on day X and the next year
is a leap year, Easter Sunday of next year will fall on one of the
following days: X-16, X-9, X+12 (extremely rare), or X+19. (The jump
X+12 occurs only once in the period 1800-2200, namely when going from
2075 to 2076.)
If you combine this knowledge with the fact that Easter Sunday never
falls before 22 March and never falls after 25 April, you can
narrow the possibilities down to two or three dates.
2.12.8. How frequently are the dates for Easter repeated?
---------------------------------------------------------
The sequence of Easter dates repeats itself every 532 years in the
Julian calendar. The number 532 is the product of the following
numbers:
19 (the Metonic cycle or the cycle of the Golden Number)
28 (the Solar cycle, see section 2.4)
The sequence of Easter dates repeats itself every 5,700,000 years in
the Gregorian calendar. Calculating this is not as simple as for the
Julian calendar, but the number 5,700,000 turns out to be the product
of the following numbers:
19 (the Metonic cycle or the cycle of the Golden Number)
400 (the Gregorian equivalent of the Solar cycle, see section 2.4)
25 (the cycle used in step 3 when calculating the Epact)
30 (the number of different Epact values)
2.12.9. What about Greek Easter?
--------------------------------
The Greek Orthodox Church does not always celebrate Easter on the same
day as the Catholic and Protestant countries. The reason is that the
Orthodox Church uses the Julian calendar when calculating Easter. This
is case even in the churches that otherwise use the Gregorian
calendar.
When the Greek Orthodox Church in 1923 decided to change to the
Gregorian calendar (or rather: a Revised Julian Calendar), they chose
to use the astronomical full moon as the basis for calculating Easter,
rather than the "official" full moon described in the previous
sections. And they chose the meridian of Jerusalem to serve as
definition of when a Sunday starts. However, except for some sporadic
use the 1920s, this system was never adopted in practice.
2.12.10. Will the Easter dates change after 2001?
-------------------------------------------------
No.
At at meeting in Aleppo, Syria (5-10 March 1997), organised by the
World Council of Churches and the Middle East Council of Churches,
representatives of several churches and Christian world communions
suggested that the discrepancies between Easter calculations in the
Western and the Eastern churches could be resolved by adopting
astronomically accurate calculations of the vernal equinox and the
full moon, instead of using the algorithm presented in section 2.12.5.
The meridian of Jerusalem should be used for the astronomical
calculations.
The new method for calculating Easter should take effect from the year
2001. In that year the Julian and Gregorian Easter dates coincide (on
15 April Gregorian/2 April Julian), and it would therefore be a
reasonable starting point for the new system.
However, the Eastern churches (especially the Russian Orthodox Church)
are reluctant to change, having already experienced a schism in the
calendar question. So nothing will happen in the near future.
If the new system were introduced, churches using the Gregorian
calendar will hardly notice the change. Only once during the period
2001-2025 would these churches note a difference: In 2019 the
Gregorian method gives an Easter date of 21 April, but the proposed
new method gives 24 March.
Note that the new method makes an Easter date of 21 March possible.
This date was not possible under the Julian or Gregorian algorithms.
(Under the new method, Easter will fall on 21 March in the year 2877.
You're all invited to my house on that date!)
2.13. How does one count years?
-------------------------------
In about AD 523, the papal chancellor, Bonifatius, asked a monk by the
name of Dionysius Exiguus to devise a way to implement the rules from
the Nicean council (the so-called "Alexandrine Rules") for general
use.
Dionysius Exiguus (in English known as Denis the Little) was a monk
from Scythia, he was a canon in the Roman curia, and his assignment
was to prepare calculations of the dates of Easter. At that time it
was customary to count years since the reign of emperor Diocletian;
but in his calculations Dionysius chose to number the years since the
birth of Christ, rather than honour the persecutor Diocletian.
Dionysius (wrongly) fixed Jesus' birth with respect to Diocletian's
reign in such a manner that it falls on 25 December 753 AUC (ab urbe
condita, i.e. since the founding of Rome), thus making the current era
start with AD 1 on 1 January 754 AUC.
How Dionysius established the year of Christ's birth is not known (see
section 2.13.1 for a couple of theories). Jesus was born under the
reign of king Herod the Great, who died in 750 AUC, which means that
Jesus could have been born no later than that year. Dionysius'
calculations were disputed at a very early stage.
When people started dating years before 754 AUC using the term "Before
Christ", they let the year 1 BC immediately precede AD 1 with no
intervening year zero.
Note, however, that astronomers frequently use another way of
numbering the years BC. Instead of 1 BC they use 0, instead of 2 BC
they use -1, instead of 3 BC they use -2, etc.
See also section 2.13.2.
It is sometimes claimed that it was the Venerable Bede (673-735) who
introduced BC dating. Although Bede seems to have used the term on at
least one occasion, it is generally believed that BC dates were not
used until the middle of the 17th century.
In this section I have used AD 1 = 754 AUC. This is the most likely
equivalence between the two systems. However, some authorities state
that AD 1 = 753 AUC or 755 AUC. This confusion is not a modern one, it
appears that even the Romans were in some doubt about how to count
the years since the founding of Rome.
2.13.1. How did Dionysius date Christ's birth?
----------------------------------------------
There are quite a few theories about this. And many of the theories
are presented as if they were indisputable historical fact.
Here are two theories that I personally consider likely:
1. According to the Gospel of Luke (3:1 & 3:23) Jesus was "about
thirty years old" shortly after "the fifteenth year of the reign of
Tiberius Caesar". Tiberius became emperor in AD 14. If you combine
these numbers you reach a birthyear for Jesus that is strikingly
close to the beginning of our year reckoning. This may have been
the basis for Dionysius' calculations.
2. Dionysius' original task was to calculate an Easter table. In the
Julian calendar, the dates for Easter repeat every 532 years (see
section 2.12.8). The first year in Dionysius' Easter tables is AD
532. Is it a coincidence that the number 532 appears twice here? Or
did Dionysius perhaps fix Jesus' birthyear so that his own Easter
tables would start exactly at the beginning of the second Easter
cycle after Jesus' birth?
2.13.2. Was Jesus born in the year 0?
-------------------------------------
No.
There are two reasons for this:
- There is no year 0.
- Jesus was born before 4 BC.
The concept of a year "zero" is a modern myth (but a very popular one).
Roman numerals do not have a figure designating zero, and treating zero
as a number on an equal footing with other numbers was not common in
the 6th century when our present year reckoning was established by
Dionysius Exiguus (see section 2.13). Dionysius let the year AD 1
start one week after what he believed to be Jesus' birthday.
Therefore, AD 1 follows immediately after 1 BC with no intervening
year zero. So a person who was born in 10 BC and died in AD 10,
would have died at the age of 19, not 20.
Furthermore, Dionysius' calculations were wrong. The Gospel of
Matthew tells us that Jesus was born under the reign of king Herod the
Great, and he died in 4 BC. It is likely that Jesus was actually born
around 7 BC. The date of his birth is unknown; it may or may not be 25
December.
2.13.3. When does the 3rd millennium start?
-------------------------------------------
The first millennium started in AD 1, so the millennia are counted in
this manner:
1st millennium: 1-1000
2nd millennium: 1001-2000
3rd millennium: 2001-3000
Thus, the 3rd millennium and, similarly, the 21st century start on
1 Jan 2001.
This is the cause of some heated debate, especially since some
dictionaries and encyclopaedias say that a century starts in years
that end in 00. Furthermore, the change 1999/2000 is obviously much
more spectacular than the change 2000/2001.
Let me propose a few compromises:
Any 100-year period is a century. Therefore the period from 23 June 2002
to 22 June 2102 is a century. So please feel free to celebrate the
start of a century any day you like!
Although the 20th century started in 1901, the 1900s started in 1900.
Similarly, we celebrated the start of the 2000s in 2000 and we can
celebrate the start of the 21st century in 2001.
2.13.4. What do AD, BC, CE, and BCE stand for?
----------------------------------------------
Years before the birth of Christ are in English traditionally
identified using the abbreviation BC ("Before Christ").
Years after the birth of Christ are traditionally identified using the
Latin abbreviation AD ("Anno Domini", that is, "In the Year of the
Lord").
Some people, who want to avoid the reference to Christ that is implied
in these terms, prefer the abbreviations BCE ("Before the Common Era"
or "Before the Christian Era") and CE ("Common Era" or "Christian Era").
2.14. What is the Indiction?
----------------------------
The Indiction was used in the middle ages to specify the position of a
year in a 15 year taxation cycle. It was introduced by emperor
Constantine the Great on 1 September 312 and ceased to be used in
1806.
The Indiction may be calculated thus:
Indiction = (year + 2) mod 15 + 1
The Indiction has no astronomical significance.
The Indiction did not always follow the calendar year. Three different
Indictions may be identified:
1) The Pontifical or Roman Indiction, which started on New Year's Day
(being either 25 December, 1 January, or 25 March).
2) The Greek or Constantinopolitan Indiction, which started on 1 September.
3) The Imperial Indiction or Indiction of Constantine, which started
on 24 September.
2.15. What is the Julian Period?
--------------------------------
The Julian period (and the Julian day number) must not be confused
with the Julian calendar.
The French scholar Joseph Justus Scaliger (1540-1609) was interested
in assigning a positive number to every year without having to worry
about BC/AD. He invented what is today known as the "Julian Period".
The Julian Period probably takes its name from the Julian calendar,
although it has been claimed that it is named after Scaliger's father,
the Italian scholar Julius Caesar Scaliger (1484-1558).
Scaliger's Julian period starts on 1 January 4713 BC (Julian calendar)
and lasts for 7980 years. AD 2000 is thus year 6713 in the Julian
period. After 7980 years the number starts from 1 again.
Why 4713 BC and why 7980 years? Well, in 4713 BC the Indiction (see
section 2.14), the Golden Number (see section 2.12.3) and the Solar
Number (see section 2.4) were all 1. The next times this happens is
15*19*28=7980 years later, in AD 3268.
Astronomers have used the Julian period to assign a unique number to
every day since 1 January 4713 BC. This is the so-called Julian Day
(JD). JD 0 designates the 24 hours from noon UTC on 1 January 4713 BC
to noon UTC on 2 January 4713 BC.
This means that at noon UTC on 1 January AD 2000, JD 2,451,545
started.
This can be calculated thus:
From 4713 BC to AD 2000 there are 6712 years.
In the Julian calendar, years have 365.25 days, so 6712 years
correspond to 6712*365.25=2,451,558 days. Subtract from this
the 13 days that the Gregorian calendar is ahead of the Julian
calendar, and you get 2,451,545.
Often fractions of Julian day numbers are used, so that 1 January AD
2000 at 15:00 UTC is referred to as JD 2,451,545.125.
Note that some people use the term "Julian day number" to refer to any
numbering of days. NASA, for example, uses the term to denote the
number of days since 1 January of the current year.
2.15.1. Is there a formula for calculating the Julian day number?
-----------------------------------------------------------------
Try this one (the divisions are integer divisions, in which remainders
are discarded):
a = (14-month)/12
y = year+4800-a
m = month + 12*a - 3
For a date in the Gregorian calendar:
JD = day + (153*m+2)/5 + y*365 + y/4 - y/100 + y/400 - 32045
For a date in the Julian calendar:
JD = day + (153*m+2)/5 + y*365 + y/4 - 32083
JD is the Julian day number that starts at noon UTC on the specified
date.
The algorithm works fine for AD dates. If you want to use it for BC
dates, you must first convert the BC year to a negative year (e.g.,
10 BC = -9). The algorithm works correctly for all dates after 4800 BC,
i.e. at least for all positive Julian day numbers.
To convert the other way (i.e., to convert a Julian day number, JD,
to a day, month, and year) these formulas can be used (again, the
divisions are integer divisions):
For the Gregorian calendar:
a = JD + 32044
b = (4*a+3)/146097
c = a - (b*146097)/4
For the Julian calendar:
b = 0
c = JD + 32082
Then, for both calendars:
d = (4*c+3)/1461
e = c - (1461*d)/4
m = (5*e+2)/153
day = e - (153*m+2)/5 + 1
month = m + 3 - 12*(m/10)
year = b*100 + d - 4800 + m/10
2.15.2. What is the modified Julian day number?
-----------------------------------------------
Sometimes a modified Julian day number (MJD) is used which is
2,400,000.5 less than the Julian day number. This brings the numbers
into a more manageable numeric range and makes the day numbers change
at midnight UTC rather than noon.
MJD 0 thus started on 17 Nov 1858 (Gregorian) at 00:00:00 UTC.
2.16. What is the correct way to write dates?
---------------------------------------------
The answer to this question depends on what you mean by "correct".
Different countries have different customs.
Most countries use a day-month-year format, such as:
25.12.1998 25/12/1998 25/12-1998 25.XII.1998
In the U.S.A. a month-day-year format is common:
12/25/1998 12-25-1998
International standard ISO-8601 mandates a year-month-day format,
namely either 1998-12-25 or 19981225.
In all of these systems, the first two digits of the year are
frequently omitted:
25.12.98 12/25/98 98-12-25
This confusion leads to misunderstandings. What is 02-03-04? To most
people it is 2 Mar 2004; to an American it is 3 Feb 2004; and to a
person using the international standard it would be 4 Mar 2002.
If you want to be sure that people understand you, I recommend that
you
* write the month with letters instead of numbers, and
* write the years as 4-digit numbers.
3. The Hebrew Calendar
----------------------
The current definition of the Hebrew calendar is generally said to
have been set down by the Sanhedrin president Hillel II in
approximately AD 359. The original details of his calendar are,
however, uncertain.
The Hebrew calendar is used for religious purposes by Jews all over
the world, and it is the official calendar of Israel.
The Hebrew calendar is a combined solar/lunar calendar, in that it
strives to have its years coincide with the tropical year and its
months coincide with the synodic months. This is a complicated goal,
and the rules for the Hebrew calendar are correspondingly
fascinating.
3.1. What does a Hebrew year look like?
---------------------------------------
An ordinary (non-leap) year has 353, 354, or 355 days.
A leap year has 383, 384, or 385 days.
The three lengths of the years are termed, "deficient", "regular",
and "complete", respectively.
An ordinary year has 12 months, a leap year has 13 months.
Every month starts (approximately) on the day of a new moon.
The months and their lengths are:
Length in a Length in a Length in a
Name deficient year regular year complete year
------- -------------- ------------ -------------
Tishri 30 30 30
Heshvan 29 29 30
Kislev 29 30 30
Tevet 29 29 29
Shevat 30 30 30
(Adar I 30 30 30)
Adar II 29 29 29
Nisan 30 30 30
Iyar 29 29 29
Sivan 30 30 30
Tammuz 29 29 29
Av 30 30 30
Elul 29 29 29
------- -------------- ------------ -------------
Total: 353 or 383 354 or 384 355 or 385
The month Adar I is only present in leap years. In non-leap years
Adar II is simply called "Adar".
Note that in a regular year the numbers 30 and 29 alternate; a
complete year is created by adding a day to Heshvan, whereas a
deficient year is created by removing a day from Kislev.
The alteration of 30 and 29 ensures that when the year starts with a
new moon, so does each month.
3.2. What years are leap years?
-------------------------------
A year is a leap year if the number 'year mod 19' is one of the
following: 0, 3, 6, 8, 11, 14, or 17.
The value for year in this formula is the "Anno Mundi" described in
section 3.8.
3.3. What years are deficient, regular, and complete?
-----------------------------------------------------
That is the wrong question to ask. The correct question to ask is: When
does a Hebrew year begin? Once you have answered that question (see
section 3.6), the length of the year is the number of days between
1 Tishri in one year and 1 Tishri in the following year.
3.4. When is New Year's day?
----------------------------
That depends. Jews have 4 different days to choose from:
1 Tishri: "Rosh HaShanah". This day is a celebration of the creation
of the world and marks the start of a new calendar
year. This will be the day we shall base our calculations on
in the following sections.
15 Shevat: "Tu B'shevat". The new year for trees, when fruit tithes
should be brought.
1 Nisan: "New Year for Kings". Nisan is considered the first month,
although it occurs 6 or 7 months after the start of the
calendar year.
1 Elul: "New Year for Animal Tithes (Taxes)".
Only the first two dates are celebrated nowadays.
3.5. When does a Hebrew day begin?
----------------------------------
A Hebrew-calendar day does not begin at midnight, but at either sunset
or when three medium-sized stars should be visible, depending on the
religious circumstance.
Sunset marks the start of the 12 night hours, whereas sunrise marks the
start of the 12 day hours. This means that night hours may be longer
or shorter than day hours, depending on the season.
3.6. When does a Hebrew year begin?
-----------------------------------
The first day of the calendary year, Rosh HaShanah, on 1 Tishri is
determined as follows:
1) The new year starts on the day of the new moon that occurs about
354 days (or 384 days if the previous year was a leap year) after
1 Tishri of the previous year
2) If the new moon occurs after noon on that day, delay the new year
by one day. (Because in that case the new crescent moon will not be
visible until the next day.)
3) If this would cause the new year to start on a Sunday, Wednesday,
or Friday, delay it by one day. (Because we want to avoid that
Yom Kippur (10 Tishri) falls on a Friday or Sunday, and that
Hoshanah Rabba (21 Tishri) falls on a Sabbath (Saturday)).
4) If two consecutive years start 356 days apart (an illegal year
length), delay the start of the first year by two days.
5) If two consecutive years start 382 days apart (an illegal year
length), delay the start of the second year by one day.
Note: Rule 4 can only come into play if the first year was supposed
to start on a Tuesday. Therefore a two day delay is used rather that a
one day delay, as the year must not start on a Wednesday as stated in
rule 3.
3.7. When is the new moon?
--------------------------
A calculated new moon is used. In order to understand the
calculations, one must know that an hour is subdivided into 1080
"parts".
The calculations are as follows:
The new moon that started the year AM 1, occurred 5 hours and 204
parts after sunset (i.e. just before midnight on Julian date 6 October
3761 BC).
The new moon of any particular year is calculated by extrapolating
from this time, using a synodic month of 29 days 12 hours and 793
parts.
Note that 18:00 Jerusalem time (15:39 UTC) is used instead of sunset in
all these calculations.
3.8. How does one count years?
------------------------------
Years are counted since the creation of the world, which is assumed to
have taken place in 3761 BC. In that year, AM 1 started (AM = Anno
Mundi = year of the world).
In the year AD 2000 we will witness the start of Hebrew year AM 5761.
4. The Islamic Calendar
-----------------------
The Islamic calendar (or Hijri calendar) is a purely lunar
calendar. It contains 12 months that are based on the motion of the
moon, and because 12 synodic months is only 12*29.53=354.36 days, the
Islamic calendar is consistently shorter than a tropical year, and
therefore it shifts with respect to the Christian calendar.
The calendar is based on the Qur'an (Sura IX, 36-37) and its proper
observance is a sacred duty for Muslims.
The Islamic calendar is the official calendar in countries around the
Gulf, especially Saudi Arabia. But other Muslim countries use the
Gregorian calendar for civil purposes and only turn to the Islamic
calendar for religious purposes.
4.1. What does an Islamic year look like?
-----------------------------------------
The names of the 12 months that comprise the Islamic year are:
1. Muharram 7. Rajab
2. Safar 8. Sha'ban
3. Rabi' al-awwal (Rabi' I) 9. Ramadan
4. Rabi' al-thani (Rabi' II) 10. Shawwal
5. Jumada al-awwal (Jumada I) 11. Dhu al-Qi'dah
6. Jumada al-thani (Jumada II) 12. Dhu al-Hijjah
(Due to different transliterations of the Arabic alphabet, other
spellings of the months are possible.)
Each month starts when the lunar crescent is first seen (by an actual
human being) after a new moon.
Although new moons may be calculated quite precisely, the actual
visibility of the crescent is much more difficult to predict. It
depends on factors such as weather, the optical properties of the
atmosphere, and the location of the observer. It is therefore very
difficult to give accurate information in advance about when a new
month will start.
Furthermore, some Muslims depend on a local sighting of the moon,
whereas others depend on a sighting by authorities somewhere in the
Muslim world. Both are valid Islamic practices, but they may lead to
different starting days for the months.
4.2. So you can't print an Islamic calendar in advance?
-------------------------------------------------------
Not a reliable one. However, calendars are printed for planning
purposes, but such calendars are based on estimates of the visibility
of the lunar crescent, and the actual month may start a day earlier or
later than predicted in the printed calendar.
Different methods for estimating the calendars are used.
Some sources mention a crude system in which all odd numbered months
have 30 days and all even numbered months have 29 days with an extra
day added to the last month in "leap years" (a concept otherwise
unknown in the calendar). Leap years could then be years in which the
number 'year mod 30' is one of the following: 2, 5, 7, 10, 13, 16, 18,
21, 24, 26, or 29. (This is the algorithm used in the calendar program
of the Gnu Emacs editor.)
Such a calendar would give an average month length of 29.53056 days,
which is quite close to the synodic month of 29.53059 days, so *on the
average* it would be quite accurate, but in any given month it is
still just a rough estimate.
Better algorithms for estimating the visibility of the new moon have
been devised. You may want to check out the following web site (and
the pages it refers to) for information about Islamic calendar
predictions:
http://www.ummah.org.uk/ildl
4.3. How does one count years?
------------------------------
Years are counted since the Hijra, that is, Mohammed's flight to
Medina, which is assumed to have taken place 16 July AD 622 (Julian
calendar). On that date AH 1 started (AH = Anno Hegirae = year of the
Hijra).
In the year AD 2000 we have witnessed the start of Islamic year AH 1421.
Note that although only 2000-622=1378 years have passed in the
Christian calendar, 1420 years have passed in the Islamic calendar,
because its year is consistently shorter (by about 11 days) than the
tropical year used by the Christian calendar.
4.4. When will the Islamic calendar overtake the Gregorian calendar?
--------------------------------------------------------------------
As the year in the Islamic calendar is about 11 days shorter than the
year in the Christian calendar, the Islamic years are slowly gaining
in on the Chistian years. But it will be many years before the two
coincide. The 1st day of the 5th month of AD 20874 in the Gregorian
calendar will also be (approximately) the 1st day of the 5th month of
AH 20874 of the Islamic calendar.
5. The Week
-----------
The Christian, the Hebrew, and the Islamic calendars all have a 7-day
week.
5.1. What is the origin of the 7-day week?
------------------------------------------
Digging into the history of the 7-day week is a very complicated
matter. Authorities have very different opinions about the history of
the week, and they frequently present their speculations as if they
were indisputable facts. The only thing we seem to know for certain
about the origin of the 7-day week is that we know nothing for
certain.
The first pages of the Bible explain how God created the world in six
days and rested on the seventh. This seventh day became the Jewish
day of rest, the sabbath, Saturday.
Extra-biblical locations sometimes mentioned as the birthplace of the
7-day week include: Babylon, Persia, and several others. The week was
known in Rome before the advent of Christianity.
5.2. What do the names of the days of the week mean?
----------------------------------------------------
An answer to this question is necessarily closely linked to the
language in question. Whereas most languages use the same names for
the months (with a few Slavonic languages as notable exceptions),
there is great variety in names that various languages use for the
days of the week. A few examples will be given here.
Except for the sabbath, Jews simply number their week days.
A related method is partially used in Portuguese and Russian:
English Portuguese Russian Meaning of Russian name
------- ---------- ------- -----------------------
Monday segunda-feira ponedelnik After "do-nothing"
Tuesday terca-feira vtornik Second
Wednesday quarta-feira sreda Middle
Thursday quinta-feira chetverg Fourth
Friday sexta-feira pyatnitsa Fifth
Saturday sabado subbota Sabbath
Sunday domingo voskresenye Resurrection
Most Latin-based languages connect each day of the week with one of
the seven "planets" of the ancient times: Sun, Moon, Mercury, Venus,
Mars, Jupiter, and Saturn. French, for example, uses:
English French "Planet"
------- ------ --------
Monday lundi Moon
Tuesday mardi Mars
Wednesday mercredi Mercury
Thursday jeudi Jupiter
Friday vendredi Venus
Saturday samedi Saturn
Sunday dimanche (Sun)
The link with the sun has been broken in French, but Sunday was
called "dies solis" (day of the sun) in Latin.
It is interesting to note that also some Asiatic languages (for
example, Hindi, Japanese, and Korean) have a similar relationship
between the week days and the planets.
English has retained the original planets in the names for Saturday,
Sunday, and Monday. For the four other days, however, the names of
Anglo-Saxon or Nordic gods have replaced the Roman gods that gave
name to the planets. Thus, Tuesday is named after Tiw, Wednesday is
named after Woden, Thursday is named after Thor, and Friday is named
after Freya.
5.3. What is the system behind the planetary day names?
-------------------------------------------------------
As we saw in the previous section, the planets have given the week
days their names following this order:
Moon, Mars, Mercury, Jupiter, Venus, Saturn, Sun
Why this particular order?
One theory goes as follows: If you order the "planets" according to
either their presumed distance from Earth (assuming the Earth to be
the center of the universe) or their period of revolution around the
Earth, you arrive at this order:
Moon, Mercury, Venus, Sun, Mars, Jupiter, Saturn
Now, assign (in reverse order) these planets to the hours of the day:
1=Saturn, 2=Jupiter, 3=Mars, 4=Sun, 5=Venus, 6=Mercury, 7=Moon,
8=Saturn, 9=Jupiter, etc., 23=Jupiter, 24=Mars
Then next day will then continue where the old day left off:
1=Sun, 2=Venus, etc., 23=Venus, 24=Mercury
And the next day will go
1=Moon, 2=Saturn, etc.
If you look at the planet assigned to the first hour of each day, you
will note that the planets come in this order:
Saturn, Sun, Moon, Mars, Mercury, Jupiter, Venus
This is exactly the order of the associated week days.
Coincidence? Maybe.
5.4. Has the 7-day week cycle ever been interrupted?
----------------------------------------------------
There is no record of the 7-day week cycle ever having been broken.
Calendar changes and reform have never interrupted the 7-day cycles.
It very likely that the week cycles have run uninterrupted at least
since the days of Moses (c. 1400 BC), possibly even longer.
Some sources claim that the ancient Jews used a calendar in which an
extra Sabbath was occasionally introduced. But this is probably not
true.
5.5. Which day is the day of rest?
----------------------------------
For the Jews, the Sabbath (Saturday) is the day of rest and
worship. On this day God rested after creating the world.
Most Christians have made Sunday their day of rest and worship,
because Jesus rose from the dead on a Sunday.
Muslims use Friday as their day of rest and worship. The Qur'an
calls Friday a holy day, the "king of days".
5.6. What is the first day of the week?
---------------------------------------
The Bible clearly makes Saturday (the Sabbath) the last day of the
week. Therefore it is common Jewish and Christian practice to regard
Sunday as the first day of the week (as is also evident from the
Portuguese names for the week days mentioned in section 5.2). However,
the fact that, for example, Russian uses the name "second" for
Tuesday, indicates that some nations regard Monday as the first day.
In international standard ISO-8601 the International Organization for
Standardization has decreed that Monday shall be the first day of the
week.
5.7. What is the week number?
-----------------------------
International standard ISO-8601 (mentioned in section 5.6) assigns a
number to each week of the year. A week that lies partly in one year
and partly in another is assigned a number in the year in which most
of its days lie. This means that
Week 1 of any year is the week that contains 4 January,
or equivalently
Week 1 of any year is the week that contains the first
Thursday in January.
Most years have 52 weeks, but years that start on a Thursday and leap
years that start on a Wednesday have 53 weeks.
Note: This standard is not used in the United States.
5.8. How can I calculate the week number?
-----------------------------------------
If you know the date, how do you calculate the corresponding week
number (as defined in ISO-8601)?
1) Using the formulas in section 2.15.1, calculate the Julian Day
Number, J.
2) Perform the following calculations (in which the divisions are
integer divisions in which the remainder is discarded):
d4 = (J+31741 - (J mod 7)) mod 146097 mod 36524 mod 1461
L = d4/1460
d1 = ((d4-L) mod 365) + L
WeekNumber = d1/7+1
(I am very grateful to Stefan Potthast for this algorithm.)
5.9. Do weeks of different lengths exist?
-----------------------------------------
If you define a "week" as a 7-day period, obviously the answer is
no. But if you define a "week" as a named interval that is greater
than a day and smaller than a month, the answer is yes.
The ancient Egyptians used a 10-day "week", as did the French
Revolutionary calendar (see section 6.1).
The Maya calendar uses a 13 and a 20-day "week" (see section 7.2).
The Soviet Union has used both a 5-day and a 6-day week. In 1929-30
the USSR gradually introduced a 5-day week. Every worker had one day
off every week, but there was no fixed day of rest. On 1 September
1931 this was replaced by a 6-day week with a fixed day of rest,
falling on the 6th, 12th, 18th, 24th, and 30th day of each month (1
March was used instead of the 30th day of February, and the last day
of months with 31 days was considered an extra working day outside
the normal 6-day week cycle). A return to the normal 7-day week was
decreed on 26 June 1940.
6. The French Revolutionary Calendar
------------------------------------
The French Revolutionary Calendar (or Republican Calendar) was
introduced in France on 24 November 1793 and abolished on 1 January
1806. It was used again briefly during under the Paris Commune in
1871.
6.1. What does a Republican year look like?
-------------------------------------------
A year consists of 365 or 366 days, divided into 12 months of 30 days
each, followed by 5 or 6 additional days. The months were:
1. Vendemiaire 7. Germinal
2. Brumaire 8. Floreal
3. Frimaire 9. Prairial
4. Nivose 10. Messidor
5. Pluviose 11. Thermidor
6. Ventose 12. Fructidor
(The second e in Vendemiaire and the e in Floreal carry an acute
accent. The o's in Nivose, Pluviose, and Ventose carry a circumflex
accent.)
The year was not divided into weeks, instead each month was divided
into three "decades" of 10 days, of which the final day was a day of
rest. This was an attempt to de-Christianize the calendar, but it was
an unpopular move, because now there were 9 work days between each day
of rest, whereas the Gregorian Calendar had only 6 work days between
each Sunday.
The ten days of each decade were called, respectively, Primidi, Duodi,
Tridi, Quartidi, Quintidi, Sextidi, Septidi, Octidi, Nonidi, Decadi.
The 5 or 6 additional days followed the last day of Fructidor and were
called:
1. Jour de la vertu (Virtue Day)
2. Jour du genie (Genius Day)
3. Jour du travail (Labour Day)
4. Jour de l'opinion (Reason Day)
5. Jour des recompenses (Rewards Day)
6. Jour de la revolution (Revolution Day) (the leap day)
Each year was supposed to start on autumnal equinox (around 22
September), but this created problems as will be seen in section 6.3.
6.2. How does one count years?
------------------------------
Years are counted since the establishment of the first French Republic
on 22 September 1792. That day became 1 Vendemiaire of the year 1 of
the Republic. (However, the Revolutionary Calendar was not introduced
until 24 November 1793.)
6.3. What years are leap years?
-------------------------------
Leap years were introduced to keep New Year's Day on autumnal
equinox. But this turned out to be difficult to handle, because
equinox is not completely simple to predict.
In fact, the first decree implementing the calendar (5 Oct 1793)
contained two contradictory rules, as it stated that:
- the first day of each year would be that of the autmunal equinox
- every 4th year would be a leap year
In practice, the first calendars were based on the equinoxial
condition.
To remove the confusion, a rule similar to the one used in the
Gregorian Calendar (including a 4000 year rule as descibed in section
2.2.2) was proposed by the calendar's author, Charles Rommes, but his
proposal ran into political problems.
In short, during the time when the French Revolutionary Calendar was
in use, the the following years were leap years: 3, 7, and 11.
6.4. How does one convert a Republican date to a Gregorian one?
---------------------------------------------------------------
The following table lists the Gregorian date on which each year of the
Republic started:
Year 1: 22 Sep 1792 Year 8: 23 Sep 1799
Year 2: 22 Sep 1793 Year 9: 23 Sep 1800
Year 3: 22 Sep 1794 Year 10: 23 Sep 1801
Year 4: 23 Sep 1795 Year 11: 23 Sep 1802
Year 5: 22 Sep 1796 Year 12: 24 Sep 1803
Year 6: 22 Sep 1797 Year 13: 23 Sep 1804
Year 7: 22 Sep 1798 Year 14: 23 Sep 1805
7. The Maya Calendar
--------------------
(I am very grateful to Chris Carrier for providing most of the
information about the Maya calendar.)
Among their other accomplishments, the ancient Mayas invented a
calendar of remarkable accuracy and complexity. The Maya calendar was
adopted by the other Mesoamerican nations, such as the Aztecs and the
Toltec, which adopted the mechanics of the calendar unaltered but
changed the names of the days of the week and the months.
The Maya calendar uses three different dating systems in parallel, the
"Long Count", the "Tzolkin" (divine calendar), and the "Haab" (civil
calendar). Of these, only the Haab has a direct relationship to the
length of the year.
A typical Mayan date looks like this: 12.18.16.2.6, 3 Cimi 4 Zotz.
12.18.16.2.6 is the Long Count date.
3 Cimi is the Tzolkin date.
4 Zotz is the Haab date.
7.1. What is the Long Count?
----------------------------
The Long Count is really a mixed base-20/base-18 representation of a
number, representing the number of days since the start of the Mayan
era. It is thus akin to the Julian Day Number (see section 2.15).
The basic unit is the "kin" (day), which is the last component of the
Long Count. Going from right to left the remaining components are:
uinal (1 uinal = 20 kin = 20 days)
tun (1 tun = 18 uinal = 360 days = approx. 1 year)
katun (1 katun = 20 tun = 7,200 days = approx. 20 years)
baktun (1 baktun = 20 katun = 144,000 days = approx. 394 years)
The kin, tun, and katun are numbered from 0 to 19.
The uinal are numbered from 0 to 17.
The baktun are numbered from 1 to 13.
Although they are not part of the Long Count, the Mayas had names for
larger time spans. The following names are sometimes quoted, although
they are not ancient Maya terms:
1 pictun = 20 baktun = 2,880,000 days = approx. 7885 years
1 calabtun = 20 pictun = 57,600,000 days = approx. 158,000 years
1 kinchiltun = 20 calabtun = 1,152,000,000 days = approx. 3 million years
1 alautun = 20 kinchiltun = 23,040,000,000 days = approx. 63 million years
The alautun is probably the longest named period in any calendar.
7.1.1. When did the Long Count start?
-------------------------------------
Logically, the first date in the Long Count should be 0.0.0.0.0, but
as the baktun (the first component) are numbered from 1 to 13 rather
than 0 to 12, this first date is actually written 13.0.0.0.0.
The authorities disagree on what 13.0.0.0.0 corresponds to in our
calendar. I have come across three possible equivalences:
13.0.0.0.0 = 8 Sep 3114 BC (Julian) = 13 Aug 3114 BC (Gregorian)
13.0.0.0.0 = 6 Sep 3114 BC (Julian) = 11 Aug 3114 BC (Gregorian)
13.0.0.0.0 = 11 Nov 3374 BC (Julian) = 15 Oct 3374 BC (Gregorian)
Assuming one of the first two equivalences, the Long Count will again
reach 13.0.0.0.0 on 21 or 23 December AD 2012 - a not too distant future.
The date 13.0.0.0.0 may have been the Mayas' idea of the date of the
creation of the world.
7.2. What is the Tzolkin?
-------------------------
The Tzolkin date is a combination of two "week" lengths.
While our calendar uses a single week of seven days, the Mayan
calendar used two different lengths of week:
- a numbered week of 13 days, in which the days were numbered from
1 to 13
- a named week of 20 days, in which the names of the days were:
0. Ahau 5. Chicchan 10. Oc 15. Men
1. Imix 6. Cimi 11. Chuen 16. Cib
2. Ik 7. Manik 12. Eb 17. Caban
3. Akbal 8. Lamat 13. Ben 18. Etznab
4. Kan 9. Muluc 14. Ix 19. Caunac
As the named week is 20 days and the smallest Long Count digit is 20
days, there is synchrony between the two; if, for example, the last
digit of today's Long Count is 0, today must be Ahau; if it is 6, it
must be Cimi. Since the numbered and the named week were both "weeks",
each of their name/number change daily; therefore, the day after 3
Cimi is not 4 Cimi, but 4 Manik, and the day after that, 5 Lamat. The
next time Cimi rolls around, 20 days later, it will be 10 Cimi instead
of 3 Cimi. The next 3 Cimi will not occur until 260 (or 13*20) days
have passed. This 260-day cycle also had good-luck or bad-luck
associations connected with each day, and for this reason, it became
known as the "divinatory year."
The "years" of the Tzolkin calendar are not counted.
7.2.1. When did the Tzolkin start?
----------------------------------
Long Count 13.0.0.0.0 corresponds to 4 Ahau. The authorities agree on
this.
7.3. What is the Haab?
----------------------
The Haab was the civil calendar of the Mayas. It consisted of 18
"months" of 20 days each, followed by 5 extra days, known as
"Uayeb". This gives a year length of 365 days.
The names of the month were:
1. Pop 7. Yaxkin 13. Mac
2. Uo 8. Mol 14. Kankin
3. Zip 9. Chen 15. Muan
4. Zotz 10. Yax 16. Pax
5. Tzec 11. Zac 17. Kayab
6. Xul 12. Ceh 18. Cumku
In contrast to the Tzolkin dates, the Haab month names changed every
20 days instead of daily; so the day after 4 Zotz would be 5 Zotz,
followed by 6 Zotz ... up to 19 Zotz, which is followed by 0 Tzec.
The days of the month were numbered from 0 to 19. This use of a 0th
day of the month in a civil calendar is unique to the Maya system; it
is believed that the Mayas discovered the number zero, and the uses to
which it could be put, centuries before it was discovered in Europe or
Asia.
The Uayeb days acquired a very derogatory reputation for bad luck;
known as "days without names" or "days without souls," and were
observed as days of prayer and mourning. Fires were extinguished and
the population refrained from eating hot food. Anyone born on those
days was "doomed to a miserable life."
The years of the Haab calendar are not counted.
The length of the Tzolkin year was 260 days and the length of the Haab
year was 365 days. The smallest number that can be divided evenly by
260 and 365 is 18,980, or 365*52; this was known as the Calendar
Round. If a day is, for example, "4 Ahau 8 Cumku," the next day
falling on "4 Ahau 8 Cumku" would be 18,980 days or about 52 years
later. Among the Aztec, the end of a Calendar Round was a time of
public panic as it was thought the world might be coming to an
end. When the Pleaides crossed the horizon on 4 Ahau 8 Cumku, they
knew the world had been granted another 52-year extension.
7.3.1. When did the Haab start?
-------------------------------
Long Count 13.0.0.0.0 corresponds to 8 Cumku. The authorities agree on
this.
7.4. Did the Mayas think a year was 365 days?
---------------------------------------------
Although there were only 365 days in the Haab year, the Mayas were
aware that a year is slightly longer than 365 days, and in fact, many
of the month-names are associated with the seasons; Yaxkin, for
example, means "new or strong sun" and, at the beginning of the Long
Count, 1 Yaxkin was the day after the winter solstice, when the sun
starts to shine for a longer period of time and higher in the
sky. When the Long Count was put into motion, it was started at
7.13.0.0.0, and 0 Yaxkin corresponded with Midwinter Day, as it did at
13.0.0.0.0 back in 3114 B.C. The available evidence indicates that the
Mayas estimated that a 365-day year precessed through all the seasons
twice in 7.13.0.0.0 or 1,101,600 days.
We can therefore derive a value for the Mayan estimate of the year by
dividing 1,101,600 by 365, subtracting 2, and taking that number and
dividing 1,101,600 by the result, which gives us an answer of
365.242036 days, which is slightly more accurate than the 365.2425
days of the Gregorian calendar.
(This apparent accuracy could, however, be a simple coincidence. The
Mayas estimated that a 365-day year precessed through all the seasons
*twice* in 7.13.0.0.0 days. These numbers are only accurate to 2-3
digits. Suppose the 7.13.0.0.0 days had corresponded to 2.001 cycles
rather than 2 cycles of the 365-day year, would the Mayas have noticed?)
8. The Chinese Calendar
-----------------------
Although the People's Republic of China uses the Gregorian calendar
for civil purposes, a special Chinese calendar is used for determining
festivals. Various Chinese communities around the world also use this
calendar.
The beginnings of the Chinese calendar can be traced back to the 14th
century BC. Legend has it that the Emperor Huangdi invented the
calendar in 2637 BC.
The Chinese calendar is based on exact astronomical observations of
the longitude of the sun and the phases of the moon. This means that
principles of modern science have had an impact on the Chinese
calendar.
I can recommend visiting Helmer Aslaksen's web site
(http://www.math.nus.edu.sg/aslaksen/calendar/chinese.shtml) for more
information about the Chinese calendar.
8.1. What does the Chinese year look like?
------------------------------------------
The Chinese calendar - like the Hebrew - is a combined solar/lunar
calendar in that it strives to have its years coincide with the
tropical year and its months coincide with the synodic months. It is
not surprising that a few similarities exist between the Chinese and
the Hebrew calendar:
* An ordinary year has 12 months, a leap year has 13 months.
* An ordinary year has 353, 354, or 355 days, a leap year has 383,
384, or 385 days.
When determining what a Chinese year looks like, one must make a
number of astronomical calculations:
First, determine the dates for the new moons. Here, a new moon is the
completely "black" moon (that is, when the moon is in conjunction with
the sun), not the first visible crescent used in the Islamic and
Hebrew calendars. The date of a new moon is the first day of a new
month.
Secondly, determine the dates when the sun's longitude is a multiple
of 30 degrees. (The sun's longitude is 0 at Vernal Equinox, 90 at
Summer Solstice, 180 at Autumnal Equinox, and 270 at Winter Solstice.)
These dates are called the "Principal Terms" and are used to determine
the number of each month:
Principal Term 1 occurs when the sun's longitude is 330 degrees.
Principal Term 2 occurs when the sun's longitude is 0 degrees.
Principal Term 3 occurs when the sun's longitude is 30 degrees.
etc.
Principal Term 11 occurs when the sun's longitude is 270 degrees.
Principal Term 12 occurs when the sun's longitude is 300 degrees.
Each month carries the number of the Principal Term that occurs in
that month.
In rare cases, a month may contain two Principal Terms; in this case
the months numbers may have to be shifted. Principal Term 11 (Winter
Solstice) must always fall in the 11th month.
All the astronomical calculations are carried out for the meridian 120
degrees east of Greenwich. This roughly corresponds to the east coast
of China.
Some variations in these rules are seen in various Chinese
communities.
8.2. What years are leap years?
-------------------------------
Leap years have 13 months. To determine if a year is a leap year,
calculate the number of new moons between the 11th month in one year
(i.e, the month containing the Winter Solstice) and the 11th month in
the following year. If there are 13 months from the start of the 11th
month in the first year to the start of the 11th month in the second
year, a leap month must be inserted.
In leap years, at least one month does not contain a Principal Term.
The first such month is the leap month. It carries the same number as
the previous month, with the additional note that it is the leap
month.
8.3. How does one count years?
------------------------------
Unlike most other calendars, the Chinese calendar does not count years
in an infinite sequence. Instead years have names that are repeated
every 60 years.
(Historically, years used to be counted since the accession of an
emperor, but this was abolished after the 1911 revolution.)
Within each 60-year cycle, each year is assigned name consisting of
two components:
The first component is a "Celestial Stem":
1. jia 6. ji
2. yi 7. geng
3. bing 8. xin
4. ding 9. ren
5. wu 10. gui
These words have no English equivalent.
The second component is a "Terrestrial Branch":
1. zi (rat) 7. wu (horse)
2. chou (ox) 8. wei (sheep)
3. yin (tiger) 9. shen (monkey)
4. mao (hare, rabbit) 10. you (rooster)
5. chen (dragon) 11. xu (dog)
6. si (snake) 12. hai (pig)
The names of the corresponding animals in the zodiac cycle of 12
animals are given in parentheses.
Each of the two components is used sequentially. Thus, the 1st year of
the 60-year cycle becomes jia-zi, the 2nd year is yi-chou, the 3rd
year is bing-yin, etc. When we reach the end of a component, we start
from the beginning: The 10th year is gui-you, the 11th year is jia-xu
(restarting the Celestial Stem), the 12th year is yi-hai, and the 13th
year is bing-zi (restarting the Terrestrial Branch). Finally, the 60th
year becomes gui-hai.
This way of naming years within a 60-year cycle goes back
approximately 2000 years. A similar naming of days and months has
fallen into disuse, but the date name is still listed in calendars.
It is customary to number the 60-year cycles since 2637 BC, when the
calendar was supposedly invented. In that year the first 60-year cycle
started.
8.4. What is the current year in the Chinese calendar?
------------------------------------------------------
The current 60-year cycle started on 2 Feb 1984. That date bears the name
bing-yin in the 60-day cycle, and the first month of that first year
bears the name gui-chou in the 60-month cycle.
This means that the year geng-chen, the 17th year in the 78th cycle,
started on 5 Feb 2000.
9. Frequently Asked Questions about this FAQ
--------------------------------------------
This chapter does not answer questions about calendars. Instead it
answers questions that I am often asked about this document.
9.1. Why doesn't the FAQ describe calendar X?
---------------------------------------------
I am frequently asked to add a chapter describing the Persian calendar,
the Japanese calendar, the Ethiopian calendar, the Hindu calendar, etc.
But I have to stop somewhere. I have discovered that the more calendars
I include in the FAQ, the more difficult it becomes to ensure that the
information given is correct. I want to work on the quality rather
than the quantity of information in this document. It is therefore not
likely that other calendars will be added in the near future.
9.2. Why doesn't the FAQ contain information X?
-----------------------------------------------
Obviously, I cannot include everything. So I have to prioritize. The
things that are most likely to be omitted from the FAQ are:
- Information that is relevant to a single country only.
- Views that are controversial and not supported by recognized
authorities.
9.3. Why don't you reply to my e-mail?
--------------------------------------
I try to reply to all the e-mail I receive. But occasionally the
amount of mail I receive is so large that I have to ignore some
letters. If this has caused your letter to be lost, I apologize.
But please don't let this stop you from writing to me. I enjoy
receiving letters, even if I can't answer them all.
9.4. How do I know that I can trust your information?
-----------------------------------------------------
I have tried to be accurate in everything I have described. If you are
unsure about something that I write, I suggest that you try to verify
the information yourself. If you come across a recognized authority
that contradicts something that I've written, please let me know.
9.5. Can you recommend any good books about calendars?
------------------------------------------------------
I'd rather not. Many of the sources I have used are Danish. Unless you
understand Danish, they won't be of much use to you.
9.6. Do you know a web site where I can find information about X?
-----------------------------------------------------------------
Probably not.
Good places to start your calendar search include:
http://www.calendarzone.com
http://personal.ecu.edu/mccartyr/calendar-reform.html
10. Date
--------
This version 2.3 of this document was finished on
Monday after the 14th Sunday after Trinity, the 25th of September
anno ab Incarnatione Domini MM, indict. VIII, epacta XXIV,
luna XXVI, anno post Margaretam Reginam Daniae natam LX, on
the feast of Saint Cadoc.
The 25th day of Elul, Anno Mundi 5760.
The 25th day of Jumada II, Anno Hegirae 1421.
The 28th day of the 8th month of the year geng-chen of the 78th
cycle.
Julian Day 2,451,813.
calendar-3.0.0/dune-project 0000664 0000000 0000000 00000000060 14321307032 0015574 0 ustar 00root root 0000000 0000000 (lang dune 1.0)
(name calendar)
(version 3.0.0)
calendar-3.0.0/headache_config.txt 0000664 0000000 0000000 00000000400 14321307032 0017060 0 ustar 00root root 0000000 0000000 # Objective Caml source
| ".*\\.mly" -> frame open:"/*" line:"*" close:"*/"
| ".*\\.ml[il4]?.*" -> frame open:"(*" line:"*" close:"*)"
# Misc
| "configure.in" -> frame open:"#" line:"#" close:"#"
| "Makefile.in" -> frame open:"#" line:"#" close:"#"
calendar-3.0.0/man_date.txt 0000664 0000000 0000000 00000003707 14321307032 0015576 0 ustar 00root root 0000000 0000000 %% a literal %
%a locale's abbreviated weekday name (Sun..Sat)
%A locale's full weekday name, variable length (Sun-
day..Saturday)
%b locale's abbreviated month name (Jan..Dec)
%B locale's full month name, variable length (Jan-
uary..December)
%c locale's date and time (Sat Nov 04 12:02:33 EST
1989)
%d day of month (01..31)
%D date (mm/dd/yy)
%e day of month, blank padded ( 1..31)
%h same as %b
%H hour (00..23)
%I hour (01..12)
%j day of year (001..366)
%k hour ( 0..23)
%l hour ( 1..12)
%m month (01..12)
%M minute (00..59)
%n a newline
%p locale's AM or PM
%r time, 12-hour (hh:mm:ss [AP]M)
%s seconds since `00:00:00 1970-01-01 UTC' (a GNU
extension)
%S second (00..60)
%t a horizontal tab
%T time, 24-hour (hh:mm:ss)
%U week number of year with Sunday as first day of
week (00..53)
%V week number of year with Monday as first day of
week (01..53)
%w day of week (0..6); 0 represents Sunday
%W week number of year with Monday as first day of
week (00..53)
%x locale's date representation (mm/dd/yy)
%X locale's time representation (%H:%M:%S)
%y last two digits of year (00..99)
%Y year (1970...)
%z RFC-822 style numeric timezone (-0500) (a nonstan-
dard extension)
%Z time zone (e.g., EDT), or nothing if no time zone
is determinable
By default, date pads numeric fields with zeroes. GNU
date recognizes the following modifiers between `%' and a
numeric directive.
`-' (hyphen) do not pad the field `_' (underscore)
pad the field with spaces
calendar-3.0.0/src/ 0000775 0000000 0000000 00000000000 14321307032 0014045 5 ustar 00root root 0000000 0000000 calendar-3.0.0/src/calendar.ml 0000664 0000000 0000000 00000003270 14321307032 0016152 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
include Calendar_builder.Make(Date)(Time)
module Precise = Calendar_builder.Make_Precise(Date)(Time)
calendar-3.0.0/src/calendar.mli 0000664 0000000 0000000 00000004067 14321307032 0016330 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Calendar implementation in which seconds are integer.
This module uses float. Then results may be unprecise, especially
comparison of calendars which differ with few seconds.
In this case, consider to use module [Precise]. *)
include Calendar_sig.S with module Date = Date and module Time = Time
(** More precise implementation of calendar in which seconds are integer.
@since 2.0 *)
module Precise: Calendar_sig.S with module Date = Date and module Time = Time
calendar-3.0.0/src/calendar_builder.ml 0000664 0000000 0000000 00000036637 14321307032 0017675 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(*S Introduction.
A calendar is representing by its (exact) Julian Day -. 0.5.
This gap of 0.5 is because the Julian period begins
January first, 4713 BC at MIDDAY (and then, this Julian day is 0.0).
But, for implementation facilities, the Julian day 0.0 is coded as
January first, 4713 BC at MIDNIGHT. *)
module Make(D: Date_sig.S)(T: Time_sig.S) = struct
(*S Datatypes. *)
include Utils.Float
module Date = D
module Time = T
type day = D.day = Sun | Mon | Tue | Wed | Thu | Fri | Sat
type month = D.month =
Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec
type year = int
type second = T.second
type field = [ D.field | T.field ]
(*S Conversions. *)
let convert x t1 t2 = x +. float (Time_Zone.gap t1 t2) /. 24.
let to_gmt x = convert x (Time_Zone.current ()) Time_Zone.UTC
let from_gmt x = convert x Time_Zone.UTC (Time_Zone.current ())
let from_date x = to_gmt (float (D.to_jd x)) -. 0.5
(* Return the integral part of [x] as a date. *)
let to_date x = D.from_jd (int_of_float (from_gmt x +. 0.5))
(* Return the fractional part of [x] as a time. *)
let to_time x =
let t, _ = modf (from_gmt x +. 0.5) in
let i = t *. 86400. in
assert (i < 86400.);
T.from_seconds (T.Second.from_float i)
(*S Constructors. *)
let is_valid x = x >= 0. && x < 2914695.
let create d t =
to_gmt
(float (D.to_jd d)
+. T.Second.to_float (T.to_seconds t) /. 86400.) -. 0.5
let make y m d h mn s =
let x = create (D.make y m d) (T.make h mn s) in
if is_valid x then x else raise D.Out_of_bounds
let lmake ~year ?(month=1) ?(day=1) ?(hour=0) ?(minute=0)
?(second=T.Second.from_int 0) () =
make year month day hour minute second
let now () =
let now = Unix.gettimeofday () in
let gmnow = Unix.gmtime now in
let frac, _ = modf now in
from_gmt (make
(gmnow.Unix.tm_year + 1900)
(gmnow.Unix.tm_mon + 1)
gmnow.Unix.tm_mday
gmnow.Unix.tm_hour
gmnow.Unix.tm_min
(T.Second.from_float (float gmnow.Unix.tm_sec +. frac)))
let from_jd x = to_gmt x
let from_mjd x = to_gmt x +. 2400000.5
(*S Getters. *)
let to_jd x = from_gmt x
let to_mjd x = from_gmt x -. 2400000.5
let days_in_month x = D.days_in_month (to_date x)
let day_of_week x = D.day_of_week (to_date x)
let day_of_month x = D.day_of_month (to_date x)
let day_of_year x = D.day_of_year (to_date x)
let week x = D.week (to_date x)
let month x = D.month (to_date x)
let year x = D.year (to_date x)
let hour x = T.hour (to_time x)
let minute x = T.minute (to_time x)
let second x = T.second (to_time x)
(*S Coercions. *)
let from_unixtm x =
make
(x.Unix.tm_year + 1900) (x.Unix.tm_mon + 1) x.Unix.tm_mday
x.Unix.tm_hour x.Unix.tm_min (T.Second.from_int x.Unix.tm_sec)
let to_unixtm x =
let tm = D.to_unixtm (to_date x)
and t = to_time x in
{ tm with
Unix.tm_sec = T.Second.to_int (T.second t);
Unix.tm_min = T.minute t;
Unix.tm_hour = T.hour t }
let jan_1_1970 = 2440587.5
let from_unixfloat x = to_gmt (x /. 86400. +. jan_1_1970)
let to_unixfloat x = (from_gmt x -. jan_1_1970) *. 86400.
(*S Boolean operations on dates. *)
let is_leap_day x = D.is_leap_day (to_date x)
let is_gregorian x = D.is_gregorian (to_date x)
let is_julian x = D.is_julian (to_date x)
let is_pm x = T.is_pm (to_time x)
let is_am x = T.is_am (to_time x)
(*S Period. *)
module Period = struct
type +'a p = { d : 'a D.Period.period; t : 'a T.Period.period }
constraint 'a = [< Period.date_field ]
type +'a period = 'a p
type t = Period.date_field period
let split x =
let rec aux s =
if s < 86400. then 0, s else let d, s = aux (s -. 86400.) in d + 1, s
in
let s = T.Second.to_float (T.Period.length x.t) in
let d, s =
if s >= 0. then aux s
else let d, s = aux (-. s) in - (d + 1), -. s +. 86400.
in
assert (s >= 0. && s < 86400.);
D.Period.day d, T.Period.second (T.Second.from_float s)
let normalize x =
let days, seconds = split x in
{ d = D.Period.add x.d days; t = seconds }
let empty = { d = D.Period.empty; t = T.Period.empty }
let make y m d h mn s =
normalize { d = D.Period.make y m d; t = T.Period.make h mn s }
let lmake ?(year=0) ?(month=0) ?(day=0) ?(hour=0) ?(minute=0)
?(second=T.Second.from_int 0) () =
make year month day hour minute second
let year x = { empty with d = D.Period.year x }
let month x = { empty with d = D.Period.month x }
let week x = { empty with d = D.Period.week x }
let day x = { empty with d = D.Period.day x }
let hour x = normalize { empty with t = T.Period.hour x }
let minute x = normalize { empty with t = T.Period.minute x }
let second x = normalize { empty with t = T.Period.second x }
let add x y =
normalize { d = D.Period.add x.d y.d; t = T.Period.add x.t y.t }
let sub x y =
normalize { d = D.Period.sub x.d y.d; t = T.Period.sub x.t y.t }
let opp x = normalize { d = D.Period.opp x.d; t = T.Period.opp x.t }
let compare x y =
let n = D.Period.compare x.d y.d in
if n = 0 then T.Period.compare x.t y.t else n
let equal x y = D.Period.equal x.d y.d && T.Period.equal x.t y.t
let hash = Hashtbl.hash
let to_date x = x.d
let from_date x = { empty with d = x }
let from_time x = { empty with t = x }
exception Not_computable = D.Period.Not_computable
let gen_to_time f x = T.Period.add (T.Period.hour (f x.d * 24)) x.t
let to_time x = gen_to_time D.Period.nb_days x (* eta-expansion required *)
let safe_to_time x = gen_to_time D.Period.safe_nb_days x
let ymds x =
let y, m, d = D.Period.ymd x.d in
y, m, d, T.Period.to_seconds x.t
end
(*S Arithmetic operations on calendars and periods. *)
let split x =
let t, d = modf (from_gmt (x +. 0.5)) in
let t, d = t *. 86400., int_of_float d in
let t, d = if t < 0. then t +. 86400., d - 1 else t, d in
assert (t >= 0. && t < 86400.);
D.from_jd d, T.from_seconds (T.Second.from_float t)
let unsplit d t =
to_gmt
(float (D.to_jd d)
+. (T.Second.to_float (T.to_seconds t) /. 86400.)) -. 0.5
let add x p =
let d, t = split x in
unsplit (D.add d (p.Period.d :> D.Period.t)) (T.add t p.Period.t)
let rem x p = add x (Period.opp (p :> Period.t))
let sub x y =
let d1, t1 = split x in
let d2, t2 = split y in
Period.normalize { Period.d = D.sub d1 d2; Period.t = T.sub t1 t2 }
let precise_sub x y =
let d1, t1 = split x in
let d2, t2 = split y in
Period.normalize { Period.d = D.precise_sub d1 d2; Period.t = T.sub t1 t2 }
let next x f =
let d, t = split x in
match f with
| #D.field as f -> unsplit (D.next d f) t
| #T.field as f -> unsplit d (T.next t f)
let prev x f =
let d, t = split x in
match f with
| #D.field as f -> unsplit (D.prev d f) t
| #T.field as f -> unsplit d (T.prev t f)
end
(* ************************************************************************* *)
(* ************************************************************************* *)
(* ************************************************************************* *)
module Make_Precise(D: Date_sig.S)(T: Time_sig.S) = struct
module Date = D
module Time = T
type t = { date: D.t; time: T.t }
type day = D.day = Sun | Mon | Tue | Wed | Thu | Fri | Sat
type month = D.month =
Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec
type year = int
type second = T.second
type field = [ D.field | T.field ]
(*S Comparison *)
let equal x y = D.equal x.date y.date && T.equal x.time y.time
let compare x y =
let n = D.compare x.date y.date in
if n = 0 then T.compare x.time y.time else n
let hash = Hashtbl.hash
(*S Conversions. *)
let normalize d t =
let t, days = T.normalize t in
{ date = D.add d (D.Period.day days); time = t }
let convert x t1 t2 =
let gap = T.Period.hour (Time_Zone.gap t1 t2) in
normalize x.date (T.add x.time gap)
let to_gmt x = convert x (Time_Zone.current ()) Time_Zone.UTC
let from_gmt x = convert x Time_Zone.UTC (Time_Zone.current ())
let from_date d = to_gmt { date = d; time = T.make 0 0 (T.Second.from_int 0) }
let to_date x = (from_gmt x).date
let to_time x = (from_gmt x).time
(*S Constructors. *)
let create d t = to_gmt { date = d; time = t }
let lower_bound, upper_bound =
let compute () =
let midday = T.midday () in
let low, up =
create (D.make (-4712) 1 1) midday, create (D.make 3268 1 22) midday
in
low, up
in
Time_Zone.on compute Time_Zone.UTC ()
let is_valid x = compare x lower_bound >= 0 && compare x upper_bound <= 0
let make y m d h mn s =
let x = create (D.make y m d) (T.make h mn s) in
if is_valid x then x else raise D.Out_of_bounds
let lmake ~year ?(month=1) ?(day=1) ?(hour=0) ?(minute=0)
?(second=T.Second.from_int 0) () =
make year month day hour minute second
let now () =
let now = Unix.gettimeofday () in
let gmnow = Unix.gmtime now in
let frac, _ = modf now in
from_gmt (make
(gmnow.Unix.tm_year + 1900)
(gmnow.Unix.tm_mon + 1)
gmnow.Unix.tm_mday
gmnow.Unix.tm_hour
gmnow.Unix.tm_min
(T.Second.from_float (float gmnow.Unix.tm_sec +. frac)))
let from_jd x =
let frac, intf = modf x in
to_gmt
{ date = D.from_jd (int_of_float intf);
time = T.from_seconds (T.Second.from_float (frac *. 86400. +. 43200.)) }
let from_mjd x = from_jd (x +. 2400000.5)
(*S Getters. *)
let to_jd x =
let x = from_gmt x in
float (D.to_jd x.date) +. T.Second.to_float (T.to_seconds x.time) /. 86400.
-. 0.5
let to_mjd x = to_jd x -. 2400000.5
let days_in_month x = D.days_in_month (to_date x)
let day_of_week x = D.day_of_week (to_date x)
let day_of_month x = D.day_of_month (to_date x)
let day_of_year x = D.day_of_year (to_date x)
let week x = D.week (to_date x)
let month x = D.month (to_date x)
let year x = D.year (to_date x)
let hour x = T.hour (to_time x)
let minute x = T.minute (to_time x)
let second x = T.second (to_time x)
(*S Coercions. *)
let from_unixtm x =
make
(x.Unix.tm_year + 1900) (x.Unix.tm_mon + 1) x.Unix.tm_mday
x.Unix.tm_hour x.Unix.tm_min (T.Second.from_int x.Unix.tm_sec)
let to_unixtm x =
let tm = D.to_unixtm (to_date x)
and t = to_time x in
{ tm with
Unix.tm_sec = T.Second.to_int (T.second t);
Unix.tm_min = T.minute t;
Unix.tm_hour = T.hour t }
let jan_1_1970 = 2440587.5
let from_unixfloat x = from_jd (x /. 86400. +. jan_1_1970)
let to_unixfloat x = (to_jd x -. jan_1_1970) *. 86400.
(*S Boolean operations on dates. *)
let is_leap_day x = D.is_leap_day (to_date x)
let is_gregorian x = D.is_gregorian (to_date x)
let is_julian x = D.is_julian (to_date x)
let is_pm x = T.is_pm (to_time x)
let is_am x = T.is_am (to_time x)
(*S Period. *)
module Period = struct
type +'a p = { d : 'a D.Period.period; t : 'a T.Period.period }
constraint 'a = [< Period.date_field ]
type +'a period = 'a p
type t = Period.date_field period
let split x =
let rec aux s =
if s < 86400. then 0, s else let d, s = aux (s -. 86400.) in d + 1, s
in
let s = T.Second.to_float (T.Period.length x.t) in
let d, s =
if s >= 0. then aux s
else let d, s = aux (-. s) in - (d + 1), -. s +. 86400.
in
assert (s >= 0. && s < 86400.);
D.Period.day d, T.Period.second (T.Second.from_float s)
let normalize x =
let days, seconds = split x in
{ d = D.Period.add x.d days; t = seconds }
let empty = { d = D.Period.empty; t = T.Period.empty }
let make y m d h mn s =
normalize { d = D.Period.make y m d; t = T.Period.make h mn s }
let lmake ?(year=0) ?(month=0) ?(day=0) ?(hour=0) ?(minute=0)
?(second=T.Second.from_int 0) () =
make year month day hour minute second
let year x = { empty with d = D.Period.year x }
let month x = { empty with d = D.Period.month x }
let week x = { empty with d = D.Period.week x }
let day x = { empty with d = D.Period.day x }
let hour x = normalize { empty with t = T.Period.hour x }
let minute x = normalize { empty with t = T.Period.minute x }
let second x = normalize { empty with t = T.Period.second x }
let add x y =
normalize { d = D.Period.add x.d y.d; t = T.Period.add x.t y.t }
let sub x y =
normalize { d = D.Period.sub x.d y.d; t = T.Period.sub x.t y.t }
let opp x = normalize { d = D.Period.opp x.d; t = T.Period.opp x.t }
let compare x y =
let n = D.Period.compare x.d y.d in
if n = 0 then T.Period.compare x.t y.t else n
let equal x y = D.Period.equal x.d y.d && T.Period.equal x.t y.t
let hash = Hashtbl.hash
let to_date x = x.d
let from_date x = { empty with d = x }
let from_time x = { empty with t = x }
exception Not_computable = D.Period.Not_computable
let gen_to_time f x = T.Period.add (T.Period.hour (f x.d * 24)) x.t
let to_time x = gen_to_time D.Period.nb_days x (* eta-expansion required *)
let safe_to_time x = gen_to_time D.Period.safe_nb_days x
let ymds x =
let y, m, d = D.Period.ymd x.d in
y, m, d, T.Period.to_seconds x.t
end
(*S Arithmetic operations on calendars and periods. *)
let add x p =
normalize
(D.add x.date (p.Period.d :> D.Period.t)) (T.add x.time p.Period.t)
let rem x p = add x (Period.opp (p :> Period.t))
let sub x y =
Period.normalize
{ Period.d = D.sub x.date y.date; Period.t = T.sub x.time y.time }
let precise_sub x y =
Period.normalize
{ Period.d = D.precise_sub x.date y.date;
Period.t = T.sub x.time y.time }
let next x = function
| #D.field as f -> normalize (D.next x.date f) x.time
| #T.field as f -> normalize x.date (T.next x.time f)
let prev x = function
| #D.field as f -> normalize (D.prev x.date f) x.time
| #T.field as f -> normalize x.date (T.prev x.time f)
end
calendar-3.0.0/src/calendar_builder.mli 0000664 0000000 0000000 00000004204 14321307032 0020027 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Generic calendar implementation.
@since 2.0 *)
(** Implement a calendar from a date implementation and a time implementation.
This module uses float. Then results may be very unprecise.
@since 2.0 *)
module Make(D:Date_sig.S)(T:Time_sig.S)
: Calendar_sig.S with module Date = D and module Time = T
(** Similar to {!Make} but results are more precise. The counterpart is that
some operations are less efficient.
@since 2.0 *)
module Make_Precise(D:Date_sig.S)(T:Time_sig.S)
: Calendar_sig.S with module Date = D and module Time = T
calendar-3.0.0/src/calendar_sig.mli 0000664 0000000 0000000 00000031537 14321307032 0017174 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Calendar interface. A calendar combines a date and a time: it may be seen
as a 6-uple (year, month, day, hour, minute, second).
If you only need operations on dates, you should better use a date
implementation (like module [Date]). But if you need to manage more precise
dates, use this module. The exact Julian period is now [[January, 1st 4713
BC at midday GMT; January 22th, 3268 AC at midday GMT]]. *)
(** Common operations for all calendar representations.
@since 2.0 (this signature was before inlined in interface of Calendar). *)
module type S = sig
(** {2 Datatypes} *)
module Date: Date_sig.S
(** Date implementation used by this calendar.
@since 2.0 *)
module Time: Time_sig.S
(** Time implementation used by this calendar.
@since 2.0 *)
type t
type day = Date.day = Sun | Mon | Tue | Wed | Thu | Fri | Sat
(** Days of the week. *)
type month = Date.month =
Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec
(** Months of the year. *)
type year = Date.year
(** Year as an int *)
type second = Time.second
type field = [ Date.field | Time.field ]
(** The different fields of a calendar. *)
(** {2 Constructors} *)
val make : int -> int -> int -> int -> int -> second -> t
(** [make year month day hour minute second] makes the calendar
"year-month-day; hour-minute-second".
@raise D.Out_of_bounds when a date is outside the Julian period.
@raise D.Undefined when a date belongs to [[October 5th, 1582; October
14th, 1582]]. *)
val lmake :
year:int -> ?month:int -> ?day:int ->
?hour:int -> ?minute:int -> ?second:second -> unit -> t
(** Labelled version of [make].
The default value of [month] and [day] (resp. of [hour], [minute]
and [second]) is [1] (resp. [0]).
@raise D.Out_of_bounds when a date is outside the Julian period.
@raise D.Undefined when a date belongs to [[October 5th, 1582; October
14th, 1582]].
@since 1.05 *)
val create : Date.t -> Time.t -> t
(** [create d t] creates a calendar from the given date and time. *)
val now : unit -> t
(** [now ()] returns the current date and time (in the current time
zone). *)
val from_jd : float -> t
(** Return the Julian day.
More precise than [Date.from_jd]: the fractional part represents the
time. *)
val from_mjd : float -> t
(** Return the Modified Julian day.
It is [Julian day - 2 400 000.5] (more precise than [Date.from_mjd]). *)
(** {2 Conversions} *)
(** Those functions have the same behaviour as those defined in
{!Time_sig.S}. *)
val convert : t -> Time_Zone.t -> Time_Zone.t -> t
(** @see Time_sig.S.convert *)
val to_gmt : t -> t
(** @see Time_sig.S.to_gmt *)
val from_gmt : t -> t
(** @see Time_sig.S.from_gmt *)
(** {2 Getters} *)
(** Those functions have the same behavious as those defined in
{!Date_sig.S}. *)
val days_in_month : t -> int
(** @see Date_sig.S.days_in_month *)
val day_of_week : t -> day
(** @see Date_sig.S.days_of_week *)
val day_of_month : t -> int
(** @see Date_sig.S.days_of_month *)
val day_of_year : t -> int
(** @see Date_sig.S.days_of_year *)
val week : t -> int
(** @see Date_sig.S.week *)
val month : t -> month
(** @see Date_sig.S.month *)
val year : t -> int
(** @see Date_sig.S.year *)
(** [to_jd] and [to_mjd] are more precise than {!Date_sig.S.to_jd} and
{!Date_sig.S.to_mjd}. *)
val to_jd : t -> float
val to_mjd : t -> float
(** Those functions have the same behavious as those defined in
{!Time_sig.S}. *)
val hour : t -> int
(** @see Time_sig.S.hour *)
val minute : t -> int
(** @see Time_sig.S.minute *)
val second : t -> second
(** @see Time_sig.S.second *)
(** {2 Calendars are comparable} *)
val equal: t -> t -> bool
(** Equality function between two calendars.
@see Utils.Comparable.equal. *)
val compare: t -> t -> int
(** Comparison function between two calendars.
@see Utils.Comparable.compare. *)
val hash: t -> int
(** Hash function for calendars.
@see Utils.Comparable.hash.
@since 2.0 *)
(** Those functions have the same behavious as those defined in
{!Date_sig.S}. *)
val is_leap_day : t -> bool
(** @see Date_sig.S.is_leap_day *)
val is_gregorian : t -> bool
(** @see Date_sig.S.is_gregorian *)
val is_julian : t -> bool
(** @see Date_sig.S.is_julian *)
(** Those functions have the same behavious as those defined in
{!Time_sig.S}. *)
val is_pm : t -> bool
(** @see Time_sig.S.is_pm *)
val is_am : t -> bool
(** @see Time_sig.S.is_am *)
(** {2 Coercions} *)
val to_unixtm : t -> Unix.tm
(** Convert a calendar into the [unix.tm] type.
The field [isdst] is always [false]. More precise than
{!Date_sig.S.to_unixtm}.
@since 1.01 *)
val from_unixtm : Unix.tm -> t
(** Inverse of [to_unixtm]. Assumes the current time zone.
So, The following invariant holds:
[hour (from_unixtm u) = u.Unix.tm_hour].
@since 1.01 *)
val to_unixfloat : t -> float
(** Convert a calendar to a float such than
[to_unixfloat (make 1970 1 1 0 0 0)] returns [0.0] at UTC.
So such a float is convertible with those of the module [Unix].
More precise than {!Date_sig.S.to_unixfloat}.
@since 1.01 *)
val from_unixfloat : float -> t
(** Inverse of [to_unixfloat]. Assumes the current time zone.
So, the following invariant holds:
[hour (from_unixfloat u) = (Unix.gmtime u).Unix.tm_hour].
@since 1.01 *)
val from_date : Date.t -> t
(** Convert a date to a calendar.
The time is midnight in the current time zone. *)
val to_date : t -> Date.t
(** Convert a calendar to a date. Time part of the calendar is ignored. *)
val to_time : t -> Time.t
(** Convert a calendar to a time. Date part of the calendar is ignored.
@since 1.03 *)
(** {2 Period} *)
(** A period is the number of seconds between two calendars. *)
module Period : sig
(** {3 Arithmetic operations} *)
type +'a period constraint 'a = [< Period.date_field ]
type t = Period.date_field period
(** Type of a period. *)
(** {3 Period is an additive monoid} *)
val empty : 'a period
(** The empty period. *)
val add : ([> `Day | `Week ] as 'a) period -> 'a period -> 'a period
(** Addition of periods. *)
val sub : ([> `Day | `Week ] as 'a) period -> 'a period -> 'a period
(** Substraction of periods. *)
val opp : ([> `Day | `Week ] as 'a) period -> 'a period
(** Opposite of a period. *)
(** {3 Periods are comparable} *)
val equal: 'a period -> 'b period -> bool
(** Equality function between two periods.
@see Utils.Comparable.equal
@since 1.09.0 *)
val compare : 'a period -> 'b period -> int
(** Comparison function between two periods.
@see Utils.Comparable.compare *)
val hash: 'a period -> int
(** Hash function for periods.
@see Utils.Comparable.hash
@since 2.0 *)
(** {3 Constructors} *)
val make : int -> int -> int -> int -> int -> second -> t
(** [make year month day hour minute second] makes a period of the
specified length. *)
val lmake :
?year:int -> ?month:int -> ?day:int ->
?hour:int -> ?minute:int -> ?second:second -> unit -> t
(** Labelled version of [make].
The default value of each argument is [0]. *)
(** Those functions have the same behavious as those defined in
{!Date_sig.S.Period}. *)
val year : int -> [> `Year ] period
(** @see Date_sig.S.Period.year *)
val month : int -> [> `Year | `Month ] period
(** @see Date_sig.S.Period.month *)
val week : int -> [> `Week | `Day ] period
(** @see Date_sig.S.Period.week *)
val day : int -> [> `Week | `Day ] period
(** @see Date_sig.S.Period.day *)
(** Those functions have the same behavious as those defined in
{Time_sig.S.Period}. *)
val hour : int -> [> `Week | `Day ] period
(** @see Time_sig.S.Period.hour *)
val minute : int -> [> `Week | `Day] period
(** @see Time_sig.S.Period.minute *)
val second : second -> [> `Week | `Day] period
(** @see Time_sig.S.Period.second *)
(** {3 Coercions} *)
val from_date : 'a Date.Period.period -> 'a period
(** Convert a date period to a calendar period. *)
val from_time : 'a Time.Period.period -> 'a period
(** Convert a time period to a calendar period. *)
val to_date : 'a period -> 'a Date.Period.period
(** Convert a calendar period to a date period.
The fractional time period is ignored.
@example [to_date (hour 60)] is equivalent to [Date.Period.days 2]. *)
exception Not_computable
(** [= Date.Period.Not_computable].
@since 1.04 *)
val to_time : 'a period -> 'a Time.Period.period
(** Convert a calendar period to a date period.
@raise Not_computable if the time period is not computable.
@example [to_time (day 6)] returns a time period of [24 * 3600 * 6 =
518400] seconds
@example [to_time (second 30)] returns a time period of [30] seconds
@example [to_time (year 1)] raises [Not_computable] because
a year is not a constant number of days.
@since 1.04
@deprecated since 2.02: use {!safe_to_time} instead*)
val safe_to_time:
([< `Week | `Day ] as 'a) period -> 'a Time.Period.period
(** Equivalent to {!to_time} but never raises any exception.
@since 2.02 *)
val ymds: 'a period -> int * int * int * second
(** Number of years, months, days and seconds in a period.
@example [ymds (make 1 2 3 1 2 3)] returns [1, 2, 3, 3723]
@example [ymds (make (-1) (-2) (-3) (-1) (-2) (-3)] returns
[-1, -2, -4, 82677].
@since 1.09.0 *)
end
(** {2 Arithmetic operations on calendars and periods} *)
(** Those functions have the same behavious as those defined in
{!Date_sig.S}. *)
val add : t -> 'a Period.period -> t
(** @see Date_sig.S.add *)
val sub : t -> t -> [> `Week | `Day ] Period.period
(** @see Date_sig.S.sub *)
val precise_sub : t -> t -> Period.t
(** @see Date_sig.S.precise_sub
@since 2.03 *)
val rem : t -> 'a Period.period -> t
(** @see Date_sig.S.rem *)
val next : t -> field -> t
(** @see Date_sig.S.next *)
val prev : t -> field -> t
(** @see Date_sig.S.prev *)
end
calendar-3.0.0/src/date.ml 0000664 0000000 0000000 00000033226 14321307032 0015322 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(*S Introduction.
This module implements operations on dates representing by their Julian day.
Most of the algorithms implemented in this module come from the FAQ
available at~:
\begin{center}http://www.tondering.dk/claus/calendar.html\end{center} *)
(*S Datatypes. *)
type field = Period.date_field
(* the integer represents the Julian day *)
type -'a date = int constraint 'a = [< field ]
type t = field date
type day = Sun | Mon | Tue | Wed | Thu | Fri | Sat
type month =
Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec
type year = int
(*S Exceptions. *)
exception Out_of_bounds
exception Undefined
(*S Locale coercions.
These coercions are used in the algorithms and do not respect ISO-8601.
The exported coercions are defined at the end of the module. *)
(* pre: 0 <= n < 7 *)
external day_of_int : int -> day = "%identity"
external int_of_day : day -> int = "%identity"
(* pre: 0 <= n < 12 *)
external month_of_int : int -> month = "%identity"
external int_of_month : month -> int = "%identity"
(* Dates are comparable *)
let compare = Utils.Int.compare
let equal = Utils.Int.equal
let ( > ) x y = compare x y = 1
let ( >= ) x y = compare x y > -1
let ( < ) x y = compare x y = -1
let ( <= ) x y = compare x y < 1
let ( > ) c (ord, x, y) =
if c = 0 then ord x y else c
let cmp_date (y1, m1, d1) (y2, m2, d2) =
compare y1 y2 > (compare, m1, m2) > (compare, d1, d2)
let hash = Utils.Int.hash
(* Constructors. *)
let lt d1 d2 = (cmp_date d1 d2) < 0
(* [date_ok] returns [true] is the date belongs to the Julian period;
[false] otherwise. *)
let date_ok y m d = lt (-4713, 12, 31) (y, m, d) && lt (y, m, d) (3268, 1, 23)
(* Coerce month to the interval ]-oo; 12].
Note that the used algorithm of [make] does not require any coercion for
negative months *)
let coerce_month y m =
if m < 0 then
y, m
(* (* the below commented lines coerce [m] inside the interval [1;12]
instead of ]-oo;12]*)
let diff_y = (m + 1) / 12 - 1 in
y + diff_y, - 12 * diff_y + m*)
else
let pred_m = pred m in
y + pred_m / 12, pred_m mod 12 + 1
let make y m d =
let y, m = coerce_month y m in
if date_ok y m d then
let a = (14 - m) / 12 in
let y' = y + 4800 - a in
let m' = m + 12 * a - 3 in
if lt (1582, 10, 14) (y, m, d) then
(* Gregorian calendar *)
d + (153 * m' + 2) / 5 + y' * 365 + y' / 4 - y' / 100 + y' / 400 - 32045
else if lt (y, m, d) (1582, 10, 5) then
(* Julian calendar *)
d + (153 * m' + 2) / 5 + y' * 365 + y' / 4 - 32083
else
raise Undefined
else
raise Out_of_bounds
let lmake ~year ?(month = 1) ?(day = 1) () = make year month day
let make_year y = make y 1 1
let make_year_month y m = make y m 1
let current_day day gmt_hour =
let hour = Time_Zone.from_gmt () + gmt_hour in
(* change the day according to the time zone *)
if hour < 0 then begin
assert (hour > - 13);
day - 1
end else if hour >= 24 then begin
assert (hour < 36);
day + 1
end else
day
let jan_1_1970 = 2440588
let from_unixfloat x =
let d = int_of_float (x /. 86400.) + jan_1_1970 in
current_day d (Unix.gmtime x).Unix.tm_hour
let from_day_of_year y d = make y 1 d
let today () = from_unixfloat (Unix.time ())
let from_jd n = n
let to_jd d = d
let from_mjd x = x + 2400001
let to_mjd d = d - 2400001
(*S Useful operations. *)
let is_leap_year y =
if y > 1582 then (* Gregorian calendar *)
y mod 4 = 0 && (y mod 100 <> 0 || y mod 400 = 0)
else (* Julian calendar *)
if y > (- 45) && y <= (- 8) then
(* every year divisible by 3 is a leap year between 45 BC and 9 BC *)
y mod 3 = 0
else if y <= (- 45) || y >= 8 then y mod 4 = 0
else (* no leap year between 8 BC and 7 AD *) false
(*S Boolean operations on dates. *)
let is_julian d = d < 2299161
let is_gregorian d = d >= 2299161
(*S Getters. *)
(* [a] and [e] are auxiliary functions for [day_of_month], [month]
and [year]. *)
let a d = d + 32044
let e d =
let c =
if is_julian d then d + 32082
else let a = a d in a - (((4 * a + 3) / 146097) * 146097) / 4
in c - (1461 * ((4 * c + 3) / 1461)) / 4
let day_of_month d =
let e = e d in
let m = (5 * e + 2) / 153 in
e - (153 * m + 2) / 5 + 1
let int_month d = let m = (5 * e d + 2) / 153 in m + 3 - 12 * (m / 10)
let month d = month_of_int (int_month d - 1)
let year d =
let b, c =
if is_julian d then 0, d + 32082
else
let a = a d in
let b = (4 * a + 3) / 146097 in
b, a - (b * 146097) / 4 in
let d = (4 * c + 3) / 1461 in
let e = c - (1461 * d) / 4 in
b * 100 + d - 4800 + ((5 * e + 2) / 153) / 10
let int_day_of_week d = (d + 1) mod 7
let day_of_week d = day_of_int (int_day_of_week d)
let day_of_year d = d - make (year d - 1) 12 31
(* [week] implements an algorithm coming from Stefan Potthast. *)
let week d =
let d4 = (d + 31741 - (d mod 7)) mod 146097 mod 36524 mod 1461 in
let l = d4 / 1460 in
(((d4 - l) mod 365) + l) / 7 + 1
let days_in_month d =
match month d with
| Jan | Mar | May | Jul | Aug | Oct | Dec -> 31
| Apr | Jun | Sep | Nov -> 30
| Feb -> if is_leap_year (year d) then 29 else 28
(* Boolean operation using some getters. *)
let is_leap_day d =
is_leap_year (year d) && month d = Feb && day_of_month d = 24
let is_valid_date y m d =
try
let t = make y m d in
year t = y && int_month t = m && day_of_month t = d
with Out_of_bounds | Undefined ->
false
(*S Period. *)
module Period = struct
(* Cannot use an [int] : periods on months and years have not a constant
number of days.
For example, if we add a "one year" period [p] to the date 2000-3-12,
[p] corresponds to 366 days (because 2000 is a leap year) and the
resulting date is 2001-3-12 (yep, one year later). But if we add [p] to
the date 1999-3-12, [p] corresponds to 365 days and the resulting date is
2000-3-12 (yep, one year later too). *)
type +'a period = { m (* month *) : int; d (* day *) : int }
constraint 'a = [< field ]
type +'a p = 'a period
type t = field period
let empty = { m = 0; d = 0 }
let make y m d = { m = 12 * y + m; d = d }
let lmake ?(year = 0) ?(month = 0) ?(day = 0) () = make year month day
let day n = { empty with d = n }
let week n = { empty with d = 7 * n }
let month n = { empty with m = n }
let year n = { empty with m = 12 * n }
let add x y = { m = x.m + y.m; d = x.d + y.d }
let sub x y = { m = x.m - y.m; d = x.d - y.d }
let opp x = { m = - x.m; d = - x.d }
(* exactly equivalent to [Pervasives.compare] but more flexible typing *)
let compare x y =
let n = compare x.m y.m in
if n = 0 then compare x.d y.d else n
let equal x y = compare x y = 0
let hash = Hashtbl.hash
exception Not_computable
let nb_days p = if p.m <> 0 then raise Not_computable else p.d
let safe_nb_days p = p.d
let ymd p = p.m / 12, p.m mod 12, p.d
end
(*S Arithmetic operations on dates and periods. *)
let add d p =
let y,m,day = Period.ymd p in
make
(year d + y)
(int_month d + m)
(day_of_month d + day)
let sub x y = { Period.empty with Period.d = x - y }
let precise_sub y x =
let rec aux m =
if x + 31 * m < y then
aux (m + 1)
else
let y' = add x (Period.month m) in
let d = y - y' in
if d < 0 then
let m = m - 1 in
(* don't use [y'] below: [m] changes *)
m, d + days_in_month (add x (Period.month m))
else if d >= days_in_month y' then
aux (m + 1)
else
m, d
in
let m, d = aux ((y - x) / 31) in
{ Period.m = m; d = d }
let rem d p = add d (Period.opp p)
let next d = function
| `Year -> add d (Period.year 1)
| `Month -> add d (Period.month 1)
| `Week -> add d (Period.day 7)
| `Day -> add d (Period.day 1)
let prev d = function
| `Year -> add d (Period.year (- 1))
| `Month -> add d (Period.month (- 1))
| `Week -> add d (Period.day (- 7))
| `Day -> add d (Period.day (- 1))
(*S Operations on years. *)
let same_calendar y1 y2 =
let d = y1 - y2 in
let aux =
if is_leap_year y1 then true
else if is_leap_year (y1 - 1) then d mod 6 = 0 || d mod 17 = 0
else if is_leap_year (y1 - 2) then d mod 11 = 0 || d mod 17 = 0
else if is_leap_year (y1 - 3) then d mod 11 = 0
else false
in d mod 28 = 0 || aux
let days_in_year =
let days = [| 31; 59; 90; 120; 151; 181; 212; 243; 273; 304; 334; 365 |] in
fun ?(month=Dec) y ->
let m = int_of_month month in
let res = days.(m) in
if is_leap_year y && m > 0 then res + 1 else res
let weeks_in_year y =
let first_day = day_of_week (make y 1 1) in
match first_day with
| Thu -> 53
| Wed -> if is_leap_year y then 53 else 52
| _ -> 52
let week_first_last w y =
let d = make y 1 4 in (* January 4th must be in the first week (ISO 8601) *)
let d = d - d mod 7 in
let b = d + 7 * (w - 1) in
b, 6 + b
let nth_weekday_of_month y m d n =
let first = make y (int_of_month m + 1) 1 in
let gap =
let diff = int_of_day d - int_day_of_week first in
if diff >= 0 then diff - 7 else diff
in
first + 7 * n + gap
let century y = if y mod 100 = 0 then y / 100 else y / 100 + 1
let millenium y = if y mod 1000 = 0 then y / 1000 else y / 1000 + 1
let solar_number y = (y + 8) mod 28 + 1
let indiction y = (y + 2) mod 15 + 1
let golden_number y = y mod 19 + 1
let epact y =
let julian_epact = (11 * (golden_number y - 1)) mod 30 in
if y <= 1582 then julian_epact (* Julian calendar *)
else (* Gregorian calendar *)
let c = y / 100 + 1 (* century *) in
(* 1900 belongs to the 20th century for this algorithm *)
abs ((julian_epact - (3 * c) / 4 + (8 * c + 5) / 25 + 8) mod 30)
(* [easter] implements the algorithm of Oudin (1940) *)
let easter y =
let g = y mod 19 in
let i, j =
if y <= 1582 then (* Julian calendar *)
let i = (19 * g + 15) mod 30 in
i, (y + y / 4 + i) mod 7
else (* Gregorian calendar *)
let c = y / 100 in
let h = (c - c / 4 - (8 * c + 13) / 25 + 19 * g + 15) mod 30 in
let i = h - (h / 28) * (1 - (h / 28) * (29 / (h + 1)) * ((21 - g) / 11))
in i, (y + y / 4 + i + 2 - c + c / 4) mod 7
in
let l = i - j in
let m = 3 + (l + 40) / 44 in
make y m (l + 28 - 31 * (m / 4))
let carnaval y = easter y - 48
let mardi_gras y = easter y - 47
let ash y = easter y - 46
let palm y = easter y - 7
let easter_friday y = easter y - 2
let easter_saturday y = easter y - 1
let easter_monday y = easter y + 1
let ascension y = easter y + 39
let withsunday y = easter y + 49
let withmonday y = easter y + 50
let corpus_christi y = easter y + 60
(*S Exported Coercions. *)
let from_unixtm x =
let d = (* current day at GMT *)
make (x.Unix.tm_year + 1900) (x.Unix.tm_mon + 1) x.Unix.tm_mday
in
current_day d x.Unix.tm_hour
let to_unixtm d =
{ Unix.tm_sec = 0; Unix.tm_min = 0; Unix.tm_hour = 0;
Unix.tm_mday = day_of_month d;
Unix.tm_mon = int_month d - 1;
Unix.tm_year = year d - 1900;
Unix.tm_wday = int_day_of_week d;
Unix.tm_yday = day_of_year d - 1;
Unix.tm_isdst = false }
let to_unixfloat x = float_of_int (x - jan_1_1970) *. 86400.
(* do not replace [*.] by [*]: the result is bigger than [max_int] ! *)
let to_business d =
let w = week d in
let y =
let y = year d in
match int_month d with
| 1 -> let x = y - 1 in if w = weeks_in_year x then x else y
| 12 -> if w = 1 then y + 1 else y
| _ -> y
in
y, w, day_of_week d
let int_of_day d = let n = int_of_day d in if n = 0 then 7 else n
(* Used by [from_business] *)
let from_business y w d =
if w < 1 || w > weeks_in_year y then invalid_arg "from_business: bad week";
let first =
try make y 1 1
with Out_of_bounds | Undefined -> invalid_arg "from_business: bad date"
in
let first_day = int_day_of_week first in
let w = if first_day > 4 then w else w - 1 in
first + w * 7 + int_of_day d - first_day
(* These coercions redefine those defined at the beginning of the module.
They respect ISO-8601. *)
let int_of_day = int_of_day
let day_of_int n =
if n > 0 && n < 7 then day_of_int n
else if n = 7 then day_of_int 0
else invalid_arg "Not a day"
let int_of_month m = int_of_month m + 1
let month_of_int n =
if n > 0 && n < 13 then month_of_int (n - 1) else invalid_arg "Not a month"
calendar-3.0.0/src/date.mli 0000664 0000000 0000000 00000003202 14321307032 0015462 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Date implementation. *)
include Date_sig.S
calendar-3.0.0/src/date_sig.mli 0000664 0000000 0000000 00000042347 14321307032 0016341 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Date interface. A date may be seen as a triple (year, month, day).
All the dates should belong to
[[January, 1st 4713 BC; January 22th, 3268 AC]] (called the Julian period).
An [Out_of_bounds] exception is raised if you attempt to create a date
outside the Julian period.
If a date [d] does not exists and if [d_bef] (resp. [d_aft]) is
the last (resp. first) existing date before (resp. after) [d],
[d] is automatically coerced to [d_aft + d - d_bef - 1].
For example, both dates "February 29th, 2003" and
"February 30th, 2003" do not exist and they are coerced respectively to the
date "Mars 1st, 2003" and "Mars 2nd, 2003".
This rule is called the coercion rule.
As an exception to the coercion rule, the date belonging to
[[October 5th, 1582; October 14th, 1582]] do not exist and an [Undefined]
exception is raised if you attempt to create such a date.
Those dropped days correspond to the change from the Julian to the Gregorian
calendar. *)
(** Common operations for all date representations.
@since 2.0 (this signature was before inlined in interface of Date). *)
module type S = sig
(** {2 Datatypes} *)
(** The different fields of a date.
@since 2.02 *)
type field = Period.date_field
(** Type of a date, without specifying any precision level.
@since 2.02 *)
type -'a date constraint 'a = [< field ]
(** Type of a date. *)
type t = field date
(** Days of the week. *)
type day = Sun | Mon | Tue | Wed | Thu | Fri | Sat
(** Months of the year. *)
type month =
Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec
(** Year as an [int]. *)
type year = int
(** {2 Exceptions} *)
exception Out_of_bounds
(** Raised when a date is outside the Julian period. *)
exception Undefined
(** Raised when a date belongs to
[[October 5th, 1582; October 14th, 1582]]. *)
(** {2 Constructors} *)
val make : year -> int -> int -> t
(** [make year month day] makes the date year-month-day. A BC year [y]
corresponds to the year [-(y+1)].
@example years (5 BC) and (1 BC) respectively correspond to years
(-4) and 0.
@raise Out_of_bounds when a date is outside the Julian period.
@raise Undefined when a date belongs to [[October 5th, 1582; October
14th, 1582]]. *)
val lmake : year:year -> ?month:int -> ?day:int -> unit -> t
(** Labelled version of [make].
The default value of [month] and [day] is [1].
@raise Out_of_bounds when a date is outside the Julian period.
@raise Undefined when a date belongs to [[October 5th, 1582; October
14th, 1582]].
@since 1.05 *)
val make_year: int -> [< `Year ] date
(** [make_year y] makes a date only represented by its year [y]. The month
and the day of such a date are not relevant.
@since 2.02 *)
val make_year_month: int -> int -> [< `Year | `Month ] date
(** [make_year_month y m] makes a date only represented by its year [y] and
its month [m]. The day of such a date is not relevant.
@since 2.02 *)
val today : unit -> t
(** Date of the current day (based on [Time_Zone.current ()]). *)
val from_jd : int -> t
(** Make a date from its Julian day.
@example [from_jd 0] returns the date 4713 BC-1-1. *)
val from_mjd : int -> t
(** Make a date from its modified Julian day (i.e. Julian day - 2 400 001).
The Modified Julian day is more manageable than the Julian day.
@example [from_mjd 0] returns the date 1858-11-17. *)
val from_day_of_year: year -> int -> t
(** Make a date from a year and its day of the year.
@example [from_day_of_year 2008 39] returns the date 2008-2-8.
@since 2.0 *)
(** {2 Getters} *)
val days_in_month : [> `Year | `Month ] date -> int
(** Number of days in the month of a date.
@example [days_in_month (make 2003 6 26)] returns [30]. *)
val day_of_week : t -> day
(** Day of the week.
@example [day_of_week (make 2003 6 26)] returns [Thu]. *)
val day_of_month : t -> int
(** Day of the month.
@example [day_of_month (make 2003 6 26)] returns [26]. *)
val day_of_year : t -> int
(** Day of the year.
@example [day_of_year (make 2003 1 5)] returns [5]
@example [day_of_year (make 2003 12 28)] returns [362]. *)
val week : t -> int
(** Week.
@example [week (make 2000 1 3)] returns [1].
@example [week (make 2000 1 2)] returns [52].
@example [week (make 2003 12 28)] returns [52].
@example [week (make 2003 12 29)] returns [1]. *)
val month : [> `Month ] date -> month
(** Month.
@example [month (make 2003 6 26)] returns [Jun]. *)
val year : [> `Year ] date -> year
(** Year.
@example [year (make 2003 6 26)] returns [2003]. *)
val to_jd : t -> int
(** Julian day.
@example [to_jd (make (-4712) 1 1)] returns 0. *)
val to_mjd : t -> int
(** Modified Julian day (i.e. Julian day - 2 400 001).
The Modified Julian day is more manageable than the Julian day.
@example [to_mjd (make 1858 11 17)] returns 0. *)
(** {2 Dates are comparable} *)
val equal: 'a date -> 'b date -> bool
(** Equality function between two dates.
@see Utils.Comparable.equal
@since 1.09.0 *)
val compare : 'a date -> 'b date -> int
(** Comparison function between two dates.
@see Utils.Comparable.compare *)
val ( > ) : 'a date -> 'b date -> bool
(** Check if the first date is later than the second *)
val ( >= ) : 'a date -> 'b date -> bool
(** Check if the first date is later or equal to the second *)
val ( < ) : 'a date -> 'b date -> bool
(** Check if the first date is earlier than the second *)
val ( <= ) : 'a date -> 'b date -> bool
(** Check if the first date is earlier or equal to the second *)
val hash: 'a date -> int
(** Hash function for dates.
@see Utils.Comparable.hash
@since 2.0 *)
(** {2 Boolean operations on dates} *)
val is_valid_date: year -> int -> int -> bool
(** Check if a date is valid, that is the date has not been coerced to look
like a real date.
@example [is_valid_date 2008 2 8] returns [true]
@example [is_valid_date 2008 2 30] returns [false]
@since 2.0 *)
val is_leap_day : t -> bool
(** Return [true] if a date is a leap day
(i.e. February, 24th of a leap year); [false] otherwise. *)
val is_gregorian : t -> bool
(** Return [true] if a date belongs to the Gregorian calendar;
[false] otherwise. *)
val is_julian : t -> bool
(** Return [true] iff a date belongs to the Julian calendar;
[false] otherwise. *)
(** {2 Coercions} *)
val to_unixtm : t -> Unix.tm
(** Convert a date into the [Unix.tm] type.
The field [is_isdst] is always [false]. The fields [Unix.tm_sec],
[Unix.tm_min] and [Unix.tm_hour] are irrelevant.
@since 1.01 *)
val from_unixtm : Unix.tm -> t
(** Inverse of [to_unixtm]. Assume the current time zone.
@since 1.01 *)
val to_unixfloat : t -> float
(** Convert a date to a float such than [to_unixfloat (make 1970 1 1)]
returns [0.0]. So such a float is convertible with those of the [Unix]
module. The fractional part of the result is always [0].
@since 1.01 *)
val from_unixfloat : float -> t
(** Inverse of [to_unixfloat]. Ignore the fractional part of the argument.
Assume the current time zone.
@since 1.01 *)
val to_business: t -> year * int * day
(** Return the "business week" and the day in this week respecting ISO 8601.
Notice that business weeks at the beginning and end of the year can
sometimes have year numbers which don't match the real year.
@example [to_business (make 2000 1 3)] returns [2000, 1, Mon]
@example [to_business (make 2000 1 2)] returns [1999, 52, Sun]
@example [to_business (make 2003 12 28)] returns [2003, 52, Sun]
@example [to_business (make 2003 12 29)] returns [2004, 1, Mon].
@since 1.09.0 *)
val from_business: year -> int -> day -> t
(** Inverse of [to_business] respecting ISO-8601.
Notice that business weeks at the beginning and end of the year
can sometimes have year numbers which don't match the real year.
@raise Invalid_argument if the date is bad.
@since 1.09.0 *)
val int_of_day : day -> int
(** Convert a day to an integer respecting ISO-8601.
So, Monday is 1, Tuesday is 2, ..., and sunday is 7. *)
val day_of_int : int -> day
(** Inverse of [int_of_day].
@raise Invalid_argument if the argument does not belong to [1; 7]. *)
val int_of_month : month -> int
(** Convert a month to an integer respecting ISO-8601.
So, January is 1, February is 2 and so on. *)
val month_of_int : int -> month
(** Inverse of [int_of_month].
@raise Invalid_argument if the argument does not belong to [1; 12]. *)
(** {2 Period} *)
(** A period is the number of days between two dates. *)
module Period : sig
(** {3 Arithmetic operations} *)
type +'a p constraint 'a = [< field ]
include Period.S with type +'a period = 'a p
(** {3 Constructors} *)
val make: int -> int -> int -> t
(** [make year month day] makes a period of the specified length. *)
val lmake: ?year:int -> ?month:int -> ?day:int -> unit -> t
(** Labelled version of [make].
The default value of each argument is [0]. *)
val year: int -> [> `Year ] period
(** [year n] makes a period of [n] years. *)
val month: int -> [> `Year | `Month ] period
(** [month n] makes a period of [n] months. *)
val week: int -> [> `Week | `Day ] period
(** [week n] makes a period of [n] weeks. *)
val day: int -> [> `Week | `Day ] period
(** [day n] makes a period of [n] days. *)
(** {3 Getters} *)
exception Not_computable
(** @since 1.04 *)
val nb_days: 'a period -> int
(** Number of days in a period.
@raise Not_computable if the number of days is not computable.
@example [nb_days (day 6)] returns [6]
@example [nb_days (year 1)] raises [Not_computable] because a year is
not a constant number of days.
@since 1.04
@deprecated since 2.02: use {!safe_nb_days} instead *)
val safe_nb_days: [< `Week | `Day ] period -> int
(** Equivalent to {!nb_days} but never raises any exception.
@since 2.02 *)
val ymd: 'a period -> int * int * int
(** Number of years, months and days in a period.
@example [ymd (make 1 2 3)] returns [1, 2, 3].
@since 1.09.0 *)
end
(** {2 Arithmetic operations on dates and periods} *)
val add : 'a date -> 'a Period.period -> 'a date
(** [add d p] returns [d + p].
@raise Out_of_bounds when the resulting date is outside the Julian
period.
@raise Undefined when the resulting date belongs to [[October 5th,
1582; October 14th, 1582]].
@example [add (make 2003 12 31) (Period.month 1)] returns the date
2004-1-31
@example [add (make 2003 12 31) (Period.month 2)] returns the date
2004-3-2 (following the coercion rule describes in the introduction). *)
val sub : 'a date -> 'a date -> [> `Week | `Day ] Period.period
(** [sub d1 d2] returns the period between [d1] and [d2]. *)
val precise_sub : 'a date -> 'a date -> Period.t
(** [precise_sub d1 d2] returns the period between [d1] and [d2].
It is equivalent to [sub], but:
- the period is expressed with a number of years, months and days, not
only with a number of days;
- it is less efficient.
@since 2.03 *)
val rem : 'a date -> 'a Period.period -> 'a date
(** [rem d p] is equivalent to [add d (Period.opp p)].
@raise Out_of_bounds when the resulting date is outside the Julian
period.
@raise Undefined when the resulting date belongs to [[October 5th,
1582; October 14th, 1582]]. *)
val next : 'a date -> ([< field ] as 'a) -> 'a date
(** [next d f] returns the date corresponding to the next specified field.
@raise Out_of_bounds when the resulting date is outside the Julian
period.
@raise Undefined when the resulting date belongs to [[October 5th,
1582; October 14th, 1582]].
@example [next (make 2003 12 31) `Month] returns the date 2004-1-31
(i.e. one month later). *)
val prev : 'a date -> ([< field ] as 'a) -> 'a date
(** [prev d f] returns the date corresponding to the previous specified
field.
@raise Out_of_bounds when the resulting date is outside the Julian
period.
@raise Undefined when the resulting date belongs to [[October 5th,
1582; October 14th, 1582]].
@example [prev (make 2003 12 31) `Year] returns the date 2002-12-31
(i.e. one year ago). *)
(** {2 Operations on years} *)
val is_leap_year : year -> bool
(** Return [true] if a year is a leap year; [false] otherwise. *)
val same_calendar : year -> year -> bool
(** Return [true] if two years have the same calendar; [false]
otherwise. *)
val days_in_year : ?month:month -> year -> int
(** Number of days in a year.
[days_in_year ~month y] returns the number of days in the year [y] up
to the end of the given month. Thus [days_in_year ~month:Dec y] is the
same as [days_in_year y]. *)
val weeks_in_year: year -> int
(** Number of weeks in a year. *)
val week_first_last: int -> year -> t * t
(** Return the first and last days of a week in a year.
@since 1.08 *)
val nth_weekday_of_month: year -> month -> day -> int -> t
(** [nth_weekday_of_month y m d n] returns the [n]-th day [d] in the month
[m] of the year [y] (for instance the 3rd Thursday of the month).
@since 1.09.0 *)
val century : year -> int
(** Century of a year.
@example [century 2000] returns 20
@example [century 2001] returns 21. *)
val millenium : year -> int
(** Millenium of a year.
@example [millenium 2000] returns 2
@example [millenium 2001] returns 3. *)
val solar_number : year -> int
(** Solar number.
In the Julian calendar there is a one-to-one relationship between the
Solar number and the day on which a particular date falls. *)
val indiction : year -> int
(** Indiction.
The Indiction was used in the middle ages to specify the position of a
year in a 15 year taxation cycle. It was introduced by emperor
Constantine the Great on 1 September 312 and ceased to be used in
1806.
The Indiction has no astronomical significance. *)
val golden_number : year -> int
(** Golden number.
Considering that the relationship between the moon's phases and the
days of the year repeats itself every 19 years, it is natural to
associate a number between 1 and 19 with each year.
This number is the so-called Golden number. *)
val epact : year -> int
(** Epact.
The Epact is a measure of the age of the moon (i.e. the number of days
that have passed since an "official" new moon) on a particular date. *)
val easter : year -> t
(** Easter Sunday.
In the Christian world, Easter (and the days immediately preceding it)
is the celebration of the death and resurrection of Jesus in
(approximately) AD 30. *)
val carnaval: year -> t
(** Carnaval Monday. [carnaval y] is [easter y - 48].
@since 1.09.0 *)
val mardi_gras: year -> t
(** Mardi Gras. [mardi_gras y] is [easter y - 47].
@since 1.09.0 *)
val ash: year -> t
(** Ash Wednesday. [ash y] is [easter y - 46].
@since 1.09.0 *)
val palm: year -> t
(** Palm Sunday. [palm y] is [easter y - 7].
@since 1.09.0 *)
val easter_friday: year -> t
(** Easter Friday. [easter_friday y] is [easter y - 2].
@since 1.09.0 *)
val easter_saturday: year -> t
(** Easter Saturday. [easter_saturday y] is [easter y - 1].
@since 1.09.0 *)
val easter_monday: year -> t
(** Easter Monday. [easter_monday y] is [easter y + 1].
@since 1.09.0 *)
val ascension: year -> t
(** Ascension. [ascension y] is [easter y + 39].
@since 1.09.0 *)
val withsunday: year -> t
(** Withsunday. [withsunday y] is [easter y + 49].
@since 1.09.0 *)
val withmonday: year -> t
(** Withmonday. [withmonday y] is [easter y + 50].
@since 1.09.0 *)
val corpus_christi: year -> t
(** Feast of Corpus Christi. [corpus_christi y] is [easter + 60].
@since 1.09.0 *)
end
calendar-3.0.0/src/dune 0000664 0000000 0000000 00000000533 14321307032 0014724 0 ustar 00root root 0000000 0000000
(library
(name calendarLib)
(public_name calendar)
(libraries re unix)
(modules_without_implementation calendar_sig date_sig period time_sig)
(flags :standard -warn-error -32 -safe-string))
(rule
(targets version.ml)
(action
(with-stdout-to %{targets}
(echo "let version = String.trim \"" %{version:calendar} "\"\n"))))
calendar-3.0.0/src/fcalendar.ml 0000664 0000000 0000000 00000003272 14321307032 0016322 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
include Calendar_builder.Make(Date)(Ftime)
module Precise = Calendar_builder.Make_Precise(Date)(Ftime)
calendar-3.0.0/src/fcalendar.mli 0000664 0000000 0000000 00000004111 14321307032 0016464 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Calendar implementation in which seconds are float.
This module uses float. Then results may be very unprecise, especially
comparison of calendars which differ with few seconds.
In this case, consider to use module [Precise].
@since 2.0 *)
include Calendar_sig.S with module Date = Date and module Time = Ftime
(** More precise implementation of calendar in which seconds are float.
@since 2.0 *)
module Precise: Calendar_sig.S with module Date = Date and module Time = Ftime
calendar-3.0.0/src/ftime.ml 0000664 0000000 0000000 00000010634 14321307032 0015507 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(*S Introduction.
A time is represents by a number of seconds in UTC.
Outside this module, a time is interpreted in the current time zone.
So, each operations have to coerce a given time according to the current
time zone. *)
(*S Datatypes. *)
include Utils.Float
type second = float
type field = [ `Hour | `Minute | `Second ]
(*S Conversions. *)
let one_day = 86400
let fone_day = 86400.
let convert t t1 t2 = t +. float (3600 * Time_Zone.gap t1 t2)
let from_gmt t = convert t Time_Zone.UTC (Time_Zone.current ())
let to_gmt t = convert t (Time_Zone.current ()) Time_Zone.UTC
(* Coerce [t] into the interval $[0; 86400[$ (i.e. a one day interval). *)
let normalize t =
let t = from_gmt t in
let t_mod, t_div = to_gmt (mod_float t fone_day), int_of_float t / one_day in
if t < 0. then t_mod +. fone_day, t_div - 1 else t_mod, t_div
(*S Constructors. *)
let make h m s = to_gmt (float (h * 3600 + m * 60) +. s)
let lmake ?(hour = 0) ?(minute = 0) ?(second = 0.) () = make hour minute second
let midnight () = to_gmt 0.
let midday () = to_gmt 43200.
let now () =
let now = Unix.gettimeofday () in
let gmnow = Unix.gmtime now in
let frac, _ = modf now in
float
(3600 * gmnow.Unix.tm_hour + 60 * gmnow.Unix.tm_min + gmnow.Unix.tm_sec)
+. frac
(*S Getters. *)
let hour t = int_of_float (from_gmt t) / 3600
let minute t = int_of_float (from_gmt t) mod 3600 / 60
let second t = mod_float (from_gmt t) 60.
let to_hours t = from_gmt t /. 3600.
let to_minutes t = from_gmt t /. 60.
let to_seconds t = from_gmt t
(*S Boolean operations. *)
let is_pm t =
let t, _ = normalize t in
let m, _ = normalize (midday ()) in
t < m
let is_am t =
let t, _ = normalize t in
let m, _ = normalize (midday ()) in
t >= m
(*S Coercions. *)
let from_hours t = to_gmt (t *. 3600.)
let from_minutes t = to_gmt (t *. 60.)
let from_seconds t = to_gmt t
(*S Seconds. *)
module Second = struct
type t = second
let from_int = float
let to_int = int_of_float
let from_float x = x
let to_float x = x
end
(*S Period. *)
module Period = struct
type +'a period = float constraint 'a = [< Period.date_field ]
include Utils.Float
let make h m s = float (h * 3600 + m * 60) +. s
let lmake ?(hour=0) ?(minute=0) ?(second=0.) () = make hour minute second
let length x = x
let hour x = float (x * 3600)
let minute x = float (x * 60)
let second x = x
let empty = 0.
let add = (+.)
let sub = (-.)
let mul = ( *. )
let div = (/.)
let opp x = -. x
let to_seconds x = x
let to_minutes x = x /. 60.
let to_hours x = x /. 3600.
end
(*S Arithmetic operations on times and periods. *)
let add = (+.)
let sub = (-.)
let rem = (-.)
let next x = function
| `Hour -> x +. 3600.
| `Minute -> x +. 60.
| `Second -> x +. 1.
let prev x = function
| `Hour -> x -. 3600.
| `Minute -> x -. 60.
| `Second -> x -. 1.
calendar-3.0.0/src/ftime.mli 0000664 0000000 0000000 00000003407 14321307032 0015660 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Time implementation in which seconds are floats.
This module uses float. Then results may be very unprecise.
@since 2.0 *)
include Time_sig.S with type second = float
calendar-3.0.0/src/period.mli 0000664 0000000 0000000 00000005661 14321307032 0016042 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** A period represents the time passed between two events (a date, a time...).
Only an interface defining arithmetic operations on periods is defined here.
An implementation of this interface depends on the kind of an event (see
module [Time.Period], [Date.Period] and [Calendar.Period]). *)
type date_field = [ `Year | `Month | `Week | `Day ]
(** Common interface for all periods. *)
module type S = sig
type +'a period constraint 'a = [< date_field ]
type t = date_field period
(** Type of a period. *)
(** {3 Period is an additive monoid} *)
val empty : 'a period
(** The empty period. *)
val add : 'a period -> 'a period -> 'a period
(** Addition of periods. *)
val sub : 'a period -> 'a period -> 'a period
(** Substraction of periods. *)
val opp : 'a period -> 'a period
(** Opposite of a period. *)
(** {3 Periods are comparable} *)
val equal: 'a period -> 'b period -> bool
(** Equality function between two periods.
@see Utils.Comparable.equal
@since 1.09.0 *)
val compare : 'a period -> 'b period -> int
(** Comparison function between two periods.
@see Utils.Comparable.compare *)
val hash: 'a period -> int
(** Hash function for periods.
@see Utils.Comparable.hash
@since 2.0 *)
end
calendar-3.0.0/src/printer.ml 0000664 0000000 0000000 00000047305 14321307032 0016073 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
module type S = sig
type t
val fprint : string -> Format.formatter -> t -> unit
val print : string -> t -> unit
val dprint : t -> unit
val sprint : string -> t -> string
val to_string : t -> string
val from_fstring : string -> string -> t
val from_string : string -> t
end
let day_name =
ref (function
| Date.Sun -> "Sunday"
| Date.Mon -> "Monday"
| Date.Tue -> "Tuesday"
| Date.Wed -> "Wednesday"
| Date.Thu -> "Thursday"
| Date.Fri -> "Friday"
| Date.Sat -> "Saturday")
let name_of_day d = !day_name d
let short_name_of_day d =
let d = name_of_day d in
try String.sub d 0 3 with Invalid_argument _ -> d
let month_name =
ref (function
| Date.Jan -> "January"
| Date.Feb -> "February"
| Date.Mar -> "March"
| Date.Apr -> "April"
| Date.May -> "May"
| Date.Jun -> "June"
| Date.Jul -> "July"
| Date.Aug -> "August"
| Date.Sep -> "September"
| Date.Oct -> "October"
| Date.Nov -> "November"
| Date.Dec -> "December")
let name_of_month m = !month_name m
let short_name_of_month m =
let m = name_of_month m in
try String.sub m 0 3 with Invalid_argument _ -> m
type pad =
| Zero
| Blank
| Empty
| Uppercase
(* [k] should be a power of 10. *)
let print_number fmt pad k n =
assert (k > 0);
let rec aux k n =
let fill fmt = function
| Zero -> Format.pp_print_int fmt 0
| Blank -> Format.pp_print_char fmt ' '
| Empty | Uppercase -> ()
in
if k = 1 then Format.pp_print_int fmt n
else begin
if n < k then fill fmt pad;
aux (k / 10) n
end
in
if n < 0 then Format.pp_print_char fmt '-';
aux k (abs n)
let bad_format s = raise (Invalid_argument ("bad format: " ^ s))
let not_match f s =
raise (Invalid_argument (s ^ " does not match the format " ^ f))
let gen_month_of_name f fmt name =
let rec aux i =
if i = 0 then not_match fmt name
else if f (Date.month_of_int i) = name then i
else aux (i-1)
in
aux 12
let month_of_name = gen_month_of_name name_of_month "%b"
let month_of_short_name = gen_month_of_name short_name_of_month "%B"
let gen_day_of_name f fmt name =
let rec aux i =
if i = 0 then not_match fmt name
else if f (Date.day_of_int i) = name then i
else aux (i-1)
in
aux 7
let day_of_name = gen_day_of_name name_of_day "%a"
let day_of_short_name = gen_day_of_name short_name_of_day "%A"
let word_regexp = ref (Re.Str.regexp "[a-zA-Z]+")
let set_word_regexp r = word_regexp := r
type 'a second_builder =
| Int of (int -> int -> int -> int -> int -> int -> 'a)
| Float of (int -> int -> int -> int -> int -> float -> 'a)
(* [Make] creates a printer from a small set of functions. *)
module Make(X : sig
type t
val make : t second_builder
val from_business: Date.year -> int -> Date.day -> t
val default_format : string
val hour : t -> int
val minute : t -> int
val second : t -> int
val day_of_week : t -> Date.day
val day_of_month : t -> int
val day_of_year : t -> int
val week : t -> int
val month : t -> Date.month
val year : t -> int
val century: t -> int
val seconds_since_1970: t -> int
end) =
struct
type t = X.t
let short_interval h =
let h = Lazy.force h mod 12 in
if h = 0 then 12 else h
let fprint f fmt x =
let len = String.length f in
let weekday = lazy (name_of_day (X.day_of_week x)) in
let sweekday = lazy (short_name_of_day (X.day_of_week x)) in
let day_of_week = lazy (Date.int_of_day (X.day_of_week x)) in
let month_name = lazy (name_of_month (X.month x)) in
let smonth_name = lazy (short_name_of_month (X.month x)) in
let int_month = lazy (Date.int_of_month (X.month x)) in
let day_of_month = lazy (X.day_of_month x) in
let day_of_year = lazy (X.day_of_year x) in
let week = lazy (X.week x) in
let year = lazy (X.year x) in
let syear = (* work only if year in (0..9999) *)
lazy (Lazy.force year mod 100) in
let century = lazy (X.century x) in
let hour = lazy (X.hour x) in
let shour = lazy (short_interval hour) in
let minute = lazy (X.minute x) in
let second = lazy (X.second x) in
let apm = lazy (if Lazy.force hour mod 24 < 12 then "AM" else "PM") in
let tz = lazy (Time_Zone.from_gmt ()) in
let seconds_since_1970 = lazy (X.seconds_since_1970 x) in
let print_char c = Format.pp_print_char fmt c in
let print_int pad k n = print_number fmt pad k (Lazy.force n) in
let print_string pad s =
let pad s = match pad with
| Uppercase -> String.uppercase_ascii s
| Empty | Zero | Blank -> s
in
Format.pp_print_string fmt (pad (Lazy.force s))
in
let print_time pad h =
print_int pad 10 h;
print_char ':';
print_int pad 10 minute;
print_char ':';
print_int pad 10 second in
let rec parse_option i pad =
let parse_char c =
let jump = ref 0 in
begin match c with
| '%' -> print_char '%'
| 'a' -> print_string pad sweekday
| 'A' -> print_string pad weekday
| 'b' | 'h' -> print_string pad smonth_name
| 'B' -> print_string pad month_name
| 'c' ->
print_string pad sweekday;
print_char ' ';
print_string pad smonth_name;
print_char ' ';
print_int pad 10 day_of_month;
print_char ' ';
print_time pad hour;
print_char ' ';
print_int pad 1000 year
| 'C' -> print_int pad 10 century
| 'd' -> print_int pad 10 day_of_month
| 'D' ->
print_int pad 10 int_month;
print_char '/';
print_int pad 10 day_of_month;
print_char '/';
print_int pad 10 syear
| 'e' -> print_int Blank 10 day_of_month
| 'F' | 'i' ->
print_int pad 1000 year;
print_char '-';
print_int pad 10 int_month;
print_char '-';
print_int pad 10 day_of_month
| 'H' -> print_int pad 10 hour;
| 'I' -> print_number fmt pad 10 (short_interval hour)
| 'j' -> print_int pad 100 day_of_year
| 'k' -> print_int Blank 10 hour
| 'l' -> print_number fmt Blank 10 (short_interval hour)
| 'm' -> print_int pad 10 int_month
| 'M' -> print_int pad 10 minute
| 'n' -> print_char '\n'
| 'p' -> print_string pad apm
| 'P' ->
Format.pp_print_string fmt (String.lowercase_ascii (Lazy.force apm))
| 'r' ->
print_time pad shour;
print_char ' ';
print_string pad apm
| 's' -> print_int pad 1 seconds_since_1970
| 'R' ->
print_int pad 10 hour;
print_char ':';
print_int pad 10 minute
| 'S' -> print_int pad 10 second
| 't' -> print_char '\t'
| 'T' -> print_time pad hour
| 'V' | 'W' -> print_int pad 10 week
| 'w' -> print_int Empty 1 day_of_week
| 'y' -> print_int pad 10 syear
| 'Y' -> print_int pad 1000 year
| 'z' ->
if Lazy.force tz >= 0 then print_char '+';
print_int pad 10 tz;
print_number fmt Zero 10 0
| ':' ->
let idx =
try Re.Str.search_forward (Re.Str.regexp "z\\|:z\\|::z") f (i+1)
with Not_found -> bad_format f
in
let next = Re.Str.matched_string f in
if idx <> i+1 then bad_format f;
if Lazy.force tz >= 0 then print_char '+';
print_int pad 10 tz;
let print_block () =
print_char ':';
print_number fmt Zero 10 0
in
jump := String.length next;
(match next with
| "z" -> print_block ()
| ":z" -> print_block (); print_block ()
| "::z" -> ()
| _ -> assert false);
| c -> bad_format ("%" ^ String.make 1 c)
end;
parse_format (i + 1 + !jump)
in
assert (i <= len);
if i = len then bad_format f;
(* else *)
let pad p =
if pad <> Zero then bad_format f;
(* else *) parse_option (i + 1) p
in
match f.[i] with
| '0' -> pad Zero
| '-' -> pad Empty
| '_' -> pad Blank
| '^' -> pad Uppercase
| c -> parse_char c
and parse_format i =
assert (i <= len);
if i = len then ()
else match f.[i] with
| '%' -> parse_option (i + 1) Zero
| c ->
Format.pp_print_char fmt c;
parse_format (i + 1)
in
parse_format 0;
Format.pp_print_flush fmt ()
let print f = fprint f Format.std_formatter
let dprint = print X.default_format
let sprint f d =
let buf = Buffer.create 15 in
let fmt = Format.formatter_of_buffer buf in
fprint f fmt d;
Buffer.contents buf
let to_string = sprint X.default_format
let from_fstring f s =
let delayed_computations = ref [] in
let day_of_week, week = ref min_int, ref min_int in
let year, month, day = ref min_int, ref min_int, ref min_int in
let hour, minute, second, pm =
ref min_int, ref min_int, ref (float min_int), ref 0
in
let tz = ref 0 in
let from_biz () =
if !week = -1 || !year = -1 then
bad_format (f ^ " (either week or year is not provided)");
let d = X.from_business !year !week (Date.day_of_int !day_of_week) in
year := X.year d;
month := Date.int_of_month (X.month d);
day := X.day_of_month d
in
let j = ref 0 in
let lenf = String.length f in
let lens = String.length s in
let read_char c =
if !j >= lens || s.[!j] != c then not_match f s;
incr j
in
let read_number n =
let jn = !j + n in
if jn > lens then not_match f s;
let res =
try int_of_string (String.sub s !j n)
with Failure _ -> not_match f s
in
j := jn;
res
in
let read_word ?(regexp=(!word_regexp)) () =
let jn =
try Re.Str.search_forward regexp s !j with Not_found -> not_match f s
in
if jn <> !j then not_match f s;
let w = Re.Str.matched_string s in
j := jn + String.length w;
w
in
let read_float =
let regexp = Re.Str.regexp "[0-9][0-9]\\(\\.[0-9]*\\)?" in
fun () ->
try float_of_string (read_word ~regexp ())
with Failure _ -> not_match f s
in
let parse_a () = ignore (day_of_short_name (read_word ())) in
let parse_b () = month := month_of_short_name (read_word ()) in
let parse_d () = day := read_number 2 in
let parse_H () = hour := read_number 2 in
let parse_I () = hour := read_number 2 in
let parse_m () = month := read_number 2 in
let parse_M () = minute := read_number 2 in
let parse_p () =
match read_word () with
| "AM" -> pm := 0
| "PM" -> pm := 12
| s -> not_match "%p" ("\"" ^ s ^ "\"")
in
let parse_S () = match X.make with
| Int _ -> second := float (read_number 2)
| Float _ -> second := read_float ()
in
let parse_V fmt =
let n = read_number 2 in
if n < 1 || n > 53 then not_match fmt (string_of_int n);
week := n
in
let parse_y () = year := read_number 2 + 1900 in
let parse_Y () = year := read_number 4 in
let parse_tz () =
let sign = match read_word ~regexp:(Re.Str.regexp "[\\+-]") () with
| "+" -> -1
| "-" -> 1
| _ -> assert false
in
let n = read_number 2 in
tz := sign * n;
in
let rec parse_option i =
assert (i <= lenf);
if i = lenf then bad_format f;
(* else *)
let jump = ref 0 in
(match f.[i] with
| '%' -> read_char '%'
| 'a' -> parse_a ()
| 'A' -> ignore (day_of_short_name (read_word ()))
| 'b' -> parse_b ()
| 'B' -> month := month_of_name (read_word ())
| 'c' ->
parse_a ();
read_char ' ';
parse_b ();
read_char ' ';
parse_d ();
read_char ' ';
parse_H ();
read_char ':';
parse_M ();
read_char ':';
parse_S ();
read_char ' ';
parse_Y ()
| 'C' -> ignore (read_number 2)
| 'd' -> parse_d ()
| 'D' ->
parse_m ();
read_char '/';
parse_d ();
read_char '/';
parse_y ()
| 'F' | 'i' ->
parse_Y ();
read_char '-';
parse_m ();
read_char '-';
parse_d ()
| 'h' -> parse_b ()
| 'H' -> parse_H ()
| 'I' -> parse_I ()
| 'j' ->
let n = read_number 3 in
if n < 1 || n > 366 then not_match "%j" (string_of_int n);
delayed_computations :=
(fun () ->
if !year = -1 then bad_format "%j (year not provided)";
let d = Date.from_day_of_year !year n in
month := Date.int_of_month (Date.month d);
day := Date.day_of_month d)
:: !delayed_computations
| 'm' -> parse_m ()
| 'M' -> parse_M ()
| 'n' -> read_char '\n'
| 'p' -> parse_p ()
| 'P' ->
(match read_word () with
| "am" -> pm := 0
| "pm" -> pm := 12
| s -> not_match "%P" ("\"" ^ s ^ "\""))
| 'r' ->
parse_I ();
read_char ':';
parse_M ();
read_char ':';
parse_S ();
read_char ' ';
parse_p ()
| 'R' ->
parse_H ();
read_char ':';
parse_M ()
| 'S' -> parse_S ()
| 't' -> read_char '\t'
| 'T' ->
parse_H ();
read_char ':';
parse_M ();
read_char ':';
parse_S ()
| 'V' -> parse_V "%V"
| 'w' ->
let n = read_number 1 in
if n < 1 || n > 7 then not_match "%w" (string_of_int n);
day_of_week := n;
delayed_computations := from_biz :: !delayed_computations;
| 'W' -> parse_V "%W"
| 'y' -> parse_y ()
| 'Y' -> parse_Y ()
| 'z' ->
parse_tz ();
ignore (read_number 2)
| ':' ->
let rec dot acc i = match f.[i] with
| ':' -> if acc = 3 then bad_format "%::::" else dot (acc+1) (i+1)
| 'z' -> acc
| c -> bad_format ("%:" ^ String.make 1 c)
in
let nb_dots = dot 1 (i+1) in
jump := nb_dots;
let next = String.make nb_dots ':' ^ "z" in
parse_tz ();
let read_block () = read_char ':'; ignore (read_number 2) in
(match next with
| ":z" -> read_block ()
| "::z" -> read_block (); read_block ()
| ":::z" -> () (* the only available precision is "hh" like "%z" *)
| _ -> assert false)
| c -> bad_format ("%" ^ String.make 1 c));
parse_format (i + 1 + !jump)
and parse_format i =
assert (i <= lenf);
if i = lenf then begin if !j != lens then not_match f s end
else match f.[i] with
| '%' -> parse_option (i + 1)
| c ->
read_char c;
parse_format (i + 1)
in
parse_format 0;
List.iter (fun f -> f ()) !delayed_computations;
let build mk = mk !year !month !day (!hour + !pm + !tz) !minute in
match X.make with
| Int f -> build f (Utils.Float.round !second)
| Float f -> build f !second
let from_string = from_fstring X.default_format
end
let cannot_create_event kind args =
if List.exists ((=) min_int) args then
raise (Invalid_argument ("Cannot create the " ^ kind))
module Date =
Make(struct
include Date
let make y m d _ _ _ =
cannot_create_event "date" [ y; m; d ];
make y m d
let make = Int make
let default_format = "%i"
let hour _ = bad_format "hour"
let minute _ = bad_format "minute"
let second _ = bad_format "second"
let century d = century (year d)
let seconds_since_1970 _ = bad_format "seconds_since_1970"
end)
module DatePrinter = Date
module Time =
Make(struct
include Time
let make _ _ _ h m s =
cannot_create_event "time" [ h; m; s ];
make h m s
let make = Int make
let default_format = "%T"
let from_business _ _ _ = bad_format "from_business"
let day_of_week _ = bad_format "day_of_week"
let day_of_month _ = bad_format "day_of_month"
let day_of_year _ = bad_format "day_of_year"
let week _ = bad_format "week"
let month _ = bad_format "month"
let int_month _ = bad_format "int_month"
let year _ = bad_format "year"
let century _ = bad_format "century"
let seconds_since_1970 _ = bad_format "seconds_since_1970"
end)
module TimePrinter = Time
module Ftime =
Make(struct
include Ftime
let make _ _ _ h m s =
cannot_create_event "time" [ h; m; Utils.Float.round s ];
make h m s
let make = Float make
let second x = Second.to_int (second x)
let default_format = "%T"
let from_business _ _ _ = bad_format "from_business"
let day_of_week _ = bad_format "day_of_week"
let day_of_month _ = bad_format "day_of_month"
let day_of_year _ = bad_format "day_of_year"
let week _ = bad_format "week"
let month _ = bad_format "month"
let int_month _ = bad_format "int_month"
let year _ = bad_format "year"
let century _ = bad_format "century"
let seconds_since_1970 _ = bad_format "seconds_since_1970"
end)
module Precise_Calendar =
Make(struct
include Calendar.Precise
let make y m d h mn s =
cannot_create_event "calendar" [ y; m; d; h; mn; s ];
make y m d h mn s
let from_business y w d = from_date (Date.from_business y w d)
let default_format = "%i %T"
let century c = Date.century (year c)
let seconds_since_1970 c =
let p = sub c (make 1970 1 1 0 0 0) in
Time.Second.to_int (Time.Period.to_seconds (Period.to_time p))
let make = Int make
end)
module Calendar =
Make(struct
include Calendar
let make y m d h mn s =
cannot_create_event "calendar" [ y; m; d; h; mn; s ];
make y m d h mn s
let from_business y w d = from_date (Date.from_business y w d)
let default_format = "%i %T"
let century c = Date.century (year c)
let seconds_since_1970 c =
let p = sub c (make 1970 1 1 0 0 0) in
Time.Second.to_int (Time.Period.to_seconds (Period.to_time p))
let make = Int make
end)
module CalendarPrinter = Calendar
module Precise_Fcalendar =
Make(struct
include Fcalendar.Precise
let make y m d h mn s =
cannot_create_event
"calendar" [ y; m; d; h; mn; Utils.Float.round s ];
make y m d h mn s
let from_business y w d = from_date (Date.from_business y w d)
let second s = Time.Second.to_int (second s)
let default_format = "%i %T"
let century c = Date.century (year c)
let seconds_since_1970 c =
let p = sub c (make 1970 1 1 0 0 0.) in
Time.Second.to_int (Time.Period.to_seconds (Period.to_time p))
let make = Float make
end)
module Fcalendar =
Make(struct
include Fcalendar
let make y m d h mn s =
cannot_create_event
"calendar" [ y; m; d; h; mn; Utils.Float.round s ];
make y m d h mn s
let from_business y w d = from_date (Date.from_business y w d)
let second s = Time.Second.to_int (second s)
let default_format = "%i %T"
let century c = Date.century (year c)
let seconds_since_1970 c =
let p = sub c (make 1970 1 1 0 0 0.) in
Time.Second.to_int (Time.Period.to_seconds (Period.to_time p))
let make = Float make
end)
calendar-3.0.0/src/printer.mli 0000664 0000000 0000000 00000023502 14321307032 0016235 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Pretty printing and parsing from string.
In the following, an "event" is either a date or a time or a calendar.
This module implements different printers: one for each kind of events.
The three printers have the same signature:
they mainly implement a [fprint : string -> formatter -> t -> unit] function
and a [from_fstring : string -> string -> t] function.
The first one prints an event according to a format string
(see below for a description of such a format).
The second one converts a string to an event according to a format string.
A format string follows the unix utility 'date' (with few modifications).
It is a string which contains two types of objects: plain characters and
conversion specifiers. Those specifiers are introduced by
a [%] character and their meanings are:
- [%%]: a literal [%]
- [%a]: short day name (by using a short version of [day_name])
- [%A]: day name (by using [day_name])
- [%b]: short month name (by using a short version of [month_name])
- [%B]: month name (by using [month_name])
- [%c]: shortcut for [%a %b %d %H:%M:%S %Y]
- [%C]: century: as %Y without the two last digits (since version 2.01)
- [%d]: day of month (01..31)
- [%D]: shortcut for [%m/%d/%y]
- [%e]: same as [%_d]
- [%F]: shortcut for [%Y-%m-%d]: ISO-8601 notation (since version 2.01)
- [%h]: same as [%b]
- [%H]: hour (00..23)
- [%I]: hour (01..12)
- [%i]: same as [%F]; deprecated since 2.01
- [%j]: day of year (001..366)
- [%k]: same as [%_H]
- [%l]: same as [%_I]
- [%m]: month (01..12)
- [%M]: minute (00..59)
- [%n]: a newline (same as [\n])
- [%p]: AM or PM
- [%P]: am or pm (same as %p in lowercase) (since version 2.01)
- [%r]: shortcut for [%I:%M:%S %p]
- [%R]: shortcut for [%H:%M] (since version 2.01)
- [%s]: number of seconds since 1970/1/1 (since version 2.01)
- [%S]: second (00..60)
- [%t]: a horizontal tab (same as [\t])
- [%T]: shortcut for [%H:%M:%S]
- [%V]: week number of year (01..53)
- [%w]: day of week (1..7)
- [%W]: same as [%V]
- [%y]: last two digits of year (00..99)
- [%Y]: year (four digits)
- [%z]: time zone in the form +hhmm (e.g. -0400) (since version 2.01)
- [%:z]: time zone in the form +hh:mm (e.g. -04:00) (since version 2.01)
- [%::z]: time zone in the form +hh:mm:ss (e.g. -04:00:00)
(since version 2.01)
- [%:::z]: time zone in the form +hh (e.g. -04) (since version 2.01)
By default, date pads numeric fields with zeroes. Two special modifiers
between [`%'] and a numeric directive are recognized:
- ['-' (hyphen)]: do not pad the field
- ['_' (underscore)]: pad the field with spaces
- ['0' (zero)]: pad the field with zeroes (default) (since version 2.01)
- ['^']: use uppercase if possible (since version 2.01)
Padding is only available for printers, not for parsers.
@example a possible output of [%D] is [01/06/03]
@example a possible output of [the date is %B, the %-dth] is
[the date is January, the 6th] is matched by ;
@example a possible output of [%c] is [Thu Sep 18 14:10:51 2003].
@since 1.05 *)
(** {2 Internationalization}
You can manage the string representations of days and months.
By default, the English names are used but you can change their by
setting the references [day_name] and [month_name].
@example
[day_name := function Date.Mon -> "lundi" | Date.Tue -> "mardi" |
Date.Wed -> "mercredi" | Date.Thu -> "jeudi" | Date.Fri -> "vendredi" |
Date.Sat -> "samedi" | Date.Sun -> "dimanche"]
sets the names of the days to the French names. *)
val day_name : (Date.day -> string) ref
(** String representation of a day. *)
val name_of_day : Date.day -> string
(** [name_of_day d] is equivalent to [!day_name d].
Used by the specifier [%A]. *)
val short_name_of_day : Date.day -> string
(** [short_name_of_day d] returns the 3 first characters of [name_of_day d].
Used by the specifier [%a]. *)
val month_name : (Date.month -> string) ref
(** String representation of a month. *)
val name_of_month : Date.month -> string
(** [name_of_month m] is equivalent to [!day_month m].
Used by the specifier [%B]. *)
val short_name_of_month : Date.month -> string
(** [short_name_of_month d] returns the 3 first characters of
[name_of_month d].
Used by the specifier [%b]. *)
val set_word_regexp: Re.Str.regexp -> unit
(** Set the regular expression used to recognize words in
[from_fstring]. Default is [[a-zA-Z]*].
@since 1.10 *)
(** {2 Printers (including parsers from string)}
Printers also contain parsers which allow to build events from strings. *)
(** Generic signature of a printer-parser. *)
module type S = sig
type t
(** Generic type of a printer. *)
val fprint : string -> Format.formatter -> t -> unit
(** [fprint format formatter x] outputs [x] on [formatter] according to
the specified [format].
@raise Invalid_argument if the format is incorrect. *)
val print : string -> t -> unit
(** [print format] is equivalent to [fprint format Format.std_formatter] *)
val dprint : t -> unit
(** Same as [print d] where [d] is the default format
(see the printer implementations). *)
val sprint : string -> t -> string
(** [sprint format date] converts [date] to a string according to
[format]. *)
val to_string : t -> string
(** Same as [sprint d] where [d] is the default format
(see the printer implementations). *)
(** {3 Parsers from string} *)
val from_fstring : string -> string -> t
(** [from_fstring format s] converts [s] to a date according to [format].
Date padding (i.e. a special directive following ['%']) and
specifiers [%e], [%k] and [%l] are not recognized. Specifiers
[%a], [%A], [%j], [%v], [%w] and [%W] are recognized but mainly ignored:
only the validity of the format is checked.
In order to recognize words (used by [%a], [%A], [%b], [%B] and [%p]), a
regular expression is used which can be configured by
{!Printer.set_word_regexp}. When the format has only two digits for the
year number, 1900 are added to this number (see examples).
@raise Invalid_argument if either the format is incorrect or the string
does not match the format or the event cannot be created (e.g. if you do
not specify a year for a date).
@example [from_fstring "the date is %D" "the date is 01/06/03"]
returns a date equivalent to [Date.make 1903 1 6]
@example [from_fstring "the date is %B, the %dth %Y" "the date is May,
the 14th 2007"] returns a date equivalent to [Date.make 2007 5 14] (with
default internationalization). *)
val from_string : string -> t
(** Same as [from_fstring d] where [d] is the default format. *)
end
(** Date printer. Specifiers which use time functionalities are not available
on this printer.
Default format is [%i].
@since 2.0 *)
module Date: S with type t = Date.t
(** @deprecated Replaced by {!Printer.Date}. *)
module DatePrinter: S with type t = Date.t
(** Time printer. Specifiers which use date functionalities are not available
on this printer.
Default format is [%T].
@since 2.0 *)
module Time: S with type t = Time.t
(** @deprecated Replaced by {!Printer.Time}. *)
module TimePrinter : S with type t = Time.t
(** Ftime printer. Seconds are rounded to integers before pretty printing.
Specifiers which use date functionalities are not available
on this printer.
Default format is [%T].
@since 2.0 *)
module Ftime: S with type t = Ftime.t
(** Precise Calendar printer. Default format is [%i %T].
@since 2.0 *)
module Precise_Calendar: S with type t = Calendar.Precise.t
(** Calendar printer. Default format is [%i %T].
@since 2.0 *)
module Calendar: S with type t = Calendar.t
(** @deprecated Replaced by {!Printer.Calendar}. *)
module CalendarPrinter: S with type t = Calendar.t
(** Precise Fcalendar printer.
Seconds are rounded to integers before pretty printing.
Default format is [%i %T].
@since 2.0 *)
module Precise_Fcalendar: S with type t = Fcalendar.Precise.t
(** Fcalendar printer. Seconds are rounded to integers before pretty printing.
Default format is [%i %T].
@since 2.0 *)
module Fcalendar: S with type t = Fcalendar.t
calendar-3.0.0/src/time.ml 0000664 0000000 0000000 00000010345 14321307032 0015340 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(*S Introduction.
A time is represents by a number of seconds in UTC.
Outside this module, a time is interpreted in the current time zone.
So, each operations have to coerce a given time according to the current
time zone. *)
(*S Datatypes. *)
include Utils.Int
type second = int
type field = [ `Hour | `Minute | `Second ]
(*S Conversions. *)
let one_day = 86400
let convert t t1 t2 = t + 3600 * Time_Zone.gap t1 t2
let from_gmt t = convert t Time_Zone.UTC (Time_Zone.current ())
let to_gmt t = convert t (Time_Zone.current ()) Time_Zone.UTC
(* Coerce [t] into the interval $[0; 86400[$ (i.e. a one day interval). *)
let normalize t =
let t = from_gmt t in
let t_mod, t_div = to_gmt (t mod one_day), t / one_day in
if t < 0 then t_mod + one_day, t_div - 1 else t_mod, t_div
(*S Constructors. *)
let make h m s = to_gmt (h * 3600 + m * 60 + s)
let lmake ?(hour = 0) ?(minute = 0) ?(second = 0) () = make hour minute second
let midnight () = to_gmt 0
let midday () = to_gmt 43200
let now () =
let now = Unix.gmtime (Unix.time ()) in
3600 * now.Unix.tm_hour + 60 * now.Unix.tm_min + now.Unix.tm_sec
(*S Getters. *)
let hour t = from_gmt t / 3600
let minute t = from_gmt t mod 3600 / 60
let second t = from_gmt t mod 60
let to_hours t = float (from_gmt t) /. 3600.
let to_minutes t = float (from_gmt t) /. 60.
let to_seconds t = from_gmt t
(*S Boolean operations. *)
let is_pm t =
let t, _ = normalize t in
let m, _ = normalize (midday ()) in
t < m
let is_am t =
let t, _ = normalize t in
let m, _ = normalize (midday ()) in
t >= m
(*S Coercions. *)
let from_hours t = to_gmt (int_of_float (t *. 3600.))
let from_minutes t = to_gmt (int_of_float (t *. 60.))
let from_seconds t = to_gmt t
(*S Seconds. *)
module Second = struct
type t = second
let from_int x = x
let to_int x = x
let from_float = Utils.Float.round
let to_float = float
end
(*S Period. *)
module Period = struct
type +'a period = int constraint 'a = [< Period.date_field ]
include Utils.Int
let make h m s = h * 3600 + m * 60 + s
let lmake ?(hour=0) ?(minute=0) ?(second=0) () = make hour minute second
let length x = x
let hour x = x * 3600
let minute x = x * 60
let second x = x
let empty = 0
let add = (+)
let sub = (-)
let mul = ( * )
let div = (/)
let opp x = - x
let to_seconds x = x
let to_minutes x = float x /. 60.
let to_hours x = float x /. 3600.
end
(*S Arithmetic operations on times and periods. *)
let add = (+)
let sub = (-)
let rem = (-)
let next x = function
| `Hour -> x + 3600
| `Minute -> x + 60
| `Second -> x + 1
let prev x = function
| `Hour -> x - 3600
| `Minute -> x - 60
| `Second -> x - 1
calendar-3.0.0/src/time.mli 0000664 0000000 0000000 00000003267 14321307032 0015516 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Time implementation in which seconds are integers. *)
include Time_sig.S with type second = int
calendar-3.0.0/src/time_Zone.ml 0000664 0000000 0000000 00000005431 14321307032 0016333 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
type t =
| UTC
| Local
| UTC_Plus of int
let tz = ref UTC
let out_of_bounds x = x < - 12 || x > 11
let in_bounds x = not (out_of_bounds x)
let make_in_bounds x =
let y = x mod 24 in
if y < -12 then y + 24
else if y > 11 then y - 24
else y
let gap_gmt_local =
let t = Unix.time () in
(Unix.localtime t).Unix.tm_hour - (Unix.gmtime t).Unix.tm_hour
let current () = !tz
let change = function
| _ as t -> tz := t
let gap t1 t2 =
let aux t1 t2 =
assert (t1 < t2);
match t1, t2 with
| UTC, Local -> gap_gmt_local
| UTC, UTC_Plus x -> x
| Local, UTC_Plus x -> x - gap_gmt_local
| UTC_Plus x, UTC_Plus y -> y - x
| _ -> assert false
in
let res =
if t1 = t2 then 0
else if t1 < t2 then aux t1 t2
else - aux t2 t1
in
make_in_bounds res
let from_gmt () = gap UTC (current ())
let to_gmt () = gap (current ()) UTC
let is_dst () =
current () = Local && (Unix.localtime (Unix.time ())).Unix.tm_isdst
let hour_of_dst () = if is_dst () then 1 else 0
let on f tz x =
let old = current () in
change tz;
try
let res = f x in
change old;
res
with exn ->
change old;
raise exn
calendar-3.0.0/src/time_Zone.mli 0000664 0000000 0000000 00000006113 14321307032 0016502 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Time zone management.
You can [change] the [current] time zone in your program by side effect. *)
(** Type of a time zone. *)
type t =
| UTC (** Greenwich Meridian Time *)
| Local (** Local Time *)
| UTC_Plus of int (** Another time zone specified from UTC *)
val current : unit -> t
(** Return the current time zone. It is [UTC] before any change. *)
val change : t -> unit
(** Change the current time zone by another one.
Raise [Invalid_argument] if the specified time zone is [UTC_Plus x] with
[x < -12] or [x > 11] *)
val gap : t -> t -> int
(** Return the gap between two time zone.
@example [gap UTC (UTC_Plus 5)] returns 5 and, at Paris in summer,
[gap Local UTC] returns -2. *)
val from_gmt : unit -> int
(** [from_gmt ()] is equivalent to [gap UTC (current ())]. *)
val to_gmt : unit -> int
(** [to_gmt ()] is equivalent to [gap (current ()) UTC]. *)
val is_dst : unit -> bool
(** [is_dst ()] checks if daylight saving time is in effect.
Only relevant in local time.
Returns alway [false] in another time zone.
@since 1.09.4 *)
val hour_of_dst : unit -> int
(** [hour_of_dst ()] returns [1] if [is_dst ()] and [0] otherwise.
@since 1.09.4 *)
val on: ('a -> 'b) -> t -> 'a -> 'b
(** [on f tz x] changes the time zone to [tz], then computes [f x], and
finally reset the time zone to the initial one and returns the result of
the computation.
@since 2.0 *)
calendar-3.0.0/src/time_sig.mli 0000664 0000000 0000000 00000021771 14321307032 0016360 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Time interface. A time may be seen as a triple (hour, minute, second).
If minutes and seconds do not belong to [\[0; 60\[], they are coerced into
this interval.
@example "30 hours, 60 minutes, 80 seconds" is coerced to "31 hours, 1
minute, 20 seconds".
Each time is interpreted in the current time zone (given by
[Time_Zone.current ()]). So, if you change the time zone (by
{!Time_Zone.change}), each time consequently changes.
If you want to express a time in another time zone (and do not affect
others times), use the [convert] function. *)
(** Interface for seconds.
@since 2.0 *)
module type Second = sig
type t
(** Type of seconds. *)
val from_int: int -> t
(** Convert an integer to an equivalent number of seconds. *)
val from_float: float -> t
(** Convert a float to an equivalent number of seconds. *)
val to_int: t -> int
(** Inverse of [from_int]. *)
val to_float: t -> float
(** Inverse of [from_float]. *)
end
(** Common operations for all time representations.
@since 2.0 (this signature was before inlined in interface of Time). *)
module type S = sig
(** {2 Datatypes} *)
type t
(** Type of a time. *)
type field = [ `Hour | `Minute | `Second ]
(** The different fields of a time. *)
(** {2 Second} *)
type second
(** Type of a second.
@since 2.0 (was an integer in previous versions). *)
(** Second implementation
@since 2.0 *)
module Second: Second with type t = second
(** {2 Constructors} *)
val make : int -> int -> second -> t
(** [make hour minute second] makes the time hour-minute-second. *)
val lmake : ?hour:int -> ?minute:int -> ?second:second -> unit -> t
(** Labelled version of [make]. The default value is [0] for each argument.
@since 1.05 *)
val now : unit -> t
(** The current time based on [Time_Zone.current ()]. *)
val midnight : unit -> t
(** [midnight ()] is midnight (expressed in the current time zone).
So, it has always the same behaviour as [make 0 0 0]. *)
val midday : unit -> t
(** [midday ()] is midday (expressed in the current time zone).
So, it has always the same behaviour as [make 12 0 0]. *)
(** {2 Conversions} *)
val convert : t -> Time_Zone.t -> Time_Zone.t -> t
(** [convert t t1 t2] converts the time [t] expressed in the time zone [t1]
to the same time expressed in the time zone [t2].
@example [convert (make 20 0 0) (Time_Zone.GMT_Plus 2)
(Time_Zone.GMT_Plus 4)] returns the time 22-0-0. *)
val from_gmt : t -> t
(** [from_gmt t] is equivalent to
[convert t Time_Zone.GMT (Time_Zone.current ())]. *)
val to_gmt : t -> t
(** [to_gmt t] is equivalent to
[convert t (Time_Zone.current ()) Time_Zone.GMT]. *)
val normalize : t -> t * int
(** [normalize t] returns [t] such that [hour t] belongs to [\[0; 24\[]. The
second component of the result is the number of days needed by the
modification.
@example [normalize (make 22 0 0)] returns the time 22-0-0 and 0,
[normalize (make 73 0 0)] returns the time 1-0-0 and 3 and [normalize
(make (-73) 0 0)] returns the time 23-0-0 and (-4). *)
(** {2 Getters} *)
val hour : t -> int
(** Hour.
@example [hour (make 20 0 0)] returns 20. *)
val minute : t -> int
(** Minute.
@example [minute (make 20 10 0)] returns 10. *)
val second : t -> second
(** Second.
@example [second (make 20 10 5)] returns 5. *)
val to_seconds : t -> second
(** Number of seconds of a time.
@example [to_seconds (make 1 2 3)] returns [3600 + 120 + 3 = 3723]. *)
val to_minutes : t -> float
(** Number of minutes of a time. The resulting fractional part represents
seconds.
@example [to_minutes (make 1 2 3)] returns [60+2+0.05 = 62.05]. *)
val to_hours : t -> float
(** Number of hours of a time. The resulting fractional part represents
minutes and seconds.
@example [to_hours (make 1 3 0)] returns [1 + 0.05 = 1.05]. *)
(** {2 Times are comparable} *)
val equal: t -> t -> bool
(** Equality function between two times.
@see Utils.Comparable.equal.
@since 1.09.0 *)
val compare : t -> t -> int
(** Comparison function between two times.
@see Utils.Comparable.compare. *)
val hash: t -> int
(** Hash function for times.
@see Utils.Comparable.hash.
@since 2.0 *)
(** {2 Boolean operations on times} *)
val is_pm : t -> bool
(** Return [true] is the time is before midday in the current time zone;
[false] otherwise.
@example both [is_pm (make 10 0 0)] and [is_pm (make 34 0 0)] return
[true]. *)
val is_am : t -> bool
(** Return [true] is the time is after midday in the current time zone;
[false] otherwise.
@example both [is_am (make 20 0 0)] and [is_am (make 44 0 0)] return
[true]. *)
(** {2 Coercions} *)
val from_seconds: second -> t
(** Inverse of [to_seconds]. *)
val from_minutes: float -> t
(** Inverse of [to_minutes]. *)
val from_hours: float -> t
(** Inverse of [to_hours]. *)
(** {2 Period} *)
(** A period is the number of seconds between two times. *)
module Period : sig
(** {3 Arithmetic operations} *)
include Period.S
val length : 'a period -> second
(** Number of seconds of a period. *)
val mul : 'a period -> 'a period -> 'a period
(** Multiplication. *)
val div : 'a period -> 'a period -> 'a period
(** Division. *)
(** {3 Constructors} *)
val make : int -> int -> second -> 'a period
(** [make hour minute second] makes a period of the specified length. *)
val lmake : ?hour:int -> ?minute:int -> ?second:second -> unit -> 'a period
(** Labelled version of [make].
The default value is [0] for each argument. *)
val hour : int -> 'a period
(** [hour n] makes a period of [n] hours. *)
val minute : int -> 'a period
(** [minute n] makes a period of [n] minutes. *)
val second : second -> 'a period
(** [second n] makes a period of [n] seconds. *)
(** {3 Getters} *)
val to_seconds : 'a period -> second
(** Number of seconds of a period.
@example [to_seconds (make 1 2 3)] returns [3600 + 120 + 3 = 3723].
@since 1.04 *)
val to_minutes : 'a period -> float
(** Number of minutes of a period. The resulting fractional part
represents seconds.
@example [to_minutes (make 1 2 3)] returns [60 + 2 + 0.05 = 62.05].
@since 1.04 *)
val to_hours : 'a period -> float
(** Number of hours of a period. The resulting fractional part represents
minutes and seconds.
@example [to_hours (make 1 3 0)] returns [1 + 0.05 = 1.05].
@since 1.04 *)
end
(** {2 Arithmetic operations on times and periods} *)
val add : t -> 'a Period.period -> t
(** [app t p] returns [t + p].
@example [add (make 20 0 0) (Period.minute 70)] returns the time
21:10:0. *)
val sub : t -> t -> 'a Period.period
(** [sub t1 t2] returns the period between [t1] and [t2]. *)
val rem : t -> 'a Period.period -> t
(** [rem t p] is equivalent to [add t (Period.opp p)]. *)
val next : t -> field -> t
(** [next t f] returns the time corresponding to the next specified field.
@example [next (make 20 3 31) `Minute] returns the time 20:04:31.
(i.e. one minute later). *)
val prev : t -> field -> t
(** [prev t f] returns the time corresponding to the previous specified
field.
@example [prev (make 20 3 31) `Second] returns the time 20:03:30
(i.e. one second ago). *)
end
calendar-3.0.0/src/utils.ml 0000664 0000000 0000000 00000004276 14321307032 0015550 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
module type Comparable = sig
type t
val equal: t -> t -> bool
val compare: t -> t -> int
val hash: t -> int
end
module Int = struct
type t = int
let equal (a: int) b = a = b
let compare (a: int) b = compare a b
let hash = Hashtbl.hash
end
module Float = struct
type t = float
let precision = ref 1e-8
let set_precision f = precision := f
let equal x y = abs_float (x -. y) < !precision
let compare x y =
if equal x y then 0
else if x < y then -1
else 1
let hash = Hashtbl.hash
let round x =
let f, i = modf x in
int_of_float i + (if f < 0.5 then 0 else 1)
end
calendar-3.0.0/src/utils.mli 0000664 0000000 0000000 00000005330 14321307032 0015711 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Some utilities.
@since 2.0 *)
(** Interface for comparable and hashable types.
Modules implementing this interface can be an argument of [Map.Make],
[Set.Make] or [Hashtbl.Make].
@since 2.0 *)
module type Comparable = sig
type t
val equal: t -> t -> bool
(** Equality over [t]. *)
val compare: t -> t -> int
(** Comparison over [t].
[compare x y] returns [0] iff [equal x y = 0]. If [x] and [y] are not
equal, it returns a negative integer iff [x] is lesser than [y] and a
positive integer otherwise. *)
val hash: t -> int
(** A hash function over [t]. *)
end
(** Integer implementation.
@since 2.0 *)
module Int: Comparable with type t = int
(** Float implementation.
@since 2.0 *)
module Float: sig
include Comparable with type t = float
val set_precision: float -> unit
(** Set the precision of [equal] and [compare] for float.
If the precision is [p], then the floats [x] and [y] are equal iff
[abs(x-y) < p]. By default, the precision is [1e-8] (that is 0.864
milliseconds if floats represent days). *)
val round: t -> int
(** Round a float to the nearest integer. *)
end
calendar-3.0.0/src/version.mli 0000664 0000000 0000000 00000003304 14321307032 0016235 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Information about version of calendar.
@since 2.0 *)
val version: string
(** Name of this version. *)
calendar-3.0.0/tests/ 0000775 0000000 0000000 00000000000 14321307032 0014420 5 ustar 00root root 0000000 0000000 calendar-3.0.0/tests/dune 0000664 0000000 0000000 00000000210 14321307032 0015267 0 ustar 00root root 0000000 0000000
(executable
(name test)
(libraries calendar alcotest))
(alias
(name runtest)
(deps test.exe)
(action (run ./test.exe -e)))
calendar-3.0.0/tests/gen_test.ml 0000664 0000000 0000000 00000003741 14321307032 0016567 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(*i $Id$ i*)
let ok_ref = ref 0
let ok () = incr ok_ref
let nb_ok () = !ok_ref
let bug_ref = ref 0
let bug () = incr bug_ref
let nb_bug () = !bug_ref
let reset () =
ok_ref := 0;
bug_ref := 0
let test x s =
if x then ok () else begin Printf.printf "%s\n" s; bug () end;;
let test_exn x s =
try
ignore (Lazy.force x);
Alcotest.failf "expected exception: %s" s
with _ ->
()
calendar-3.0.0/tests/gen_test.mli 0000664 0000000 0000000 00000003447 14321307032 0016743 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(*i $Id$ i*)
(* Generic functions used in the tests. *)
val reset : unit -> unit
val nb_ok : unit -> int
val nb_bug : unit -> int
val test : bool -> string -> unit
val test_exn : 'a Lazy.t -> string -> unit
calendar-3.0.0/tests/test.ml 0000664 0000000 0000000 00000003701 14321307032 0015732 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(*i $Id$ i*)
(* Display the results *)
let suite = [
"timezone", Test_timezone.suite;
"time", Test_time.suite;
"ftime", Test_ftime.suite;
"date", Test_date.suite;
"calendar", Test_calendar.suite;
"pcalendar", Test_pcalendar.suite;
"fpcalendar", Test_fpcalendar.suite;
"printer", Test_printer.suite;
]
let () =
Alcotest.run "calendar tests" suite
calendar-3.0.0/tests/test_calendar.ml 0000664 0000000 0000000 00000020443 14321307032 0017565 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
Printf.printf "Tests of Calendar:\n";;
open CalendarLib;;
open Calendar;;
let test() =
let test x s = Alcotest.(check bool) s true x in
let eps = 0.000001 in
Time_Zone.change Time_Zone.UTC;
(* Calendar *)
Gen_test.test_exn (lazy (make (-4712) 1 1 12 0 (-1))) "-4713-12-31-23-59-59";
test (make (-4712) 1 1 12 0 0 = make (-4712) 1 0 36 0 0) "calendar coercion";
test (from_jd 0. = make (-4712) 1 1 12 0 0) "from_jd 0 = 4713 BC-1-1";
test (from_mjd 0. = make 1858 11 17 0 0 0) "from_mjd 0 = 1858-11-17";
test (Precise.compare (Precise.make 2009 12 14 13 49 0) (Precise.make 2009 12 14 13 49 1) < 0)
"Precise.compare 2009/12/14/13/19/0 2009/12/14/13/19/1";
Utils.Float.set_precision 1e-5;
test (compare (make 2009 12 14 13 49 0) (make 2009 12 14 13 49 1) < 0)
"compare 2009/12/14/13/19/0 2009/12/14/13/19/1";
Utils.Float.set_precision 1e-3;
Time_Zone.change (Time_Zone.UTC_Plus 5);
test (abs_float (to_jd (from_jd 12345.6789) -. 12345.6789) < eps)
"to_jd (from_jd x) = x";
test (abs_float (to_mjd (from_mjd 12345.6789) -. 12345.6789) < eps)
"to_mjd (from_mjd x) = x";
test (Period.to_date (Period.hour 60) = Date.Period.day 2)
"period(60h) = period(2d)";
test (Period.compare (Period.day 2) (Period.hour 60) < 0) "Period.compare <";
test (Period.compare (Period.day 3) (Period.hour 60) > 0) "Period.compare >";
test (Period.compare
(Period.add (Period.day 2) (Period.hour 12))
(Period.hour 60) = 0) "Period.compare =";
test
(add (make 1 2 3 4 5 6) (Period.make 9 8 7 6 5 4) = make 10 10 10 10 10 10)
"add 1-2-3-4-5-6 9-8-7-6-5-4";
test
(add (make 3 1 1 0 0 0) (Period.make 0 0 0 (-25) 0 (-1)) =
make 2 12 30 22 59 59)
"add 3-1-1-0-0-0 0-0-0-(-25)-0-(-1)";
test
(equal (rem (make 9 8 7 6 5 4) (Period.make 1 2 3 4 5 6))
(make 8 6 4 1 59 58))
"rem 9-8-7-6-5-4 1-2-3-4-5-6";
test (Period.equal
(sub (make 0 0 7 6 5 4) (make 0 0 3 54 5 6))
(Period.make 0 0 1 23 59 58))
"sub 0-0-7-6-5-4 0-0-3-54-5-6";
test (Date.Period.ymd
(Period.to_date
(precise_sub (make 2010 10 5 0 0 0) (make 2010 6 2 0 0 0)))
= (0, 4, 3))
"precise_sub 2010-10-5 2010-6-2";
test (Date.Period.ymd
(Period.to_date
(precise_sub (make 2010 10 5 0 2 3) (make 2010 6 5 0 0 0))) =
(0, 4, 0))
"precise_sub 2010-10-5 2010-6-2";
test (Date.Period.ymd
(Period.to_date
(precise_sub (make 2010 10 5 0 32 12) (make 2010 6 6 0 31 3)))
= (0, 3, 29))
"precise_sub 2010-10-5 2010-6-6";
test (Date.Period.ymd
(Period.to_date
(precise_sub (make 2010 10 5 1 3 3) (make 2010 6 4 0 23 3))) =
(0, 4, 1))
"precise_sub 2010-10-5 2010-6-4";
test (Date.Period.ymd
(Period.to_date
(precise_sub (make 2010 1 1 0 0 0) (make 2000 1 1 0 0 0)))
= (10, 0, 0))
"precise_sub 2010-1-1 2000-1-1";
test (Period.equal
(Period.opp (Period.make 0 0 2 3 0 0))
(Period.make 0 0 (-2) (-3) 0 0))
"period opp";
(* Date *)
let d = make 2003 12 31 12 24 48 in
test (next d `Month = make 2004 1 31 12 24 48) "2003-12-31 + 1 mois";
test (add d (Period.month 2) = make 2004 3 2 12 24 48) "2003-12-31 + 2 mois";
let d3 = make 2011 3 24 0 0 0 in
test (prev d3 `Year = make 2010 3 24 0 0 0) "2011-3-24 - 1 year";
let d2 = make (-3000) 1 1 6 12 24 in
test (equal (rem d (sub d d2)) d2) "rem x (sub x y) = y";
test (is_leap_day (make 2000 2 24 0 0 0)) "2000-2-24 leap day";
test (not (is_leap_day (make 2000 2 25 0 0 0))) "2000-2-25 not leap day";
test (is_gregorian (make 1600 1 1 0 0 0)) "1600-1-1 gregorian";
test (not (is_gregorian (make 1400 1 1 0 0 0))) "1400-1-1 not gregorian";
test (is_julian (make 1582 1 1 0 0 0)) "1582-1-1 julian";
test (not (is_julian (make 1583 1 1 0 0 0))) "1583-1-1 not julian";
(* Time *)
test (let n = Unix.gmtime (Unix.time ()) in
hour (from_unixtm n) = n.Unix.tm_hour) "from_unixtm invariant UTC";
test (let n = Unix.time () in
hour (from_unixfloat n) = (Unix.gmtime n).Unix.tm_hour)
"from_unixfloat invariant UTC";
Time_Zone.change (Time_Zone.UTC_Plus 10);
test (let n = Unix.gmtime (Unix.time ()) in
hour (from_unixtm n) = n.Unix.tm_hour) "from_unixtm invariant +10";
test (let n = Unix.time () in
hour (from_unixfloat n) = (Unix.gmtime n).Unix.tm_hour)
"from_unixfloat invariant +10";
test (equal (add (make 0 0 0 10 0 0) (Period.hour 30)) (make 0 0 1 16 0 0))
"add 0-0-0-20-0-0 30h";
test (equal (next (make 1999 12 31 23 59 59) `Second) (make 2000 1 1 0 0 0))
"next 1999-31-12-23-59-59 `Second";
let n = now () in
test (equal (prev (next n `Minute) `Minute) n) "prev next = id";
test (equal
(convert
(make 0 0 0 23 0 0)
(Time_Zone.UTC_Plus 2)
(Time_Zone.UTC_Plus 4))
(make 0 0 1 1 0 0)) "convert";
test (hour (make 0 0 0 20 0 0) = 20) "hour";
test (minute (make 0 0 0 20 10 0) = 10) "minute";
test (second (make 0 0 0 20 10 5) = 5) "second";
test (is_pm (make 0 0 0 10 0 0)) "is_pm 10-0-0";
test (is_pm (make 0 0 0 34 0 0)) "is_pm 34-0-0";
test (not (is_pm (make 0 0 0 (- 10) 0 0))) "not (is_pm (- 10) 0 0)";
test (is_am (make 0 0 0 20 0 0)) "is_am 20-0-0";
test (is_am (make 0 0 0 (- 34) 0 0)) "is_am (- 34) 0 0";
test (not (is_am (make 0 0 0 34 0 0))) "not (is_pm 34 0 0)";
Time_Zone.change Time_Zone.UTC;
test (let n = Unix.gmtime (Unix.time ()) in
hour (from_unixtm n) = n.Unix.tm_hour) "from_unixtm invariant UTC2";
test (let n = Unix.time () in
hour (from_unixfloat n) = (Unix.gmtime n).Unix.tm_hour)
"from_unixfloat invariant UTC2";
test (to_unixfloat (make 1970 1 1 0 0 0) = 0.) "to_unixfloat 1 Jan 1970";
test (from_unixfloat 0. = make 1970 1 1 0 0 0) "from_unixfloat 1 Jan 1970";
test (Utils.Float.equal (to_unixfloat (make 2004 11 13 19 17 9)) 1100373429.)
"to_unixfloat";
test (equal (from_unixfloat 1100373429.) (make 2004 11 13 19 17 9))
"from_unixfloat";
test (from_unixtm (to_unixtm (make 2003 7 16 23 22 21)) =
make 2003 7 16 23 22 21)
"from_unixtm to_unixtm = id";
test (Period.to_time (Period.second 30) = Time.Period.second 30)
"Period.to_time second";
test (Period.to_time (Period.day 6) = Time.Period.second 518400)
"Period.to_time day";
test (Period.safe_to_time (Period.second 30) = Time.Period.second 30)
"Period.safe_to_time second";
test (Period.safe_to_time (Period.day 6) = Time.Period.second 518400)
"Period.safe_to_time day";
Gen_test.test_exn (lazy (Period.to_time (Period.year 1))) "Period.to_time year";
test (Period.ymds (Period.make 1 2 3 1 2 3) = (1, 2, 3, 3723)) "Period.ymds";
test
(Period.ymds (Period.make (-1) (-2) (-3) (-1) (-2) (-3)) = (-1,-2,-4,82677))
"Period.ymds neg";
()
let suite = ["test-calendar", `Quick, test]
calendar-3.0.0/tests/test_date.ml 0000664 0000000 0000000 00000024203 14321307032 0016727 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
open CalendarLib;;
open Date;;
let test() =
let test x s = Alcotest.(check bool) s true x in
Gen_test.test_exn (lazy (make (-4713) 1 1)) "make (-4713) 1 1";
Gen_test.test_exn (lazy (make 3268 1 23)) "make 3268 1 23";
Gen_test.test_exn (lazy (make 1582 10 5)) "make 1582 10 10";
test (compare (make 2003 2 29) (make 2003 3 1) = 0) "2003-2-29 = 2003-3-1";
test ((make 2018 10 29) > (make 2018 10 28)) "2018-10-29 > 2018-10-28";
test ((make 2018 10 29) >= (make 2018 10 28)) "2018-10-29 >= 2018-10-28";
test ((make 2018 10 29) >= (make 2018 10 29)) "2018-10-29 >= 2018-10-29";
test ((make 2018 10 29) < (make 2018 10 30)) "2018-10-29 < 2018-10-30";
test ((make 2018 10 29) <= (make 2018 10 30)) "2018-10-29 <= 2018-10-30";
test ((make 2018 10 29) <= (make 2018 10 29)) "2018-10-29 <= 2018-10-29";
let d = make 2003 12 31 in
test (next d `Month = make 2004 1 31) "2003-12-31 + 1 mois";
test (add d (Period.month 2) = make 2004 3 2) "2003-12-31 + 2 mois";
test (add (make 2008 12 31) (Period.month 6) = make 2009 7 1)
"2008-12-31 + 6 mois";
test (rem (make 2008 6 2) (Period.month 12) = make 2007 6 2)
"2008-6-2 - 12 mois";
test (rem (make 2007 2 30) (Period.month 4) = make 2006 11 2)
"2008-2-30 - 4 mois";
test (make 2007 (-38) 30 = make 2003 10 30)
"2007-(-38)-30 - 2003 10 30";
test (rem (make 2007 2 30) (Period.month 40) = make 2003 11 2)
"2008-2-30 - 40 mois";
let d2 = make (-3000) 1 1 in
test (rem d (sub d d2) = d2) "rem x (sub x y) = y";
test (Period.ymd (precise_sub (make 2010 10 5) (make 2010 6 2)) = (0, 4, 3))
"precise_sub 2010-10-5 2010-6-2";
test (Period.ymd (precise_sub (make 2010 10 5) (make 2010 6 5)) = (0, 4, 0))
"precise_sub 2010-10-5 2010-6-2";
test (Period.ymd (precise_sub (make 2010 10 5) (make 2010 6 6)) = (0, 3, 29))
"precise_sub 2010-10-5 2010-6-6";
test (Period.ymd (precise_sub (make 2010 10 5) (make 2010 6 4)) = (0, 4, 1))
"precise_sub 2010-10-5 2010-6-4";
test (Period.ymd (precise_sub (make 2010 1 1) (make 2000 1 1)) = (10, 0, 0))
"precise_sub 2010-1-1 2000-1-1";
test (from_jd 0 = make (-4712) 1 1) "from_jd 0 = 4713 BC-1-1";
test (to_jd (from_jd 12345) = 12345) "to_jd (from_jd x) = x";
test (from_mjd 0 = make 1858 11 17) "from_mjd 0 = 1858-11-17";
test (to_mjd (from_mjd 12345) = 12345) "to_mjd (from_mjd x) = x";
test (is_leap_day (make 2000 2 24)) "2000-2-24 leap day";
test (not (is_leap_day (make 2000 2 25))) "2000-2-25 not leap day";
test (is_gregorian (make 1600 1 1)) "1600-1-1 gregorian";
test (not (is_gregorian (make 1400 1 1))) "1400-1-1 not gregorian";
test (is_julian (make 1582 1 1)) "1582-1-1 julian";
test (not (is_julian (make 1583 1 1))) "1583-1-1 not julian";
test (int_of_day Mon = 1) "Monday = 1";
test (int_of_day Sun = 7) "Sunday = 7";
test (day_of_int 1 = Mon) "1 = Monday";
test (day_of_int 7 = Sun) "1 = Monday";
test (int_of_month Jan = 1) "January = 1";
test (month_of_int 12 = Dec) "12 = December";
test (not (is_leap_year 1999)) "1999 not leap year";
test (not (is_leap_year 1800)) "1800 not leap year";
test (is_leap_year 1996) "1996 leap year";
test (is_leap_year 1600) "1600 leap year";
test (same_calendar 1956 1900) "same calendar 1956 1900";
test (same_calendar 2001 2013) "same calendar 2001 2013";
test (same_calendar 1998 2009) "same calendar 1998 2009";
test (same_calendar 2003 2025) "same calendar 2003 2025";
test (days_in_year 2000 = 366) "days_in_year 2000";
test (days_in_year 1900 = 365) "days_in_year 1900";
test (days_in_year ~month:Jan 2000 = 31) "days_in_year Jan 2000";
test (days_in_year ~month:Feb 2000 = 60) "days_in_year Feb 2000";
test (days_in_year ~month:Jan 2000 = 31) "days_in_year Jan 2000";
test (days_in_year ~month:Mar 1900 = 90) "days_in_year Mar 1900";
test (weeks_in_year 2000 = 52) "weeks_in_year 2000";
test (weeks_in_year 2020 = 53) "weeks_in_year 2020";
test (weeks_in_year 1991 = 52) "weeks_in_year 1991";
test (weeks_in_year 1999 = 52) "weeks_in_year 1999";
test (days_in_month (make 2000 2 18) = 29) "days_in_month 2000-2-18";
test (days_in_month (make_year_month 2000 2) = 29) "days_in_month 2000-2";
(* untypable: *)
(* test (days_in_month ((make_year 2000 :> [ `Year | `Month ] Date.date)) = 29) "days_in_month 2000-2"; *)
test (days_in_year 1900 = 365) "days_in_year 1900";
test (century 2000 = 20) "century 2000";
test (century 2001 = 21) "century 2001";
test (millenium 2000 = 2) "millenium 2000";
test (millenium 2001 = 3) "millenium 2001";
test (year (make_year_month 2000 3) = 2000) "year 2000-3";
test (year (make_year 2000) = 2000) "year 2000";
test (month (make 2000 4 23) = Apr) "year 2000-4-23";
test (month (make_year_month 2000 3) = Mar) "year 2000-3";
(* untypable: *)
(*test (month (make_year 2000) = Mar) "year 2000";*)
test (easter 2003 = make 2003 4 20) "Paques 2003";
test (Period.nb_days (Period.make 0 0 6) = 6) "Period.nb_days ok";
test (Period.safe_nb_days (Period.week 3) = 21) "Period.safe_nb_days ok";
Gen_test.test_exn (lazy (Period.nb_days (Period.make 1 0 0))) "Period.nb_days ko";
test (week_first_last 21 2004 = (make 2004 5 17, make 2004 5 23))
"week_beggining_end";
(* January 4th must be in the first week (ISO 8601) *)
(* 2015 is an interesting year in this regard as it tests this rule
to its extreme *)
test (week_first_last 1 2015 = (make 2014 12 29, make 2015 1 4))
"iso_week_number_startof_2015";
test (week_first_last 53 2015 = (make 2015 12 28, make 2016 1 3))
"iso_week_number_endof_2015";
test (Period.ymd (Period.make 1 2 3) = (1, 2, 3)) "Period.ymd";
test (nth_weekday_of_month 2004 Oct Thu 4 = make 2004 10 28)
"nth_weekday_of_month";
test (nth_weekday_of_month 2006 Mar Fri 3 = make 2006 3 17)
"nth_weekday_of_month";
test (equal (from_day_of_year 2008 39) (make 2008 2 8))
"from_day_of_year";
test (is_valid_date 2008 2 8) "is_valid_date";
test (not (is_valid_date 2008 2 30)) "not is_valid_date";
(* Unix *)
Time_Zone.change Time_Zone.UTC;
test (to_unixfloat (make 1970 1 1) = 0.) "to_unixfloat 1 Jan 1970";
test (from_unixfloat 0. = make 1970 1 1) "from_unixfloat 0.";
test (to_unixfloat (make 2004 11 13) = 1100304000.) "to_unixfloat";
test (from_unixfloat 1100304000. = make 2004 11 13) "from_unixfloat";
test (from_unixtm (to_unixtm (make 2003 7 16)) = make 2003 7 16)
"from_unixtm to_unixtm = id";
Time_Zone.change (Time_Zone.UTC_Plus (-1));
test (from_unixfloat 0. = make 1969 12 31) "from_unixfloat 0. (dec-)";
test (from_unixtm { Unix.tm_sec = 0; tm_min = 0; tm_hour = 0; tm_mday = 1;
tm_mon = 0; tm_year = 70; tm_wday = 4; tm_yday = 0;
tm_isdst = false } = make 1969 12 31)
"from_unixtm (dec-)";
Time_Zone.change (Time_Zone.UTC_Plus 1);
test (from_unixfloat 1100390390. = make 2004 11 14) "from_unixfloat (dec+)";
test (from_unixtm { Unix.tm_sec = 0; tm_min = 0; tm_hour = 0; tm_mday = 14;
tm_mon = 10; tm_year = 104; tm_wday = 0; tm_yday = 318;
tm_isdst = false } = make 2004 11 14)
"from_unixtm (dec+)";
test (from_unixtm (to_unixtm (make 2003 7 16)) = make 2003 7 16)
"from_unixtm to_unixtm = id";
(* to_business *)
test (to_business (make 2003 1 1) = (2003, 1, Wed)) "to_business 1";
test (to_business (make 2003 12 31) = (2004, 1, Wed)) "to_business 2";
test (to_business (make 2002 12 31) = (2003, 1, Tue)) "to_business 3";
test (to_business (make 2005 1 1) = (2004, 53, Sat)) "to_business 4";
test (to_business (make 2004 12 31) = (2004, 53, Fri)) "to_business 5";
test (to_business (make 2006 1 1) = (2005, 52, Sun)) "to_business 6";
test (to_business (make 2005 1 17) = (2005, 3, Mon)) "to_business 7";
test (to_business (make 2006 1 31) = (2006, 5, Tue)) "to_business 8";
test (to_business (make 2005 1 31) = (2005, 5, Mon)) "to_business 9";
(* from_business *)
test (from_business 2003 1 Wed = make 2003 1 1) "from_business 1";
test (from_business 2004 1 Wed = make 2003 12 31) "from_business 2";
test (from_business 2003 1 Tue = make 2002 12 31) "from_business 3";
test (from_business 2004 53 Sat = make 2005 1 1) "from_business 4";
test (from_business 2004 53 Fri = make 2004 12 31) "from_business 5";
test (from_business 2005 52 Sun = make 2006 1 1) "from_business 6";
test (from_business 2005 3 Mon = make 2005 1 17) "from_business 7";
test (from_business 2006 5 Tue = make 2006 1 31) "from_business 8";
test (from_business 2005 5 Mon = make 2005 1 31) "from_business 9";
Gen_test.test_exn (lazy (from_business 2005 0 Sun)) "from_business_bad 1";
Gen_test.test_exn (lazy (from_business 2005 53 Sun)) "from_business_bad 2";
()
let suite = ["test_date", `Quick, test]
calendar-3.0.0/tests/test_fcalendar.ml 0000664 0000000 0000000 00000016244 14321307032 0017737 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(*i $Id$ i*)
open CalendarLib;;
open Fcalendar;;
include Gen_test;;
reset ();;
let eps = 0.000001;;
Time_Zone.change Time_Zone.UTC;;
(* Fcalendar *)
test_exn (lazy (make (-4712) 1 1 12 0 (-1.))) "-4713-12-31-23-59-59";;
test (make (-4712) 1 1 12 0 0. = make (-4712) 1 0 36 0 0.) "calendar coercion";;
test (from_jd 0. = make (-4712) 1 1 12 0 0.) "from_jd 0 = 4713 BC-1-1";;
test (from_mjd 0. = make 1858 11 17 0 0 0.) "from_mjd 0 = 1858-11-17";;
Time_Zone.change (Time_Zone.UTC_Plus 5);;
test (abs_float (to_jd (from_jd 12345.6789) -. 12345.6789) < eps)
"to_jd (from_jd x) = x";;
test (abs_float (to_mjd (from_mjd 12345.6789) -. 12345.6789) < eps)
"to_mjd (from_mjd x) = x";;
test (Period.to_date (Period.hour 60) = Date.Period.day 2)
"period(60h) = period(2d)";;
test (Period.compare (Period.day 2) (Period.hour 60) < 0) "Period.compare <";;
test (Period.compare (Period.day 3) (Period.hour 60) > 0) "Period.compare >";;
test (Period.compare
(Period.add (Period.day 2) (Period.hour 12))
(Period.hour 60) = 0) "Period.compare =";;
test
(add (make 1 2 3 4 5 6.) (Period.make 9 8 7 6 5 4.5) =
make 10 10 10 10 10 10.5)
"add 1-2-3-4-5-6 9-8-7-6-5-4.5";;
test
(add (make 3 1 1 0 0 0.7) (Period.make 0 0 0 (-25) 0 (-1.3)) =
make 2 12 30 22 59 59.4)
"add 3-1-1-0-0-0.7 0-0-0-(-25)-0-(-1.3)";;
test
(equal (rem (make 9 8 7 6 5 4.9) (Period.make 1 2 3 4 5 6.4))
(make 8 6 4 1 59 58.5))
"rem 9-8-7-6-5-4 1-2-3-4-5-6";;
test (Period.equal
(sub (make 0 0 7 6 5 4.) (make 0 0 3 54 5 6.))
(Period.make 0 0 1 23 59 58.))
"sub 0-0-7-6-5-4 0-0-3-54-5-6";;
test (Period.equal
(Period.opp (Period.make 0 0 2 3 0 0.))
(Period.make 0 0 (-2) (-3) 0 0.))
"period opp";;
(* Date *)
let d = make 2003 12 31 12 24 48.;;
test (next d `Month = make 2004 1 31 12 24 48.) "2003-12-31 + 1 mois";;
test (add d (Period.month 2) = make 2004 3 2 12 24 48.) "2003-12-31 + 2 mois";;
let d3 = make 2011 3 24 0 0 0.;;
test (prev d3 `Year = make 2010 3 24 0 0 0.) "2011-3-24 - 1 year";;
let d2 = make (-3000) 1 1 6 12 24.5;;
test (equal (rem d (sub d d2)) d2) "rem x (sub x y) = y";;
test (is_leap_day (make 2000 2 24 0 0 0.)) "2000-2-24 leap day";;
test (not (is_leap_day (make 2000 2 25 0 0 0.))) "2000-2-25 not leap day";;
test (is_gregorian (make 1600 1 1 0 0 0.4)) "1600-1-1 gregorian";;
test (not (is_gregorian (make 1400 1 1 0 0 0.1))) "1400-1-1 not gregorian";;
test (is_julian (make 1582 1 1 0 0 0.1)) "1582-1-1 julian";;
test (not (is_julian (make 1583 1 1 0 0 0.9832))) "1583-1-1 not julian";;
(* Time *)
test (let n = Unix.gmtime (Unix.time ()) in
hour (from_unixtm n) = n.Unix.tm_hour) "from_unixtm invariant UTC";;
test (let n = Unix.time () in
hour (from_unixfloat n) = (Unix.gmtime n).Unix.tm_hour)
"from_unixfloat invariant UTC";;
Time_Zone.change (Time_Zone.UTC_Plus 10);;
test (let n = Unix.gmtime (Unix.time ()) in
hour (from_unixtm n) = n.Unix.tm_hour) "from_unixtm invariant +10";;
test (let n = Unix.time () in
hour (from_unixfloat n) = (Unix.gmtime n).Unix.tm_hour)
"from_unixfloat invariant +10";;
test (equal (add (make 0 0 0 10 0 0.1) (Period.hour 30)) (make 0 0 1 16 0 0.1))
"add 0-0-0-20-0-0 30h";;
test (equal
(next (make 1999 12 31 23 59 59.43) `Second)
(make 2000 1 1 0 0 0.43))
"next 1999-31-12-23-59-59 `Second";;
let n = now ();;
test (equal (prev (next n `Minute) `Minute) n) "prev next = id";;
test (equal
(convert
(make 0 0 0 23 0 0.1234)
(Time_Zone.UTC_Plus 2)
(Time_Zone.UTC_Plus 4))
(make 0 0 1 1 0 0.1234)) "convert";;
(* Loss of precision *)
test (hour (make 0 0 0 20 0 0.) = 19) "hour";;
test (hour (make 0 0 0 20 0 0.2) = 20) "hour";;
test (minute (make 0 0 0 20 10 0.2) = 10) "minute";;
(* Loss of precision *)
test (Utils.Float.equal (second (make 0 0 0 20 10 5.123)) 5.123004) "second";;
test (is_pm (make 0 0 0 10 0 0.1)) "is_pm 10-0-0";;
test (is_pm (make 0 0 0 34 0 0.)) "is_pm 34-0-0";;
test (not (is_pm (make 0 0 0 (- 10) 0 0.))) "not (is_pm (- 10) 0 0)";;
test (is_am (make 0 0 0 20 0 0.)) "is_am 20-0-0";;
test (is_am (make 0 0 0 (- 34) 0 0.)) "is_am (- 34) 0 0";;
test (not (is_am (make 0 0 0 34 0 0.))) "not (is_pm 34 0 0)";;
Time_Zone.change Time_Zone.UTC;;
test (let n = Unix.gmtime (Unix.time ()) in
hour (from_unixtm n) = n.Unix.tm_hour) "from_unixtm invariant UTC2";;
test (let n = Unix.time () in
hour (from_unixfloat n) = (Unix.gmtime n).Unix.tm_hour)
"from_unixfloat invariant UTC2";;
test (to_unixfloat (make 1970 1 1 0 0 0.) = 0.) "to_unixfloat 1 Jan 1970";;
test (from_unixfloat 0. = make 1970 1 1 0 0 0.) "from_unixfloat 1 Jan 1970";;
test (Utils.Float.equal (to_unixfloat (make 2004 11 13 19 17 9.)) 1100373429.)
"to_unixfloat";;
test (equal (from_unixfloat 1100373429.) (make 2004 11 13 19 17 9.))
"from_unixfloat";;
(* Loss of precision *)
test (equal
(from_unixtm (to_unixtm (make 2003 7 16 23 22 21.)))
(make 2003 7 16 23 22 20.))
"from_unixtm to_unixtm = id";;
test (Period.to_time (Period.second 30.12) = Time.Period.second 30.12)
"Period.to_time second";;
test (Period.to_time (Period.day 6) = Time.Period.second 518400.)
"Period.to_time day";;
test (Period.safe_to_time (Period.second 30.12) = Time.Period.second 30.12)
"Period.safe_to_time second";;
test (Period.safe_to_time (Period.day 6) = Time.Period.second 518400.)
"Period.safe_to_time day";;
test_exn (lazy (Period.to_time (Period.year 1))) "Period.to_time year";;
test (Period.ymds (Period.make 1 2 3 1 2 3.1) = (1, 2, 3, 3723.1))
"Period.ymds";;
test
(Period.ymds (Period.make (-1) (-2) (-3) (-1) (-2) (-3.)) = (-1,-2,-4,82677.))
"Period.ymds neg";;
let ok = nb_ok ();;
let bug = nb_bug ();;
Printf.printf "tests ok : %d; tests ko : %d\n" ok bug;;
flush stdout;;
calendar-3.0.0/tests/test_fpcalendar.ml 0000664 0000000 0000000 00000016071 14321307032 0020115 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(*i $Id$ i*)
open CalendarLib;;
open Fcalendar.Precise;;
let test () =
let test x s = Alcotest.(check bool) s true x in
let eps = 0.000001 in
Time_Zone.change Time_Zone.UTC;
(* Fcalendar *)
Gen_test.test_exn (lazy (make (-4712) 1 1 12 0 (-1.))) "-4713-12-31-23-59-59";
test (make (-4712) 1 1 12 0 0. = make (-4712) 1 0 36 0 0.) "calendar coercion";
test (from_jd 0. = make (-4712) 1 1 12 0 0.) "from_jd 0 = 4713 BC-1-1";
test (from_mjd 0. = make 1858 11 17 0 0 0.) "from_mjd 0 = 1858-11-17";
Time_Zone.change (Time_Zone.UTC_Plus 5);
test (abs_float (to_jd (from_jd 12345.6789) -. 12345.6789) < eps)
"to_jd (from_jd x) = x";
test (abs_float (to_mjd (from_mjd 12345.6789) -. 12345.6789) < eps)
"to_mjd (from_mjd x) = x";
test (Period.to_date (Period.hour 60) = Date.Period.day 2)
"period(60h) = period(2d)";
test (Period.compare (Period.day 2) (Period.hour 60) < 0) "Period.compare <";
test (Period.compare (Period.day 3) (Period.hour 60) > 0) "Period.compare >";
test (Period.compare
(Period.add (Period.day 2) (Period.hour 12))
(Period.hour 60) = 0) "Period.compare =";
test
(add (make 1 2 3 4 5 6.) (Period.make 9 8 7 6 5 4.5) =
make 10 10 10 10 10 10.5)
"add 1-2-3-4-5-6 9-8-7-6-5-4.5";
test
(add (make 3 1 1 0 0 0.7) (Period.make 0 0 0 (-25) 0 (-1.3)) =
make 2 12 30 22 59 59.4)
"add 3-1-1-0-0-0.7 0-0-0-(-25)-0-(-1.3)";
test
(equal (rem (make 9 8 7 6 5 4.9) (Period.make 1 2 3 4 5 6.4))
(make 8 6 4 1 59 58.5))
"rem 9-8-7-6-5-4 1-2-3-4-5-6";
test (Period.equal
(sub (make 0 0 7 6 5 4.) (make 0 0 3 54 5 6.))
(Period.make 0 0 1 23 59 58.))
"sub 0-0-7-6-5-4 0-0-3-54-5-6";
test (Period.equal
(Period.opp (Period.make 0 0 2 3 0 0.))
(Period.make 0 0 (-2) (-3) 0 0.))
"period opp";
(* Date *)
let d = make 2003 12 31 12 24 48. in
test (next d `Month = make 2004 1 31 12 24 48.) "2003-12-31 + 1 mois";
test (add d (Period.month 2) = make 2004 3 2 12 24 48.) "2003-12-31 + 2 mois";
let d3 = make 2011 3 24 0 0 0. in
test (prev d3 `Year = make 2010 3 24 0 0 0.) "2011-3-24 - 1 year";
let d2 = make (-3000) 1 1 6 12 24.5 in
test (equal (rem d (sub d d2)) d2) "rem x (sub x y) = y";
test (is_leap_day (make 2000 2 24 0 0 0.)) "2000-2-24 leap day";
test (not (is_leap_day (make 2000 2 25 0 0 0.))) "2000-2-25 not leap day";
test (is_gregorian (make 1600 1 1 0 0 0.4)) "1600-1-1 gregorian";
test (not (is_gregorian (make 1400 1 1 0 0 0.1))) "1400-1-1 not gregorian";
test (is_julian (make 1582 1 1 0 0 0.1)) "1582-1-1 julian";
test (not (is_julian (make 1583 1 1 0 0 0.9832))) "1583-1-1 not julian";
(* Time *)
test (let n = Unix.gmtime (Unix.time ()) in
hour (from_unixtm n) = n.Unix.tm_hour) "from_unixtm invariant UTC";
test (let n = Unix.time () in
hour (from_unixfloat n) = (Unix.gmtime n).Unix.tm_hour)
"from_unixfloat invariant UTC";
Time_Zone.change (Time_Zone.UTC_Plus 10);
test (let n = Unix.gmtime (Unix.time ()) in
hour (from_unixtm n) = n.Unix.tm_hour) "from_unixtm invariant +10";
test (let n = Unix.time () in
hour (from_unixfloat n) = (Unix.gmtime n).Unix.tm_hour)
"from_unixfloat invariant +10";
test (equal (add (make 0 0 0 10 0 0.1) (Period.hour 30)) (make 0 0 1 16 0 0.1))
"add 0-0-0-20-0-0 30h";
test (equal
(next (make 1999 12 31 23 59 59.43) `Second)
(make 2000 1 1 0 0 0.43))
"next 1999-31-12-23-59-59 `Second";
let n = now () in
test (equal (prev (next n `Minute) `Minute) n) "prev next = id";
test (equal
(convert
(make 0 0 0 23 0 0.1234)
(Time_Zone.UTC_Plus 2)
(Time_Zone.UTC_Plus 4))
(make 0 0 1 1 0 0.1234)) "convert";
test (hour (make 0 0 0 20 0 0.) = 20) "hour";
test (minute (make 0 0 0 20 10 0.2) = 10) "minute";
test (Utils.Float.equal (second (make 0 0 0 20 10 5.123)) 5.123) "second";
test (is_pm (make 0 0 0 10 0 0.1)) "is_pm 10-0-0";
test (is_pm (make 0 0 0 34 0 0.)) "is_pm 34-0-0";
test (not (is_pm (make 0 0 0 (- 10) 0 0.))) "not (is_pm (- 10) 0 0)";
test (is_am (make 0 0 0 20 0 0.)) "is_am 20-0-0";
test (is_am (make 0 0 0 (- 34) 0 0.)) "is_am (- 34) 0 0";
test (not (is_am (make 0 0 0 34 0 0.))) "not (is_pm 34 0 0)";
Time_Zone.change Time_Zone.UTC;
test (let n = Unix.gmtime (Unix.time ()) in
hour (from_unixtm n) = n.Unix.tm_hour) "from_unixtm invariant UTC2";
test (let n = Unix.time () in
hour (from_unixfloat n) = (Unix.gmtime n).Unix.tm_hour)
"from_unixfloat invariant UTC2";
test (to_unixfloat (make 1970 1 1 0 0 0.) = 0.) "to_unixfloat 1 Jan 1970";
test (from_unixfloat 0. = make 1970 1 1 0 0 0.) "from_unixfloat 1 Jan 1970";
test (floor (to_unixfloat (make 2004 11 13 19 17 10.)) = 1100373429.)
"to_unixfloat";
test (equal (from_unixfloat 1100373429.) (make 2004 11 13 19 17 09.))
"from_unixfloat";
test (equal
(from_unixtm (to_unixtm (make 2003 7 16 23 22 21.)))
(make 2003 7 16 23 22 21.))
"from_unixtm to_unixtm = id";
test (Period.safe_to_time (Period.second 30.12) = Time.Period.second 30.12)
"Period.safe_to_time second";
test (Period.safe_to_time (Period.day 6) = Time.Period.second 518400.)
"Period.safe_to_time day";
Gen_test.test_exn (lazy (Period.to_time (Period.year 1))) "Period.to_time year";
test (Period.ymds (Period.make 1 2 3 1 2 3.1) = (1, 2, 3, 3723.1))
"Period.ymds";
test
(Period.ymds (Period.make (-1) (-2) (-3) (-1) (-2) (-3.)) = (-1,-2,-4,82677.))
"Period.ymds neg";
()
let suite = ["fpcalendar", `Quick, test]
calendar-3.0.0/tests/test_ftime.ml 0000664 0000000 0000000 00000010435 14321307032 0017120 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(*i $Id$ i*)
open CalendarLib
open Ftime;;
let test x s = Alcotest.(check bool) s true x
let test_f x y s = Alcotest.(check @@ testable Fmt.float Utils.Float.equal) s x y
let test1 () =
Time_Zone.change (Time_Zone.UTC_Plus 10);
(* Some [=] are used which should be replaced by [equal]. *)
test (make 30 60 80.5 = make 31 1 20.5) "30-60-80.5 = 31-1-20.5";
test (normalize (make 22 0 0.1) = (make 22 0 0.1, 0)) "normalize 22-0-0.1";
test (normalize (make 73 0 0.) = (make 1 0 0., 3)) "normalize 73-0-0";
test (normalize (make (-73) 0 0.) = (make 23 0 0., -4)) "normalize (-73)-0-0";
test (add (make 20 0 0.2) (Period.minute 70) = make 21 10 0.2)
"add 20-0-0.2 70mn";
test (next (make 20 3 31.) `Minute = make 20 4 31.) "next 20-3-31 `Minute";
test (prev (make 20 3 31.34) `Second = make 20 3 30.34)
"prev 20-3-31.34 `Second";
test (Period.equal (sub (make 6 5 4.) (make 4 5 6.1)) (Period.make 1 59 57.9))
"sub 6-5-4. 4-5-6.1";
test (convert (make 20 0 0.123) (Time_Zone.UTC_Plus 2) (Time_Zone.UTC_Plus 4) =
make 22 0 0.123) "convert";
test (to_gmt (make 20 0 0.) = make 10 0 0.) "to_gmt";
test (from_gmt (make 20 0 0.) = make 30 0 0.) "from_gmt";
test (midnight () = make 0 0 0.) "midnight";
test (midday () = make 12 0 0.) "midday";
test (hour (make 20 0 59.99) = 20) "hour";
test (minute (make 20 10 0.) = 10) "minute";
test (second (make 20 10 5.) = 5.) "second";
()
let test2() =
Time_Zone.change (Time_Zone.UTC_Plus 10);
Utils.Float.set_precision 1e-6;
let one_two_three = make 1 2 3. in
test (to_seconds one_two_three = 3723.) "to_seconds";
test (to_minutes one_two_three = 62.05) "to_minutes";
test_f (to_hours (make 1 3 0.4)) 1.050111 "to_hours";
test (equal (from_seconds 3723.2) (from_minutes 62.053333333))
"from_seconds; from_minutes";
test (from_hours 1.05 = make 1 3 0.) "from_hours";
test (is_pm (midnight ())) "is_pm midnight";
test (is_pm (make 10 0 0.)) "is_pm 10-0-0";
test (is_pm (make 34 0 0.)) "is_pm 34-0-0";
test (not (is_pm (make (- 10) 0 0.))) "not (is_pm (- 10) 0 0)";
test (is_am (midday ())) "is_am midday";
test (is_am (make 20 0 0.)) "is_am 20-0-0";
test (is_am (make (- 34) 0 0.)) "is_am (- 34) 0 0";
test (not (is_am (make 34 0 0.))) "not (is_pm 34 0 0)";
()
let test3() =
Time_Zone.change (Time_Zone.UTC_Plus 10);
Utils.Float.set_precision 1e-6;
let one_two_three = Period.make 1 2 3. in
test_f (Period.to_seconds one_two_three) 3723.
"Period.to_seconds";
test_f (Period.to_minutes one_two_three) 62.05
"Period.to_minutes";
test_f (Period.to_hours (Period.make 1 3 0.1)) 1.050028
"Period.to_hours";
()
let suite = [
"ftime1", `Quick, test1;
"ftime2", `Quick, test2;
"ftime3", `Quick, test3;
]
calendar-3.0.0/tests/test_pcalendar.ml 0000664 0000000 0000000 00000016066 14321307032 0017753 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(*i $Id$ i*)
open CalendarLib;;
open Calendar.Precise;;
let test() =
let test x s = Alcotest.(check bool) s true x in
let eps = 0.000001 in
Time_Zone.change Time_Zone.UTC;
(* Calendar *)
Gen_test.test_exn (lazy (make (-4712) 1 1 12 0 (-1))) "-4713-12-31-23-59-59";
test (make (-4712) 1 1 12 0 0 = make (-4712) 1 0 36 0 0) "calendar coercion";
test (from_jd 0. = make (-4712) 1 1 12 0 0) "from_jd 0 = 4713 BC-1-1";
test (from_mjd 0. = make 1858 11 17 0 0 0) "from_mjd 0 = 1858-11-17";
Time_Zone.change (Time_Zone.UTC_Plus 5);
test (abs_float (to_jd (from_jd 12345.6789) -. 12345.6789) < eps)
"to_jd (from_jd x) = x";
test (abs_float (to_mjd (from_mjd 12345.6789) -. 12345.6789) < eps)
"to_mjd (from_mjd x) = x";
test (Period.to_date (Period.hour 60) = Date.Period.day 2)
"period(60h) = period(2d)";
test (Period.compare (Period.day 2) (Period.hour 60) < 0) "Period.compare <";
test (Period.compare (Period.day 3) (Period.hour 60) > 0) "Period.compare >";
test (Period.compare
(Period.add (Period.day 2) (Period.hour 12))
(Period.hour 60) = 0) "Period.compare =";
test
(add (make 1 2 3 4 5 6) (Period.make 9 8 7 6 5 4) = make 10 10 10 10 10 10)
"add 1-2-3-4-5-6 9-8-7-6-5-4";
test
(add (make 3 1 1 0 0 0) (Period.make 0 0 0 (-25) 0 (-1)) =
make 2 12 30 22 59 59)
"add 3-1-1-0-0-0 0-0-0-(-25)-0-(-1)";
test
(equal (rem (make 9 8 7 6 5 4) (Period.make 1 2 3 4 5 6))
(make 8 6 4 1 59 58))
"rem 9-8-7-6-5-4 1-2-3-4-5-6";
test (sub (make 0 0 7 6 5 4) (make 0 0 3 54 5 6) = Period.make 0 0 1 23 59 58)
"sub 0-0-7-6-5-4 0-0-3-54-5-6";
test (Period.equal
(Period.opp (Period.make 0 0 2 3 0 0))
(Period.make 0 0 (-2) (-3) 0 0))
"period opp";
(* Date *)
let d = make 2003 12 31 12 24 48 in
test (next d `Month = make 2004 1 31 12 24 48) "2003-12-31 + 1 mois";
test (add d (Period.month 2) = make 2004 3 2 12 24 48) "2003-12-31 + 2 mois";
let d3 = make 2011 3 24 0 0 0 in
test (prev d3 `Year = make 2010 3 24 0 0 0) "2011-3-24 - 1 year";
let d2 = make (-3000) 1 1 6 12 24 in
test (equal (rem d (sub d d2)) d2) "rem x (sub x y) = y";
test (is_leap_day (make 2000 2 24 0 0 0)) "2000-2-24 leap day";
test (not (is_leap_day (make 2000 2 25 0 0 0))) "2000-2-25 not leap day";
test (is_gregorian (make 1600 1 1 0 0 0)) "1600-1-1 gregorian";
test (not (is_gregorian (make 1400 1 1 0 0 0))) "1400-1-1 not gregorian";
test (is_julian (make 1582 1 1 0 0 0)) "1582-1-1 julian";
test (not (is_julian (make 1583 1 1 0 0 0))) "1583-1-1 not julian";
(* Time *)
test (let n = Unix.gmtime (Unix.time ()) in
hour (from_unixtm n) = n.Unix.tm_hour) "from_unixtm invariant UTC";
test (let n = Unix.time () in
hour (from_unixfloat n) = (Unix.gmtime n).Unix.tm_hour)
"from_unixfloat invariant UTC";
Time_Zone.change (Time_Zone.UTC_Plus 10);
test (let n = Unix.gmtime (Unix.time ()) in
hour (from_unixtm n) = n.Unix.tm_hour) "from_unixtm invariant +10";
test (let n = Unix.time () in
hour (from_unixfloat n) = (Unix.gmtime n).Unix.tm_hour)
"from_unixfloat invariant +10";
test (equal (add (make 0 0 0 10 0 0) (Period.hour 30)) (make 0 0 1 16 0 0))
"add 0-0-0-20-0-0 30h";
test (equal (next (make 1999 12 31 23 59 59) `Second) (make 2000 1 1 0 0 0))
"next 1999-31-12-23-59-59 `Second";
let n = now () in
test (equal (prev (next n `Minute) `Minute) n) "prev next = id";
test (equal
(convert
(make 0 0 0 23 0 0)
(Time_Zone.UTC_Plus 2)
(Time_Zone.UTC_Plus 4))
(make 0 0 1 1 0 0)) "convert";
test (hour (make 0 0 0 20 0 0) = 20) "hour";
test (minute (make 0 0 0 20 10 0) = 10) "minute";
test (second (make 0 0 0 20 10 5) = 5) "second";
test (is_pm (make 0 0 0 10 0 0)) "is_pm 10-0-0";
test (is_pm (make 0 0 0 34 0 0)) "is_pm 34-0-0";
test (not (is_pm (make 0 0 0 (- 10) 0 0))) "not (is_pm (- 10) 0 0)";
test (is_am (make 0 0 0 20 0 0)) "is_am 20-0-0";
test (is_am (make 0 0 0 (- 34) 0 0)) "is_am (- 34) 0 0";
test (not (is_am (make 0 0 0 34 0 0))) "not (is_pm 34 0 0)";
Time_Zone.change Time_Zone.UTC;
test (let n = Unix.gmtime (Unix.time ()) in
hour (from_unixtm n) = n.Unix.tm_hour) "from_unixtm invariant UTC2";
test (let n = Unix.time () in
hour (from_unixfloat n) = (Unix.gmtime n).Unix.tm_hour)
"from_unixfloat invariant UTC2";
test (to_unixfloat (make 1970 1 1 0 0 0) = 0.) "to_unixfloat 1 Jan 1970";
test (from_unixfloat 0. = make 1970 1 1 0 0 0) "from_unixfloat 1 Jan 1970";
test (Utils.Float.equal (to_unixfloat (make 2004 11 13 19 17 9)) 1100373429.)
"to_unixfloat";
test (equal (from_unixfloat 1100373429.) (make 2004 11 13 19 17 9))
"from_unixfloat";
test (from_unixtm (to_unixtm (make 2003 7 16 23 22 21)) =
make 2003 7 16 23 22 21)
"from_unixtm to_unixtm = id";
test (Period.to_time (Period.second 30) = Time.Period.second 30)
"Period.to_time second";
test (Period.safe_to_time (Period.second 30) = Time.Period.second 30)
"Period.safe_to_time second";
test (Period.to_time (Period.day 6) = Time.Period.second 518400)
"Period.to_time day";
test (Period.safe_to_time (Period.day 6) = Time.Period.second 518400)
"Period.safe_to_time day";
Gen_test.test_exn (lazy (Period.to_time (Period.year 1))) "Period.to_time year";
test (Period.ymds (Period.make 1 2 3 1 2 3) = (1, 2, 3, 3723)) "Period.ymds";
test
(Period.ymds (Period.make (-1) (-2) (-3) (-1) (-2) (-3)) = (-1,-2,-4,82677))
"Period.ymds neg";
()
let suite = ["pcalendar", `Quick, test]
calendar-3.0.0/tests/test_printer.ml 0000664 0000000 0000000 00000013655 14321307032 0017506 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
open CalendarLib;;
open Printer.Date;;
let test () =
let test x s = Alcotest.(check bool) s true x in
let d = Date.make 2003 1 6 in
test (sprint "%D" d = "01/06/03") "sprint %D";
test (sprint "the date is %B, the %-dth" d = "the date is January, the 6th")
"sprint (long sentence)";
test (sprint "%^B, the %0dth" d = "JANUARY, the 06th") "sprint padding";
test (sprint "%j" d = "006") "sprint %j";
test (sprint "%-j" d = "6") "sprint %j";
test (sprint "%_j" d = " 6") "sprint %j";
test (sprint "%j" (Date.make 2003 1 10) = "010") "sprint %j";
test (sprint "%-j" (Date.make 2003 1 10) = "10") "sprint %j";
test (sprint "%_j" (Date.make 2003 1 10) = " 10") "sprint %j";
test (sprint "%C" (Date.make 2008 12 5) = "21") "sprint %C";
test (from_string "2003-01-06" = Date.make 2003 1 6) "from_string";
test (from_fstring "%y-%m-%d" "03-01-06" = Date.make 1903 1 6) "from_fstring";
test
(from_fstring "%Y%t%m%t%d" "1903\t01\t06" = Date.make 1903 1 6)
"from_fstring %t";
test
(from_fstring "%Y-%B-%d" "2007-May-14" = Date.make 2007 5 14)
"from_fstring %B";
test
(from_fstring "%Y-%b-%d" "2007-Jan-14" = Date.make 2007 1 14)
"from_fstring %B";
test (from_fstring "%Y %V %w" "2004 01 1" = Date.make 2003 12 29)
"from_fstring %Y %V %w";
test (from_fstring "%V %Y %w" "52 1999 7" = Date.make 2000 1 2)
"from_fstring %V %Y %w";
Gen_test.test_exn (lazy (from_fstring "%Y %w" "1999 7")) "from_fstring_exn";
test (from_fstring "%Y%j" "1903001" = Date.make 1903 1 1) "from_fstring %Y%j";
test (from_fstring "%j%Y" "0011903" = Date.make 1903 1 1) "from_fstring %j%Y";
Gen_test.test_exn (lazy (from_fstring "%j" "001")) "from_fstring_exn 2";
let open Printer.Time in
test (to_string (Time.make 12 1 4) = "12:01:04") "to_string (on TimePrinter)";
test (sprint "%I" (Time.make 36 4 3) = "12") "sprint %I (on TimePrinter)";
test (sprint "%r" (Time.make 24 4 3) = "12:04:03 AM")
"sprint %r (on TimePrinter)";
test (sprint "%R %z" (Time.make 12 24 5) = "12:24 +0000") "sprint %R %z";
test
(Time_Zone.on (fun () -> sprint "%R %z" (Time.make 12 24 5))
(Time_Zone.UTC_Plus (-3)) () = "12:24 -0300")
"sprint %R %z neg";
test (sprint "%R %S %:z" (Time.make 23 47 55) = "23:47 55 +00:00")
"sprint %R %S %:z";
test
(Time_Zone.on (fun () -> sprint "%R %S %::z" (Time.make 7 47 55))
(Time_Zone.UTC_Plus 3) () = "07:47 55 +03:00:00")
"sprint %R %S %::z";
Gen_test.test_exn (lazy (sprint "%R %:a" (Time.make 23 47 55))) "sprint %R %:a";
Gen_test.test_exn (lazy (sprint "%::::z %R" (Time.make 23 47 55))) "sprint %::::z %R";
test (from_fstring "%R %S %z" "10:47 55 -0300" = Time.make 13 47 55)
"from_fstring %R %S %z";
test (from_fstring "%R %S %:z" "10:47 55 -13:00" = Time.make 23 47 55)
"from_fstring %R %S %:z";
Gen_test.test_exn (lazy (from_fstring "%R %S %:z" "10:47 55 -0300"))
"from_fstring %R %S %:z bug1";
Gen_test.test_exn (lazy (from_fstring "%R %S %:z" "10:47 55 -03:00:00"))
"from_fstring %R %S %:z bug2";
test (from_fstring "%R %S %::z" "10:47 55 +03:00:00" = Time.make 7 47 55)
"from_fstring %R %S %::z";
test (from_fstring "%R %S %:::z" "10:47 55 -03" = Time.make 13 47 55)
"from_fstring %R %S %:::z";
Gen_test.test_exn (lazy (from_fstring "%R %S %::::z" "10:47 55 -0300"))
"from_fstring %R %S %::::z";
test (from_fstring "%r" "10:47:25 AM" = Time.make 10 47 25)
"from_fstring AM (on TimePrinter)";
test (from_fstring "%r" "10:47:25 PM" = Time.make 22 47 25)
"from_fstring PM (on TimePrinter)";
Gen_test.test_exn (lazy (from_fstring "%p %I:%M:%S" "TM 5:26:17"))
"from_fstring error on %p (on TimePrinter)";
let open Printer.Calendar in
test (sprint "%c" (Calendar.make 2003 1 6 12 1 4) = "Mon Jan 06 12:01:04 2003")
"sprint %c";
test (to_string (Calendar.make 2004 10 25 24 0 1) = "2004-10-26 00:00:01")
"to_string (on CalendarPrinter)";
test
(from_fstring "%c" "Mon May 14 10:30:00 2007"
= Calendar.make 2007 5 14 10 30 0)
"from_fstring (on CalendarPrinter)";
test (sprint "%s" (Calendar.make 1971 1 1 0 0 0) = "31536000")
"sprint %s";
test (Utils.Float.equal
(Ftime.second
(Printer.Ftime.from_fstring
"%Y-%m-%dT%H:%M:%S%:z" "2014-03-19T15:51:25.05-07:00"))
25.05)
"from_string with floating seconds";
()
let suite = ["printer", `Quick, test]
calendar-3.0.0/tests/test_time.ml 0000664 0000000 0000000 00000007473 14321307032 0016762 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(*i $Id$ i*)
open CalendarLib
open Time;;
let test () =
let test x s = Alcotest.(check bool) s true x in
Time_Zone.change (Time_Zone.UTC_Plus 10);
test (make 30 60 80 = make 31 1 20) "30-60-80 = 31-1-20";
test (normalize (make 22 0 0) = (make 22 0 0, 0)) "normalize 22-0-0";
test (normalize (make 73 0 0) = (make 1 0 0, 3)) "normalize 73-0-0";
test (normalize (make (-73) 0 0) = (make 23 0 0, -4)) "normalize (-73)-0-0";
test (add (make 20 0 0) (Period.minute 70) = make 21 10 0) "add 20-0-0 70mn";
test (next (make 20 3 31) `Minute = make 20 4 31) "next 20-3-31 `Minute";
test (prev (make 20 3 31) `Second = make 20 3 30) "prev 20-3-31 `Second";
test (sub (make 6 5 4) (make 4 5 6) = Period.make 1 59 58) "sub 6-5-4 4-5-6";
test (convert (make 20 0 0) (Time_Zone.UTC_Plus 2) (Time_Zone.UTC_Plus 4) =
make 22 0 0) "convert";
test (to_gmt (make 20 0 0) = make 10 0 0) "to_gmt";
test (from_gmt (make 20 0 0) = make 30 0 0) "from_gmt";
test (midnight () = make 0 0 0) "midnight";
test (midday () = make 12 0 0) "midday";
test (hour (make 20 0 0) = 20) "hour";
test (minute (make 20 10 0) = 10) "minute";
test (second (make 20 10 5) = 5) "second";
let one_two_three = make 1 2 3 in
test (to_seconds one_two_three = 3723) "to_seconds";
test (Utils.Float.equal (to_minutes one_two_three) 62.05) "to_minutes";
test (to_hours (make 1 3 0) = 1.05) "to_hours";
test (from_seconds 3723 = from_minutes 62.05) "from_seconds; from_minutes";
test (from_hours 1.05 = make 1 3 0) "from_hours";
test (is_pm (midnight ())) "is_pm midnight";
test (is_pm (make 10 0 0)) "is_pm 10-0-0";
test (is_pm (make 34 0 0)) "is_pm 34-0-0";
test (not (is_pm (make (- 10) 0 0))) "not (is_pm (- 10) 0 0)";
test (is_am (midday ())) "is_am midday";
test (is_am (make 20 0 0)) "is_am 20-0-0";
test (is_am (make (- 34) 0 0)) "is_am (- 34) 0 0";
test (not (is_am (make 34 0 0))) "not (is_pm 34 0 0)";
let one_two_three = Period.make 1 2 3 in
test (Period.to_seconds one_two_three = 3723) "Period.to_seconds";
test (Utils.Float.equal (Period.to_minutes one_two_three) 62.05)
"Period.to_minutes";
test (Utils.Float.equal (Period.to_hours (Period.make 1 3 0)) 1.05)
"Period.to_hours";
()
let suite = [
"time", `Quick, test;
]
calendar-3.0.0/tests/test_timezone.ml 0000664 0000000 0000000 00000004605 14321307032 0017650 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(*i $Id$ i*)
open CalendarLib
open Time_Zone;;
let tz = Alcotest.testable (Fmt.always "timezone") (=) ;;
let test () =
change UTC;
Alcotest.(check tz) "current () = UTC" UTC (current ());
change Local;
Alcotest.(check tz) "current () = Local" Local (current ());
Alcotest.(check int) "gap UTC (UTC_Plus (-5)) = -5" ~-5 (gap UTC (UTC_Plus ~-5));
let g6 = UTC_Plus 6 in
Alcotest.(check int)
"gap g6 Local = gap g6 UTC + gap UTC Local"
(gap g6 Local) (gap g6 UTC + gap UTC Local);
Gen_test.test_exn (lazy (change (UTC_Plus 13))) "change 13";
Gen_test.test_exn (lazy (change (UTC_Plus (-15)))) "change (-15)";
change (UTC_Plus 4);
Alcotest.(check int) "from_gmt () = 4" 4 (from_gmt ()) ;
Alcotest.(check int) "to_gmt () = -4" ~-4 (to_gmt ());
()
let suite = ["timezone", `Quick, test]
calendar-3.0.0/utils/ 0000775 0000000 0000000 00000000000 14321307032 0014416 5 ustar 00root root 0000000 0000000 calendar-3.0.0/utils/example.ml.3 0000664 0000000 0000000 00000005464 14321307032 0016555 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Version for OCaml 3.* *)
(** Add a tag @example *)
class example = object (self)
inherit Odoc_html.html as super
method html_of_example txt =
let buf = Buffer.create 97 in
self#html_of_text buf txt;
Format.sprintf "%s
\n" (Buffer.contents buf);
method html_of_examples = function
| [] -> ""
| [ txt ] -> Format.sprintf "Example: %s" (self#html_of_example txt)
| examples ->
let s = Format.sprintf "Examples:" in
let s =
List.fold_left
(fun acc txt ->
Format.sprintf "%s- %s
"
acc
(self#html_of_example txt))
s
examples;
in
Format.sprintf "%s
" s
(** Redefine [html_of_custom] *)
method html_of_custom b l =
let examples = ref [] in
List.iter
(fun (tag, text) ->
try
if tag = "example" then examples := text :: !examples
else assert false
with
Not_found ->
Odoc_info.warning (Odoc_messages.tag_not_handled tag))
l;
Buffer.add_string b (self#html_of_examples !examples)
initializer
tag_functions <- ("example", self#html_of_example) :: tag_functions
end
let () =
Odoc_args.set_doc_generator (Some ((new example) :> Odoc_args.doc_generator))
calendar-3.0.0/utils/example.ml.4 0000664 0000000 0000000 00000005570 14321307032 0016554 0 ustar 00root root 0000000 0000000 (**************************************************************************)
(* *)
(* This file is part of Calendar. *)
(* *)
(* Copyright (C) 2003-2011 Julien Signoles *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License version 2.1 as published by the *)
(* Free Software Foundation, with a special linking exception (usual *)
(* for Objective Caml libraries). *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(* *)
(* See the GNU Lesser General Public Licence version 2.1 for more *)
(* details (enclosed in the file LGPL). *)
(* *)
(* The special linking exception is detailled in the enclosed file *)
(* LICENSE. *)
(**************************************************************************)
(** Version for OCaml 4.* *)
(** Add a tag @example *)
module Generator (G : Odoc_html.Html_generator) =
struct
class html = object (self)
inherit G.html as super
method private html_of_example txt =
let buf = Buffer.create 97 in
self#html_of_text buf txt;
Format.sprintf "%s
\n" (Buffer.contents buf);
method private html_of_examples = function
| [] -> ""
| [ txt ] -> Format.sprintf "Example: %s" (self#html_of_example txt)
| examples ->
let s = Format.sprintf "Examples:" in
let s =
List.fold_left
(fun acc txt ->
Format.sprintf "%s- %s
"
acc
(self#html_of_example txt))
s
examples;
in
Format.sprintf "%s
" s
(** Redefine [html_of_custom] *)
method html_of_custom b l =
let examples = ref [] in
List.iter
(fun (tag, text) ->
try
if tag = "example" then examples := text :: !examples
else assert false
with
Not_found ->
Odoc_info.warning (Odoc_messages.tag_not_handled tag))
l;
Buffer.add_string b (self#html_of_examples !examples)
initializer
tag_functions <- ("example", self#html_of_example) :: tag_functions
end
end
let () =
Odoc_args.extend_html_generator
(module Generator : Odoc_gen.Html_functor)