﻿<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text" xml:lang="en">mfgames-culture-js</title>
  <link type="application/atom+xml" href="https://d.moonfire.us/tags/mfgames-culture-js/atom.xml" rel="self" />
  <link type="text/html" href="https://d.moonfire.us/tags/mfgames-culture-js/" rel="alternate" />
  <updated>2026-03-09T17:42:47Z</updated>
  <id>https://d.moonfire.us/tags/mfgames-culture-js/</id>
  <author>
    <name>D. Moonfire</name>
  </author>
  <rights>Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International</rights>
  <entry>
    <title>Changes to MfGames Culture</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2017/07/17/mfgames-culture/" />
    <updated>2017-07-17T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2017/07/17/mfgames-culture/</id>
    <category term="programming" scheme="https://d.moonfire.us/categories/" label="Programming" />
    <category term="fedran" scheme="https://d.moonfire.us/tags/" label="Fedran" />
    <category term="mfgames-culture" scheme="https://d.moonfire.us/tags/" label="mfgames-culture" />
    <category term="mfgames-culture-js" scheme="https://d.moonfire.us/tags/" label="mfgames-culture-js" />
    <summary type="html">In the process of [updating my website](/blog/2017/07/16/website-improvements/), I ended up doing significant amount of work on my arbitrary culture library, [mfgames-culture](https://gitlab.com/mfgames-culture/).</summary>
    <content type="html">&lt;p&gt;In the process of &lt;a href="/blog/2017/07/16/website-improvements/"&gt;updating my website&lt;/a&gt;, I ended up doing significant amount of work on my arbitrary culture library, &lt;a href="https://gitlab.com/mfgames-culture/"&gt;mfgames-culture&lt;/a&gt;. This was used to let me enter the events and dates in a world-specific formats (such as &amp;lsquo;1454/7/41 MTR 17::61&amp;rsquo;) and convert them into other formats (including the ISO standard used by the timeline library, &lt;a href="http://visjs.org/docs/timeline/"&gt;vis.js&lt;/a&gt;).&lt;/p&gt;
&lt;h1&gt;Why Arbitrary?&lt;/h1&gt;
&lt;p&gt;I can't find the page where I talk about the reason &lt;em&gt;why&lt;/em&gt; I'm creating this library, so I'll give a brief run down. In the process of creating world-specific calendars (such as &lt;a href="/blog/2013/09/21/mansupi-tachira-ripochya-solar-calendar/"&gt;here&lt;/a&gt; and &lt;a href="/blog/2015/01/01/tarsan-standard-calendar/"&gt;here&lt;/a&gt;), I don't base all the work off the Gregorian calendar. Instead, I built it up from the ground-up based on the culture, keeping in mind their politics, holy numbers, and other elements.&lt;/p&gt;
&lt;p&gt;This creates a good flavor for the world but makes it difficult to create a good timeline for a novel or the world. Most organization programs don't work outside of Gregorian calendars or formats. That means I have a choice of ignoring my world-specific elements for tracking purposes or find some way of making those in-world calendars to work.&lt;/p&gt;
&lt;p&gt;That is the crux of &lt;em&gt;mfgames-culture&lt;/em&gt;, to create an API and tools for working with arbitrary cultures that are described purely with data files. Eventually, I'll have other versions of this but I'm using the &lt;a href="https://gitlab.com/mfgames-culture/mfgames-culture-js/"&gt;Typescript&lt;/a&gt; library as the reference implementation.&lt;/p&gt;
&lt;h1&gt;Examples&lt;/h1&gt;
&lt;p&gt;Below are some examples using a command-line program that uses the library. I also have an alias that uses my own culture information.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ sudo npm install --global mfgames-culture-cli
$ alias fedran=&amp;quot;mfgames-culture --culture=kyo --data=$SRC/fedran-culture-data/dist&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Parsing&lt;/h1&gt;
&lt;p&gt;Right now, I'm only focusing on dates and times. There are two parts: the structure and the appearance. The structure is the components of the calendar, such as there are twelve months in a year, 28-31 days in a month, one hundred years is called a &amp;ldquo;century&amp;rdquo;. The appearance is how those components are formatted, such as the US using &lt;code&gt;MM/DD/YYYY&lt;/code&gt; but the UK uses &lt;code&gt;DD/MM/YYYY&lt;/code&gt;. It is the same calendar (structure) but different names for months.&lt;/p&gt;
&lt;p&gt;The basic idea of the library is to take a &lt;a href="https://gitlab.com/mfgames-culture/mfgames-culture-data/blob/master/data/gregorian.json"&gt;JSON&lt;/a&gt; or YAML file that describes a calendar and provide an API for using it like many other calendar libraries, such as &lt;a href="https://momentjs.com/"&gt;moment.js&lt;/a&gt;. It doesn't many any assumptions of about how many months, days, or even seconds in a day. Instead, everything is calculated based on the file and it produces a rich object that contains that information.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ mfgames-culture parse 7/7/2017 --indent 2
{
  &amp;quot;julian&amp;quot;: 2457941.5,
  &amp;quot;type&amp;quot;: &amp;quot;instant&amp;quot;,
  &amp;quot;year&amp;quot;: 2017,
  &amp;quot;century&amp;quot;: 20,
  &amp;quot;millenniumCentury&amp;quot;: 0,
  &amp;quot;decade&amp;quot;: 201,
  &amp;quot;centuryDecade&amp;quot;: 1,
  &amp;quot;centuryYear&amp;quot;: 17,
  &amp;quot;decadeYear&amp;quot;: 7,
  &amp;quot;millennium&amp;quot;: 2,
  &amp;quot;yearDay&amp;quot;: 187,
  &amp;quot;yearMonth&amp;quot;: 6,
  &amp;quot;monthDay&amp;quot;: 6,
  &amp;quot;hour24&amp;quot;: 0,
  &amp;quot;meridiem&amp;quot;: 0,
  &amp;quot;hour12&amp;quot;: 0,
  &amp;quot;hourMinute&amp;quot;: 0,
  &amp;quot;minuteSecond&amp;quot;: 0
}
$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, I need to be able to do the same with my in-world calendar.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ fedran parse &amp;quot;1454/7/41 MTR 17::61&amp;quot; --no-json --yaml
julian: 2383794.0875
type: instant
mochyu: 1454
mochyuRote: 317
mochyuRichi: 6
richiRote: 40
koga: 16
mugi: 60
bidashu: 0
$
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Data Files&lt;/h1&gt;
&lt;p&gt;In both examples, the data files are located somewhere the CLI can find it. In the first case, the files from &lt;a href="https://gitlab.com/mfgames-culture/mfgames-culture-data"&gt;mfgames-culture-data&lt;/a&gt; are packaged with the utility. For the Fedran data, you can find it &lt;a href="https://gitlab.com/fedran/fedran-culture-data/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to download them somewhere, they are just NPM packages.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ npm install mfgames-culture-data fedran-culture-data
$ ls node_modules/mfgames-culture-data/dist/
combined.json        duodecimal-period.json      gregorian.json
combined.min.json    duodecimal-period.min.json  gregorian.min.json
duodecimal.json      en-US.json                  index.json
duodecimal.min.json  en-US.min.json              index.min.json
$ ls node_modules/fedran-culture-data/dist/
combined.json                      mifuno-kopachi-period.json
combined.min.json                  mifuno-kopachi-period.min.json
index.json                         natural.json
index.min.json                     natural.min.json
kyo.json                           seasons.json
kyo.min.json                       seasons.min.json
mansupi-tachira-ripochya.json      tar.json
mansupi-tachira-ripochya.min.json  tar.min.json
mifuno-kopachi.json                tarsan-standard-calendar.json
mifuno-kopachi.min.json            tarsan-standard-calendar.min.json
$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you are curious why I have the data files as npm packages, I decided to make it easier to version them so the website won't break until I'm ready to upload it. Not to mention, &lt;a href="http://semver.org/"&gt;semantic versions&lt;/a&gt; is useful for more than libraries.&lt;/p&gt;
&lt;h1&gt;Calendars&lt;/h1&gt;
&lt;p&gt;I'm not going to go into too much directions of how to create the format. I have decent &lt;a href="https://gitlab.com/mfgames-culture/mfgames-culture-data/blob/master/docs/index.md"&gt;documentation&lt;/a&gt; on the purpose and setup.&lt;/p&gt;
&lt;p&gt;The main part is a calendar consists of cycles. For example, the Gregorian is based on a year. A month is calculated from days within a year and decades are a formula based on decades. The system recursively goes through these cycles to figure out the individual amounts that you saw above.&lt;/p&gt;
&lt;h1&gt;Cultures&lt;/h1&gt;
&lt;p&gt;Cultures are where dates (instants) and periods (durations) are formatted. A culture has many ways of formatting any given instant, once you have one, you can pull it out in a variety of ways.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ mfgames-culture format &amp;quot;2017-07-14 23:19:04&amp;quot; --output-style markdown-table
| format                | results                      |
| --------------------- | ---------------------------- |
| JD                    | 2457949.47157407407407407407 |
| M/D/YYYY              | 7/14/2017                    |
| M/D/YYYY h:mm tt      | 7/14/2017 11:19 PM           |
| MM/DD/YYYY            | 07/14/2017                   |
| MM/DD/YYYY h:mm:ss tt | 07/14/2017 11:19:04 PM       |
| MMM DD, YY            | Jul 14, 17                   |
| YYYY-MM-DD            | 2017-07-14                   |
| YYYY-MM-DD HH:mm:ss   | 2017-07-14 23:19:04          |
| default               | 7/14/2017 11:19 PM           |
| h:mm tt               | 11:19 PM                     |
| shortDate             | 7/14/2017                    |
| shortDateTime         | 7/14/2017 11:19 PM           |
| shortTime             | 11:19 PM                     |
$ mfgames-culture format &amp;quot;2017-07-14 23:19:04&amp;quot; --output-format shortDateTime
7/14/2017 11:19 PM
$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, this can be done with my fantasy calendar also.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-shell"&gt;$ fedran format &amp;quot;1454/7/41 MTR 17::61&amp;quot; --output-style markdown-table
| format              | results                |
| ------------------- | ---------------------- |
| JD                  | 2383794.0875           |
| YYYY                | 1454                   |
| YYYY MTR            | 1454 MTR               |
| YYYY/OOO            | 1454/318               |
| YYYY/OOO K::        | 1454/318 17::          |
| YYYY/OOO K::M       | 1454/318 17::61        |
| YYYY/OOO K::M:B     | 1454/318 17::61:1      |
| YYYY/OOO MTR        | 1454/318 MTR           |
| YYYY/OOO MTR K::    | 1454/318 MTR 17::      |
| YYYY/OOO MTR K::M   | 1454/318 MTR 17::61    |
| YYYY/OOO MTR K::M:B | 1454/318 MTR 17::61:1  |
| YYYY/R              | 1454/7                 |
| YYYY/R MTR          | 1454/7 MTR             |
| YYYY/R/O            | 1454/7/41              |
| YYYY/R/O K::        | 1454/7/41 17::         |
| YYYY/R/O K::M       | 1454/7/41 17::61       |
| YYYY/R/O K::M:B     | 1454/7/41 17::61:1     |
| YYYY/R/O MTR        | 1454/7/41 MTR          |
| YYYY/R/O MTR K::    | 1454/7/41 MTR 17::     |
| YYYY/R/O MTR K::M   | 1454/7/41 MTR 17::61   |
| YYYY/R/O MTR K::M:B | 1454/7/41 MTR 17::61:1 |
| default             | 1454/7/41 17::61       |
| shortDate           | 1454/7/41              |
| shortDateTime       | 1454/7/41 17::61       |
| shortTime           | 17::61                 |
$ fedran format &amp;quot;1454/7/41 MTR 17::61&amp;quot; --output-format shortDateTime
1454/7/41 17::61
$
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Typescript/Javascript&lt;/h1&gt;
&lt;p&gt;These libraries can also be used directly. This is how I implemented the &lt;a href="https://fedran.com/timeline/"&gt;timeline&lt;/a&gt; on my website. It is also used by the build process to create the date/time tooltips like you can see on &lt;a href="https://fedran.com/rutejimo/"&gt;Rutejìmo's&lt;/a&gt; page.&lt;/p&gt;
&lt;p&gt;The first part is to load a culture.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-typescript"&gt;import * as mfgamesCulture from &amp;quot;mfgames-culture&amp;quot;;
import * as mfgamesCultureData from &amp;quot;mfgames-culture-data&amp;quot;;

// Create a data provider for the basic culture data. The entire JSON files is
// exported as `.combined` which is passed into the property provider.
var provider = new mfgamesCulture.PropertyCultureDataProvider(
    mfgamesCultureData.combined
);
var cultureData = provider.getCultureSync(&amp;quot;en-US&amp;quot;);
var culture = new mfgamesCulture.Culture(cultureData);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(There is a promise version in &lt;code&gt;getCulturePromise&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Once a culture is loaded, it can be used to create an in-memory representation of a format described in the culture file. A single point in time is called an &lt;code&gt;instant&lt;/code&gt; and a range of time is called a &lt;code&gt;period&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-typescript"&gt;var instant = culture.parseInstant(&amp;quot;2015-01-02 13:14:15&amp;quot;);
console.log(instant);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This produces an output of:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json"&gt;{ julian:
   { [String: '2457025.0515625']
     s: 1,
     e: 6,
     c: [ 2, 4, 5, 7, 0, 2, 5, 0, 5, 1, 5, 6, 2, 5 ],
     constructor: { [Function: Big] DP: 20, RM: 1, E_NEG: -7, E_POS: 21 } },
  type: 'instant',
  year: 2015,
  century: 20,
  millenniumCentury: 0,
  decade: 201,
  centuryDecade: 1,
  centuryYear: 15,
  decadeYear: 5,
  millennium: 2,
  yearDay: 1,
  yearMonth: 0,
  monthDay: 1,
  hour24: 13,
  meridiem: 1,
  hour12: 1,
  hourMinute: 14,
  minuteSecond: 15 }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It can also be used to format results.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-typescript"&gt;var format = culture.formatInstant(instant, &amp;quot;YYYY-MM-DD HH:mm:ss&amp;quot;);
console.log(format);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;... which produces:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2015-01-02 13:14:15
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get the timeline page, I basically parse the in-world dates, convert them to Julian Dates (using the &lt;code&gt;JD&lt;/code&gt; format), then use that number to figure out the ISO date and time. Then I override the labels to take the Gregorian date and convert it back to the in-world dates so the reader never sees how I use Gregorian as the intermediary format.&lt;/p&gt;
&lt;p&gt;This is why I also have every instant also figure out an effective Julian Date. That way, I can convert between any instant, even between multiple cultures.&lt;/p&gt;
</content>
  </entry>
</feed>
