mirror of
https://github.com/quantum5/qcal.git
synced 2025-07-27 03:34:11 -04:00
Compare commits
No commits in common. "1fd038e900f0e5249454063727c306aca6c0f400" and "6bbd0d0ad9b28370d4c341bfb251b8a6b44c40c7" have entirely different histories.
1fd038e900
...
6bbd0d0ad9
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
@ -6,7 +6,7 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
node-version: [16.x, 18.x]
|
||||
directory: [common, frcal, jcal, mcal]
|
||||
directory: [common, frcal, jcal]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
|
|
|
@ -74,7 +74,7 @@ export type Haab = {
|
|||
day: HaabDay,
|
||||
};
|
||||
|
||||
export const haabNames: Record<HaabMonth, string> = {
|
||||
const haabNames: Record<HaabMonth, string> = {
|
||||
1: 'Pop',
|
||||
2: 'Woʼ',
|
||||
3: 'Sip',
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
const {aliasWebpack, aliasJest} = require('react-app-alias-ex');
|
||||
|
||||
const options = {};
|
||||
module.exports = aliasWebpack(options);
|
||||
module.exports.jest = function (config) {
|
||||
const result = aliasJest(options)(config);
|
||||
result.moduleDirectories.unshift(require('path').resolve(__dirname, '../node_modules'));
|
||||
return result;
|
||||
};
|
163
mcal/index.html
163
mcal/index.html
|
@ -1,163 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<meta name="theme-color" content="#ff0000"/>
|
||||
<meta name="description" content="An interactive French Republican Calendar (a.k.a. French Revolutionary Calendar) that uses the original equinox method and never drifts out of sync with the seasons, along with revolutionary decimal time."/>
|
||||
<meta property="og:title" content="French Republican Calendar"/>
|
||||
<meta property="og:type" content="website"/>
|
||||
<meta property="og:url" content="%PUBLIC_URL%"/>
|
||||
<meta property="og:description" content="An interactive French Republican Calendar (a.k.a. French Revolutionary Calendar) that uses the original equinox method and never drifts out of sync with the seasons, along with revolutionary decimal time."/>
|
||||
<meta property="og:image" content="%PUBLIC_URL%/logo512.png"/>
|
||||
<meta property="og:image:type" content="image/png"/>
|
||||
<meta property="og:image:width" content="512"/>
|
||||
<meta property="og:image:height" content="512"/>
|
||||
<meta property="og:image:alt" content="A calendar icon that displays the date 18 Brumaire."/>
|
||||
<link rel="canonical" href="%PUBLIC_URL%/"/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png"/>
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
|
||||
<title>French Republican Calendar (a.k.a. French Revolutionary Calendar)</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-md navbar-light">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="#">French Republican Calendar</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#nav-anchors"
|
||||
aria-controls="nav-anchors" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="nav-anchors">
|
||||
<ul class="nav navbar-nav mr-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#explanation">Explanation</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://jcal.qt.ax">Julian Calendar</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://gcal.qt.ax">Gregorian Calendar</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<div class="main">
|
||||
<h2 id="explanation">Explanation</h2>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">What is this?</h4>
|
||||
<p class="lead">The <a href="https://en.wikipedia.org/wiki/French_Republican_calendar">French Republican
|
||||
calendar</a> was a calendar created and implemented during the French Revolution.</p>
|
||||
<p>It is also frequently referred to as the <em>French Revolutionary Calendar</em>, but this is a misnomer:
|
||||
year 1 of the calendar started on 22 September 1792, the day after the
|
||||
<a href="https://en.wikipedia.org/wiki/Proclamation_of_the_abolition_of_the_monarchy">abolition of the
|
||||
monarchy</a> and the founding of the <a href="https://en.wikipedia.org/wiki/French_First_Republic">French
|
||||
First Republic</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">How does it work?</h4>
|
||||
<p class="lead">A year consists of 12 months of 30 days each, divided into three <em>décades</em> of 10 days
|
||||
each, followed by 5 complementary days (6 in leap years).</p>
|
||||
<p>The year starts on the day of the autumnal equinox at the Paris Observatory (longitude 2°20′14.03″ E). A
|
||||
leap year follow directly from this definition: a year is a leap year when the next autumnal equinox
|
||||
happens 366 days later instead of the normal 365. By this definition, the year will <b>never</b> drift
|
||||
with respect to the seasons.</p>
|
||||
<p>The 12 months are: <em>Vendémiaire</em>, <em>Brumaire</em>, <em>Frimaire</em>, <em>Nivôse</em>, <em>Pluviôse</em>,
|
||||
<em>Ventôse</em>, <em>Germinal</em>, <em>Floréal</em>, <em>Prairial</em>, <em>Messidor</em>, <em>Thermidor</em>,
|
||||
<em>Fructidor.</em> Every three months represent a season, and the endings of the names reflect this
|
||||
fact.</p>
|
||||
<p>The complementary days are: <em>la Fête de la Vertu</em>, <em>la Fête du Génie</em>, <em>la Fête du
|
||||
Travail</em>, <em>la Fête de l'Opinion</em>, <em>la Fête des Récompenses,</em> and <em>la Fête de la
|
||||
Révolution</em> (leap years only).</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">What's so special about this version?</h4>
|
||||
<p class="lead">Most versions of the calendar floating around doesn't use the original definition above.</p>
|
||||
<p>Most versions uses the so-called <em>Romme</em> method for leap years, using the same leap year rules as
|
||||
the Gregorian calendar, i.e. every year divisible by four, except century years not divisible by 400.
|
||||
This method might make sense, except years 3, 7, and 11 were leap years under the original rules and
|
||||
were observed as such in real life, but the <em>Romme</em> method instead makes years 4, 8, 12 leap
|
||||
years instead.</p>
|
||||
<p>This version uses the original rules. The <a href="https://ssd.jpl.nasa.gov/planets/eph_export.html">JPL's
|
||||
DE440 and DE441 ephemerides</a> were used to calculate the exact timings of the autumnal equinoxes
|
||||
between the Gregorian years 13201 BCE and 17191 CE (corresponding to the French Republican years -14991
|
||||
to 15399). The times were then converted to UT1+00:09:21, the exact local time at the Paris Observatory.
|
||||
UT1 was chosen to keep track of the Earth's rotation without having to worry about the issues posed by
|
||||
leap seconds in UTC. Note that due to the uncertainty over
|
||||
<a href="https://en.wikipedia.org/wiki/%CE%94T_(timekeeping)">ΔT</a> — the difference between UT1 and
|
||||
Terrestrial Time (TT) used in the ephemerides — it is theoretically possible for there to be
|
||||
inaccuracies when the equinox occurs very close to midnight.</p>
|
||||
<p>For more details about how I calculated this calendar, please see
|
||||
<a href="https://quantum5.ca/2022/03/09/art-of-time-keeping-part-4-french-republican-calendar/">my blog
|
||||
post on the topic</a>. This is the fourth part of a series on time-keeping, and you are highly
|
||||
encouraged to read the
|
||||
<a href="https://quantum5.ca/2022/02/16/art-of-time-keeping-part-1-years-dates/">first</a>
|
||||
<a href="https://quantum5.ca/2022/02/23/art-of-time-keeping-part-2-time/">three</a>
|
||||
<a href="https://quantum5.ca/2022/03/02/art-of-time-keeping-part-3-astronomy-equinoxes/">parts</a>
|
||||
for a more complete understanding.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">What are those names above the Gregorian date?</h4>
|
||||
<p>Those are the names of the days in the
|
||||
<a href="https://en.wikipedia.org/wiki/French_Republican_calendar#Rural_calendar">rural version of the
|
||||
calendar</a>. This was intended to replace the Catholic Church's calendar of saints, as the French
|
||||
Revolution wanted to reduce the influence of the church. Every day of the year has a unique name
|
||||
associated with the rural economy and these names are supposed to correspond with the season.</p>
|
||||
<p>Every <em>quintidi</em> is named after an animal, every <em>décadi</em> is named after an agricultural
|
||||
tool, and the remaining days are named after various plants or produce. The only exception is the winter
|
||||
month of Nivôse, which has the remaining days named after minerals.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">What are those numbers below the Gregorian date?</h4>
|
||||
<p>The five (or more) numbers separated by dots is the corresponding
|
||||
<a href="https://en.wikipedia.org/wiki/Mesoamerican_Long_Count_calendar">Mesoamerican Long Count
|
||||
calendar</a> date. This is commonly known as the “Mayan calendar.” This calendar is not
|
||||
available for dates before August 11, 3114 BCE (25 Thermidor -4905).</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">What is decimal time?</h4>
|
||||
<p class="lead">Decimal time is a time system used during the French Revolution that divided the day into 10
|
||||
hours, each with 100 minutes, which contained 100 seconds each.</p>
|
||||
<p>The result is 100,000 seconds in one day, compared to the 86,400 seconds with the normal 24-hour
|
||||
system. This makes it very easy to denote time as a decimal fraction of a day. For example, decimal time
|
||||
5:67:72 (around 13:37:31) on January 1, 2000 can be represented as <code>2000-01-01.56772</code>.</p>
|
||||
<p>Also note that each decimal hour is 2.4 normal hours, each decimal minute is 1.44 normal minutes, and
|
||||
each decimal second is 0.864 normal seconds.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<p class="text-muted">Copyright © 2022-<%= new Date().getFullYear() %>
|
||||
<a href="https://quantum5.ca">Quantum</a>.
|
||||
Licensed under <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">GNU AGPLv3</a>.
|
||||
Source code available on <a href="https://github.com/quantum5/qcal">GitHub</a>.<br>
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
<script>
|
||||
(function(r,e,p,u,b,l,i,c){r['GoogleAnalyticsObject']=b;r[b]=r[b]||function(){
|
||||
(r[b].q=r[b].q||[]).push(arguments)},r[b].l=1*new Date();l=e.createElement(p),
|
||||
i=e.getElementsByTagName(p)[0];l.async=1;l.src=u;i.parentNode.insertBefore(l,i)
|
||||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-102581070-4', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"short_name": "French Republican Calendar",
|
||||
"name": "French Republican Calendar",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "128x128 64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#ff0000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
{
|
||||
"name": "mcal",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@testing-library/jest-dom": "^5.16.2",
|
||||
"@testing-library/react": "^12.1.2",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@types/node": "^16.11.24",
|
||||
"@types/react": "^17.0.39",
|
||||
"@types/react-dom": "^17.0.11",
|
||||
"bootstrap": "~5.1.3",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-scripts": "5.0.0",
|
||||
"sass": "^1.49.7",
|
||||
"sass-loader": "^12.4.0",
|
||||
"typescript": "^4.5.5",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-app-rewired start",
|
||||
"build": "react-app-rewired build",
|
||||
"test": "react-app-rewired test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bootstrap": "^5.1.9",
|
||||
"react-app-alias-ex": "^2.1.0",
|
||||
"react-app-rewired": "^2.2.1"
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 97 KiB |
|
@ -1,163 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<meta name="theme-color" content="#ff0000"/>
|
||||
<meta name="description" content="An interactive French Republican Calendar (a.k.a. French Revolutionary Calendar) that uses the original equinox method and never drifts out of sync with the seasons, along with revolutionary decimal time."/>
|
||||
<meta property="og:title" content="French Republican Calendar"/>
|
||||
<meta property="og:type" content="website"/>
|
||||
<meta property="og:url" content="%PUBLIC_URL%"/>
|
||||
<meta property="og:description" content="An interactive French Republican Calendar (a.k.a. French Revolutionary Calendar) that uses the original equinox method and never drifts out of sync with the seasons, along with revolutionary decimal time."/>
|
||||
<meta property="og:image" content="%PUBLIC_URL%/logo512.png"/>
|
||||
<meta property="og:image:type" content="image/png"/>
|
||||
<meta property="og:image:width" content="512"/>
|
||||
<meta property="og:image:height" content="512"/>
|
||||
<meta property="og:image:alt" content="A calendar icon that displays the date 18 Brumaire."/>
|
||||
<link rel="canonical" href="%PUBLIC_URL%/"/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png"/>
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
|
||||
<title>French Republican Calendar (a.k.a. French Revolutionary Calendar)</title>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-md navbar-light">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="#">French Republican Calendar</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#nav-anchors"
|
||||
aria-controls="nav-anchors" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="nav-anchors">
|
||||
<ul class="nav navbar-nav mr-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#explanation">Explanation</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://jcal.qt.ax">Julian Calendar</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://gcal.qt.ax">Gregorian Calendar</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<div class="main">
|
||||
<h2 id="explanation">Explanation</h2>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">What is this?</h4>
|
||||
<p class="lead">The <a href="https://en.wikipedia.org/wiki/French_Republican_calendar">French Republican
|
||||
calendar</a> was a calendar created and implemented during the French Revolution.</p>
|
||||
<p>It is also frequently referred to as the <em>French Revolutionary Calendar</em>, but this is a misnomer:
|
||||
year 1 of the calendar started on 22 September 1792, the day after the
|
||||
<a href="https://en.wikipedia.org/wiki/Proclamation_of_the_abolition_of_the_monarchy">abolition of the
|
||||
monarchy</a> and the founding of the <a href="https://en.wikipedia.org/wiki/French_First_Republic">French
|
||||
First Republic</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">How does it work?</h4>
|
||||
<p class="lead">A year consists of 12 months of 30 days each, divided into three <em>décades</em> of 10 days
|
||||
each, followed by 5 complementary days (6 in leap years).</p>
|
||||
<p>The year starts on the day of the autumnal equinox at the Paris Observatory (longitude 2°20′14.03″ E). A
|
||||
leap year follow directly from this definition: a year is a leap year when the next autumnal equinox
|
||||
happens 366 days later instead of the normal 365. By this definition, the year will <b>never</b> drift
|
||||
with respect to the seasons.</p>
|
||||
<p>The 12 months are: <em>Vendémiaire</em>, <em>Brumaire</em>, <em>Frimaire</em>, <em>Nivôse</em>, <em>Pluviôse</em>,
|
||||
<em>Ventôse</em>, <em>Germinal</em>, <em>Floréal</em>, <em>Prairial</em>, <em>Messidor</em>, <em>Thermidor</em>,
|
||||
<em>Fructidor.</em> Every three months represent a season, and the endings of the names reflect this
|
||||
fact.</p>
|
||||
<p>The complementary days are: <em>la Fête de la Vertu</em>, <em>la Fête du Génie</em>, <em>la Fête du
|
||||
Travail</em>, <em>la Fête de l'Opinion</em>, <em>la Fête des Récompenses,</em> and <em>la Fête de la
|
||||
Révolution</em> (leap years only).</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">What's so special about this version?</h4>
|
||||
<p class="lead">Most versions of the calendar floating around doesn't use the original definition above.</p>
|
||||
<p>Most versions uses the so-called <em>Romme</em> method for leap years, using the same leap year rules as
|
||||
the Gregorian calendar, i.e. every year divisible by four, except century years not divisible by 400.
|
||||
This method might make sense, except years 3, 7, and 11 were leap years under the original rules and
|
||||
were observed as such in real life, but the <em>Romme</em> method instead makes years 4, 8, 12 leap
|
||||
years instead.</p>
|
||||
<p>This version uses the original rules. The <a href="https://ssd.jpl.nasa.gov/planets/eph_export.html">JPL's
|
||||
DE440 and DE441 ephemerides</a> were used to calculate the exact timings of the autumnal equinoxes
|
||||
between the Gregorian years 13201 BCE and 17191 CE (corresponding to the French Republican years -14991
|
||||
to 15399). The times were then converted to UT1+00:09:21, the exact local time at the Paris Observatory.
|
||||
UT1 was chosen to keep track of the Earth's rotation without having to worry about the issues posed by
|
||||
leap seconds in UTC. Note that due to the uncertainty over
|
||||
<a href="https://en.wikipedia.org/wiki/%CE%94T_(timekeeping)">ΔT</a> — the difference between UT1 and
|
||||
Terrestrial Time (TT) used in the ephemerides — it is theoretically possible for there to be
|
||||
inaccuracies when the equinox occurs very close to midnight.</p>
|
||||
<p>For more details about how I calculated this calendar, please see
|
||||
<a href="https://quantum5.ca/2022/03/09/art-of-time-keeping-part-4-french-republican-calendar/">my blog
|
||||
post on the topic</a>. This is the fourth part of a series on time-keeping, and you are highly
|
||||
encouraged to read the
|
||||
<a href="https://quantum5.ca/2022/02/16/art-of-time-keeping-part-1-years-dates/">first</a>
|
||||
<a href="https://quantum5.ca/2022/02/23/art-of-time-keeping-part-2-time/">three</a>
|
||||
<a href="https://quantum5.ca/2022/03/02/art-of-time-keeping-part-3-astronomy-equinoxes/">parts</a>
|
||||
for a more complete understanding.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">What are those names above the Gregorian date?</h4>
|
||||
<p>Those are the names of the days in the
|
||||
<a href="https://en.wikipedia.org/wiki/French_Republican_calendar#Rural_calendar">rural version of the
|
||||
calendar</a>. This was intended to replace the Catholic Church's calendar of saints, as the French
|
||||
Revolution wanted to reduce the influence of the church. Every day of the year has a unique name
|
||||
associated with the rural economy and these names are supposed to correspond with the season.</p>
|
||||
<p>Every <em>quintidi</em> is named after an animal, every <em>décadi</em> is named after an agricultural
|
||||
tool, and the remaining days are named after various plants or produce. The only exception is the winter
|
||||
month of Nivôse, which has the remaining days named after minerals.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">What are those numbers below the Gregorian date?</h4>
|
||||
<p>The five (or more) numbers separated by dots is the corresponding
|
||||
<a href="https://en.wikipedia.org/wiki/Mesoamerican_Long_Count_calendar">Mesoamerican Long Count
|
||||
calendar</a> date. This is commonly known as the “Mayan calendar.” This calendar is not
|
||||
available for dates before August 11, 3114 BCE (25 Thermidor -4905).</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">What is decimal time?</h4>
|
||||
<p class="lead">Decimal time is a time system used during the French Revolution that divided the day into 10
|
||||
hours, each with 100 minutes, which contained 100 seconds each.</p>
|
||||
<p>The result is 100,000 seconds in one day, compared to the 86,400 seconds with the normal 24-hour
|
||||
system. This makes it very easy to denote time as a decimal fraction of a day. For example, decimal time
|
||||
5:67:72 (around 13:37:31) on January 1, 2000 can be represented as <code>2000-01-01.56772</code>.</p>
|
||||
<p>Also note that each decimal hour is 2.4 normal hours, each decimal minute is 1.44 normal minutes, and
|
||||
each decimal second is 0.864 normal seconds.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<p class="text-muted">Copyright © 2022-<%= new Date().getFullYear() %>
|
||||
<a href="https://quantum5.ca">Quantum</a>.
|
||||
Licensed under <a href="https://www.gnu.org/licenses/agpl-3.0.en.html">GNU AGPLv3</a>.
|
||||
Source code available on <a href="https://github.com/quantum5/qcal">GitHub</a>.<br>
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
<script>
|
||||
(function(r,e,p,u,b,l,i,c){r['GoogleAnalyticsObject']=b;r[b]=r[b]||function(){
|
||||
(r[b].q=r[b].q||[]).push(arguments)},r[b].l=1*new Date();l=e.createElement(p),
|
||||
i=e.getElementsByTagName(p)[0];l.async=1;l.src=u;i.parentNode.insertBefore(l,i)
|
||||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-102581070-4', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 7.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 19 KiB |
Binary file not shown.
Before Width: | Height: | Size: 76 KiB |
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"short_name": "French Republican Calendar",
|
||||
"name": "French Republican Calendar",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "128x128 64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#ff0000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
|
@ -1,3 +0,0 @@
|
|||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
|
@ -1,42 +0,0 @@
|
|||
import React from 'react';
|
||||
import {Calendar} from './Calendar';
|
||||
import {GregorianJumper} from '@common/dateJump';
|
||||
import MonthBasedApp from '@common/ui/MonthBasedApp';
|
||||
import {HaabMonth, HaabYear, jdnHaabExt} from '@common/mayan';
|
||||
import {gregorianJDN} from '@common/gregorian';
|
||||
|
||||
// Not real limitations other than JS number precision.
|
||||
const START_JDN = gregorianJDN(-10_000_000_000_000, 1, 1);
|
||||
const END_JDN = gregorianJDN(10_000_000_000_000, 12, 31);
|
||||
|
||||
export default class App extends MonthBasedApp<HaabYear, HaabMonth> {
|
||||
override parseYearMonth(year: string, month: string) {
|
||||
if (+month < 1 || +month > 19)
|
||||
return null;
|
||||
return {year: +year, month: +month as HaabMonth};
|
||||
}
|
||||
|
||||
override defaultSelector(todayJDN: number) {
|
||||
const {year, month} = jdnHaabExt(todayJDN);
|
||||
return {year, month};
|
||||
}
|
||||
|
||||
goToJDN = (jdn: number) => {
|
||||
const {year, month} = jdnHaabExt(jdn);
|
||||
this.setState({selector: {year, month}});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {selector: {year, month}, todayJDN} = this.state;
|
||||
return <>
|
||||
<Calendar
|
||||
year={year} month={month} todayJDN={todayJDN}
|
||||
onSwitch={(year, month) => this.setState({selector: {year, month}})}/>
|
||||
|
||||
<div className="navigate">
|
||||
<h4>Go to a date</h4>
|
||||
<GregorianJumper minJDN={START_JDN} maxJDN={END_JDN} initialJDN={todayJDN} onJump={this.goToJDN}/>
|
||||
</div>
|
||||
</>;
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
@import 'bootstrap/scss/functions';
|
||||
@import 'bootstrap/scss/variables';
|
||||
@import 'bootstrap/scss/mixins';
|
||||
@import 'bootstrap/scss/forms';
|
||||
@import 'bootstrap/scss/grid';
|
||||
@import 'bootstrap/scss/buttons';
|
||||
@import '@common/ui/consts.scss';
|
||||
@import '@common/ui/MonthBasedCalendar.scss';
|
||||
|
||||
.Day-haabMonth {
|
||||
font-weight: 400;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(xs) {
|
||||
.DayOuter {
|
||||
@include make-col($size: 1, $columns: 2);
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
.DayOuter {
|
||||
@include make-col($size: 1, $columns: 3);
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
.DayOuter {
|
||||
@include make-col($size: 1, $columns: 4);
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
.DayOuter {
|
||||
@include make-col($size: 1, $columns: 6);
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(xxl) {
|
||||
.DayOuter {
|
||||
@include make-col($size: 1, $columns: 8);
|
||||
}
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
import React from 'react';
|
||||
import './Calendar.scss';
|
||||
import {jdnDate} from '@common/gregorian';
|
||||
import {jdnLongCount} from '@common/longCount';
|
||||
import {MonthBasedCalendar} from '@common/ui/MonthBasedCalendar';
|
||||
import {
|
||||
formatLordOfNight, formatTzolkin,
|
||||
HaabDay,
|
||||
haabExtJDN,
|
||||
HaabMonth,
|
||||
haabMonthDays,
|
||||
haabNames,
|
||||
HaabYear,
|
||||
jdnHaabExt,
|
||||
jdnLordOfNight, jdnTzolkin,
|
||||
} from '@common/mayan';
|
||||
|
||||
type MonthProps = {
|
||||
year: HaabYear;
|
||||
month: HaabMonth;
|
||||
};
|
||||
|
||||
type DateProps = MonthProps & {
|
||||
day: HaabDay;
|
||||
};
|
||||
|
||||
function Day({year, month, day, todayJDN}: DateProps & { todayJDN: number }): JSX.Element {
|
||||
const jdn = haabExtJDN({year, month, day});
|
||||
return <div className={`Day ${jdn === todayJDN ? 'Day-today' : ''}`}>
|
||||
<div className="Day-name">{day}<span className="Day-haabMonth"> {haabNames[month]}</span></div>
|
||||
<div className="Day-tzolkin">{formatTzolkin(jdnTzolkin(jdn))}</div>
|
||||
<div className="Day-lc">{jdnLongCount(jdn)?.join('.')}</div>
|
||||
<div className="Day-lordOfNight">{formatLordOfNight(jdnLordOfNight(jdn))}</div>
|
||||
<div className="Day-gregorian">{jdnDate(jdn).toDateString()}</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
function Month({year, month, todayJDN}: MonthProps & { todayJDN: number }): JSX.Element {
|
||||
return <div className="Month">
|
||||
<div className="Month-days">{
|
||||
Array.from(Array(haabMonthDays(month)).keys()).map(i => <div key={i} className="DayOuter">
|
||||
<Day year={year} month={month} day={i + 1 as HaabDay} todayJDN={todayJDN}/>
|
||||
</div>)
|
||||
}</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
export class Calendar extends MonthBasedCalendar<HaabYear, HaabMonth> {
|
||||
override parseYear(year: string): HaabYear {
|
||||
return +year;
|
||||
}
|
||||
|
||||
override parseMonth(month: string): HaabMonth {
|
||||
return +month as HaabMonth;
|
||||
}
|
||||
|
||||
override yearToString(year: HaabYear): string {
|
||||
return year.toString();
|
||||
}
|
||||
|
||||
override monthToString(month: HaabMonth): string {
|
||||
return month.toString();
|
||||
}
|
||||
|
||||
private goToNormalized(year: number, month: number) {
|
||||
while (month < 1) {
|
||||
--year;
|
||||
month += 19;
|
||||
}
|
||||
|
||||
while (month > 19) {
|
||||
++year;
|
||||
month -= 19;
|
||||
}
|
||||
|
||||
this.goTo(year, month as HaabMonth);
|
||||
}
|
||||
|
||||
override prevYear = () => {
|
||||
this.goToNormalized(this.props.year - 1, this.props.month);
|
||||
};
|
||||
|
||||
override prevMonth = () => {
|
||||
this.goToNormalized(this.props.year, this.props.month - 1);
|
||||
};
|
||||
|
||||
override nextYear = () => {
|
||||
this.goToNormalized(this.props.year + 1, this.props.month);
|
||||
};
|
||||
|
||||
override nextMonth = () => {
|
||||
this.goToNormalized(this.props.year, this.props.month + 1);
|
||||
};
|
||||
|
||||
override isValidYear(year: string): boolean {
|
||||
return /^-?\d+/.test(year);
|
||||
}
|
||||
|
||||
override jdnLookup(jdn: number): { year: HaabYear; month: HaabMonth } {
|
||||
return jdnHaabExt(jdn);
|
||||
}
|
||||
|
||||
override monthName(year: HaabYear, month: HaabMonth): string {
|
||||
return `${haabNames[month]} ${year}`;
|
||||
}
|
||||
|
||||
override renderMonthOptions(): JSX.Element[] {
|
||||
return Array.from(Array(19).keys()).map(i => {
|
||||
const month = i + 1 as HaabMonth;
|
||||
return <option key={i} value={month}>{haabNames[month]}</option>;
|
||||
});
|
||||
}
|
||||
|
||||
override renderBody(): JSX.Element {
|
||||
return <Month year={this.props.year} month={this.props.month} todayJDN={this.props.todayJDN}/>;
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
@import '@common/ui/index.scss';
|
||||
|
||||
.download {
|
||||
max-width: $calendar-width;
|
||||
margin-top: $spacer;
|
||||
@include make-container();
|
||||
|
||||
.input-group-text {
|
||||
width: 6em;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
max-width: 5em;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
.download form {
|
||||
display: flex;
|
||||
|
||||
.input-group {
|
||||
width: fit-content;
|
||||
margin-right: $spacer / 2;
|
||||
}
|
||||
|
||||
.input-group-text {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import 'bootstrap/js/dist/collapse';
|
||||
import './index.scss';
|
||||
import App from './App';
|
||||
import reportWebVitals from '@common/ui/reportWebVitals';
|
||||
import {MobileTooltipProvider} from '@common/ui/MobileTooltip';
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<MobileTooltipProvider>
|
||||
<App/>
|
||||
</MobileTooltipProvider>
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root'),
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
1
mcal/src/react-app-env.d.ts
vendored
1
mcal/src/react-app-env.d.ts
vendored
|
@ -1 +0,0 @@
|
|||
/// <reference types="react-scripts" />
|
|
@ -1,5 +0,0 @@
|
|||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"extends": "./tsconfig.paths.json",
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@common/*": ["../common/src/*"]
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue